├── .gitignore
├── Gruntfile.js
├── README.md
├── assets
├── images
│ └── toolbar
│ │ ├── brackets
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ └── 4.png
│ │ ├── button
│ │ ├── brackets.png
│ │ ├── frac.png
│ │ ├── pi.png
│ │ ├── script.png
│ │ ├── sqrt.png
│ │ └── tick.png
│ │ ├── char
│ │ ├── greek
│ │ │ ├── alpha.png
│ │ │ ├── beta.png
│ │ │ ├── chi.png
│ │ │ ├── delta.png
│ │ │ ├── epsilon.png
│ │ │ ├── eta.png
│ │ │ ├── gamma.png
│ │ │ ├── iota.png
│ │ │ ├── kappa.png
│ │ │ ├── lambda.png
│ │ │ ├── mu.png
│ │ │ ├── nu.png
│ │ │ ├── omega.png
│ │ │ ├── omicron.png
│ │ │ ├── phi.png
│ │ │ ├── pi.png
│ │ │ ├── psi.png
│ │ │ ├── rho.png
│ │ │ ├── sigma.png
│ │ │ ├── tau.png
│ │ │ ├── theta.png
│ │ │ ├── upsilon.png
│ │ │ ├── xi.png
│ │ │ └── zeta.png
│ │ └── math
│ │ │ ├── div.png
│ │ │ ├── eq.png
│ │ │ ├── equiv.png
│ │ │ ├── geq.png
│ │ │ ├── gg.png
│ │ │ ├── gt.png
│ │ │ ├── infty.png
│ │ │ ├── leq.png
│ │ │ ├── ll.png
│ │ │ ├── lt.png
│ │ │ ├── mp.png
│ │ │ ├── pm.png
│ │ │ ├── sim.png
│ │ │ ├── simeq.png
│ │ │ ├── tanhao.png
│ │ │ └── times.png
│ │ ├── frac
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── c1.png
│ │ ├── c2.png
│ │ ├── c4.png
│ │ └── c5.png
│ │ ├── script
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── c1.png
│ │ ├── c2.png
│ │ └── c3.png
│ │ ├── sqrt
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── c1.png
│ │ └── c2.png
│ │ └── ys
│ │ ├── 1.png
│ │ ├── 2.png
│ │ └── 3.png
└── styles
│ ├── base.css
│ ├── page.css
│ └── ui.css
├── c.js
├── dev-lib
├── cmd-define.js
├── dev-define.js
├── dev-start.js
├── exports.js
├── jquery-1.11.0.min.js
├── kity-formula.all.js
├── kity-formula.all.min.js
├── kityformula-parser.all.js
├── kityformula-parser.all.min.js
├── kitygraph.all.js
├── kitygraph.all.min.js
├── sea-debug.js
├── sea.js
└── sea.js.map
├── dist
├── kf-editor.all.js
└── kf-editor.all.min.js
├── index.html
├── package.json
└── src
├── base
├── common.js
├── event
│ ├── event.js
│ └── kfevent.js
└── utils.js
├── editor
└── editor.js
├── jquery.js
├── kf-ext
├── def.js
├── expression
│ └── placeholder.js
├── extension.js
└── operator
│ └── placeholder.js
├── kf.js
├── kity.js
├── parse
├── def.js
└── parser.js
├── position
└── position.js
├── render
└── render.js
├── syntax
├── move.js
└── syntax.js
└── ui
├── control
└── zoom.js
├── toolbar-ele-list.js
├── toolbar
└── toolbar.js
├── ui-impl
├── area.js
├── box.js
├── button.js
├── def
│ ├── box-type.js
│ ├── ele-type.js
│ └── item-type.js
├── delimiter.js
├── drapdown-box.js
├── list.js
├── ui-utils.js
└── ui.js
└── ui.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.sublime-project
3 | *.sublime-workspace
4 | *.node_module
5 | node_modules
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*global module:false*/
2 | module.exports = function (grunt) {
3 |
4 | // Project configuration.
5 | grunt.initConfig({
6 |
7 | // Metadata.
8 | pkg: grunt.file.readJSON('package.json'),
9 |
10 | // Task configuration.
11 | "transport": {
12 |
13 | options: {
14 |
15 | // module path
16 | paths: [ 'src' ],
17 | debug: false
18 |
19 | },
20 |
21 | cmd: {
22 |
23 | files: [ {
24 |
25 | cwd: 'src',
26 | src: '**/*.js',
27 | dest: '.build_tmp'
28 |
29 | } ]
30 |
31 | }
32 |
33 | },
34 |
35 | concat: {
36 |
37 | options: {
38 |
39 | paths: [ 'src' ],
40 | include: 'all',
41 | noncmd: true
42 |
43 | },
44 |
45 | cmd: {
46 |
47 | files: {
48 | '.build_tmp/kf-editor-o.js': '.build_tmp/**/*.js'
49 | }
50 |
51 | },
52 |
53 | full: {
54 |
55 | options: {
56 |
57 | banner: '/*!\n' +
58 | ' * ====================================================\n' +
59 | ' * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
60 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
61 | '<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
62 | ' * GitHub: <%= pkg.repository.url %> \n' +
63 | ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
64 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n' +
65 | ' * ====================================================\n' +
66 | ' */\n\n' +
67 | '(function () {\n',
68 |
69 | footer: '})();'
70 |
71 | },
72 |
73 | files: {
74 | 'dist/kf-editor.all.js': [ 'dev-lib/cmd-define.js', '.build_tmp/kf-editor-o.js', 'dev-lib/exports.js' ]
75 | }
76 |
77 | }
78 |
79 | },
80 |
81 | uglify: {
82 |
83 | options: {
84 |
85 | banner: '/*!\n' +
86 | ' * ====================================================\n' +
87 | ' * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
88 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
89 | '<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
90 | ' * GitHub: <%= pkg.repository.url %> \n' +
91 | ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
92 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n' +
93 | ' * ====================================================\n' +
94 | ' */\n'
95 |
96 | },
97 |
98 | minimize: {
99 |
100 | files: {
101 | 'dist/kf-editor.all.min.js': 'dist/kf-editor.all.js'
102 | }
103 |
104 | }
105 |
106 | },
107 |
108 | clean: {
109 |
110 | tmp: [ '.build_tmp' ]
111 |
112 | }
113 |
114 | });
115 |
116 | // These plugins provide necessary tasks.
117 | grunt.loadNpmTasks( 'grunt-cmd-transport' );
118 | grunt.loadNpmTasks( 'grunt-cmd-concat' );
119 | grunt.loadNpmTasks('grunt-contrib-uglify');
120 | grunt.loadNpmTasks('grunt-contrib-clean');
121 |
122 | // Default task.
123 | grunt.registerTask( 'default', [ 'transport:cmd', 'concat:cmd', 'concat:full', 'uglify:minimize', 'clean:tmp' ] );
124 |
125 | };
126 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | KityFormula Editor
2 | =======
3 | 基于 SVG 的公式编辑器,百度前端富应用小组开发
4 |
5 | 当前文档工作未完善,有疑惑之处请发邮件联系我们。
6 |
7 | email:kity@baidu.com
--------------------------------------------------------------------------------
/assets/images/toolbar/brackets/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/brackets/1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/brackets/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/brackets/2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/brackets/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/brackets/3.png
--------------------------------------------------------------------------------
/assets/images/toolbar/brackets/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/brackets/4.png
--------------------------------------------------------------------------------
/assets/images/toolbar/button/brackets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/button/brackets.png
--------------------------------------------------------------------------------
/assets/images/toolbar/button/frac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/button/frac.png
--------------------------------------------------------------------------------
/assets/images/toolbar/button/pi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/button/pi.png
--------------------------------------------------------------------------------
/assets/images/toolbar/button/script.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/button/script.png
--------------------------------------------------------------------------------
/assets/images/toolbar/button/sqrt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/button/sqrt.png
--------------------------------------------------------------------------------
/assets/images/toolbar/button/tick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/button/tick.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/alpha.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/beta.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/chi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/chi.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/delta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/delta.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/epsilon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/epsilon.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/eta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/eta.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/gamma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/gamma.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/iota.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/iota.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/kappa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/kappa.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/lambda.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/lambda.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/mu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/mu.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/nu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/nu.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/omega.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/omega.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/omicron.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/omicron.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/phi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/phi.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/pi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/pi.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/psi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/psi.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/rho.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/rho.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/sigma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/sigma.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/tau.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/tau.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/theta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/theta.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/upsilon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/upsilon.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/xi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/xi.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/greek/zeta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/greek/zeta.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/div.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/div.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/eq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/eq.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/equiv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/equiv.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/geq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/geq.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/gg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/gg.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/gt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/gt.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/infty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/infty.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/leq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/leq.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/ll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/ll.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/lt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/lt.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/mp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/mp.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/pm.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/sim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/sim.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/simeq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/simeq.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/tanhao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/tanhao.png
--------------------------------------------------------------------------------
/assets/images/toolbar/char/math/times.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/char/math/times.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/3.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/c1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/c1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/c2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/c2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/c4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/c4.png
--------------------------------------------------------------------------------
/assets/images/toolbar/frac/c5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/frac/c5.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/3.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/4.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/c1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/c1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/c2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/c2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/script/c3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/script/c3.png
--------------------------------------------------------------------------------
/assets/images/toolbar/sqrt/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/sqrt/1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/sqrt/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/sqrt/2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/sqrt/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/sqrt/3.png
--------------------------------------------------------------------------------
/assets/images/toolbar/sqrt/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/sqrt/4.png
--------------------------------------------------------------------------------
/assets/images/toolbar/sqrt/c1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/sqrt/c1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/sqrt/c2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/sqrt/c2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/ys/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/ys/1.png
--------------------------------------------------------------------------------
/assets/images/toolbar/ys/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/ys/2.png
--------------------------------------------------------------------------------
/assets/images/toolbar/ys/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fex-team/kityformula-editor/365b8cf7a674ba7b7f4bdc53a392c7c026856908/assets/images/toolbar/ys/3.png
--------------------------------------------------------------------------------
/assets/styles/base.css:
--------------------------------------------------------------------------------
1 |
2 | .kf-editor {
3 | width: 100%;
4 | height: 100%;
5 |
6 | position: fixed;
7 | top: 0;
8 | left: 0;
9 |
10 | overflow: hidden;
11 | z-index: 2;
12 | }
13 |
14 | .kf-editor-toolbar {
15 | width: 100%;
16 | height: 80px;
17 | padding: 5px;
18 | background: -webkit-linear-gradient(top, white, white 60%, rgba(248, 248, 248, 0.72) 80%, rgba(218, 218, 218, 0.72));
19 | position: absolute;
20 | top: 0;
21 | left: 0;
22 | z-index: 3;
23 | }
24 |
25 | .kf-editor-edit-area {
26 | position: relative;
27 | top: 0;
28 | left: 0;
29 |
30 | z-index: 2;
31 | /*background-color: white;*/
32 | /*background-size: 21px 21px;*/
33 | /*background-position: 0 0,10px 10px;*/
34 | /*background-image: -webkit-linear-gradient(45deg,#efefef 25%,transparent 25%,transparent 75%,#efefef 75%,#efefef),-webkit-linear-gradient(45deg,#efefef 25%,transparent 25%,transparent 75%,#efefef 75%,#efefef);*/
35 | /*background-image: linear-gradient(45deg,#efefef 25%,transparent 25%,transparent 75%,#efefef 75%,#efefef),linear-gradient(45deg,#efefef 25%,transparent 25%,transparent 75%,#efefef 75%,#efefef);*/
36 | }
37 |
38 | .kf-editor-input-box {
39 | width: 1000px;
40 | position: fixed;
41 | top: 0;
42 | left: 0;
43 | z-index: 999999;
44 | }
--------------------------------------------------------------------------------
/assets/styles/page.css:
--------------------------------------------------------------------------------
1 |
2 | html, body {
3 | width: 100%;
4 | height: 100%;
5 | padding: 0;
6 | margin: 0;
7 | }
--------------------------------------------------------------------------------
/assets/styles/ui.css:
--------------------------------------------------------------------------------
1 | /* 按钮 */
2 | .kf-editor-ui-button {
3 | width: 50px;
4 | height: 100%;
5 | font-size: 10px;
6 | display: inline-block;
7 | border: 1px solid transparent;
8 | cursor: default;
9 | position: relative;
10 | top: 0;
11 | left: 0;
12 | vertical-align: top;
13 | }
14 |
15 | .kf-editor-ui-overlap-button {
16 | width: 100%;
17 | background: #8f8f8f;
18 | position: relative;
19 | top: 0;
20 | left: 0;
21 | z-index: 2;
22 | }
23 |
24 | .kf-editor-ui-button-icon {
25 | width: 32px;
26 | height: 32px;
27 | margin: 2px auto;
28 | }
29 |
30 | .kf-editor-ui-button-label {
31 | text-align: center;
32 | display: block;
33 | padding: 8px 0;
34 | }
35 |
36 | .kf-editor-ui-overlap-button .kf-editor-ui-button-label {
37 | padding: 5px 5px;
38 | text-align: left;
39 | color: white;
40 | font-size: 14px;
41 | }
42 |
43 | .kf-editor-ui-overlap-button .kf-editor-ui-button-label:HOVER {
44 | color: #ffbf00;
45 | }
46 |
47 | .kf-editor-ui-button-sign {
48 | border: 5px solid transparent;
49 | border-top-color: #2d2d2d;
50 | width: 0;
51 | height: 0;
52 | margin: 0 auto;
53 | }
54 |
55 | .kf-editor-ui-button-mount-point {
56 | display: none;
57 | position: absolute;
58 | top: 81px;
59 | left: -1px;
60 | }
61 |
62 | .kf-editor-ui-overlap-button .kf-editor-ui-button-mount-point {
63 | width: 100%;
64 | height: 1000px;
65 | }
66 |
67 | .kf-editor-ui-overlap-button .kf-editor-ui-button-mount-point {
68 | top: 27px;
69 | }
70 |
71 | .kf-editor-ui-button:HOVER {
72 | background: -webkit-linear-gradient( top, rgba(255, 180, 11, 0.41), rgba(255, 180, 11, 0.61), rgba(255, 180, 11, 0.41) );
73 | border: 1px solid #ffbf00;
74 | box-shadow: inset 0 0 1px 1px white;
75 | }
76 |
77 | .kf-editor-ui-overlap-button:HOVER {
78 | background: #8f8f8f;
79 | border-color: transparent;
80 | box-shadow: none;
81 | }
82 |
83 | .kf-editor-ui-overlap-button.kf-editor-ui-button-in {
84 | background: #8f8f8f!important;
85 | border-color: transparent!important;
86 | box-shadow: none!important;
87 | }
88 |
89 | .kf-editor-toolbar .kf-editor-ui-button-in {
90 | background: -webkit-linear-gradient( top, rgba(255, 180, 30, 0.81), rgba(255, 177, 24, 0.91), rgba(255, 180, 30, 0.81) );
91 | border-color: #b88212;
92 | box-shadow: none;
93 | }
94 |
95 | /* 分割符 */
96 | .kf-editor-ui-delimiter {
97 | width: 11px;
98 | height: 100%;
99 | display: inline-block;
100 | }
101 |
102 | .kf-editor-ui-delimiter-line {
103 | width: 1px;
104 | height: 100%;
105 | margin: 0 auto;
106 | background: -webkit-linear-gradient(top, rgba(233, 233, 233, 0.11), rgba(92, 92, 92, 0.20) 60%, rgba(92, 92, 92, 0.41) 80%, rgba(123, 123, 123, 0.50));
107 | }
108 |
109 | /* box */
110 | .kf-editor-ui-box {
111 | border: 1px solid #c2c2c2;
112 | box-shadow: 2px 2px 2px 2px rgba(0, 0, 0, 0.13);
113 | background: white;
114 | }
115 |
116 | .kf-editor-ui-box-group-title {
117 | background: #e1e1e1;
118 | padding: 5px;
119 | }
120 |
121 | .kf-editor-ui-box-group-item-container {
122 | padding: 5px;
123 | }
124 |
125 | .kf-editor-ui-overlap-container {
126 | overflow: hidden;
127 | }
128 |
129 | .kf-editor-ui-box-item {
130 | border: 1px solid transparent;
131 | padding: 5px;
132 | display: inline-block;
133 | }
134 |
135 | .kf-editor-ui-box-item:HOVER {
136 | background: -webkit-linear-gradient( top, rgba(255, 180, 11, 0.41), rgba(255, 180, 11, 0.61), rgba(255, 180, 11, 0.41) );
137 | border: 1px solid #ffbf00;
138 | box-shadow: inset 0 0 1px 1px white;
139 | }
140 |
141 | .kf-editor-ui-area .kf-editor-ui-box-item {
142 | position: relative;
143 | top: 0;
144 | left: 0;
145 | width: 32px;
146 | height: 32px;
147 | border: 0;
148 | margin: 0 5px 5px 0;
149 | padding: 0;
150 | z-index: 1;
151 | }
152 |
153 | .kf-editor-ui-area .kf-editor-ui-box-item img {
154 | width: 32px;
155 | height: 32px;
156 | }
157 |
158 |
159 | .kf-editor-ui-box-item-label {
160 | margin-bottom: 5px;
161 | }
162 |
163 | .kf-editor-ui-box-item-content {
164 | background: white;
165 | border: 1px solid black;
166 | }
167 |
168 | .kf-editor-ui-area .kf-editor-ui-box-item-content {
169 | position: absolute;
170 | top: 0;
171 | left: 0;
172 | }
173 |
174 | .kf-editor-ui-area .kf-editor-ui-box-item-content:HOVER {
175 | border: 2px solid #ffbd19;
176 | top: -1px;
177 | left: -1px;
178 | }
179 |
180 | .kf-editor-ui-box-item-val {
181 | padding: 5px;
182 | margin-bottom: 5px;
183 | line-height: 0;
184 | }
185 |
186 | .kf-editor-ui-area .kf-editor-ui-box-item-val {
187 | padding: 0;
188 | margin: 0;
189 | }
190 |
191 | /* area */
192 | .kf-editor-ui-area {
193 | height: 90%;
194 | display: inline-block;
195 | cursor: default;
196 | position: relative;
197 | top: 0;
198 | left: 0;
199 | vertical-align: top;
200 | }
201 |
202 | .kf-editor-ui-area-container {
203 | width: 510px;
204 | height: 100%;
205 | display: inline-block;
206 | border: 1px solid #D3D3D3;
207 | border-right: 0;
208 | vertical-align: top;
209 | }
210 |
211 | .kf-editor-ui-area-button {
212 | width: 15px;
213 | height: 100%;
214 | line-height: 70px;
215 | text-align: center;
216 | color: #5c5c5c;
217 | display: inline-block;
218 | border: 1px solid #D3D3D3;
219 | }
220 |
221 | .kf-editor-ui-area-button:HOVER {
222 | border-color: #ffbf00;
223 | background: rgba(255, 207, 15, 0.5);
224 | }
225 |
226 | .kf-editor-ui-area-mount {
227 | position: absolute;
228 | top: 0;
229 | left: 0;
230 | display: none;
231 | }
232 |
233 | .kf-editor-ui-overlap-title {
234 | width: 100%;
235 | line-height: 1.5;
236 | }
237 |
238 | /* list */
239 | .kf-editor-ui-list {
240 | background: white;
241 | padding: 5px;
242 | border: 1px solid #b1b1b1;
243 | position: relative;
244 | top: 0;
245 | left: 0;
246 | }
247 |
248 | .kf-editor-ui-list-bg {
249 | width: 1px;
250 | height: 100%;
251 | position: absolute;
252 | top: 0;
253 | left: 34px;
254 | background: rgba(238, 238, 238, 0.84);
255 | box-shadow: 0px 0 1px 1px rgba(224, 224, 224, 0.16);
256 | z-index: 1;
257 | }
258 |
259 | .kf-editor-ui-list-item-container {
260 | position: relative;
261 | top: 0;
262 | left: 0;
263 | z-index: 2;
264 | }
265 |
266 | .kf-editor-ui-list-item {
267 | line-height: 16px;
268 | padding: 2px 5px;
269 | border: 1px solid transparent;
270 | }
271 |
272 | .kf-editor-ui-list-item:HOVER {
273 | border-color: #ffbd19;
274 | background: rgba(255, 207, 15, 0.5);
275 | }
276 |
277 | .kf-editor-ui-list-item-icon {
278 | width: 16px;
279 | height: 16px;
280 | display: inline-block;
281 | vertical-align: bottom;
282 | margin-right: 10px;
283 | border: 1px solid rgba(255, 207, 15, 0.8);
284 | visibility: hidden;
285 | }
286 |
287 | /* area 内容区 */
288 | .kf-editor-ui-area-item {
289 | width: 24px;
290 | height: 24px;
291 | margin: 5px 0 0 5px;
292 | position: relative;
293 | top: 0;
294 | left: 0;
295 | display: inline-block;
296 | }
297 |
298 | .kf-editor-ui-area-item-content {
299 | border: 1px solid black;
300 | position: absolute;
301 | top: -1px;
302 | left: -1px;
303 | line-height: 0;
304 | }
305 |
306 | .kf-editor-ui-area-item-content:HOVER {
307 | border: 2px solid #ffbd19;
308 | top: -2px;
309 | left: -2px;
310 | }
311 |
312 | .kf-editor-ui-area-item-content img {
313 | width: 24px;
314 | height: 24px;
315 | }
--------------------------------------------------------------------------------
/dev-lib/cmd-define.js:
--------------------------------------------------------------------------------
1 | /**
2 | * cmd 内部定义
3 | * build用
4 | */
5 |
6 | // 模块存储
7 | var _modules = {};
8 |
9 | function define ( id, deps, factory ) {
10 |
11 | _modules[ id ] = {
12 |
13 | exports: {},
14 | value: null,
15 | factory: null
16 |
17 | };
18 |
19 | if ( arguments.length === 2 ) {
20 |
21 | factory = deps;
22 |
23 | }
24 |
25 | if ( _modules.toString.call( factory ) === '[object Object]' ) {
26 |
27 | _modules[ id ][ 'value' ] = factory;
28 |
29 | } else if ( typeof factory === 'function' ) {
30 |
31 | _modules[ id ][ 'factory' ] = factory;
32 |
33 | } else {
34 |
35 | throw new Error( 'define函数未定义的行为' );
36 |
37 | }
38 |
39 | }
40 |
41 | function require ( id ) {
42 |
43 | var module = _modules[ id ],
44 | exports = null;
45 |
46 | if ( !module ) {
47 |
48 | return null;
49 |
50 | }
51 |
52 | if ( module.value ) {
53 |
54 | return module.value;
55 |
56 | }
57 |
58 | exports = module.factory.call( null, require, module.exports, module );
59 |
60 | // return 值不为空, 则以return值为最终值
61 | if ( exports ) {
62 |
63 | module.exports = exports;
64 |
65 | }
66 |
67 | module.value = module.exports;
68 |
69 | return module.value;
70 |
71 | }
72 |
73 | function use ( id ) {
74 |
75 | return require( id );
76 |
77 | }
--------------------------------------------------------------------------------
/dev-lib/dev-define.js:
--------------------------------------------------------------------------------
1 | /**
2 | * cmd 内部定义
3 | * 开发用
4 | */
5 |
6 | ( function ( global ) {
7 |
8 | var _modules = {},
9 | loaded = {};
10 |
11 | global.inc = {
12 |
13 | base: '',
14 |
15 | config: function ( options ) {
16 |
17 | this.base = options.base || '';
18 |
19 | },
20 |
21 | use: function ( id ) {
22 |
23 | return require( id );
24 |
25 | },
26 |
27 | remove: function ( node ) {
28 |
29 | node.parentNode.removeChild( node );
30 |
31 | }
32 |
33 | };
34 |
35 | global.define = function ( id, deps, f ) {
36 |
37 | var argLen = arguments.length,
38 | module = null;
39 |
40 | switch ( argLen ) {
41 |
42 | case 1:
43 | var scriptNode = document.getElementsByTagName( 'script' );
44 | f = id;
45 | id = scriptNode[ scriptNode.length - 1 ].getAttribute( "data-id" );
46 | break;
47 |
48 | case 2:
49 | if ( typeof id === 'string' ) {
50 |
51 | f = deps;
52 |
53 | } else {
54 |
55 | var scriptNode = document.getElementsByTagName( 'script' );
56 | f = deps;
57 | id = scriptNode[ scriptNode.length - 1 ].getAttribute( "data-id" );
58 |
59 | }
60 |
61 | break;
62 |
63 | }
64 |
65 | module = _modules[ id ] = {
66 |
67 | exports: {},
68 | value: null,
69 | factory: null
70 |
71 | };
72 |
73 | loadDeps( f );
74 |
75 | if ( typeof f === 'function' ) {
76 |
77 | module.factory = f;
78 |
79 | } else {
80 |
81 | module.value = f;
82 |
83 | }
84 |
85 | }
86 |
87 | function require ( id ) {
88 |
89 | var exports = {},
90 | module = _modules[ id ];
91 |
92 | if ( module.value ) {
93 |
94 | return module.value;
95 |
96 | }
97 |
98 | exports = module.factory( require, module.exports, module );
99 |
100 | if ( exports ) {
101 |
102 | module.exports = exports;
103 |
104 | }
105 |
106 | module.value = module.exports;
107 | module.exports = null;
108 | module.factory = null;
109 |
110 | return module.value;
111 |
112 | }
113 |
114 | function loadDeps ( factory ) {
115 |
116 | var deps = null,
117 | pathname = location.pathname,
118 | uri = location.protocol + '//' + location.host;
119 |
120 | pathname = pathname.split( '/');
121 |
122 | if ( pathname[ pathname.length - 1 ] !== '' ) {
123 |
124 | pathname[ pathname.length - 1 ] = '';
125 |
126 | }
127 |
128 | uri += pathname.join( '/' );
129 |
130 | if ( typeof factory === 'function' ) {
131 |
132 | deps = loadDepsByFunction( factory );
133 |
134 | } else {
135 |
136 | // 未处理object的情况
137 | return;
138 |
139 | }
140 |
141 | for ( var i = 0, len = deps.length; i < len; i++ ) {
142 |
143 | var key = deps[ i ];
144 |
145 | if ( loaded[ key ] ) {
146 | continue;
147 | }
148 |
149 | loaded[ key ] = true;
150 |
151 | document.write( '' );
152 |
153 | }
154 |
155 | }
156 |
157 | function loadDepsByFunction ( factory ) {
158 |
159 | var content = factory.toString(),
160 | match = null,
161 | deps = [],
162 | pattern = /require\s*\(\s*([^)]+?)\s*\)/g;
163 |
164 | while ( match = pattern.exec( content ) ) {
165 |
166 | deps.push( match[ 1 ].replace( /'|"/g, '' ) );
167 |
168 | }
169 |
170 | return deps;
171 |
172 | }
173 |
174 | } )( this );
--------------------------------------------------------------------------------
/dev-lib/dev-start.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 13-12-4.
3 | */
4 | // 启动脚本
5 | inc.use( 'kf.start' );
--------------------------------------------------------------------------------
/dev-lib/exports.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 模块暴露
3 | */
4 |
5 | ( function ( global ) {
6 |
7 | define( 'kf.start', function ( require ) {
8 |
9 | var KFEditor = require( "editor/editor" );
10 |
11 | // 注册组件
12 | KFEditor.registerComponents( "ui", require( "ui/ui" ) );
13 | KFEditor.registerComponents( "parser", require( "parse/parser" ) );
14 | KFEditor.registerComponents( "render", require( "render/render" ) );
15 | KFEditor.registerComponents( "position", require( "position/position" ) );
16 | KFEditor.registerComponents( "syntax", require( "syntax/syntax" ) );
17 |
18 | kf.Editor = KFEditor;
19 |
20 | } );
21 |
22 | // build环境中才含有use
23 | try {
24 | use( 'kf.start' );
25 | } catch ( e ) {
26 | }
27 |
28 | } )( this );
29 |
--------------------------------------------------------------------------------
/dev-lib/kityformula-parser.all.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * ====================================================
3 | * kityformula-editor - v1.0.0 - 2014-04-03
4 | * https://github.com/HanCong03/kityformula-editor
5 | * GitHub: https://github.com/kitygraph/kityformula-editor.git
6 | * Copyright (c) 2014 Baidu Kity Group; Licensed MIT
7 | * ====================================================
8 | */
9 | !function(){function a(a,b,c){if(d[a]={exports:{},value:null,factory:null},2===arguments.length&&(c=b),"[object Object]"===d.toString.call(c))d[a].value=c;else{if("function"!=typeof c)throw new Error("define函数未定义的行为");d[a].factory=c}}function b(a){var c=d[a],e=null;return c?c.value?c.value:(e=c.factory.call(null,b,c.exports,c),e&&(c.exports=e),c.value=c.exports,c.value):null}function c(a){return b(a)}var d={};a("assembly",[],function(){function a(a,b){this.formula=new kf.Formula(a,b)}function b(a,b,e,f,g){var i,j=null,k=null,l=[],m=b.operand||[],n=null;if(e.operand=[],-1===b.name.indexOf("text")){for(var o=0,p=m.length;p>o;o++)j=m[o],j!==h?j?"string"==typeof j?(m[o]="brackets"===b.name&&2>o?j:c("text",j),e.operand.push(m[o])):(e.operand.push({}),m[o]=arguments.callee(a.operand[o],j,e.operand[e.operand.length-1],f,g)):(m[o]=c("empty"),e.operand.push(m[o])):(l.push(o),g.hasOwnProperty("startOffset")||(g.startOffset=o),g.endOffset=o,b.attr&&b.attr.id&&(g.groupId=b.attr.id));for(;o=l.length;)o=l[o-1],m.splice(o,1),l.length--,a.operand.splice(o,1)}if(n=d(b.name),!n)throw new Error("operator type error: not found "+b.operator);i=function(){},i.prototype=n.prototype,k=new i,n.apply(k,m),e.func=k;for(var q in b.callFn)b.callFn.hasOwnProperty(q)&&k[q]&&k[q].apply(k,b.callFn[q]);return b.attr&&(b.attr.id&&(f[b.attr.id]={objGroup:k,strGroup:a}),k.setAttr(b.attr)),k}function c(a,b){switch(a){case"empty":return new kf.EmptyExpression;case"text":return new kf.TextExpression(b)}}function d(a){return g[a]||kf[a.replace(/^[a-z]/i,function(a){return a.toUpperCase()}).replace(/-([a-z])/gi,function(a,b){return b.toUpperCase()})+"Expression"]}function e(a){var b={};if("[object Array]"==={}.toString.call(a)){b=[];for(var c=0,d=a.length;d>c;c++)b[c]=f(a[c])}else for(var e in a)a.hasOwnProperty(e)&&(b[e]=f(a[e]));return b}function f(a){return a?"object"!=typeof a?a:e(a):a}var g={},h="";return a.prototype.generateBy=function(a){var c=a.tree,d={},f={},g={};return"string"!=typeof c?(this.formula.appendExpression(b(c,e(c),d,g,f)),{select:f,parsedTree:c,tree:d,mapping:g}):(d=new kf.TextExpression(c),void this.formula.appendExpression(d))},a.prototype.regenerateBy=function(a){return this.formula.clearExpressions(),this.generateBy(a)},{use:function(b,c){return new a(b,c)}}}),a("impl/latex/base/latex-utils",["impl/latex/base/rpn","impl/latex/base/utils","impl/latex/define/type","impl/latex/base/tree","impl/latex/handler/combination"],function(a){return{toRPNExpression:a("impl/latex/base/rpn"),generateTree:a("impl/latex/base/tree")}}),a("impl/latex/base/rpn",["impl/latex/base/utils","impl/latex/define/operator","impl/latex/define/func","impl/latex/handler/func","impl/latex/define/type"],function(a){function b(a){for(var b=[],c=null;void 0!==(c=a.pop());)if(c&&"object"==typeof c&&c.sign===!1){var d=c.handler(c,[],b.reverse());b.unshift(d),b.reverse()}else b.push(c);return b.reverse()}var c=a("impl/latex/base/utils");return function(d){var e=[],f=(a("impl/latex/define/type"),null);for(d=b(d);f=d.shift();)"combination"===f.name&&1===f.operand.length&&"brackets"===f.operand[0].name&&(f=f.operand[0]),e.push(c.isArray(f)?arguments.callee(f):f);return e}}),a("impl/latex/base/tree",["impl/latex/define/type","impl/latex/handler/combination","impl/latex/base/utils","impl/latex/define/operator","impl/latex/define/func","impl/latex/handler/func"],function(a){var b=(a("impl/latex/define/type"),a("impl/latex/handler/combination")),c=a("impl/latex/base/utils");return function(a){for(var d=null,e=[],f=0,g=a.length;g>f;f++)c.isArray(a[f])&&(a[f]=arguments.callee(a[f]));for(;d=a.shift();)e.push("object"==typeof d&&d.handler?d.handler(d,e,a):d);return b(e)}}),a("impl/latex/base/utils",["impl/latex/define/operator","impl/latex/handler/script","impl/latex/handler/func","impl/latex/define/type","impl/latex/handler/fraction","impl/latex/handler/sqrt","impl/latex/handler/summation","impl/latex/handler/integration","impl/latex/handler/brackets","impl/latex/define/func","impl/latex/handler/lib/int-extract"],function(a){var b=a("impl/latex/define/operator"),c=a("impl/latex/define/func"),d=a("impl/latex/handler/func"),e={getLatexType:function(a){return a=a.replace(/^\\/,""),b[a]?"operator":c[a]?"function":"text"},isArray:function(a){return a&&"[object Array]"===Object.prototype.toString.call(a)},getDefine:function(a){return e.extend({},b[a.replace("\\","")])},getFuncDefine:function(a){return{name:"function",params:a.replace(/^\\/,""),handler:d}},getBracketsDefine:function(a,c){return e.extend({params:[a,c]},b.brackets)},extend:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}};return e}),a("impl/latex/define/brackets",[],function(){var a=!0;return{".":a,"{":a,"}":a,"[":a,"]":a,"(":a,")":a,"|":a}}),a("impl/latex/define/func",[],function(){return{sin:1,cos:1,arccos:1,cosh:1,det:1,inf:1,limsup:1,Pr:1,tan:1,arcsin:1,cot:1,dim:1,ker:1,ln:1,sec:1,tanh:1,arctan:1,coth:1,exp:1,lg:1,log:1,arg:1,csc:1,gcd:1,lim:1,max:1,sinh:1,cos:1,deg:1,hom:1,liminf:1,min:1,sup:1}}),a("impl/latex/define/operator",["impl/latex/handler/script","impl/latex/handler/func","impl/latex/handler/lib/int-extract","impl/latex/define/type","impl/latex/handler/fraction","impl/latex/handler/sqrt","impl/latex/handler/summation","impl/latex/handler/integration","impl/latex/handler/brackets","impl/latex/define/brackets"],function(a){var b=a("impl/latex/handler/script"),c=(a("impl/latex/handler/func"),a("impl/latex/define/type"));return{"^":{name:"superscript",type:c.OP,handler:b},_:{name:"subscript",type:c.OP,handler:b},frac:{name:"fraction",type:c.FN,sign:!1,handler:a("impl/latex/handler/fraction")},sqrt:{name:"radical",type:c.FN,sign:!1,handler:a("impl/latex/handler/sqrt")},sum:{name:"summation",type:c.FN,traversal:"rtl",handler:a("impl/latex/handler/summation")},"int":{name:"integration",type:c.FN,traversal:"rtl",handler:a("impl/latex/handler/integration")},brackets:{name:"brackets",type:"TYPE.FN",handler:a("impl/latex/handler/brackets")}}}),a("impl/latex/define/pre",["impl/latex/pre/sqrt","impl/latex/pre/int"],function(a){return{sqrt:a("impl/latex/pre/sqrt"),"int":a("impl/latex/pre/int")}}),a("impl/latex/define/reverse",["impl/latex/reverse/combination","impl/latex/reverse/fraction","impl/latex/reverse/func","impl/latex/reverse/integration","impl/latex/reverse/subscript","impl/latex/reverse/superscript","impl/latex/reverse/script","impl/latex/reverse/sqrt","impl/latex/reverse/summation","impl/latex/reverse/brackets"],function(a){return{combination:a("impl/latex/reverse/combination"),fraction:a("impl/latex/reverse/fraction"),"function":a("impl/latex/reverse/func"),integration:a("impl/latex/reverse/integration"),subscript:a("impl/latex/reverse/subscript"),superscript:a("impl/latex/reverse/superscript"),script:a("impl/latex/reverse/script"),radical:a("impl/latex/reverse/sqrt"),summation:a("impl/latex/reverse/summation"),brackets:a("impl/latex/reverse/brackets")}}),a("impl/latex/define/type",[],function(){return{OP:1,FN:2}}),a("impl/latex/handler/brackets",["impl/latex/define/brackets"],function(a){var b=a("impl/latex/define/brackets");return function(a,c,d){for(var e=0,f=a.params.length;f>e;e++)if(!(a.params[e]in b))throw new Error("Brackets: invalid params");return a.operand=a.params,a.params[2]=d.shift(),delete a.handler,delete a.params,a}}),a("impl/latex/handler/combination",[],function(){return function(){return 0===arguments[0].length?null:{name:"combination",operand:arguments[0]}}}),a("impl/latex/handler/fraction",[],function(){return function(a,b,c){var d=c.shift(),e=c.shift();if(void 0===d||void 0===e)throw new Error("Frac: Syntax Error");return a.operand=[d,e],delete a.handler,a}}),a("impl/latex/handler/func",["impl/latex/handler/lib/int-extract"],function(a){var b=a("impl/latex/handler/lib/int-extract");return function(a,c,d){var e=b(d);return a.operand=[a.params,e.exp,e.sup,e.sub],delete a.params,delete a.handler,a}}),a("impl/latex/handler/integration",["impl/latex/handler/lib/int-extract"],function(a){var b=a("impl/latex/handler/lib/int-extract");return function(a,c,d){var e=d.shift(),f=b(d);return a.operand=[f.exp,f.sup,f.sub],a.callFn={setType:[0|e]},delete a.handler,a}}),a("impl/latex/handler/lib/int-extract",[],function(){return function(a){var b=a.shift()||null,c=null,d=null;return null!==b&&("string"==typeof b?(d=b,b=null):"superscript"===b.name?(b=a.shift()||null,b&&(c=a.shift()||null,c&&("subscript"===c.name?(c=a.shift()||null,d=a.shift()||null):(d=c,c=null)))):"subscript"===b.name?(c=a.shift()||null,c&&(b=a.shift()||null,b&&("superscript"===b.name?(b=a.shift()||null,d=a.shift()||null):(d=b,b=null)))):(d=b,b=null)),{sub:c,sup:b,exp:d}}}),a("impl/latex/handler/script",[],function(){return function(a,b,c){var d=b.pop(),e=c.shift()||null;if(!e)throw new Error("Missing script");if(d=d||"",d.name===a.name||"script"===d.name)throw new Error("script error");return"subscript"===d.name?(d.name="script",d.operand[2]=d.operand[1],d.operand[1]=e,d):"superscript"===d.name?(d.name="script",d.operand[2]=e,d):(a.operand=[d,e],delete a.handler,a)}}),a("impl/latex/handler/sqrt",[],function(){return function(a,b,c){var d=c.shift(),e=c.shift();return a.operand=[e,d],delete a.handler,a}}),a("impl/latex/handler/summation",["impl/latex/handler/lib/int-extract"],function(a){var b=a("impl/latex/handler/lib/int-extract");return function(a,c,d){var e=b(d);return a.operand=[e.exp,e.sup,e.sub],delete a.handler,a}}),a("impl/latex/latex",["parser","impl/latex/base/latex-utils","impl/latex/base/rpn","impl/latex/base/tree","impl/latex/define/pre","impl/latex/pre/sqrt","impl/latex/pre/int","impl/latex/serialization","impl/latex/define/reverse","impl/latex/define/operator","impl/latex/handler/script","impl/latex/handler/func","impl/latex/define/type","impl/latex/handler/fraction","impl/latex/handler/sqrt","impl/latex/handler/summation","impl/latex/handler/integration","impl/latex/handler/brackets","impl/latex/reverse/combination","impl/latex/reverse/fraction","impl/latex/reverse/func","impl/latex/reverse/integration","impl/latex/reverse/subscript","impl/latex/reverse/superscript","impl/latex/reverse/script","impl/latex/reverse/sqrt","impl/latex/reverse/summation","impl/latex/reverse/brackets","impl/latex/base/utils","impl/latex/define/func"],function(a){function b(a){var b=k.getLatexType(a);switch(b){case"operator":return k.getDefine(a);case"function":return k.getFuncDefine(a);default:return c(a)}}function c(a){return 0===a.indexOf("\\")?a+"\\":a}function d(a){return a.replace(/\\\s+/,"").replace(/\s*([^a-z0-9\s])\s*/gi,function(a,b){return b})}var e=a("parser").Parser,f=a("impl/latex/base/latex-utils"),g=a("impl/latex/define/pre"),h=a("impl/latex/serialization"),i=a("impl/latex/define/operator"),j=a("impl/latex/define/reverse"),k=a("impl/latex/base/utils"),l="",m="",n=new RegExp(l+"|"+m,"g"),o=new RegExp(l,"g"),p=new RegExp(m,"g");e.register("latex",e.implement({parse:function(a){var b=this.split(this.format(a));return b=this.parseToGroup(b),b=this.parseToStruct(b),this.generateTree(b)},serialization:function(a,b){return h(a,b)},expand:function(a){var b=a.parse,c=null,d=a.pre,e=a.reverse;for(var f in b)b.hasOwnProperty(f)&&(c=f.replace(/\\/g,""),i[c]=b[f]);for(var f in e)e.hasOwnProperty(f)&&(j[f.replace(/\\/g,"")]=e[f]);if(d)for(var f in d)d.hasOwnProperty(f)&&(g[f.replace(/\\/g,"")]=d[f])},format:function(a){a=d(a),a=a.replace(n,"").replace(/\\{/gi,l).replace(/\\}/gi,m);for(var b in g)g.hasOwnProperty(b)&&(a=g[b](a));return a},split:function(a){var b=[],c=/(?:\\[a-z]+\s*)|(?:[{}]\s*)|(?:[^\\{}]\s*)/gi,d=/^\s+|\s+$/g,e=null;for(a=a.replace(d,"");e=c.exec(a);)e=e[0].replace(d,""),e&&b.push(e);return b},generateTree:function(a){for(var b=[],c=null;c=a.shift();)b.push(k.isArray(c)?this.generateTree(c):c);return b=f.toRPNExpression(b),f.generateTree(b)},parseToGroup:function(a){for(var b=[],c=[b],d=0,e=0,f=0,g=a.length;g>f;f++)switch(a[f]){case"{":d++,c.push(b),b.push([]),b=b[b.length-1];break;case"}":d--,b=c.pop();break;case"\\left":e++,c.push(b),b.push([[]]),b=b[b.length-1][0],b.type="brackets",f++,b.leftBrackets=a[f].replace(o,"{").replace(p,"}");break;case"\\right":e--,f++,b.rightBrackets=a[f].replace(o,"{").replace(p,"}"),b=c.pop();break;default:b.push(a[f].replace(o,"{").replace(p,"}"))}if(0!==d)throw new Error("Group Error!");if(0!==e)throw new Error("Brackets Error!");return c[0]},parseToStruct:function(a){for(var c=[],d=0,e=a.length;e>d;d++)k.isArray(a[d])?"brackets"===a[d].type?(c.push(k.getBracketsDefine(a[d].leftBrackets,a[d].rightBrackets)),c.push(this.parseToStruct(a[d]))):c.push(this.parseToStruct(a[d])):c.push(b(a[d]));return c}}))}),a("impl/latex/pre/int",[],function(){return function(a){return a.replace(/\\(i+)nt(\b|[^a-zA-Z])/g,function(a,b,c){return"\\int "+b.length+c})}}),a("impl/latex/pre/sqrt",[],function(){return function(a){return a.replace(/\\sqrt\s*((?:\[[^\]]*\])?)/g,function(a,b){return"\\sqrt{"+b.replace(/^\[|\]$/g,"")+"}"})}}),a("impl/latex/reverse/brackets",[],function(){return function(a){return["\\left",a[0],a[2],"\\right",a[1]].join(" ")}}),a("impl/latex/reverse/combination",[],function(){new RegExp("","g");return function(a){return this.attr["data-root"]||this.attr["data-placeholder"]?a.join(""):"{"+a.join("")+"}"}}),a("impl/latex/reverse/fraction",[],function(){return function(a){return"\\frac "+a[0]+" "+a[1]}}),a("impl/latex/reverse/func",[],function(){return function(a){var b=["\\"+a[0]];return a[2]&&b.push("^"+a[2]),a[3]&&b.push("_"+a[3]),b.push(" "+a[1]),b.join("")}}),a("impl/latex/reverse/integration",[],function(){return function(a){var b=["\\int"];return a[1]&&b.push("^"+a[1]),a[2]&&b.push("_"+a[2]),b.push(" "+a[0]),a.join("")}}),a("impl/latex/reverse/script",[],function(){return function(a){return a[0]+"^"+a[1]+"_"+a[2]}}),a("impl/latex/reverse/sqrt",[],function(){return function(a){var b=["\\sqrt"];return a[1]&&b.push("["+a[1]+"]"),b.push(" "+a[0]),b.join("")}}),a("impl/latex/reverse/subscript",[],function(){return function(a){return a[0]+"_"+a[1]}}),a("impl/latex/reverse/summation",[],function(){return function(a){var b=["\\sum"];return a[1]&&b.push("^"+a[1]),a[2]&&b.push("_"+a[2]),b.push(" "+a[0]),b.join("")}}),a("impl/latex/reverse/superscript",[],function(){return function(a){return a[0]+"^"+a[1]}}),a("impl/latex/serialization",["impl/latex/define/reverse","impl/latex/reverse/combination","impl/latex/reverse/fraction","impl/latex/reverse/func","impl/latex/reverse/integration","impl/latex/reverse/subscript","impl/latex/reverse/superscript","impl/latex/reverse/script","impl/latex/reverse/sqrt","impl/latex/reverse/summation","impl/latex/reverse/brackets"],function(a){function b(a,e){var f=[],g=null;if("object"!=typeof a)return a.replace(d,function(a,b){return b+" "});"combination"===a.name&&1===a.operand.length&&"combination"===a.operand[0].name&&(a=a.operand[0]),g=a.operand;for(var h=0,i=g.length;i>h;h++)f.push(g[h]?b(g[h]):g[h]);return c[a.name].call(a,f,e)}var c=a("impl/latex/define/reverse"),d=/(\\[\w]+)\\/g;return function(a,c){return b(a,c)}}),a("parser",[],function(a,b,c){function d(a){this.impl=new a,this.conf={}}function e(){this.conf={}}var f={},g={},h={extend:function(a,b){var c=null;b=[].slice.call(arguments,1);for(var d=0,e=b.length;e>d;d++){c=b[d];for(var f in c)c.hasOwnProperty(f)&&(a[f]=c[f])}},setData:function(a,b,c){if("string"==typeof b)a[b]=c;else{if("object"!=typeof b)throw new Error("invalid option");for(c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}}},i={use:function(a){if(!g[a])throw new Error("unknown parser type");return this.proxy(g[a])},config:function(a,b){return h.setData(f,a,b),this},register:function(a,b){return g[a.toLowerCase()]=b,this},implement:function(a){var b=function(){},c=a.constructor||function(){},d=function(){e.call(this),c.call(this)};b.prototype=e.prototype,d.prototype=new b,delete a.constructor;for(var f in a)"constructor"!==f&&a.hasOwnProperty(f)&&(d.prototype[f]=a[f]);return d},proxy:function(a){return new d(a)}};h.extend(d.prototype,{config:function(a,b){h.setData(this.conf,a,b)},set:function(a,b){this.impl.set(a,b)},parse:function(a){var b={config:{},tree:this.impl.parse(a)};return h.extend(b.config,f,this.conf),b},serialization:function(a,b){return this.impl.serialization(a,b)},expand:function(a){this.impl.expand(a)}}),h.extend(e.prototype,{set:function(a,b){h.extend(this.conf,a,b)},parse:function(){throw new Error("Abstract function")}}),c.exports={Parser:i,ParserInterface:e}}),function(b){a("kf.start",function(a){var c=a("parser").Parser;a("impl/latex/latex"),b.kf.Parser=c,b.kf.Assembly=a("assembly")});try{c("kf.start")}catch(d){}}(this)}();
--------------------------------------------------------------------------------
/dev-lib/sea.js:
--------------------------------------------------------------------------------
1 | /*! Sea.js 2.1.1 | seajs.org/LICENSE.md
2 | //# sourceMappingURL=sea.js.map
3 | */(function(t,u){function v(b){return function(c){return Object.prototype.toString.call(c)==="[object "+b+"]"}}function Q(){return w++}function I(b,c){var a;a=b.charAt(0);if(R.test(b))a=b;else if("."===a){a=(c?c.match(E)[0]:h.cwd)+b;for(a=a.replace(S,"/");a.match(J);)a=a.replace(J,"/")}else a="/"===a?(a=h.cwd.match(T))?a[0]+b.substring(1):b:h.base+b;return a}function K(b,c){if(!b)return"";var a=b,d=h.alias,a=b=d&&F(d[a])?d[a]:a,d=h.paths,g;if(d&&(g=a.match(U))&&F(d[g[1]]))a=d[g[1]]+g[2];g=a;var e=h.vars;
4 | e&&-11*navigator.userAgent.replace(/.*AppleWebKit\/(\d+)\..*/,"$1"),Z=/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g,$=/\\\\/g,r=f.cache={},C,G={},H={},D={},j=e.STATUS={FETCHING:1,
8 | SAVED:2,LOADING:3,LOADED:4,EXECUTING:5,EXECUTED:6};e.prototype.resolve=function(){for(var b=this.dependencies,c=[],a=0,d=b.length;a=j.LOADING)){this.status=j.LOADING;var b=this.resolve();m("load",b);for(var c=this._remain=b.length,a,d=0;d=j.EXECUTING)return this.exports;this.status=j.EXECUTING;var c=this.uri;b.resolve=function(a){return e.resolve(a,c)};b.async=function(a,g){e.use(a,g,c+"_async_"+w++);return b};var a=this.factory,a=
12 | x(a)?a(b,this.exports={},this):a;a===u&&(a=this.exports);null===a&&!O.test(c)&&m("error",this);delete this.factory;this.exports=a;this.status=j.EXECUTED;m("exec",this);return a};e.resolve=function(b,c){var a={id:b,refUri:c};m("resolve",a);return a.uri||K(a.id,c)};e.define=function(b,c,a){var d=arguments.length;1===d?(a=b,b=u):2===d&&(a=c,A(b)?(c=b,b=u):c=u);if(!A(c)&&x(a)){var g=[];a.toString().replace($,"").replace(Z,function(a,b,c){c&&g.push(c)});c=g}d={id:b,uri:e.resolve(b),deps:c,factory:a};if(!d.uri&&
13 | n.attachEvent){var f=W();f&&(d.uri=f.src)}m("define",d);d.uri?e.save(d.uri,d):C=d};e.save=function(b,c){var a=e.get(b);a.status
2 |
3 |
4 | 公式编辑器
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kityformula-editor",
3 | "title": "Kityformula-Editor",
4 | "description": "HTML(SVG) Formula display solutions",
5 | "version": "1.0.0",
6 | "homepage": "https://github.com/kitygraph/formula",
7 | "author": {
8 | "name": "Baidu Kity Group",
9 | "url": "http://ueditor.baidu.com"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/kitygraph/formula.git"
14 | },
15 | "keywords": [
16 | "formula",
17 | "kity",
18 | "svg",
19 | "graphic",
20 | "javascript",
21 | "library"
22 | ],
23 | "bugs": {
24 | "url": "http://www.ueditorbbs.com/forum.php"
25 | },
26 | "licenses": [
27 | {
28 | "type": "MIT",
29 | "url": "https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt"
30 | }
31 | ],
32 | "dependencies": {},
33 | "devDependencies": {
34 | "grunt": "~0.4.1",
35 | "grunt-cmd-transport": "~0.3.0",
36 | "grunt-cmd-concat": "~0.2.5",
37 | "grunt-contrib-concat": "~0.3.0",
38 | "grunt-contrib-uglify": "~0.2.6",
39 | "grunt-contrib-clean": "~0.5.0"
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/src/base/common.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-17.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | // copy保护
8 | var MAX_COPY_DEEP = 10,
9 |
10 | commonUtils = {
11 | extend: function ( target, source ) {
12 |
13 | var isDeep = false;
14 |
15 | if ( typeof target === "boolean" ) {
16 | isDeep = target;
17 | target = source;
18 | source = [].splice.call( arguments, 2 );
19 | } else {
20 | source = [].splice.call( arguments, 1 );
21 | }
22 |
23 | if ( !target ) {
24 | throw new Error( 'Utils: extend, target can not be empty' );
25 | }
26 |
27 | commonUtils.each( source, function ( src ) {
28 |
29 | if ( src && typeof src === "object" || typeof src === "function" ) {
30 |
31 | copy( isDeep, target, src );
32 |
33 | }
34 |
35 | } );
36 |
37 | return target;
38 |
39 | },
40 |
41 | isArray: function ( obj ) {
42 | return obj && ({}).toString.call( obj ) === "[object Array]";
43 | },
44 |
45 | isString: function ( obj ) {
46 | return typeof obj === "string";
47 | },
48 |
49 | proxy: function ( fn, context ) {
50 |
51 | return function () {
52 | return fn.apply( context, arguments );
53 | };
54 |
55 | },
56 |
57 | each: function ( obj, fn ) {
58 |
59 | if ( !obj ) {
60 | return;
61 | }
62 |
63 | if ( 'length' in obj && typeof obj.length === "number" ) {
64 |
65 | for ( var i = 0, len = obj.length; i < len; i++ ) {
66 |
67 | if ( fn.call( null, obj[ i ], i, obj ) === false ) {
68 | break;
69 | }
70 |
71 | }
72 |
73 | } else {
74 |
75 | for ( var key in obj ) {
76 |
77 | if ( obj.hasOwnProperty( key ) ) {
78 | if ( fn.call( null, obj[ key ], key, obj ) === false ) {
79 | break;
80 | }
81 | }
82 |
83 | }
84 |
85 | }
86 |
87 | }
88 | };
89 |
90 | function copy ( isDeep, target, source, count ) {
91 |
92 | count = count | 0;
93 |
94 | if ( count > MAX_COPY_DEEP ) {
95 | return source;
96 | }
97 |
98 | count++;
99 |
100 | commonUtils.each( source, function ( value, index, origin ) {
101 |
102 | if ( isDeep ) {
103 |
104 | if ( !value || ( typeof value !== "object" && typeof value !== "function" ) ) {
105 | target[ index ] = value;
106 | } else {
107 | target[ index ] = target[ index ] || ( commonUtils.isArray( value ) ? [] : {} );
108 | target[ index ] = copy( isDeep, target[ index ], value, count );
109 | }
110 |
111 | } else {
112 | target[ index ] = value;
113 | }
114 |
115 | } );
116 |
117 | return target;
118 |
119 | }
120 |
121 | return commonUtils;
122 |
123 | } );
--------------------------------------------------------------------------------
/src/base/event/event.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-17.
3 | */
4 |
5 | define( function ( require, exports, modules ) {
6 |
7 | var EVENT_LISTENER = {},
8 | eid = 0,
9 | Utils = this,
10 | BEFORE_RESULT = true,
11 | KFEvent = require( "base/event/kfevent" ),
12 | commonUtils = require( "base/common" ),
13 | EVENT_HANDLER = function ( e ) {
14 |
15 | var type = e.type,
16 | target = e.target,
17 | eid = this.__kfe_eid,
18 | hasAutoTrigger = /^(?:before|after)/.test( type ),
19 | HANDLER_LIST = EVENT_LISTENER[ eid ][ type ];
20 |
21 | if ( !hasAutoTrigger ) {
22 |
23 | EventListener.trigger( target, 'before' + type );
24 |
25 | if ( BEFORE_RESULT === false ) {
26 | BEFORE_RESULT = true;
27 | return false;
28 | }
29 |
30 | }
31 |
32 | commonUtils.each( HANDLER_LIST, function ( handler, index ) {
33 |
34 | if ( !handler ) {
35 | return;
36 | }
37 |
38 | if ( handler.call( target, e ) === false ) {
39 | BEFORE_RESULT = false;
40 | return BEFORE_RESULT;
41 | }
42 |
43 | } );
44 |
45 | if ( !hasAutoTrigger ) {
46 |
47 | EventListener.trigger( target, 'after' + type );
48 |
49 | }
50 |
51 | };
52 |
53 | var EventListener = {
54 |
55 | addEvent: function ( target, type, handler ) {
56 |
57 | var hasHandler = true,
58 | eventCache = null;
59 |
60 | if ( !target.__kfe_eid ) {
61 | hasHandler = false;
62 | target.__kfe_eid = generateId();
63 | EVENT_LISTENER[ target.__kfe_eid ] = {};
64 | }
65 |
66 | eventCache = EVENT_LISTENER[ target.__kfe_eid ];
67 |
68 | if ( !eventCache[ type ] ) {
69 | hasHandler = false;
70 | eventCache[ type ] = [];
71 | }
72 |
73 | eventCache[ type ].push( handler );
74 |
75 | if ( hasHandler ) {
76 | return;
77 | }
78 |
79 | target.addEventListener( type, EVENT_HANDLER, false );
80 |
81 | },
82 |
83 | trigger: function ( target, type, e ) {
84 |
85 | e = e || KFEvent.createEvent( type, e );
86 |
87 | target.dispatchEvent( e );
88 |
89 | }
90 |
91 | };
92 |
93 | function generateId () {
94 |
95 | return ++eid;
96 |
97 | }
98 |
99 | return EventListener;
100 |
101 | } );
--------------------------------------------------------------------------------
/src/base/event/kfevent.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-17.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | return {
8 |
9 | createEvent: function ( type, e ) {
10 |
11 | var evt = document.createEvent( 'Event' );
12 |
13 | evt.initEvent( type, true, true );
14 |
15 | return evt;
16 |
17 | }
18 |
19 | };
20 |
21 | } );
--------------------------------------------------------------------------------
/src/base/utils.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 基础工具包
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var Utils = {},
8 | commonUtils = require( "base/common" );
9 |
10 | commonUtils.extend( Utils, commonUtils, require( "base/event/event" ) );
11 |
12 | return Utils;
13 |
14 | } );
15 |
--------------------------------------------------------------------------------
/src/editor/editor.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 编辑器主体结构
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 | Utils = require( "base/utils" ),
9 | defaultOpt = {
10 | controller: {
11 | zoom: true,
12 | maxzoom: 5,
13 | minzoom: 0.5
14 | },
15 | formula: {
16 | fontsize: 50,
17 | autoresize: false
18 | }
19 |
20 | };
21 |
22 | var COMPONENTS = {};
23 |
24 | var KFEditor = kity.createClass( 'KFEditor', {
25 |
26 | constructor: function ( container, opt ) {
27 |
28 | this.options = Utils.extend( true, {}, defaultOpt, opt );
29 |
30 | this.container = container;
31 | this.services = {};
32 | this.commands = {};
33 |
34 | this.initComponents();
35 |
36 | },
37 |
38 | getContainer: function () {
39 | return this.container;
40 | },
41 |
42 | getOptions: function () {
43 | return this.options;
44 | },
45 |
46 | initComponents: function () {
47 |
48 | var _self = this;
49 |
50 | Utils.each( COMPONENTS, function ( component ) {
51 |
52 | new component( _self );
53 |
54 | } );
55 |
56 | },
57 |
58 | requestService: function ( serviceName, args ) {
59 |
60 | var serviceObject = getService.call( this, serviceName );
61 |
62 | return serviceObject.service[ serviceObject.key ].apply( serviceObject.provider, [].slice.call( arguments, 1 ) );
63 |
64 | },
65 |
66 | request: function ( serviceName ) {
67 |
68 | var serviceObject = getService.call( this, serviceName );
69 |
70 | return serviceObject.service;
71 |
72 | },
73 |
74 | registerService: function ( serviceName, provider, serviceObject ) {
75 |
76 | var key = null;
77 |
78 | for ( key in serviceObject ) {
79 |
80 | if ( serviceObject[ key ] && serviceObject.hasOwnProperty( key ) ) {
81 | serviceObject[ key ] = Utils.proxy( serviceObject[ key ], provider );
82 | }
83 |
84 | }
85 |
86 | this.services[ serviceName ] = {
87 | provider: provider,
88 | key: key,
89 | service: serviceObject
90 | };
91 |
92 | },
93 |
94 | registerCommand: function ( commandName, executor, execFn ) {
95 |
96 | this.commands[ commandName ] = {
97 | executor: executor,
98 | execFn: execFn
99 | };
100 |
101 | },
102 |
103 | execCommand: function ( commandName, args ) {
104 |
105 | var commandObject = this.commands[ commandName ];
106 |
107 | if ( !commandObject ) {
108 | throw new Error( 'KFEditor: not found command, ' + commandName );
109 | }
110 |
111 | return commandObject.execFn.apply( commandObject.executor, [].slice.call( arguments, 1 ) );
112 |
113 | }
114 |
115 | } );
116 |
117 | function getService ( serviceName ) {
118 |
119 | var serviceObject = this.services[ serviceName ];
120 |
121 | if ( !serviceObject ) {
122 | throw new Error( 'KFEditor: not found service, ' + serviceName );
123 | }
124 |
125 | return serviceObject;
126 |
127 | }
128 |
129 | Utils.extend( KFEditor, {
130 |
131 | registerComponents: function ( name, component ) {
132 |
133 | COMPONENTS[ name ] = component;
134 |
135 | }
136 |
137 | } );
138 |
139 |
140 | return KFEditor;
141 |
142 | } );
143 |
--------------------------------------------------------------------------------
/src/jquery.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-31.
3 | */
4 |
5 | define( function () {
6 | return window.jQuery;
7 | } );
--------------------------------------------------------------------------------
/src/kf-ext/def.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-18.
3 | */
4 |
5 | define( function () {
6 |
7 | return {
8 | selectColor: 'rgba(42, 106, 189, 0.2)',
9 | allSelectColor: 'rgba(42, 106, 189, 0.6)'
10 | };
11 |
12 | } );
--------------------------------------------------------------------------------
/src/kf-ext/expression/placeholder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 占位符表达式, 扩展KF自有的Empty表达式
3 | */
4 |
5 |
6 | define( function ( require, exports, module ) {
7 |
8 | var kity = require( "kity" ) ,
9 |
10 | kf = require( "kf" ),
11 |
12 | PlaceholderOperator = require( "kf-ext/operator/placeholder" );
13 |
14 | return kity.createClass( 'PlaceholderExpression', {
15 |
16 | base: kf.CompoundExpression,
17 |
18 | constructor: function () {
19 |
20 | this.callBase();
21 |
22 | this.setFlag( "Placeholder" );
23 |
24 | this.box.setAttr( "data-type", null );
25 | this.setOperator( new PlaceholderOperator() );
26 |
27 | },
28 |
29 | select: function () {
30 |
31 | this.getOperator().select();
32 |
33 | },
34 |
35 | selectAll: function () {
36 |
37 | this.getOperator().selectAll();
38 |
39 | },
40 |
41 | unselect: function () {
42 | this.getOperator().unselect();
43 | }
44 |
45 | } );
46 |
47 | } );
--------------------------------------------------------------------------------
/src/kf-ext/extension.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 公式扩展接口
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kf = require( "kf" ),
8 | kity = require( "kity" ),
9 | SELECT_COLOR = require( "kf-ext/def" ).selectColor,
10 | ALL_SELECT_COLOR = require( "kf-ext/def" ).allSelectColor;
11 |
12 | function ext ( parser ) {
13 |
14 | kf.PlaceholderExpression = require( "kf-ext/expression/placeholder" );
15 |
16 | kf.Expression.prototype.select = function () {
17 |
18 | this.box.fill( SELECT_COLOR );
19 |
20 | };
21 |
22 | kf.Expression.prototype.selectAll = function () {
23 | this.box.fill( ALL_SELECT_COLOR );
24 | };
25 |
26 | kf.Expression.prototype.unselect = function () {
27 |
28 | this.box.fill( "transparent" );
29 |
30 | }
31 |
32 | // 扩展解析和逆解析
33 | parser.getKFParser().expand( {
34 |
35 | parse: {
36 | "placeholder": {
37 | name: "placeholder",
38 | handler: function ( info ) {
39 |
40 | delete info.handler;
41 | info.operand = [];
42 |
43 | return info;
44 |
45 | },
46 | sign: false
47 | }
48 | },
49 |
50 | reverse: {
51 |
52 | "placeholder": function () {
53 |
54 | return "\\placeholder";
55 |
56 | }
57 |
58 | }
59 |
60 | } );
61 |
62 | }
63 |
64 | return {
65 | ext: ext
66 | };
67 |
68 | } );
69 |
--------------------------------------------------------------------------------
/src/kf-ext/operator/placeholder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 占位符操作符
3 | */
4 |
5 | define( function ( require, exports, modules ) {
6 |
7 | var kity = require( "kity" ),
8 | SELECT_COLOR = require( "kf-ext/def" ).selectColor,
9 | ALL_SELECT_COLOR = require( "kf-ext/def" ).allSelectColor;
10 |
11 | return kity.createClass( 'PlaceholderOperator', {
12 |
13 | base: require( "kf" ).Operator,
14 |
15 | constructor: function () {
16 |
17 | this.opShape = null;
18 | this.callBase( "Placeholder" );
19 |
20 | },
21 |
22 | applyOperand: function () {
23 |
24 | this.setBoxSize( 17, 27 );
25 | this.opShape = generateOPShape();
26 | this.addOperatorShape( this.opShape );
27 |
28 | },
29 |
30 | select: function () {
31 |
32 | this.opShape.fill( SELECT_COLOR );
33 |
34 | },
35 |
36 | selectAll: function () {
37 |
38 | this.opShape.fill( ALL_SELECT_COLOR );
39 |
40 | },
41 |
42 | unselect: function () {
43 |
44 | this.opShape.fill( "transparent" );
45 |
46 | }
47 |
48 | } );
49 |
50 | function generateOPShape () {
51 |
52 | var w = 13,
53 | h = 17,
54 | shape = null;
55 |
56 | shape = new kity.Rect( w, h, 0, 0 ).stroke( "black" ).fill( "transparent" ).translate( 2, 6 );
57 | shape.setAttr( "stroke-dasharray", "1, 2" );
58 |
59 | return shape;
60 |
61 | }
62 |
63 | } );
--------------------------------------------------------------------------------
/src/kf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-12.
3 | */
4 |
5 | define( function () {
6 |
7 | return window.kf;
8 |
9 | } );
--------------------------------------------------------------------------------
/src/kity.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 数学公式Latex语法解析器
3 | */
4 |
5 | define( function () {
6 |
7 | return window.kity;
8 |
9 | } );
10 |
11 |
--------------------------------------------------------------------------------
/src/parse/def.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 定义了一个转换对照表
3 | */
4 |
5 | define( function () {
6 |
7 | return {
8 |
9 | "radical": true,
10 | "fraction": true,
11 | "summation": true,
12 | "integration": true,
13 | "placeholder": true,
14 | "script": true,
15 | "superscript": true,
16 | "subscript": true,
17 | "brackets": true
18 |
19 | };
20 |
21 | } );
--------------------------------------------------------------------------------
/src/parse/parser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 数学公式解析器
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var KFParser = require( "kf" ).Parser,
8 | kity = require( "kity" ),
9 | COMPARISON_TABLE = require( "parse/def" ),
10 | PID_PREFIX = "_kf_editor_",
11 | GROUP_TYPE = "kf-editor-group",
12 | V_GROUP_TYPE = "kf-editor-virtual-group",
13 | PID = 0;
14 |
15 | var Parser = kity.createClass( "Parser", {
16 |
17 | constructor: function ( kfEditor ) {
18 |
19 | this.kfEditor = kfEditor;
20 |
21 | this.callBase();
22 | // kityformula 解析器
23 | this.kfParser = KFParser.use( "latex" );
24 |
25 | this.initKFormulExtension();
26 |
27 | this.pid = generateId();
28 | this.groupRecord = 0;
29 |
30 | this.tree = null;
31 |
32 | this.isResetId = true;
33 |
34 | this.initServices();
35 |
36 | },
37 |
38 | parse: function ( str, isResetId ) {
39 |
40 | var parsedResult = null;
41 |
42 | this.isResetId = !!isResetId;
43 |
44 | if ( this.isResetId ) {
45 | this.resetGroupId();
46 | }
47 |
48 | parsedResult = this.kfParser.parse( str );
49 |
50 | // 对解析出来的结果树做适当的处理,使得编辑器能够更容易地识别当前表达式的语义
51 | supplementTree( this, parsedResult.tree );
52 |
53 | return parsedResult;
54 |
55 | },
56 |
57 | // 序列化, parse的逆过程
58 | serialization: function ( tree ) {
59 |
60 | return this.kfParser.serialization( tree );
61 |
62 | },
63 |
64 | initServices: function () {
65 |
66 | this.kfEditor.registerService( "parser.parse", this, {
67 | parse: this.parse
68 | } );
69 |
70 | this.kfEditor.registerService( "parser.latex.serialization", this, {
71 | serialization: this.serialization
72 | } );
73 |
74 | },
75 |
76 | getKFParser: function () {
77 |
78 | return this.kfParser;
79 |
80 | },
81 |
82 | // 初始化KF扩展
83 | initKFormulExtension: function () {
84 |
85 | require( "kf-ext/extension" ).ext( this );
86 |
87 | },
88 |
89 | resetGroupId: function () {
90 | this.groupRecord = 0;
91 | },
92 |
93 | getGroupId: function () {
94 | return this.pid + "_" + ( ++this.groupRecord );
95 | }
96 |
97 | } );
98 |
99 | // 把解析树丰富成公式编辑器的语义树, 该语义化的树同时也是合法的解析树
100 | function supplementTree ( parser, tree, parentTree ) {
101 |
102 | var currentOperand = null,
103 | // 只有根节点才没有parentTree
104 | isRoot = !parentTree;
105 |
106 | tree.attr = tree.attr || {};
107 |
108 | tree.attr.id = parser.getGroupId();
109 |
110 | // 组类型已经存在则不用再处理
111 | if ( !tree.attr[ "data-type" ] ) {
112 |
113 | tree.attr[ "data-type" ] = GROUP_TYPE;
114 |
115 | if ( COMPARISON_TABLE[ tree.name ] ) {
116 | tree.attr[ "data-type" ] = V_GROUP_TYPE;
117 | }
118 |
119 | }
120 |
121 | if ( isRoot ) {
122 | // 如果isResetId为false, 表示当前生成的是子树
123 | // 则不做data-root标记, 同时更改该包裹的类型为V_GROUP_TYPE
124 | if ( !parser.isResetId ) {
125 | tree.attr[ "data-type" ] = V_GROUP_TYPE;
126 | } else {
127 | tree.attr[ "data-root" ] = "true";
128 | }
129 | }
130 |
131 | if ( tree.name === "brackets" ) {
132 | tree.attr[ "data-brackets" ] = "true";
133 | }
134 |
135 | for ( var i = 0, len= tree.operand.length; i < len; i++ ) {
136 |
137 | currentOperand = tree.operand[ i ];
138 |
139 | if ( !currentOperand ) {
140 |
141 | tree.operand[ i ] = currentOperand;
142 |
143 | } else {
144 |
145 | if ( COMPARISON_TABLE[ tree.name ] ) {
146 |
147 | if ( typeof currentOperand === "string" ) {
148 |
149 | // brackets树的前两个节点不用处理
150 | if ( tree.name !== "brackets" || i > 1 ) {
151 | tree.operand[ i ] = {
152 | name: "combination",
153 | operand: [ currentOperand ],
154 | attr: {
155 | id: parser.getGroupId(),
156 | "data-type": GROUP_TYPE
157 | }
158 | };
159 | }
160 |
161 | } else {
162 |
163 | // 包裹函数的参数
164 | if ( currentOperand.name !== "combination" ) {
165 |
166 | tree.operand[ i ] = {
167 | name: "combination",
168 | operand: [ null ],
169 | attr: {
170 | id: parser.getGroupId(),
171 | "data-type": GROUP_TYPE
172 | }
173 | };
174 |
175 | // 占位符特殊处理
176 | if ( currentOperand.name === "placeholder" ) {
177 | tree.operand[ i ].operand[ 0 ] = {
178 | name: "combination",
179 | operand: [ currentOperand ],
180 | attr: {
181 | id: parser.getGroupId(),
182 | "data-type": GROUP_TYPE,
183 | "data-placeholder": "true"
184 | }
185 | };
186 | currentOperand.attr = {
187 | id: parser.getGroupId()
188 | };
189 | } else {
190 | tree.operand[ i ].operand[ 0 ] = supplementTree( parser, currentOperand, tree.operand[ i ] );
191 | }
192 |
193 | } else {
194 |
195 | currentOperand.attr = {
196 | "data-type": GROUP_TYPE
197 | };
198 |
199 | tree.operand[ i ] = supplementTree( parser, currentOperand, tree );
200 |
201 | }
202 |
203 | }
204 |
205 | } else {
206 |
207 | if ( typeof currentOperand === "string" ) {
208 | tree.operand[ i ] = currentOperand;
209 | } else {
210 |
211 | // // 重置组类型
212 | // if ( !isRoot && tree.operand.length === 1 ) {
213 | // tree.attr[ "data-type" ] = V_GROUP_TYPE;
214 | // }
215 |
216 | // 占位符附加包裹
217 | if ( currentOperand.name === "placeholder" ) {
218 | tree.operand[ i ] = {
219 | name: "combination",
220 | operand: [ currentOperand ],
221 | attr: {
222 | id: parser.getGroupId(),
223 | "data-type": GROUP_TYPE,
224 | "data-placeholder": "true"
225 | }
226 | };
227 | currentOperand.attr = {
228 | id: parser.getGroupId()
229 | };
230 | } else {
231 | tree.operand[ i ] = supplementTree( parser, currentOperand, tree );
232 | }
233 |
234 | }
235 |
236 | }
237 |
238 | }
239 |
240 | }
241 |
242 | return tree;
243 |
244 | }
245 |
246 | function generateId () {
247 | return PID_PREFIX + ( ++PID );
248 | }
249 |
250 | return Parser;
251 |
252 | } );
253 |
254 |
--------------------------------------------------------------------------------
/src/position/position.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 定位模块
3 | */
4 |
5 |
6 | define( function ( require ) {
7 |
8 | var kity = require( "kity" ),
9 |
10 | // 表达式的内容组"标签"
11 | CONTENT_DATA_TYPE = "kf-editor-exp-content-box",
12 |
13 | PositionComponenet = kity.createClass( 'PositionComponenet', {
14 |
15 | constructor: function ( kfEditor ) {
16 |
17 | this.kfEditor = kfEditor;
18 |
19 | this.initServices();
20 |
21 | },
22 |
23 | initServices: function () {
24 |
25 | this.kfEditor.registerService( "position.get.group", this, {
26 | getGroupByTarget: this.getGroupByTarget
27 | } );
28 |
29 | this.kfEditor.registerService( "position.get.parent.group", this, {
30 | getParentGroupByTarget: this.getParentGroupByTarget
31 | } );
32 |
33 | this.kfEditor.registerService( "position.get.wrap", this, {
34 | getWrap: this.getWrap
35 | } );
36 |
37 | this.kfEditor.registerService( "position.get.group.info", this, {
38 | getGroupInfoByNode: this.getGroupInfoByNode
39 | } );
40 |
41 | this.kfEditor.registerService( "position.get.parent.info", this, {
42 | getParentInfoByNode: this.getParentInfoByNode
43 | } );
44 |
45 | },
46 |
47 | getGroupByTarget: function ( target ) {
48 |
49 | var groupDom = getGroup( target, false, false );
50 |
51 | if ( groupDom ) {
52 | return this.kfEditor.requestService( "syntax.get.group.content", groupDom.id );
53 | }
54 |
55 | return null;
56 |
57 | },
58 |
59 | getParentGroupByTarget: function ( target ) {
60 |
61 | var groupDom = getGroup( target, true, false );
62 |
63 | if ( groupDom ) {
64 | return this.kfEditor.requestService( "syntax.get.group.content", groupDom.id );
65 | }
66 |
67 | return null;
68 |
69 | },
70 |
71 | getWrap: function ( node ) {
72 |
73 | return getGroup( node, true, true );
74 |
75 | },
76 |
77 | /**
78 | * 给定一个节点, 获取其节点所属的组及其在该组内的偏移
79 | * @param target 目标节点
80 | */
81 | getGroupInfoByNode: function ( target ) {
82 |
83 | var result = null,
84 | oldTarget = null;
85 |
86 | oldTarget = target;
87 | while ( target = getGroup( target, true, false ) ) {
88 |
89 | if ( target.getAttribute( "data-type" ) === "kf-editor-group" ) {
90 | break;
91 | }
92 |
93 | oldTarget = target
94 |
95 | }
96 |
97 | result = {
98 | group: this.kfEditor.requestService( "syntax.get.group.content", target.id )
99 | };
100 |
101 | result.index = result.group.content.indexOf( oldTarget );
102 |
103 | return result;
104 |
105 | },
106 |
107 | /**
108 | * 给定一个节点, 获取其节点所属的直接包含组及其在该直接包含组内的偏移
109 | * @param target 目标节点
110 | */
111 | getParentInfoByNode: function ( target ) {
112 |
113 | var group = getGroup( target, true, false );
114 |
115 | group = this.kfEditor.requestService( "syntax.get.group.content", group.id );
116 |
117 | return {
118 | group: group,
119 | index: group.content.indexOf( target )
120 | };
121 |
122 | }
123 |
124 | } );
125 |
126 | /**
127 | * 获取给定节点元素所属的组
128 | * @param node 当前点击的节点
129 | * @param isAllowVirtual 是否允许选择虚拟组
130 | * @param isAllowWrap 是否允许选择目标节点的最小包裹单位
131 | * @returns {*}
132 | */
133 | function getGroup ( node, isAllowVirtual, isAllowWrap ) {
134 |
135 | var tagName = null;
136 |
137 | if ( !node.ownerSVGElement ) {
138 | return null;
139 | }
140 |
141 | node = node.parentNode;
142 |
143 | tagName = node.tagName.toLowerCase();
144 |
145 | if ( node && tagName !== "body" && tagName !== "svg" ) {
146 |
147 | if ( node.getAttribute( "data-type" ) === "kf-editor-group" ) {
148 | return node;
149 | }
150 |
151 | if ( isAllowVirtual && node.getAttribute( "data-type" ) === "kf-editor-virtual-group" ) {
152 | return node;
153 | }
154 |
155 | if ( isAllowWrap && node.getAttribute( "data-flag" ) !== null ) {
156 | return node;
157 | }
158 |
159 | return getGroup( node, isAllowVirtual, isAllowWrap );
160 |
161 | } else {
162 | return null;
163 | }
164 |
165 | }
166 |
167 | function getWrap ( isAllowWrap ) {
168 |
169 | }
170 |
171 | return PositionComponenet;
172 |
173 | } );
--------------------------------------------------------------------------------
/src/render/render.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-17.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | Assembly = require( "kf" ).Assembly,
10 |
11 | DEFAULT_OPTIONS = {
12 | autoresize: false,
13 | fontsize: 30,
14 | padding: [ 20, 50 ]
15 | },
16 |
17 | RenderComponenet = kity.createClass( 'RenderComponent', {
18 |
19 | constructor: function ( kfEditor ) {
20 |
21 | this.kfEditor = kfEditor;
22 | this.assembly = null;
23 | this.formula = null;
24 |
25 | this.canvasZoom = 1;
26 |
27 | this.record = {
28 | select: {},
29 | cursor: {}
30 | };
31 |
32 | this.initCanvas();
33 |
34 | this.initServices();
35 | this.initCommands();
36 |
37 | },
38 |
39 | initCanvas: function () {
40 |
41 | var canvasContainer = this.kfEditor.requestService( "ui.get.canvas.container" );
42 |
43 | this.assembly = Assembly.use( canvasContainer, DEFAULT_OPTIONS );
44 | this.formula = this.assembly.formula;
45 |
46 | },
47 |
48 | initServices: function () {
49 |
50 | this.kfEditor.registerService( "render.relocation", this, {
51 | relocation: this.relocation
52 | } );
53 |
54 | this.kfEditor.registerService( "render.select.group.content", this, {
55 | selectGroupContent: this.selectGroupContent
56 | } );
57 |
58 | this.kfEditor.registerService( "render.select.group", this, {
59 | selectGroup: this.selectGroup
60 | } );
61 |
62 | this.kfEditor.registerService( "render.select.group.all", this, {
63 | selectAllGroup: this.selectAllGroup
64 | } );
65 |
66 | this.kfEditor.registerService( "render.select.current.cursor", this, {
67 | selectCurrentCursor: this.selectCurrentCursor
68 | } );
69 |
70 | this.kfEditor.registerService( "render.reselect", this, {
71 | reselect: this.reselect
72 | } );
73 |
74 | this.kfEditor.registerService( "render.clear.select", this, {
75 | clearSelect: this.clearSelect
76 | } );
77 |
78 | this.kfEditor.registerService( "render.set.canvas.zoom", this, {
79 | setCanvasZoom: this.setCanvasZoom
80 | } );
81 |
82 | this.kfEditor.registerService( "render.get.canvas.zoom", this, {
83 | getCanvasZoom: this.getCanvasZoom
84 | } );
85 |
86 | this.kfEditor.registerService( "render.get.paper.offset", this, {
87 | getPaperOffset: this.getPaperOffset
88 | } );
89 |
90 | this.kfEditor.registerService( "render.draw", this, {
91 | render: this.render
92 | } );
93 |
94 | this.kfEditor.registerService( "render.insert.string", this, {
95 | insertString: this.insertString
96 | } );
97 |
98 | this.kfEditor.registerService( "render.insert.group", this, {
99 | insertGroup: this.insertGroup
100 | } );
101 |
102 | this.kfEditor.registerService( "render.get.paper", this, {
103 | getPaper: this.getPaper
104 | } );
105 |
106 | },
107 |
108 | initCommands: function () {
109 |
110 | this.kfEditor.registerCommand( "render", this, this.render );
111 |
112 | this.kfEditor.registerCommand( "getPaper", this, this.getPaper );
113 |
114 | },
115 |
116 | relocation: function () {
117 |
118 | var formulaSpace = this.formula.container.getRenderBox(),
119 | viewPort = this.formula.getViewPort();
120 |
121 | viewPort.center.x = formulaSpace.width / 2;
122 | viewPort.center.y = formulaSpace.height / 2;
123 |
124 | this.formula.setViewPort( viewPort );
125 |
126 | },
127 |
128 | selectGroup: function ( groupId ) {
129 |
130 | var groupObject = this.kfEditor.requestService( "syntax.get.group.object", groupId ),
131 | isPlaceholder = this.kfEditor.requestService( "syntax.valid.placeholder", groupId );
132 |
133 | this.clearSelect();
134 |
135 | if ( groupObject.node.getAttribute( "data-root" ) ) {
136 | // 根节点不着色
137 | return;
138 | }
139 |
140 | // 占位符着色
141 | if ( isPlaceholder ) {
142 | // 替换占位符包裹组为占位符本身
143 | groupObject = this.kfEditor.requestService( "syntax.get.group.object", groupObject.operands[ 0 ].node.id );
144 | }
145 |
146 | this.record.select.lastSelect = groupObject;
147 |
148 | groupObject.select();
149 |
150 | },
151 |
152 | selectGroupContent: function ( group ) {
153 |
154 | // 处理占位符
155 | if ( group.groupObj.getAttribute( "data-placeholder" ) !== null ) {
156 | group = {
157 | id: group.content[ 0 ].id
158 | };
159 | }
160 |
161 | var groupObject = this.kfEditor.requestService( "syntax.get.group.object", group.id );
162 |
163 | this.clearSelect();
164 |
165 | this.record.select.lastSelect = groupObject;
166 |
167 | if ( groupObject.node.getAttribute( "data-root" ) ) {
168 | // 根节点不着色
169 | return;
170 | }
171 | groupObject.select();
172 |
173 | },
174 |
175 | selectAllGroup: function ( group ) {
176 |
177 | // 处理占位符
178 | if ( group.groupObj.getAttribute( "data-placeholder" ) !== null ) {
179 | group = {
180 | id: group.content[ 0 ].id
181 | };
182 | }
183 |
184 | var groupObject = this.kfEditor.requestService( "syntax.get.group.object", group.id );
185 |
186 | this.clearSelect();
187 |
188 | this.record.select.lastSelect = groupObject;
189 |
190 | groupObject.selectAll();
191 |
192 | },
193 |
194 | selectCurrentCursor: function () {
195 |
196 | var cursorInfo = this.kfEditor.requestService( "syntax.get.record.cursor" ),
197 | group = this.kfEditor.requestService( "syntax.get.group.object", cursorInfo.groupId ),
198 | box = null,
199 | offset = -1,
200 | width = 0,
201 | height = group.getRenderBox().height,
202 | startIndex = Math.min( cursorInfo.startOffset, cursorInfo.endOffset ),
203 | endIndex = Math.max( cursorInfo.startOffset, cursorInfo.endOffset );
204 |
205 | this.clearSelect();
206 |
207 | // 更新记录
208 | this.record.select.lastSelect = group;
209 |
210 | for ( var i = startIndex, len = endIndex; i < len; i++ ) {
211 |
212 | box = group.getOperand( i ).getRenderBox();
213 |
214 | if ( offset == -1 ) {
215 | offset = box.x;
216 | }
217 |
218 | width += box.width;
219 |
220 | }
221 |
222 | group.setBoxSize( width, height );
223 | group.selectAll();
224 | group.getBox().translate( offset, 0 );
225 |
226 | },
227 |
228 | reselect: function () {
229 |
230 | var cursorInfo = this.kfEditor.requestService( "syntax.get.record.cursor" ),
231 | groupObject = null;
232 |
233 | groupObject = this.kfEditor.requestService( "syntax.get.group.object", cursorInfo.groupId );
234 |
235 | this.clearSelect();
236 |
237 | this.record.select.lastSelect = groupObject;
238 |
239 | if ( groupObject.node.getAttribute( "data-root" ) ) {
240 | // 根节点不着色
241 | return;
242 | }
243 | groupObject.select();
244 |
245 | },
246 |
247 | clearSelect: function () {
248 |
249 | var box = null,
250 | transform = null,
251 | currentSelect = this.record.select.lastSelect;
252 |
253 | if ( !currentSelect ) {
254 | return;
255 | }
256 |
257 | currentSelect.unselect();
258 | box = currentSelect.getRenderBox();
259 | currentSelect.setBoxSize( box.width, box.height );
260 |
261 | transform = currentSelect.getBox().getTransform();
262 |
263 | if ( transform ) {
264 | transform.m.e = 0;
265 | transform.m.f = 0;
266 | }
267 |
268 | currentSelect.getBox().setTransform( transform );
269 |
270 | },
271 |
272 | getPaper: function () {
273 | return this.formula;
274 | },
275 |
276 | render: function ( latexStr ) {
277 |
278 | var parsedTree = this.kfEditor.requestService( "parser.parse", latexStr, true ),
279 | objTree = this.assembly.regenerateBy( parsedTree );
280 |
281 | // 更新语法模块所维护的树
282 | this.kfEditor.requestService( "syntax.update.objtree", objTree );
283 | this.relocation();
284 |
285 | },
286 |
287 | setCanvasZoom: function ( zoom ) {
288 |
289 | var viewPort = this.formula.getViewPort();
290 |
291 | this.canvasZoom = zoom;
292 | viewPort.zoom = zoom;
293 |
294 | this.formula.setViewPort( viewPort );
295 |
296 | },
297 |
298 | getCanvasZoom: function () {
299 | return this.canvasZoom;
300 | }
301 |
302 | } );
303 |
304 | return RenderComponenet;
305 |
306 | } );
--------------------------------------------------------------------------------
/src/syntax/move.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 光标控制
3 | */
4 |
5 | define( function ( require, exports, module ) {
6 |
7 | var kity = require( "kity" ),
8 | DIRECTION = {
9 | LEFT: 'left',
10 | RIGHT: 'right'
11 | };
12 |
13 | return kity.createClass( "MoveComponent", {
14 |
15 | constructor: function ( parentComponent, kfEditor ) {
16 |
17 | this.parentComponent = parentComponent;
18 | this.kfEditor = kfEditor;
19 |
20 | },
21 |
22 | leftMove: function () {
23 |
24 | var cursorInfo = this.parentComponent.getCursorRecord();
25 |
26 | cursorInfo = updateCursorGoLeft.call( this, cursorInfo );
27 |
28 | // cursorInfo 为null则不用处理
29 | if ( cursorInfo ) {
30 | this.parentComponent.updateCursor( cursorInfo.groupId, cursorInfo.startOffset, cursorInfo.endOffset );
31 | }
32 |
33 | },
34 |
35 | rightMove: function () {
36 |
37 | var cursorInfo = this.parentComponent.getCursorRecord();
38 |
39 | cursorInfo = updateCursorGoRight.call( this, cursorInfo );
40 |
41 | // cursorInfo 为null则不用处理
42 | if ( cursorInfo ) {
43 | this.parentComponent.updateCursor( cursorInfo.groupId, cursorInfo.startOffset, cursorInfo.endOffset );
44 | }
45 |
46 | }
47 |
48 | } );
49 |
50 |
51 | function updateCursorGoLeft ( cursorInfo ) {
52 |
53 | var prevGroupNode = null,
54 | syntaxComponent = this.parentComponent,
55 | containerInfo = null;
56 |
57 | if ( cursorInfo.startOffset === cursorInfo.endOffset ) {
58 |
59 | containerInfo = syntaxComponent.getGroupContent( cursorInfo.groupId );
60 |
61 | if ( isPlaceholderNode( containerInfo.groupObj ) ) {
62 | return locateOuterIndex( this, containerInfo.groupObj, DIRECTION.LEFT );
63 | }
64 |
65 | if ( cursorInfo.startOffset > 0 ) {
66 |
67 | prevGroupNode = containerInfo.content[ cursorInfo.startOffset - 1 ];
68 |
69 | if ( isGroupNode( prevGroupNode ) ) {
70 | cursorInfo = locateIndex( this, prevGroupNode, DIRECTION.LEFT );
71 | } else {
72 | cursorInfo.startOffset -= 1;
73 | cursorInfo.endOffset = cursorInfo.startOffset;
74 | }
75 |
76 | // 跳出当前容器, 回溯
77 | } else {
78 |
79 | cursorInfo = locateOuterIndex( this, containerInfo.groupObj, DIRECTION.LEFT );
80 |
81 | }
82 |
83 | } else {
84 |
85 | cursorInfo.startOffset = Math.min( cursorInfo.startOffset, cursorInfo.endOffset );
86 | // 收缩
87 | cursorInfo.endOffset = cursorInfo.startOffset;
88 |
89 | }
90 |
91 | return cursorInfo;
92 |
93 | }
94 |
95 | function updateCursorGoRight ( cursorInfo ) {
96 |
97 | var nextGroupNode = null,
98 | syntaxComponent = this.parentComponent,
99 | containerInfo = null;
100 |
101 | if ( cursorInfo.startOffset === cursorInfo.endOffset ) {
102 |
103 | containerInfo = syntaxComponent.getGroupContent( cursorInfo.groupId );
104 |
105 | if ( isPlaceholderNode( containerInfo.groupObj ) ) {
106 | return locateOuterIndex( this, containerInfo.groupObj, DIRECTION.RIGHT );
107 | }
108 |
109 | if ( cursorInfo.startOffset < containerInfo.content.length ) {
110 |
111 | nextGroupNode = containerInfo.content[ cursorInfo.startOffset ];
112 |
113 | // 进入容器内部
114 | if ( isGroupNode( nextGroupNode ) ) {
115 | cursorInfo = locateIndex( this, nextGroupNode, DIRECTION.RIGHT );
116 | } else {
117 | cursorInfo.startOffset += 1;
118 | cursorInfo.endOffset = cursorInfo.startOffset;
119 | }
120 |
121 | // 跳出当前容器, 回溯
122 | } else {
123 |
124 | cursorInfo = locateOuterIndex( this, containerInfo.groupObj, DIRECTION.RIGHT );
125 |
126 | }
127 |
128 | } else {
129 |
130 | cursorInfo.endOffset = Math.max( cursorInfo.startOffset, cursorInfo.endOffset );
131 | // 收缩
132 | cursorInfo.startOffset = cursorInfo.endOffset;
133 |
134 | }
135 |
136 | return cursorInfo;
137 |
138 | }
139 |
140 | /**
141 | * 组内寻址, 入组
142 | */
143 | function locateIndex ( moveComponent, groupNode, dir ) {
144 |
145 | switch ( dir ) {
146 |
147 | case DIRECTION.LEFT:
148 | return locateLeftIndex( moveComponent, groupNode );
149 |
150 | case DIRECTION.RIGHT:
151 | return locateRightIndex( moveComponent, groupNode );
152 |
153 | }
154 |
155 | throw new Error( "undefined move direction!" );
156 |
157 | }
158 |
159 | /**
160 | * 组外寻址, 出组
161 | */
162 | function locateOuterIndex ( moveComponent, groupNode, dir ) {
163 |
164 | switch ( dir ) {
165 |
166 | case DIRECTION.LEFT:
167 | return locateOuterLeftIndex( moveComponent, groupNode );
168 |
169 | case DIRECTION.RIGHT:
170 | return locateOuterRightIndex( moveComponent, groupNode );
171 |
172 | }
173 |
174 | throw new Error( "undefined move direction!" );
175 |
176 | }
177 |
178 | // 左移内部定位
179 | function locateLeftIndex ( moveComponent, groupNode ) {
180 |
181 | var syntaxComponent = moveComponent.parentComponent,
182 | groupInfo = null,
183 | groupElement = null;
184 |
185 | if ( isPlaceholderNode( groupNode ) || isEmptyNode( groupNode ) ) {
186 | return locateOuterLeftIndex( moveComponent, groupNode );
187 | }
188 |
189 | if ( isGroupNode( groupNode ) ) {
190 |
191 | groupInfo = syntaxComponent.getGroupContent( groupNode.id );
192 | // 容器内部中末尾的元素
193 | groupElement = groupInfo.content[ groupInfo.content.length - 1 ];
194 |
195 | // 空检测
196 | if ( isEmptyNode( groupElement ) ) {
197 |
198 | // 做跳出处理
199 | return locateOuterLeftIndex( moveComponent, groupElement );
200 |
201 | }
202 |
203 | // 待定位的组本身就是一个容器, 则检测其内部结构是否还包含容器
204 | if ( isContainerNode( groupNode ) ) {
205 |
206 | // 进入到占位符包裹容器内
207 | if ( isPlaceholderNode( groupElement ) ) {
208 |
209 | return {
210 | groupId: groupElement.id,
211 | startOffset: 0,
212 | endOffset: 0
213 | };
214 |
215 | // 内部元素仍然是一个容器并且只有这一个内部元素,则进行递归处理
216 | } else if ( isContainerNode( groupElement ) && groupInfo.content.length === 1 ) {
217 | return locateLeftIndex( moveComponent, groupElement );
218 | }
219 |
220 | return {
221 | groupId: groupNode.id,
222 | startOffset: groupInfo.content.length,
223 | endOffset: groupInfo.content.length
224 | };
225 |
226 | // 仅是一个组, 进入组内部处理, 找到目标容器
227 | } else {
228 |
229 | while ( !isContainerNode( groupElement ) && !isEmptyNode( groupElement ) && !isPlaceholderNode( groupElement ) ) {
230 | groupInfo = syntaxComponent.getGroupContent( groupElement.id );
231 | groupElement = groupInfo.content[ groupInfo.content.length - 1 ];
232 | }
233 |
234 | if ( isEmptyNode( groupElement ) ) {
235 | return locateOuterLeftIndex( moveComponent, groupElement );
236 | }
237 |
238 | if ( isPlaceholderNode( groupElement ) ) {
239 | return {
240 | groupId: groupElement.id,
241 | startOffset: groupInfo.content.length,
242 | endOffset: groupInfo.content.length
243 | };
244 | }
245 |
246 | return locateLeftIndex( moveComponent, groupElement );
247 |
248 | }
249 |
250 | }
251 |
252 | return null;
253 |
254 | }
255 |
256 | // 左移外部定位
257 | function locateOuterLeftIndex ( moveComponent, groupNode ) {
258 |
259 | var kfEditor = moveComponent.kfEditor,
260 | syntaxComponent = moveComponent.parentComponent,
261 | outerGroupInfo = null,
262 | groupInfo = null;
263 |
264 | // 根容器, 不用再跳出
265 | if ( isRootNode( groupNode ) ) {
266 | return null;
267 | }
268 |
269 | outerGroupInfo = kfEditor.requestService( "position.get.parent.info", groupNode );
270 |
271 | while ( outerGroupInfo.index === 0 ) {
272 |
273 | if ( isRootNode( outerGroupInfo.group.groupObj ) ) {
274 | return {
275 | groupId: outerGroupInfo.group.id,
276 | startOffset: 0,
277 | endOffset: 0
278 | };
279 | }
280 |
281 | // 如果父组是一个容器, 并且该容器包含不止一个节点, 则跳到父组开头
282 | if ( isContainerNode( outerGroupInfo.group.groupObj ) && outerGroupInfo.group.content.length > 1 ) {
283 | return {
284 | groupId: outerGroupInfo.group.id,
285 | startOffset: 0,
286 | endOffset: 0
287 | };
288 | }
289 |
290 | outerGroupInfo = kfEditor.requestService( "position.get.parent.info", outerGroupInfo.group.groupObj );
291 |
292 | }
293 |
294 | groupNode = outerGroupInfo.group.content[ outerGroupInfo.index - 1 ];
295 |
296 | // 定位到的组是一个容器, 则定位到容器尾部
297 | if ( isGroupNode( groupNode ) ) {
298 |
299 | // 容器节点
300 | if ( isContainerNode( groupNode ) ) {
301 |
302 | // 进入容器内部
303 | return locateLeftIndex( moveComponent, groupNode );
304 |
305 | // 组节点
306 | } else {
307 |
308 | return locateLeftIndex( moveComponent, groupNode );
309 |
310 | }
311 |
312 | return {
313 | groupId: groupNode.id,
314 | startOffset: groupInfo.content.length,
315 | endOffset: groupInfo.content.length
316 | };
317 |
318 | }
319 |
320 | if ( isEmptyNode( groupNode ) ) {
321 | return locateOuterLeftIndex( moveComponent, groupNode );
322 | }
323 |
324 | return {
325 | groupId: outerGroupInfo.group.id,
326 | startOffset: outerGroupInfo.index,
327 | endOffset: outerGroupInfo.index
328 | };
329 |
330 | }
331 |
332 | // 右移内部定位
333 | function locateRightIndex ( moveComponent, groupNode ) {
334 |
335 | var syntaxComponent = moveComponent.parentComponent,
336 | groupInfo = null,
337 | groupElement = null;
338 |
339 | if ( isGroupNode( groupNode ) ) {
340 |
341 | groupInfo = syntaxComponent.getGroupContent( groupNode.id );
342 | // 容器内部中末尾的元素
343 | groupElement = groupInfo.content[ 0 ];
344 |
345 | // 待定位的组本身就是一个容器, 则检测其内部结构是否还包含容器
346 | if ( isContainerNode( groupNode ) ) {
347 |
348 | // 内部元素仍然是一个容器
349 | if ( isContainerNode( groupElement ) ) {
350 | // 递归处理
351 | return locateRightIndex( moveComponent, groupElement );
352 | }
353 |
354 | return {
355 | groupId: groupNode.id,
356 | startOffset: 0,
357 | endOffset: 0
358 | };
359 |
360 | // 仅是一个组, 进入组内部处理, 找到目标容器
361 | } else {
362 |
363 | while ( !isContainerNode( groupElement ) && !isPlaceholderNode( groupElement ) && !isEmptyNode( groupElement ) ) {
364 | groupInfo = syntaxComponent.getGroupContent( groupElement.id );
365 | groupElement = groupInfo.content[ 0 ];
366 | }
367 |
368 | // 定位到占位符内部
369 | if ( isPlaceholderNode( groupElement ) ) {
370 | return {
371 | groupId: groupElement.id,
372 | startOffset: 0,
373 | endOffset: 0
374 | };
375 | } else if ( isEmptyNode( groupElement ) ) {
376 | return locateOuterRightIndex( moveComponent, groupElement );
377 | } else {
378 | return locateRightIndex( moveComponent, groupElement );
379 | }
380 |
381 | }
382 |
383 | }
384 |
385 | return null;
386 |
387 | }
388 |
389 | // 右移外部定位
390 | function locateOuterRightIndex ( moveComponent, groupNode ) {
391 |
392 | var kfEditor = moveComponent.kfEditor,
393 | syntaxComponent = moveComponent.parentComponent,
394 | outerGroupInfo = null,
395 | groupInfo = null;
396 |
397 | // 根容器, 不用再跳出
398 | if ( isRootNode( groupNode ) ) {
399 | return null;
400 | }
401 |
402 | outerGroupInfo = kfEditor.requestService( "position.get.parent.info", groupNode );
403 |
404 | // 仍然需要回溯
405 | while ( outerGroupInfo.index === outerGroupInfo.group.content.length - 1 ) {
406 |
407 | if ( isRootNode( outerGroupInfo.group.groupObj ) ) {
408 | return {
409 | groupId: outerGroupInfo.group.id,
410 | startOffset: outerGroupInfo.group.content.length,
411 | endOffset: outerGroupInfo.group.content.length
412 | };
413 | }
414 |
415 | // 如果父组是一个容器, 并且该容器包含不止一个节点, 则跳到父组末尾
416 | if ( isContainerNode( outerGroupInfo.group.groupObj ) && outerGroupInfo.group.content.length > 1 ) {
417 | return {
418 | groupId: outerGroupInfo.group.id,
419 | startOffset: outerGroupInfo.group.content.length,
420 | endOffset: outerGroupInfo.group.content.length
421 | };
422 | }
423 |
424 | outerGroupInfo = kfEditor.requestService( "position.get.parent.info", outerGroupInfo.group.groupObj );
425 |
426 | }
427 |
428 | groupNode = outerGroupInfo.group.content[ outerGroupInfo.index + 1 ];
429 |
430 | // 空节点处理
431 | if ( isEmptyNode( groupNode ) ) {
432 | return locateOuterRightIndex( moveComponent, groupNode );
433 | }
434 |
435 | // 定位到的组是一个容器, 则定位到容器内部开头位置上
436 | if ( isContainerNode( groupNode ) ) {
437 |
438 | return {
439 | groupId: groupNode.id,
440 | startOffset: 0,
441 | endOffset: 0
442 | };
443 |
444 | }
445 |
446 | return {
447 | groupId: outerGroupInfo.group.id,
448 | startOffset: outerGroupInfo.index + 1,
449 | endOffset: outerGroupInfo.index + 1
450 | };
451 |
452 | }
453 |
454 | function isRootNode ( node ) {
455 |
456 | return !!node.getAttribute( "data-root" );
457 |
458 | }
459 |
460 | function isContainerNode ( node ) {
461 | return node.getAttribute( "data-type" ) === "kf-editor-group"
462 | }
463 |
464 | function isGroupNode ( node ) {
465 | var dataType = node.getAttribute( "data-type" );
466 | return dataType === "kf-editor-group" || dataType === "kf-editor-virtual-group";
467 | }
468 |
469 | function isPlaceholderNode ( node ) {
470 | return !!node.getAttribute( "data-placeholder" );
471 | }
472 |
473 | function isEmptyNode ( node ) {
474 | return node.getAttribute( "data-flag" ) === "Empty";
475 | }
476 |
477 | } );
--------------------------------------------------------------------------------
/src/syntax/syntax.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 语法控制单元
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | MoveComponent = require( "syntax/move" ),
10 |
11 | CURSOR_CHAR = "\uF155",
12 |
13 | SyntaxComponenet = kity.createClass( 'SyntaxComponenet', {
14 |
15 | constructor: function ( kfEditor ) {
16 |
17 | this.kfEditor = kfEditor;
18 |
19 | // 数据记录表
20 | this.record = {
21 |
22 | // 光标位置
23 | cursor: {
24 | group: null,
25 | startOffset: -1,
26 | endOffset: -1
27 | }
28 |
29 | };
30 |
31 | // 子组件结构
32 | this.components = {};
33 |
34 | // 对象树
35 | this.objTree = null;
36 |
37 | this.initComponents();
38 | this.initServices();
39 |
40 | },
41 |
42 | initComponents: function () {
43 | this.components[ 'move' ] = new MoveComponent( this, this.kfEditor );
44 | },
45 |
46 | initServices: function () {
47 |
48 | this.kfEditor.registerService( "syntax.update.objtree", this, {
49 | updateObjTree: this.updateObjTree
50 | } );
51 |
52 | this.kfEditor.registerService( "syntax.get.objtree", this, {
53 | getObjectTree: this.getObjectTree
54 | } );
55 |
56 | this.kfEditor.registerService( "syntax.get.group.object", this, {
57 | getGroupObject: this.getGroupObject
58 | } );
59 |
60 | this.kfEditor.registerService( "syntax.valid.placeholder", this, {
61 | isPlaceholder: this.isPlaceholder
62 | } );
63 |
64 | this.kfEditor.registerService( "syntax.valid.brackets", this, {
65 | isBrackets: this.isBrackets
66 | } );
67 |
68 | this.kfEditor.registerService( "syntax.get.group.content", this, {
69 | getGroupContent: this.getGroupContent
70 | } );
71 |
72 | this.kfEditor.registerService( "syntax.update.record.cursor", this, {
73 | updateCursor: this.updateCursor
74 | } );
75 |
76 | this.kfEditor.registerService( "syntax.update.selection", this, {
77 | updateSelection: this.updateSelection
78 | } );
79 |
80 | this.kfEditor.registerService( "syntax.get.record.cursor", this, {
81 | getCursorRecord: this.getCursorRecord
82 | } );
83 |
84 | this.kfEditor.registerService( "syntax.get.latex.info", this, {
85 | getLatexInfo: this.getLatexInfo
86 | } );
87 |
88 | this.kfEditor.registerService( "syntax.insert.string", this, {
89 | insertString: this.insertString
90 | } );
91 |
92 | this.kfEditor.registerService( "syntax.insert.group", this, {
93 | insertGroup: this.insertGroup
94 | } );
95 |
96 | this.kfEditor.registerService( "syntax.serialization", this, {
97 | serialization: this.serialization
98 | } );
99 |
100 | this.kfEditor.registerService( "syntax.cursor.move.left", this, {
101 | leftMove: this.leftMove
102 | } );
103 |
104 | this.kfEditor.registerService( "syntax.cursor.move.right", this, {
105 | rightMove: this.rightMove
106 | } );
107 |
108 | },
109 |
110 | updateObjTree: function ( objTree ) {
111 |
112 | var selectInfo = objTree.select;
113 |
114 | if ( selectInfo && selectInfo.groupId ) {
115 | this.updateCursor( selectInfo.groupId, selectInfo.startOffset, selectInfo.endOffset );
116 | }
117 |
118 | this.objTree = objTree;
119 |
120 | },
121 |
122 | // 验证给定ID的组是否是占位符
123 | isPlaceholder: function ( groupId ) {
124 | return !!this.objTree.mapping[ groupId ].objGroup.node.getAttribute( "data-placeholder" );
125 | },
126 |
127 | isBrackets: function ( groupId ) {
128 | return !!this.objTree.mapping[ groupId ].objGroup.node.getAttribute( "data-brackets" );
129 | },
130 |
131 | getObjectTree: function () {
132 | return this.objTree;
133 | },
134 |
135 | getGroupObject: function ( id ) {
136 |
137 | return this.objTree.mapping[ id ].objGroup || null;
138 |
139 | },
140 |
141 | getCursorRecord: function () {
142 |
143 | return kity.Utils.extend( {}, this.record.cursor ) || null;
144 |
145 | },
146 |
147 | getGroupContent: function ( groupId ) {
148 |
149 | var groupInfo = this.objTree.mapping[ groupId ],
150 | content = [],
151 | operands = groupInfo.objGroup.operands,
152 | offset = operands.length - 1,
153 | isLtr = groupInfo.strGroup.traversal !== "rtl";
154 |
155 | kity.Utils.each( operands, function ( operand, i ) {
156 |
157 | if ( isLtr ) {
158 | content.push( operand.node );
159 | } else {
160 | content[ offset - i ] = operand.node;
161 | }
162 |
163 | } );
164 |
165 | return {
166 | id: groupId,
167 | traversal: groupInfo.strGroup.traversal || "ltr",
168 | groupObj: groupInfo.objGroup.node,
169 | content: content
170 | };
171 |
172 | },
173 |
174 | updateSelection: function ( group ) {
175 |
176 | var groupObj = this.objTree.mapping[ group.id ],
177 | curStrGroup = groupObj.strGroup,
178 | parentGroup = null,
179 | parentGroupObj = null,
180 | resultStr = null,
181 | startOffset = -1,
182 | endOffset = -1;
183 |
184 | parentGroup = group;
185 | parentGroupObj = groupObj;
186 |
187 | if ( curStrGroup.name === "combination" ) {
188 |
189 | this.record.cursor = {
190 | groupId: parentGroup.id,
191 | startOffset: 0,
192 | endOffset: curStrGroup.operand.length
193 | };
194 |
195 | // 字符内容处理
196 | curStrGroup.operand.unshift( CURSOR_CHAR );
197 | curStrGroup.operand.push( CURSOR_CHAR );
198 |
199 | } else {
200 |
201 | // 函数处理, 找到函数所处的最大范围
202 | while ( parentGroupObj.strGroup.name !== "combination" || parentGroup.content === 1 ) {
203 |
204 | group = parentGroup;
205 | groupObj = parentGroupObj;
206 |
207 | parentGroup = this.kfEditor.requestService( "position.get.parent.group", groupObj.objGroup.node );
208 | parentGroupObj = this.objTree.mapping[ parentGroup.id ];
209 |
210 | }
211 |
212 | var parentIndex = [].indexOf.call( parentGroup.content, group.groupObj );
213 |
214 | this.record.cursor = {
215 | groupId: parentGroup.id,
216 | startOffset: parentIndex,
217 | endOffset: parentIndex + 1
218 | };
219 |
220 | // 在当前函数所在的位置作标记
221 | parentGroupObj.strGroup.operand.splice( parentIndex+1, 0, CURSOR_CHAR );
222 | parentGroupObj.strGroup.operand.splice( parentIndex, 0, CURSOR_CHAR );
223 |
224 | }
225 |
226 | // 返回结构树进过序列化后所对应的latex表达式, 同时包含有当前光标定位点信息
227 | resultStr = this.kfEditor.requestService( "parser.latex.serialization", this.objTree.parsedTree );
228 |
229 | startOffset = resultStr.indexOf( CURSOR_CHAR );
230 | resultStr = resultStr.replace( CURSOR_CHAR, "" );
231 | endOffset = resultStr.indexOf( CURSOR_CHAR );
232 |
233 | parentGroupObj.strGroup.operand.splice( this.record.cursor.startOffset, 1 );
234 | parentGroupObj.strGroup.operand.splice( this.record.cursor.endOffset, 1 );
235 |
236 | return {
237 | str: resultStr,
238 | startOffset: startOffset,
239 | endOffset: endOffset
240 | }
241 |
242 | },
243 |
244 | getLatexInfo: function () {
245 |
246 | var cursor = this.record.cursor,
247 | objGroup = this.objTree.mapping[ cursor.groupId ],
248 | curStrGroup = objGroup.strGroup,
249 | resultStr = null,
250 | strStartIndex = -1,
251 | strEndIndex = -1,
252 | isPlaceholder = !!curStrGroup.attr[ "data-placeholder" ];
253 |
254 | // 格式化偏移值, 保证在处理操作数时, 标记位置不会出错
255 | strStartIndex = Math.min( cursor.endOffset, cursor.startOffset );
256 | strEndIndex = Math.max( cursor.endOffset, cursor.startOffset );
257 |
258 | if ( !isPlaceholder ) {
259 |
260 | curStrGroup.operand.splice( strEndIndex, 0, CURSOR_CHAR );
261 | curStrGroup.operand.splice( strStartIndex, 0, CURSOR_CHAR );
262 | strEndIndex += 1;
263 |
264 | } else {
265 | // 找到占位符的包裹元素
266 | curStrGroup = this.kfEditor.requestService( "position.get.parent.group", objGroup.objGroup.node )
267 | curStrGroup = this.objTree.mapping[ curStrGroup.id ].strGroup;
268 | curStrGroup.operand.unshift( CURSOR_CHAR );
269 | curStrGroup.operand.push( CURSOR_CHAR );
270 | }
271 |
272 | // 返回结构树进过序列化后所对应的latex表达式, 同时包含有当前光标定位点信息
273 | resultStr = this.kfEditor.requestService( "parser.latex.serialization", this.objTree.parsedTree );
274 |
275 | if ( !isPlaceholder ) {
276 | curStrGroup.operand.splice( strEndIndex, 1 );
277 | curStrGroup.operand.splice( strStartIndex, 1 );
278 | } else {
279 | curStrGroup.operand.shift();
280 | curStrGroup.operand.pop();
281 | }
282 |
283 | strStartIndex = resultStr.indexOf( CURSOR_CHAR );
284 | // 清除掉一个符号
285 | resultStr = resultStr.replace( CURSOR_CHAR, "" );
286 | strEndIndex = resultStr.lastIndexOf( CURSOR_CHAR );
287 |
288 | return {
289 | str: resultStr,
290 | startOffset: strStartIndex,
291 | endOffset: strEndIndex
292 | }
293 |
294 | },
295 |
296 | // 更新光标记录, 同时更新数据
297 | updateCursor: function ( groupId, startOffset, endOffset ) {
298 |
299 | if ( endOffset === undefined ) {
300 | endOffset = startOffset;
301 | }
302 |
303 | this.record.cursor = {
304 | groupId: groupId,
305 | startOffset: startOffset,
306 | endOffset: endOffset
307 | };
308 |
309 | window.tt = this.record.cursor;
310 |
311 | },
312 |
313 | serialization: function () {
314 |
315 | // 返回结构树进过序列化后所对应的latex表达式, 同时包含有当前光标定位点信息
316 | return this.kfEditor.requestService( "parser.latex.serialization", this.objTree.parsedTree );
317 |
318 |
319 | },
320 |
321 | insertGroup: function ( latexStr ) {
322 |
323 | var parsedResult = this.kfEditor.requestService( "parser.parse", latexStr ),
324 | subtree = parsedResult.tree;
325 |
326 | this.insertSubtree( subtree );
327 |
328 | },
329 |
330 | leftMove: function () {
331 | this.components.move.leftMove();
332 | },
333 |
334 | rightMove: function () {
335 | this.components.move.rightMove();
336 | },
337 |
338 | insertSubtree: function ( subtree ) {
339 |
340 | var cursorInfo = this.record.cursor,
341 | // 当前光标信息所在的子树
342 | startOffset = 0,
343 | endOffset = 0,
344 | currentTree = null,
345 | diff = 0;
346 |
347 | if ( this.isPlaceholder( cursorInfo.groupId ) ) {
348 | // 当前在占位符内,所以用子树替换占位符
349 | this.replaceTree( subtree );
350 |
351 | } else {
352 |
353 | startOffset = Math.min( cursorInfo.startOffset, cursorInfo.endOffset );
354 | endOffset = Math.max( cursorInfo.startOffset, cursorInfo.endOffset );
355 | diff = endOffset - startOffset;
356 |
357 | currentTree = this.objTree.mapping[ cursorInfo.groupId ].strGroup;
358 |
359 | // 插入子树
360 | currentTree.operand.splice( startOffset, diff, subtree );
361 |
362 | // 更新光标记录
363 | cursorInfo.startOffset += 1;
364 | cursorInfo.endOffset = cursorInfo.startOffset;
365 | }
366 |
367 | },
368 |
369 | replaceTree: function ( subtree ) {
370 |
371 | var cursorInfo = this.record.cursor,
372 | groupNode = this.objTree.mapping[ cursorInfo.groupId ].objGroup.node,
373 | parentInfo = this.kfEditor.requestService( "position.get.parent.info", groupNode ),
374 | currentTree = this.objTree.mapping[ parentInfo.group.id ].strGroup;
375 |
376 | // 替换占位符为子树
377 | currentTree.operand[ parentInfo.index ] = subtree;
378 |
379 | // 更新光标
380 | cursorInfo.groupId = parentInfo.group.id;
381 | cursorInfo.startOffset = parentInfo.index + 1;
382 | cursorInfo.endOffset = parentInfo.index + 1;
383 |
384 | }
385 |
386 | });
387 |
388 | return SyntaxComponenet;
389 |
390 | } );
--------------------------------------------------------------------------------
/src/ui/control/zoom.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 滚动缩放控制器
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var Utils = require( "base/utils" ),
8 | kity = require( "kity"),
9 |
10 | DEFAULT_OPTIONS = {
11 | min: 0.5,
12 | max: 5
13 | },
14 |
15 | ScrollZoomController = kity.createClass( 'ScrollZoomController', {
16 |
17 | constructor: function ( parentComponent, kfEditor, target, options ) {
18 |
19 | this.kfEditor = kfEditor;
20 | this.target = target;
21 |
22 | this.zoom = 1;
23 | this.step = 0.05;
24 |
25 | this.options = Utils.extend( {}, DEFAULT_OPTIONS, options );
26 |
27 | this.initEvent();
28 |
29 | },
30 |
31 | initEvent: function () {
32 |
33 | var kfEditor = this.kfEditor,
34 | _self = this,
35 | min = this.options.min,
36 | max = this.options.max,
37 | step = this.step;
38 |
39 | Utils.addEvent( this.target, 'mousewheel', function ( e ) {
40 |
41 | e.preventDefault();
42 |
43 | if ( e.wheelDelta < 0 ) {
44 | // 缩小
45 | _self.zoom -= _self.zoom * step;
46 | } else {
47 | // 放大
48 | _self.zoom += _self.zoom * step;
49 | }
50 |
51 | _self.zoom = Math.max( _self.zoom, min );
52 | _self.zoom = Math.min( _self.zoom, max );
53 |
54 | kfEditor.requestService( "render.set.canvas.zoom", _self.zoom );
55 |
56 | } );
57 |
58 | }
59 |
60 | } );
61 |
62 |
63 | return ScrollZoomController;
64 |
65 | } );
66 |
67 |
--------------------------------------------------------------------------------
/src/ui/toolbar-ele-list.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * toolbar元素列表定义
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var UI_ELE_TYPE = require( "ui/ui-impl/def/ele-type" ),
8 | BOX_TYPE = require( "ui/ui-impl/def/box-type" ),
9 | kity = require( "kity" );
10 |
11 | var config = [ {
12 | type: UI_ELE_TYPE.DRAPDOWN_BOX,
13 | options: {
14 | button: {
15 | label: "预设",
16 | icon: "assets/images/toolbar/button/pi.png"
17 | },
18 | box: {
19 | group: [ {
20 | title: "预设公式",
21 | content: [ {
22 | label: "二次公式",
23 | item: {
24 | show: '
',
25 | val: "x=\\frac {-b\\pm\\sqrt {b^2-4ac}}{2a}"
26 | }
27 | }, {
28 | label: "二项式定理",
29 | item: {
30 | show: '
',
31 | val: "{\\left(x+a\\right)}^2=\\sum^n_{k=0}{\\left(^n_k\\right)x^ka^{n-k}}"
32 | }
33 | }, {
34 | label: "勾股定理",
35 | item: {
36 | show: '
',
37 | val: "a^2+b^2=c^2"
38 | }
39 | } ]
40 | } ]
41 | }
42 | }
43 | }, {
44 | type: UI_ELE_TYPE.DELIMITER
45 | }, {
46 | type: UI_ELE_TYPE.AREA,
47 | options: {
48 | button: {
49 | icon: "assets/images/toolbar/char/button.png"
50 | },
51 | box: {
52 | width: 527,
53 | type: BOX_TYPE.OVERLAP,
54 | group: [ {
55 | title: "基础数学",
56 | content: [ {
57 | item: {
58 | show: '
',
59 | val: "\\pm"
60 | }
61 | }, {
62 | item: {
63 | show: '
',
64 | val: "\\infty"
65 | }
66 | }, {
67 | item: {
68 | show: '
',
69 | val: "="
70 | }
71 | }, {
72 | item: {
73 | show: '
',
74 | val: "\\sim"
75 | }
76 | }, {
77 | item: {
78 | show: '
',
79 | val: "\\times"
80 | }
81 | }, {
82 | item: {
83 | show: '
',
84 | val: "\\div"
85 | }
86 | }, {
87 | item: {
88 | show: '
',
89 | val: "!"
90 | }
91 | }, {
92 | item: {
93 | show: '
',
94 | val: "<"
95 | }
96 | }, {
97 | item: {
98 | show: '
',
99 | val: "\\ll"
100 | }
101 | }, {
102 | item: {
103 | show: '
',
104 | val: ">"
105 | }
106 | }, {
107 | item: {
108 | show: '
',
109 | val: "\\gg"
110 | }
111 | }, {
112 | item: {
113 | show: '
',
114 | val: "\\leq"
115 | }
116 | }, {
117 | item: {
118 | show: '
',
119 | val: "\\geq"
120 | }
121 | }, {
122 | item: {
123 | show: '
',
124 | val: "\\mp"
125 | }
126 | }, {
127 | item: {
128 | show: '
',
129 | val: "\\simeq"
130 | }
131 | }, {
132 | item: {
133 | show: '
',
134 | val: "\\equiv"
135 | }
136 | } ]
137 | }, {
138 | title: "希腊字母",
139 | content: []
140 | } ]
141 | }
142 | }
143 | }, {
144 | type: UI_ELE_TYPE.DELIMITER
145 | }, {
146 | type: UI_ELE_TYPE.DRAPDOWN_BOX,
147 | options: {
148 | button: {
149 | label: "分数",
150 | icon: "assets/images/toolbar/button/frac.png"
151 | },
152 | box: {
153 | width: 378,
154 | group: [ {
155 | title: "分数",
156 | content: [ {
157 | item: {
158 | show: '
',
159 | val: "\\frac \\placeholder\\placeholder"
160 | }
161 | }, {
162 | item: {
163 | show: '
',
164 | val: "\\placeholder/\\placeholder"
165 | }
166 | } ]
167 | }, {
168 | title: "常用分数",
169 | content: [ {
170 | item: {
171 | show: '
',
172 | val: "\\frac {dy}{dx}"
173 | }
174 | }, {
175 | item: {
176 | show: '
',
177 | val: "\\frac {\\Delta y}{\\Delta x}"
178 | }
179 | }, {
180 | item: {
181 | show: '
',
182 | val: "\\frac {\\delta y}{\\delta x}"
183 | }
184 | }, {
185 | item: {
186 | show: '
',
187 | val: "\\frac \\pi 2"
188 | }
189 | } ]
190 | } ]
191 | }
192 | }
193 | }, {
194 | type: UI_ELE_TYPE.DRAPDOWN_BOX,
195 | options: {
196 | button: {
197 | label: "上下标",
198 | icon: "assets/images/toolbar/button/script.png"
199 | },
200 | box: {
201 | width: 378,
202 | group: [ {
203 | title: "上标和下标",
204 | content: [ {
205 | item: {
206 | show: '
',
207 | val: "\\placeholder^\\placeholder"
208 | }
209 | }, {
210 | item: {
211 | show: '
',
212 | val: "\\placeholder_\\placeholder"
213 | }
214 | }, {
215 | item: {
216 | show: '
',
217 | val: "\\placeholder^\\placeholder_\\placeholder"
218 | }
219 | }, {
220 | item: {
221 | show: '
',
222 | val: "^\\placeholder_\\placeholder\\placeholder"
223 | }
224 | } ]
225 | }, {
226 | title: "常用的上标和下标",
227 | content: [ {
228 | item: {
229 | show: '
',
230 | val: "e^{-i\\omega t}"
231 | }
232 | }, {
233 | item: {
234 | show: '
',
235 | val: "x^2"
236 | }
237 | }, {
238 | item: {
239 | show: '
',
240 | val: "^n_1Y"
241 | }
242 | } ]
243 | } ]
244 | }
245 | }
246 | }, {
247 | type: UI_ELE_TYPE.DRAPDOWN_BOX,
248 | options: {
249 | button: {
250 | label: "根式",
251 | icon: "assets/images/toolbar/button/sqrt.png"
252 | },
253 | box: {
254 | width: 378,
255 | group: [ {
256 | title: "根式",
257 | content: [ {
258 | item: {
259 | show: '
',
260 | val: "\\sqrt \\placeholder"
261 | }
262 | }, {
263 | item: {
264 | show: '
',
265 | val: "\\sqrt [\\placeholder] \\placeholder"
266 | }
267 | }, {
268 | item: {
269 | show: '
',
270 | val: "\\sqrt [2] \\placeholder"
271 | }
272 | }, {
273 | item: {
274 | show: '
',
275 | val: "\\sqrt [3] \\placeholder"
276 | }
277 | } ]
278 | }, {
279 | title: "常用根式",
280 | content: [ {
281 | item: {
282 | show: '
',
283 | val: "\\frac {-b\\pm\\sqrt{b^2-4ac}}{2a}"
284 | }
285 | }, {
286 | item: {
287 | show: '
',
288 | val: "\\sqrt {a^2+b^2}"
289 | }
290 | } ]
291 | } ]
292 | }
293 | }
294 | }, {
295 | type: UI_ELE_TYPE.DRAPDOWN_BOX,
296 | options: {
297 | button: {
298 | label: "括号",
299 | icon: "assets/images/toolbar/button/brackets.png"
300 | },
301 | box: {
302 | width: 378,
303 | group: [ {
304 | title: "方括号",
305 | content: [ {
306 | item: {
307 | show: '
',
308 | val: "\\left(\\placeholder\\right)"
309 | }
310 | }, {
311 | item: {
312 | show: '
',
313 | val: "\\left[\\placeholder\\right]"
314 | }
315 | }, {
316 | item: {
317 | show: '
',
318 | val: "\\left\\{\\placeholder\\right\\}"
319 | }
320 | }, {
321 | item: {
322 | show: '
',
323 | val: "\\left|\\placeholder\\right|"
324 | }
325 | } ]
326 | } ]
327 | }
328 | }
329 | } ];
330 |
331 | // 初始化希腊字符配置
332 | ( function () {
333 |
334 | var greekList = [ "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega" ],
335 | greekConf = config[ 2 ].options.box.group[ 1 ].content;
336 |
337 | kity.Utils.each( greekList, function ( greekChar, index ) {
338 |
339 | greekConf.push( {
340 | item: {
341 | show: '
',
342 | val: "\\" + greekChar
343 | }
344 | } );
345 |
346 | } );
347 |
348 | } )();
349 |
350 | return config;
351 |
352 | } );
--------------------------------------------------------------------------------
/src/ui/toolbar/toolbar.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 工具条组件
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | UiImpl = require( "ui/ui-impl/ui" ),
10 |
11 | $$ = require( "ui/ui-impl/ui-utils" ),
12 |
13 | UI_ELE_TYPE = require( "ui/ui-impl/def/ele-type" ),
14 |
15 | Tollbar = kity.createClass( "Tollbar", {
16 |
17 | constructor: function ( kfEditor, uiComponent, elementList ) {
18 |
19 | this.kfEditor = kfEditor;
20 | this.uiComponent = uiComponent;
21 |
22 | // 工具栏元素定义列表
23 | this.elementList = elementList;
24 |
25 | this.elements = [];
26 |
27 | this.initToolbarElements();
28 |
29 | this.initEvent();
30 |
31 | },
32 |
33 | initEvent: function () {
34 |
35 | var _self = this;
36 |
37 | // 通知所有组件关闭
38 | $$.on( this.kfEditor.getContainer(), "mousedown", function () {
39 | _self.notify( "closeAll" );
40 | } );
41 |
42 | // 订阅数据选择主题
43 | $$.subscribe( "data.select", function ( data ) {
44 |
45 | _self.insertSource( data );
46 |
47 | } );
48 |
49 | },
50 |
51 | insertSource: function ( val ) {
52 |
53 | this.kfEditor.requestService( "control.insert.group", val );
54 |
55 | },
56 |
57 | // 接受到关闭通知
58 | notify: function ( type ) {
59 |
60 | var caller = null;
61 |
62 | switch ( type ) {
63 |
64 | // 关闭所有组件
65 | case "closeAll":
66 | // 关闭其他组件
67 | case "closeOther":
68 | this.closeElement( arguments[ 1 ] );
69 | return;
70 |
71 | }
72 |
73 | },
74 |
75 | closeElement: function ( exception ) {
76 |
77 | kity.Utils.each( this.elements, function ( ele ) {
78 |
79 | if ( ele != exception ) {
80 | ele.hide && ele.hide();
81 | }
82 |
83 | } );
84 |
85 | },
86 |
87 | initToolbarElements: function () {
88 |
89 | var elements = this.elements,
90 | doc = this.uiComponent.toolbarContainer.ownerDocument,
91 | _self = this;
92 |
93 | kity.Utils.each( this.elementList, function ( eleInfo, i ) {
94 |
95 | var ele = createElement( eleInfo.type, doc, eleInfo.options );
96 | elements.push( ele );
97 | _self.appendElement( ele );
98 |
99 | } );
100 |
101 | },
102 |
103 | appendElement: function ( uiElement ) {
104 |
105 | uiElement.setToolbar( this );
106 | uiElement.attachTo( this.uiComponent.toolbarContainer );
107 |
108 | }
109 |
110 | } );
111 |
112 | function createElement ( type, doc, options ) {
113 |
114 | switch ( type ) {
115 |
116 | case UI_ELE_TYPE.DRAPDOWN_BOX:
117 | return createDrapdownBox( doc, options );
118 |
119 | case UI_ELE_TYPE.DELIMITER:
120 | return createDelimiter( doc );
121 |
122 | case UI_ELE_TYPE.AREA:
123 | return createArea( doc, options );
124 |
125 |
126 | }
127 |
128 | }
129 |
130 | function createDrapdownBox ( doc, options ) {
131 |
132 | return new UiImpl.DrapdownBox( doc, options );
133 |
134 | }
135 |
136 | function createDelimiter ( doc ) {
137 | return new UiImpl.Delimiter( doc );
138 | }
139 |
140 | function createArea ( doc, options ) {
141 | return new UiImpl.Area( doc, options );
142 | }
143 |
144 | return Tollbar;
145 |
146 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/area.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 特殊字符区域
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | PREFIX = "kf-editor-ui-",
10 |
11 | // UiUitls
12 | $$ = require( "ui/ui-impl/ui-utils" ),
13 |
14 | Box = require( "ui/ui-impl/box" ),
15 |
16 | Area = kity.createClass( "Area", {
17 |
18 | constructor: function ( doc, options ) {
19 |
20 | this.options = options;
21 |
22 | this.doc = doc;
23 | this.toolbar = null;
24 |
25 | this.element = this.createArea();
26 | this.container = this.createContainer();
27 | this.button = this.createButton();
28 | this.mountPoint = this.createMountPoint();
29 |
30 | this.boxObject = this.createBox();
31 | this.mergeElement();
32 | this.mount();
33 |
34 | this.setListener();
35 | this.initEvent();
36 |
37 | this.updateContent();
38 |
39 | },
40 |
41 | initEvent: function () {
42 |
43 | var _self = this;
44 |
45 | $$.on( this.button, "click", function () {
46 |
47 | _self.showMount();
48 |
49 | } );
50 |
51 | $$.delegate( this.container, ".kf-editor-ui-area-item", "mousedown", function ( e ) {
52 |
53 | e.preventDefault();
54 |
55 | if ( e.which !== 1 ) {
56 | return;
57 | }
58 |
59 | $$.publish( "data.select", this.getAttribute( "data-value" ) );
60 |
61 | } );
62 |
63 | this.boxObject.initEvent();
64 |
65 | },
66 |
67 | setListener: function () {
68 |
69 | var _self = this;
70 |
71 | this.boxObject.setSelectHandler( function ( val ) {
72 | // 发布
73 | $$.publish( "data.select", val );
74 | _self.hide();
75 | } );
76 |
77 | // 内容面板切换
78 | this.boxObject.setChangeHandler( function ( index ) {
79 | _self.updateContent();
80 | } );
81 |
82 | },
83 |
84 | createArea: function () {
85 |
86 | var areaNode = $$.ele( this.doc, "div", {
87 | className: PREFIX + "area"
88 | });
89 |
90 | if ( "width" in this.options ) {
91 | areaNode.style.width = this.options.width + "px";
92 | }
93 |
94 | return areaNode;
95 |
96 | },
97 |
98 | updateContent: function () {
99 |
100 | var items = this.boxObject.getOverlapContent(),
101 | newContent = [];
102 |
103 | // 清空原有内容
104 | this.container.innerHTML = "";
105 |
106 | kity.Utils.each( items, function ( item, index ) {
107 |
108 | item = item.item;
109 |
110 | newContent.push( '' );
111 |
112 | } );
113 |
114 | this.container.innerHTML = newContent.join( "" );
115 |
116 | },
117 |
118 | // 挂载
119 | mount: function () {
120 |
121 | this.boxObject.mountTo( this.mountPoint );
122 |
123 | },
124 |
125 | showMount: function () {
126 | this.mountPoint.style.display = "block";
127 | },
128 |
129 | hideMount: function () {
130 | this.mountPoint.style.display = "none";
131 | },
132 |
133 | hide: function () {
134 | this.hideMount();
135 | this.boxObject.hide();
136 | },
137 |
138 | createButton: function () {
139 |
140 | return $$.ele( this.doc, "div", {
141 | className: PREFIX + "area-button",
142 | content: "▼"
143 | } );
144 |
145 | },
146 |
147 | createMountPoint: function () {
148 |
149 | return $$.ele( this.doc, "div", {
150 | className: PREFIX + "area-mount"
151 | } );
152 |
153 | },
154 |
155 | createBox: function () {
156 |
157 | return new Box( this.doc, this.options.box );
158 |
159 | },
160 |
161 | createContainer: function () {
162 |
163 | var node = $$.ele( this.doc, "div", {
164 | className: PREFIX + "area-container"
165 | } );
166 |
167 | return node;
168 |
169 | },
170 |
171 | mergeElement: function () {
172 |
173 | this.element.appendChild( this.container );
174 | this.element.appendChild( this.button );
175 | this.element.appendChild( this.mountPoint );
176 |
177 | },
178 |
179 | setToolbar: function ( toolbar ) {
180 | this.toolbar = toolbar;
181 | },
182 |
183 | attachTo: function ( container ) {
184 | container.appendChild( this.element );
185 | }
186 |
187 | } );
188 |
189 | return Area;
190 |
191 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/box.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-31.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | PREFIX = "kf-editor-ui-",
10 |
11 | // UiUitls
12 | $$ = require( "ui/ui-impl/ui-utils" ),
13 |
14 | BOX_TYPE = require( "ui/ui-impl/def/box-type" ),
15 |
16 | ITEM_TYPE = require( "ui/ui-impl/def/item-type" ),
17 |
18 | Button = require( "ui/ui-impl/button" ),
19 |
20 | List = require( "ui/ui-impl/list" ),
21 |
22 | Box = kity.createClass( "Box", {
23 |
24 | constructor: function ( doc, options ) {
25 |
26 | this.options = options;
27 |
28 | this.options.type = this.options.type || BOX_TYPE.DETACHED;
29 |
30 | this.doc = doc;
31 |
32 | this.overlapButtonObject = null;
33 |
34 | this.overlapIndex = -1;
35 |
36 | this.element = this.createBox();
37 | this.groupContainer = this.createGroupContainer();
38 | this.itemGroups = this.createItemGroup();
39 |
40 | this.mergeElement();
41 |
42 | },
43 |
44 | createBox: function () {
45 |
46 | var boxNode = $$.ele( this.doc, "div", {
47 | className: PREFIX + "box"
48 | } );
49 |
50 | if ( "width" in this.options ) {
51 | boxNode.style.width = this.options.width + "px";
52 | }
53 |
54 | return boxNode;
55 |
56 | },
57 |
58 | initEvent: function () {
59 |
60 | var className = "." + PREFIX + "box-item",
61 | _self = this;
62 |
63 | $$.delegate( this.groupContainer, className, "mousedown", function ( e ) {
64 |
65 | e.preventDefault();
66 |
67 | if ( e.which !== 1 ) {
68 | return;
69 | }
70 |
71 | _self.onselectHandler && _self.onselectHandler( this.getAttribute( "data-value" ) );
72 |
73 | } );
74 |
75 | $$.on( this.element, "mousedown", function ( e ) {
76 |
77 | e.stopPropagation();
78 | e.preventDefault();
79 |
80 | } );
81 |
82 | },
83 |
84 | getNode: function () {
85 | return this.element;
86 | },
87 |
88 | setSelectHandler: function ( onselectHandler ) {
89 | this.onselectHandler = onselectHandler;
90 | },
91 |
92 | setChangeHandler: function ( changeHandler ) {
93 | this.onchangeHandler = changeHandler;
94 | },
95 |
96 | onchangeHandler: function ( index ) {},
97 |
98 | createGroupContainer: function () {
99 |
100 | return $$.ele( this.doc, "div", {
101 | className: PREFIX + "box-container"
102 | } );
103 |
104 | },
105 |
106 | createItemGroup: function () {
107 |
108 | var groups = this.createGroup();
109 |
110 | switch ( this.options.type ) {
111 |
112 | case BOX_TYPE.DETACHED:
113 | return groups;
114 |
115 | case BOX_TYPE.OVERLAP:
116 | return this.createOverlapGroup( groups );
117 |
118 | }
119 |
120 | return null;
121 |
122 | },
123 |
124 | hide: function () {
125 | this.overlapButtonObject && this.overlapButtonObject.hideMount();
126 | },
127 |
128 | getOverlapContent: function () {
129 |
130 | // 只有重叠式才可以获取重叠内容
131 | if ( this.options.type !== BOX_TYPE.OVERLAP ) {
132 | return null;
133 | }
134 |
135 | return this.options.group[ this.overlapIndex ].content;
136 |
137 | },
138 |
139 | createOverlapGroup: function ( groups ) {
140 |
141 | var list = this.getGroupList(),
142 | _self = this,
143 | overlapContainer = createOverlapContainer( this.doc),
144 | overlapButtonObject = createOverlapButton( this.doc ),
145 | overlapListObject = createOverlapList( this.doc, list );
146 |
147 | this.overlapButtonObject = overlapButtonObject;
148 |
149 | // 组合选择组件
150 | overlapButtonObject.mount( overlapListObject );
151 |
152 | overlapButtonObject.initEvent();
153 | overlapListObject.initEvent();
154 |
155 | // 切换面板
156 | overlapListObject.setSelectHandler( function ( index, oldIndex ) {
157 |
158 | _self.overlapIndex = index;
159 |
160 | overlapButtonObject.setLabel( list.items[index] + " ▼" );
161 | overlapButtonObject.hideMount();
162 |
163 | // 切换内容
164 | groups[ oldIndex ].style.display = "none";
165 | groups[ index ].style.display = "block";
166 |
167 | _self.onchangeHandler( index );
168 |
169 | } );
170 |
171 | overlapContainer.appendChild( overlapButtonObject.getNode() );
172 |
173 | kity.Utils.each( groups, function ( group, index ) {
174 |
175 | if ( index > 0 ) {
176 | group.style.display = "none";
177 | }
178 |
179 | overlapContainer.appendChild( group );
180 |
181 | } );
182 |
183 | overlapListObject.select( 0 );
184 |
185 | return [ overlapContainer ];
186 |
187 | },
188 |
189 | // 获取group的list列表, 该类表满足box的group参数格式
190 | getGroupList: function () {
191 |
192 | var lists = [];
193 |
194 | kity.Utils.each( this.options.group, function ( group, index ) {
195 |
196 | lists.push( group.title );
197 |
198 | } );
199 |
200 | return {
201 | width: 150,
202 | items: lists
203 | };
204 |
205 | },
206 |
207 | createGroup: function () {
208 |
209 | var doc = this.doc,
210 | groups = [],
211 | groupNode = null,
212 | groupTitle = null,
213 | itemType = BOX_TYPE.DETACHED === this.options.type ? ITEM_TYPE.BIG : ITEM_TYPE.SMALL,
214 | itemContainer = null;
215 |
216 | groupNode = $$.ele( this.doc, "div", {
217 | className: PREFIX + "box-group"
218 | } );
219 |
220 | itemContainer = groupNode.cloneNode( false );
221 | itemContainer.className = PREFIX + "box-group-item-container";
222 |
223 | kity.Utils.each( this.options.group, function ( group, i ) {
224 |
225 | groupNode = groupNode.cloneNode( false );
226 | itemContainer = itemContainer.cloneNode( false );
227 |
228 | groupTitle = $$.ele( doc, "div", {
229 | className: PREFIX + "box-group-title",
230 | content: group.title
231 | } );
232 |
233 | groupNode.appendChild( groupTitle );
234 | groupNode.appendChild( itemContainer );
235 |
236 | kity.Utils.each( createItems( doc, group.content, itemType ), function ( item ) {
237 |
238 | item.appendTo( itemContainer );
239 |
240 | } );
241 |
242 | groups.push( groupNode );
243 |
244 | } );
245 |
246 | return groups;
247 |
248 | },
249 |
250 | mergeElement: function () {
251 |
252 | var groupContainer = this.groupContainer;
253 |
254 | this.element.appendChild( groupContainer );
255 |
256 | kity.Utils.each( this.itemGroups, function ( group ) {
257 |
258 | groupContainer.appendChild( group );
259 |
260 | } );
261 |
262 | },
263 |
264 | mountTo: function ( container ) {
265 | container.appendChild( this.element );
266 | },
267 |
268 | appendTo: function ( container ) {
269 | container.appendChild( this.element );
270 | }
271 |
272 | } ),
273 |
274 | BoxItem = kity.createClass( "BoxItem", {
275 |
276 | constructor: function ( type, doc, options ) {
277 |
278 | this.type = type;
279 | this.doc = doc;
280 | this.options = options;
281 |
282 | this.element = this.createItem();
283 |
284 | // 项的label是可选的
285 | this.labelNode = this.createLabel();
286 | this.contentNode = this.createContent();
287 |
288 | this.mergeElement();
289 |
290 | },
291 |
292 | getNode: function () {
293 | return this.element;
294 | },
295 |
296 | createItem: function () {
297 |
298 | var itemNode = $$.ele( this.doc, "div", {
299 | className: PREFIX + "box-item"
300 | } );
301 |
302 | return itemNode;
303 |
304 | },
305 |
306 | createLabel: function () {
307 |
308 | var labelNode = null;
309 |
310 | if ( !( "label" in this.options ) ) {
311 | return;
312 | }
313 |
314 | labelNode = $$.ele( this.doc, "div", {
315 | className: PREFIX + "box-item-label",
316 | content: this.options.label
317 | } );
318 |
319 | return labelNode;
320 |
321 | },
322 |
323 | getContent: function () {
324 |
325 |
326 |
327 | },
328 |
329 | createContent: function () {
330 |
331 | switch ( this.type ) {
332 |
333 | case ITEM_TYPE.BIG:
334 | return this.createBigContent();
335 |
336 | case ITEM_TYPE.SMALL:
337 | return this.createSmallContent();
338 |
339 | }
340 |
341 | },
342 |
343 | createBigContent: function () {
344 |
345 | var doc = this.doc,
346 | contentNode = $$.ele( doc, "div", {
347 | className: PREFIX + "box-item-content"
348 | }),
349 | cls = PREFIX + "box-item-val",
350 | tmpContent = this.options.item,
351 | tmpNode = null;
352 |
353 | if ( typeof tmpContent === "string" ) {
354 | tmpContent = {
355 | show: tmpContent,
356 | val: tmpContent
357 | };
358 | }
359 |
360 | tmpNode = $$.ele( doc, "div", {
361 | className: cls
362 | } );
363 |
364 | tmpNode.innerHTML = tmpContent.show;
365 | // 附加属性到项的根节点上
366 | this.element.setAttribute( "data-value", tmpContent.val );
367 |
368 | contentNode.appendChild( tmpNode );
369 |
370 | return contentNode;
371 |
372 | },
373 |
374 | createSmallContent: function () {
375 |
376 | var doc = this.doc,
377 | contentNode = $$.ele( doc, "div", {
378 | className: PREFIX + "box-item-content"
379 | }),
380 | cls = PREFIX + "box-item-val",
381 | tmpContent = this.options.item,
382 | tmpNode = null;
383 |
384 | if ( typeof tmpContent === "string" ) {
385 | tmpContent = {
386 | show: tmpContent,
387 | val: tmpContent
388 | };
389 | }
390 |
391 | tmpNode = $$.ele( doc, "div", {
392 | className: cls
393 | } );
394 |
395 | tmpNode.innerHTML = tmpContent.show;
396 | // 附加属性到项的根节点上
397 | this.element.setAttribute( "data-value", tmpContent.val );
398 |
399 | contentNode.appendChild( tmpNode );
400 |
401 | return contentNode;
402 |
403 | },
404 |
405 | mergeElement: function () {
406 |
407 | if ( this.labelNode ) {
408 | this.element.appendChild( this.labelNode );
409 | }
410 |
411 | this.element.appendChild( this.contentNode );
412 |
413 | },
414 |
415 | appendTo: function ( container ) {
416 | container.appendChild( this.element );
417 | }
418 |
419 | } );
420 |
421 |
422 | function createItems ( doc, group, type ) {
423 |
424 | var items = [];
425 |
426 | kity.Utils.each( group, function ( itemVal, i ) {
427 |
428 | items.push( new BoxItem( type, doc, itemVal) );
429 |
430 | } );
431 |
432 | return items;
433 |
434 | }
435 |
436 | // 为重叠式box创建容器
437 | function createOverlapContainer ( doc ) {
438 |
439 | return $$.ele( doc, "div", {
440 | className: PREFIX + "overlap-container"
441 | } );
442 |
443 | }
444 |
445 | function createOverlapButton ( doc ) {
446 |
447 | return new Button( doc, {
448 | sign: false,
449 | className: "overlap-button",
450 | label: ""
451 | } );
452 |
453 | }
454 |
455 | function createOverlapList ( doc, list ) {
456 | return new List( doc, list );
457 | }
458 |
459 | return Box;
460 |
461 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/button.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-31.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | PREFIX = "kf-editor-ui-",
10 |
11 | // UiUitls
12 | $$ = require( "ui/ui-impl/ui-utils" ),
13 |
14 | Button = kity.createClass( "Button", {
15 |
16 | constructor: function ( doc, options ) {
17 |
18 | this.options = options;
19 |
20 | // 事件状态, 是否已经初始化
21 | this.eventState = false;
22 |
23 | this.doc = doc;
24 |
25 | this.element = this.createButton();
26 |
27 | this.icon = this.createIcon();
28 | this.label = this.createLabel();
29 | this.sign = this.createSign();
30 | this.mountPoint = this.createMountPoint();
31 |
32 | this.mergeElement();
33 |
34 | },
35 |
36 | initEvent: function () {
37 |
38 | var _self = this;
39 |
40 | if ( this.eventState ) {
41 | return;
42 | }
43 |
44 | this.eventState = true;
45 |
46 | $$.on( this.element, "mousedown", function ( e ) {
47 |
48 | e.preventDefault();
49 | e.stopPropagation();
50 |
51 | if ( e.which !== 1 ) {
52 | return;
53 | }
54 |
55 | _self.toggleSelect();
56 | _self.toggleMountElement();
57 |
58 | } );
59 |
60 | },
61 |
62 | toggleMountElement: function () {
63 |
64 | var state = this.mountPoint.style.display || "none";
65 | this.mountPoint.style.display = state === "none" ? "block" : "none";
66 |
67 | },
68 |
69 | setLabel: function ( labelText ) {
70 | this.label.innerHTML = labelText;
71 | },
72 |
73 | toggleSelect: function () {
74 | this.element.classList.toggle( PREFIX + "button-in" );
75 | },
76 |
77 | unselect: function () {
78 | this.element.classList.remove( PREFIX + "button-in" );
79 | },
80 |
81 | select: function () {
82 | this.element.classList.add( PREFIX + "button-in" );
83 | },
84 |
85 | show: function () {
86 | this.select();
87 | this.showMount();
88 | },
89 |
90 | hide: function () {
91 | this.unselect();
92 | this.hideMount();
93 | },
94 |
95 | showMount: function () {
96 | this.mountPoint.style.display = "block";
97 | },
98 |
99 | hideMount: function () {
100 | this.mountPoint.style.display = "none";
101 | },
102 |
103 | getNode: function () {
104 | return this.element;
105 | },
106 |
107 | mount: function ( source ) {
108 | source.mountTo( this.mountPoint );
109 | },
110 |
111 | createButton: function () {
112 |
113 | var buttonNode = $$.ele( this.doc, "div", {
114 | className: PREFIX + "button"
115 | } );
116 |
117 | // 附加className
118 | if ( this.options.className ) {
119 | buttonNode.className += " " + PREFIX + this.options.className;
120 | }
121 |
122 | return buttonNode;
123 |
124 | },
125 |
126 | createIcon: function () {
127 |
128 | if ( !this.options.icon ) {
129 | return null;
130 | }
131 |
132 | var iconNode = $$.ele( this.doc, "div", {
133 | className: PREFIX + "button-icon"
134 | } );
135 |
136 | iconNode.style.backgroundImage = "url(" + this.options.icon + ")";
137 |
138 | return iconNode;
139 |
140 | },
141 |
142 | createLabel: function () {
143 |
144 | var labelNode = $$.ele( this.doc, "div", {
145 | className: PREFIX + "button-label",
146 | content: this.options.label
147 | } );
148 |
149 |
150 | return labelNode;
151 |
152 | },
153 |
154 | createSign: function () {
155 |
156 | if ( !this.options.sign ) {
157 | return null;
158 | }
159 |
160 | return $$.ele( this.doc, "div", {
161 | className: PREFIX + "button-sign"
162 | } );
163 |
164 | },
165 |
166 | createMountPoint: function () {
167 |
168 | return $$.ele( this.doc, "div", {
169 | className: PREFIX + "button-mount-point"
170 | } );
171 |
172 | },
173 |
174 | mergeElement: function () {
175 |
176 | this.icon && this.element.appendChild( this.icon );
177 | this.element.appendChild( this.label );
178 | this.sign && this.element.appendChild( this.sign );
179 | this.element.appendChild( this.mountPoint );
180 |
181 | }
182 |
183 | } );
184 |
185 | return Button;
186 |
187 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/def/box-type.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * box类型定义
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | return {
8 | // 分离式
9 | "DETACHED": 1,
10 | // 重叠式
11 | "OVERLAP": 2
12 | };
13 |
14 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/def/ele-type.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * toolbar元素类型定义
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | return {
8 | "DRAPDOWN_BOX": 1,
9 | "AREA": 2,
10 | "DELIMITER": 3
11 | };
12 |
13 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/def/item-type.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 组元素类型定义
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | return {
8 | "BIG": 1,
9 | "SMALL": 2
10 | };
11 |
12 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/delimiter.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * 分割符
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | PREFIX = "kf-editor-ui-",
10 |
11 | // UiUitls
12 | $$ = require( "ui/ui-impl/ui-utils" ),
13 |
14 | Delimiter = kity.createClass( "Delimiter", {
15 |
16 | constructor: function ( doc ) {
17 |
18 | this.doc = doc;
19 | this.element = this.createDilimiter();
20 |
21 | },
22 |
23 | setToolbar: function ( toolbar ) {
24 | // do nothing
25 | },
26 |
27 | createDilimiter: function () {
28 |
29 | var dilimiterNode = $$.ele( this.doc, "div", {
30 | className: PREFIX + "delimiter"
31 | } );
32 |
33 | dilimiterNode.appendChild( $$.ele( this.doc, "div", {
34 | className: PREFIX + "delimiter-line"
35 | } ) );
36 |
37 | return dilimiterNode;
38 |
39 | },
40 |
41 | attachTo: function ( container ) {
42 |
43 | container.appendChild( this.element );
44 |
45 | }
46 |
47 | });
48 |
49 | return Delimiter;
50 |
51 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/drapdown-box.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-31.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | PREFIX = "kf-editor-ui-",
10 |
11 | // UiUitls
12 | $$ = require( "ui/ui-impl/ui-utils" ),
13 |
14 | Button = require( "ui/ui-impl/button" ),
15 | Box = require( "ui/ui-impl/box" ),
16 |
17 | DrapdownBox = kity.createClass( "DrapdownBox", {
18 |
19 | constructor: function ( doc, options ) {
20 |
21 | this.options = options;
22 | this.toolbar = null;
23 | this.doc = doc;
24 |
25 | this.buttonElement = this.createButton();
26 |
27 | this.element = this.buttonElement.getNode();
28 |
29 | this.boxElement = this.createBox();
30 |
31 | this.buttonElement.mount( this.boxElement );
32 |
33 | this.initEvent();
34 |
35 | },
36 |
37 | initEvent: function () {
38 |
39 | var _self = this;
40 |
41 | // 通知工具栏互斥
42 | $$.on( this.element, "mousedown", function ( e ) {
43 |
44 | e.preventDefault();
45 | e.stopPropagation();
46 |
47 | _self.toolbar.notify( "closeOther", _self );
48 |
49 | } );
50 |
51 |
52 | this.buttonElement.initEvent();
53 | this.boxElement.initEvent();
54 |
55 | this.boxElement.setSelectHandler( function ( val ) {
56 | // 发布
57 | $$.publish( "data.select", val );
58 | _self.buttonElement.hide();
59 | } );
60 |
61 | },
62 |
63 | setToolbar: function ( toolbar ) {
64 |
65 | this.toolbar = toolbar;
66 |
67 | },
68 |
69 | createButton: function () {
70 |
71 | return new Button( this.doc, this.options.button );
72 |
73 | },
74 |
75 | show: function () {
76 | this.buttonElement.show();
77 | },
78 |
79 | hide: function () {
80 | this.buttonElement.hide();
81 | },
82 |
83 | createBox: function () {
84 |
85 | return new Box( this.doc, this.options.box );
86 |
87 | },
88 |
89 | attachTo: function ( container ) {
90 |
91 | container.appendChild( this.element );
92 |
93 | }
94 |
95 | });
96 |
97 | return DrapdownBox;
98 |
99 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/list.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-31.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var kity = require( "kity" ),
8 |
9 | PREFIX = "kf-editor-ui-",
10 |
11 | // UiUitls
12 | $$ = require( "ui/ui-impl/ui-utils" ),
13 |
14 | List = kity.createClass( "List", {
15 |
16 | constructor: function ( doc, options ) {
17 |
18 | this.options = options;
19 |
20 | this.doc = doc;
21 |
22 | this.onselectHandler = null;
23 |
24 | this.currentSelect = -1;
25 |
26 | this.element = this.createBox();
27 | this.itemGroups = this.createItems();
28 |
29 | this.mergeElement();
30 |
31 | },
32 |
33 | onselectHandler: function ( index, oldIndex ) {},
34 |
35 | setSelectHandler: function ( selectHandler ) {
36 | this.onselectHandler = selectHandler;
37 | },
38 |
39 | createBox: function () {
40 |
41 | var boxNode = $$.ele( this.doc, "div", {
42 | className: PREFIX + "list"
43 | } ),
44 |
45 | // 创建背景
46 | bgNode = $$.ele( this.doc, "div", {
47 | className: PREFIX + "list-bg"
48 | } );
49 |
50 | if ( "width" in this.options ) {
51 | boxNode.style.width = this.options.width + "px";
52 | }
53 |
54 | boxNode.appendChild( bgNode );
55 |
56 | return boxNode;
57 |
58 | },
59 |
60 | select: function ( index ) {
61 |
62 | var oldSelect = this.currentSelect;
63 |
64 | if ( oldSelect === -1 ) {
65 | oldSelect = index;
66 | }
67 |
68 | this.unselect( oldSelect );
69 |
70 | this.currentSelect = index;
71 |
72 | this.itemGroups.items[ index ].firstChild.style.visibility = "visible";
73 |
74 | this.onselectHandler( index, oldSelect );
75 |
76 | },
77 |
78 | unselect: function ( index ) {
79 |
80 | this.itemGroups.items[ index ].firstChild.style.visibility = "hidden";
81 |
82 | },
83 |
84 | initEvent: function () {
85 |
86 | var className = "." + PREFIX + "list-item",
87 | _self = this;
88 |
89 | $$.delegate( this.itemGroups.container, className, "mousedown", function ( e ) {
90 |
91 | e.preventDefault();
92 |
93 | if ( e.which !== 1 ) {
94 | return;
95 | }
96 |
97 | _self.select( this.getAttribute( "data-index" ) );
98 |
99 | } );
100 |
101 | $$.on( this.element, "mousedown", function ( e ) {
102 |
103 | e.stopPropagation();
104 | e.preventDefault();
105 |
106 | } );
107 |
108 | },
109 |
110 | createItems: function () {
111 |
112 | var doc = this.doc,
113 | groupNode = null,
114 | itemNode = null,
115 | iconNode = null,
116 | items = [],
117 | itemContainer = null;
118 |
119 | groupNode = $$.ele( this.doc, "div", {
120 | className: PREFIX + "list-item"
121 | } );
122 |
123 | itemContainer = groupNode.cloneNode( false );
124 | itemContainer.className = PREFIX + "list-item-container";
125 |
126 | kity.Utils.each( this.options.items, function ( itemText, i ) {
127 |
128 | itemNode = groupNode.cloneNode( false );
129 |
130 | iconNode = groupNode.cloneNode( false );
131 | iconNode.className = PREFIX + "list-item-icon";
132 | iconNode.innerHTML = '
';
133 |
134 | itemNode.appendChild( iconNode );
135 | itemNode.appendChild( $$.ele( doc, "text", itemText ) );
136 |
137 | itemNode.setAttribute( "data-index", i );
138 |
139 | items.push( itemNode );
140 | itemContainer.appendChild( itemNode );
141 |
142 | } );
143 |
144 | return {
145 | container: itemContainer,
146 | items: items
147 | };
148 |
149 | },
150 |
151 | mergeElement: function () {
152 |
153 | this.element.appendChild( this.itemGroups.container );
154 |
155 | },
156 |
157 | mountTo: function ( container ) {
158 | container.appendChild( this.element );
159 | }
160 |
161 | } );
162 |
163 | return List;
164 |
165 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/ui-utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-4-1.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | var $ = require( "jquery" ),
8 | kity = require( "kity" ),
9 | TOPIC_POOL = {};
10 |
11 | return {
12 |
13 | ele: function ( doc, name, options ) {
14 |
15 | var node = null;
16 |
17 | if ( name === "text" ) {
18 | return doc.createTextNode( options );
19 | }
20 |
21 | node = doc.createElement( name );
22 | options.className && ( node.className = options.className );
23 |
24 | if ( options.content ) {
25 | node.innerHTML = options.content;
26 | }
27 | return node;
28 | },
29 |
30 | on: function ( target, type, fn ) {
31 | $( target ).on( type, fn );
32 | return this;
33 | },
34 |
35 | delegate: function ( target, selector, type, fn ) {
36 |
37 | $( target ).delegate( selector, type, fn );
38 | return this;
39 |
40 | },
41 |
42 | publish: function ( topic, args ) {
43 |
44 | var callbackList = TOPIC_POOL[ topic ];
45 |
46 | if ( !callbackList ) {
47 | return;
48 | }
49 |
50 | args = [].slice.call( arguments, 1 );
51 |
52 | kity.Utils.each( callbackList, function ( callback ) {
53 |
54 | callback.apply( null, args );
55 |
56 | } );
57 |
58 | },
59 |
60 | subscribe: function ( topic, callback ) {
61 |
62 | if ( !TOPIC_POOL[ topic ] ) {
63 |
64 | TOPIC_POOL[ topic ] = [];
65 |
66 | }
67 |
68 | TOPIC_POOL[ topic ].push( callback );
69 |
70 | }
71 |
72 | };
73 |
74 | } );
--------------------------------------------------------------------------------
/src/ui/ui-impl/ui.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-31.
3 | */
4 |
5 | define( function ( require ) {
6 |
7 | return {
8 |
9 | DrapdownBox: require( "ui/ui-impl/drapdown-box" ),
10 | Delimiter: require( "ui/ui-impl/delimiter" ),
11 | Area: require( "ui/ui-impl/area" )
12 |
13 | };
14 |
15 | } );
--------------------------------------------------------------------------------
/src/ui/ui.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by hn on 14-3-17.
3 | */
4 |
5 | define( function ( require, exports, modules ) {
6 |
7 | var kity = require( "kity"),
8 |
9 | Utils = require( "base/utils" ),
10 |
11 | Toolbar = require( "ui/toolbar/toolbar" ),
12 | // 控制组件
13 | ScrollZoom = require( "ui/control/zoom" ),
14 |
15 | ELEMENT_LIST = require( "ui/toolbar-ele-list" ),
16 |
17 | UIComponent = kity.createClass( 'UIComponent', {
18 |
19 | constructor: function ( kfEditor ) {
20 |
21 | var currentDocument = null;
22 |
23 | this.container = kfEditor.getContainer();
24 |
25 | currentDocument = this.container.ownerDocument;
26 |
27 | // ui组件实例集合
28 | this.components = {};
29 |
30 | this.kfEditor = kfEditor;
31 |
32 | this.resizeTimer = null;
33 |
34 | this.toolbarContainer = createToolbarContainer( currentDocument );
35 | this.editArea = createEditArea( currentDocument );
36 | this.canvasContainer = createCanvasContainer( currentDocument );
37 |
38 | this.updateContainerSize( this.container, this.toolbarContainer, this.editArea, this.canvasContainer );
39 |
40 | this.container.appendChild( this.toolbarContainer );
41 | this.editArea.appendChild( this.canvasContainer );
42 | this.container.appendChild( this.editArea );
43 |
44 | this.initCanvas();
45 | this.initComponents();
46 |
47 | this.initServices();
48 |
49 | this.initResizeEvent();
50 |
51 | },
52 |
53 | // 组件实例化
54 | initComponents: function () {
55 |
56 | // 工具栏组件
57 | this.components.toolbar = new Toolbar( this.kfEditor, this, ELEMENT_LIST );
58 | this.components.scrollZoom = new ScrollZoom( this, this.kfEditor, this.canvasContainer );
59 |
60 | },
61 |
62 | initCanvas: function () {
63 |
64 | },
65 |
66 | updateContainerSize: function ( container, toolbar, editArea, canvasContainer ) {
67 |
68 | var containerBox = container.getBoundingClientRect();
69 |
70 | toolbar.style.width = containerBox.width - 12 + "px";
71 | toolbar.style.height = 80 + "px";
72 |
73 | editArea.style.marginTop = 80 + "px";
74 | editArea.style.width = containerBox.width + "px";
75 | editArea.style.height = containerBox.height - 80 + "px";
76 |
77 | },
78 |
79 | // 初始化服务
80 | initServices: function () {
81 |
82 | this.kfEditor.registerService( "ui.get.canvas.container", this, {
83 | getCanvasContainer: SERVICE_LIST.getCanvasContainer
84 | } );
85 |
86 | this.kfEditor.registerService( "ui.canvas.container.event", this, {
87 | on: SERVICE_LIST.addEvent,
88 | off: SERVICE_LIST.removeEvent,
89 | trigger: SERVICE_LIST.trigger,
90 | fire: SERVICE_LIST.trigger
91 | } );
92 |
93 | },
94 |
95 | initResizeEvent: function () {
96 |
97 | var _self = this;
98 |
99 | this.canvasContainer.ownerDocument.defaultView.onresize = function () {
100 |
101 | window.clearTimeout( _self.resizeTimer );
102 |
103 | _self.resizeTimer = window.setTimeout( function () {
104 | _self.kfEditor.requestService( "render.relocation" );
105 | }, 80 );
106 |
107 | };
108 |
109 | }
110 |
111 | } ),
112 |
113 | SERVICE_LIST = {
114 |
115 | getCanvasContainer: function () {
116 |
117 | return this.canvasContainer;
118 |
119 | },
120 |
121 | addEvent: function ( type, handler ) {
122 |
123 | Utils.addEvent( this.canvasContainer, type, handler );
124 |
125 | },
126 |
127 | removeEvent: function () {},
128 |
129 | trigger: function ( type ) {
130 |
131 | Utils.trigger( this.canvasContainer, type );
132 |
133 | }
134 |
135 | };
136 |
137 |
138 | function createToolbarContainer ( doc ) {
139 | var container = doc.createElement( "div" );
140 | container.className = "kf-editor-toolbar";
141 | return container;
142 | }
143 |
144 | function createEditArea ( doc ) {
145 | var container = doc.createElement( "div" );
146 | container.className = "kf-editor-edit-area";
147 | container.style.width = "80%";
148 | container.style.height = "800px";
149 | return container;
150 | }
151 |
152 | function createCanvasContainer ( doc ) {
153 | var container = doc.createElement( "div" );
154 | container.className = "kf-editor-canvas-container";
155 | return container;
156 | }
157 |
158 | return UIComponent;
159 |
160 | } );
--------------------------------------------------------------------------------