Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
kityminder-core
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
吴志俊
kityminder-core
Commits
e3d55a0f
Commit
e3d55a0f
authored
Sep 05, 2014
by
techird
Browse files
Options
Browse Files
Download
Plain Diff
merge multiline select
parents
d87b85c6
9f8f1eeb
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
989 additions
and
615 deletions
+989
-615
import.js
import.js
+1
-0
kity
lib/kity
+1
-1
editor.range.js
spec/module/editor.range.js
+47
-0
editor.receiver.js
spec/module/editor.receiver.js
+31
-0
node.js
src/core/node.js
+11
-2
utils.js
src/core/utils.js
+40
-0
basestyle.js
src/module/basestyle.js
+8
-4
editor.js
src/module/editor.js
+34
-40
editor.keyboard.js
src/module/editor.keyboard.js
+326
-0
editor.range.js
src/module/editor.range.js
+154
-62
editor.receiver.js
src/module/editor.receiver.js
+190
-451
editor.selection.js
src/module/editor.selection.js
+87
-23
font.js
src/module/font.js
+7
-5
text.js
src/module/text.js
+46
-24
default.js
src/theme/default.js
+2
-1
fresh.js
src/theme/fresh.js
+2
-1
snow.js
src/theme/snow.js
+2
-1
No files found.
import.js
View file @
e3d55a0f
...
...
@@ -78,6 +78,7 @@
'src/module/select.js'
,
'src/module/history.js'
,
'src/module/editor.js'
,
'src/module/editor.keyboard.js'
,
'src/module/editor.range.js'
,
'src/module/editor.receiver.js'
,
'src/module/editor.selection.js'
,
...
...
kity
@
fee45f69
Subproject commit f
83c5f109addefd4f89ba11b4dfa88c191809e77
Subproject commit f
ee45f69801839d897e5e6245be93eaefafd615a
spec/module/editor.range.js
0 → 100644
View file @
e3d55a0f
describe
(
"editor.range"
,
function
()
{
var
_div
=
document
.
createElement
(
'div'
);
_div
.
setAttribute
(
'contenteditable'
,
true
);
var
range
=
new
KM
.
Minder
.
Range
(
_div
);
describe
(
"getStartOffset"
,
function
(){
_div
.
innerHTML
=
'xxx<br
\
/><br
\
/>xxx<br
\
/>'
;
it
(
"选区在容器上"
,
function
()
{
range
.
startContainer
=
_div
;
range
.
startOffset
=
2
;
expect
(
range
.
getStartOffset
()).
toBe
(
4
);
});
it
(
"选区在文本节点上"
,
function
()
{
range
.
startContainer
=
_div
.
childNodes
[
3
];
range
.
startOffset
=
2
;
expect
(
range
.
getStartOffset
()).
toBe
(
7
);
});
});
describe
(
"setStartOffset"
,
function
(){
_div
.
innerHTML
=
'sdfsdfsdfsdf<br><br>sdf3<br>23232<br>'
;
it
(
"选区在容器上"
,
function
()
{
range
.
container
=
_div
;
debugger
range
.
setStartOffset
(
26
);
expect
(
range
.
startContainer
).
toBe
(
_div
);
});
// it("选区在文本节点上", function () {
//
// range.startContainer = _div.childNodes[3];
// range.startOffset = 2;
// expect(range.getStartOffset()).toBe(7);
// });
})
});
spec/module/editor.receiver.js
0 → 100644
View file @
e3d55a0f
describe
(
"editor.receiver"
,
function
()
{
debugger
var
_div
=
window
.
document
.
createElement
(
'div'
);
_div
.
id
=
"testDiv"
;
var
km
=
KM
.
getMinder
(
'testDiv'
);
var
sel
=
new
KM
.
Minder
.
Selection
();
var
range
=
new
KM
.
Minder
.
Range
();
var
receiver
=
new
KM
.
Minder
.
Receiver
(
this
,
sel
,
range
);
describe
(
"getStartOffset"
,
function
(){
//
// _div.innerHTML = 'xxx<br\/><br\/>xxx<br\/>';
// it("选区在容器上", function () {
//
// range.startContainer = _div;
// range.startOffset = 2;
// expect(range.getStartOffset()).toBe(4);
// });
// it("选区在文本节点上", function () {
//
// range.startContainer = _div.childNodes[3];
// range.startOffset = 2;
// expect(range.getStartOffset()).toBe(7);
// });
})
});
src/core/node.js
View file @
e3d55a0f
...
...
@@ -108,6 +108,9 @@ var MinderNode = KityMinder.MinderNode = kity.createClass('MinderNode', {
* @param {String} text 文本数据
*/
setText
:
function
(
text
)
{
if
(
utils
.
isArray
(
text
)){
text
=
text
.
join
(
'
\
n'
);
}
return
this
.
setData
(
'text'
,
text
);
},
...
...
@@ -115,8 +118,14 @@ var MinderNode = KityMinder.MinderNode = kity.createClass('MinderNode', {
* 获取节点的文本数据
* @return {String}
*/
getText
:
function
()
{
return
this
.
getData
(
'text'
);
getText
:
function
(
str2arr
)
{
var
text
=
this
.
getData
(
'text'
);
if
(
str2arr
){
text
=
text
.
split
(
'
\
n'
);
}
return
text
;
},
/**
...
...
src/core/utils.js
View file @
e3d55a0f
...
...
@@ -271,8 +271,48 @@ var utils = Utils = KityMinder.Utils = {
},
cloneArr
:
function
(
arr
){
return
[].
concat
(
arr
);
},
clearWhitespace
:
function
(
str
){
return
str
.
replace
(
/
[\u
200b
\t\r\n]
/g
,
''
);
},
getValueByIndex
:
function
(
data
,
index
){
var
initIndex
=
0
,
result
=
0
;
utils
.
each
(
data
,
function
(
i
,
arr
){
if
(
initIndex
+
arr
.
length
>=
index
){
if
(
index
-
initIndex
==
arr
.
length
){
result
=
{
x
:
arr
[
arr
.
length
-
1
].
x
+
arr
[
arr
.
length
-
1
].
width
,
y
:
arr
[
arr
.
length
-
1
].
y
};
}
else
{
result
=
arr
[
index
-
initIndex
];
}
return
false
;
}
else
{
initIndex
+=
arr
.
length
+
(
arr
.
length
==
1
&&
arr
[
0
].
width
===
0
?
0
:
1
);
}
});
return
result
;
},
getNodeIndex
:
function
(
node
,
ignoreTextNode
)
{
var
preNode
=
node
,
i
=
0
;
while
(
preNode
=
preNode
.
previousSibling
)
{
if
(
ignoreTextNode
&&
preNode
.
nodeType
==
3
)
{
if
(
preNode
.
nodeType
!=
preNode
.
nextSibling
.
nodeType
){
i
++
;
}
continue
;
}
i
++
;
}
return
i
;
}
};
Utils
.
each
([
'String'
,
'Function'
,
'Array'
,
'Number'
,
'RegExp'
,
'Object'
],
function
(
i
,
v
)
{
...
...
src/module/basestyle.js
View file @
e3d55a0f
...
...
@@ -5,11 +5,15 @@ KityMinder.registerModule('basestylemodule', function() {
return
node
.
getData
(
name
)
||
node
.
getStyle
(
name
);
}
KityMinder
.
TextRenderer
.
registerStyleHook
(
function
(
node
,
text
)
{
text
.
setFont
({
weight
:
getNodeDataOrStyle
(
node
,
'font-weight'
),
style
:
getNodeDataOrStyle
(
node
,
'font-style'
)
KityMinder
.
TextRenderer
.
registerStyleHook
(
function
(
node
,
textGroup
)
{
textGroup
.
eachItem
(
function
(
index
,
item
){
item
.
setFont
({
'weight'
:
getNodeDataOrStyle
(
node
,
'font-weight'
),
'style'
:
getNodeDataOrStyle
(
node
,
'font-style'
)
});
});
});
return
{
'commands'
:
{
...
...
src/module/editor.js
View file @
e3d55a0f
...
...
@@ -5,14 +5,13 @@ KityMinder.registerModule('TextEditModule', function() {
var
sel
=
new
Minder
.
Selection
();
var
range
=
new
Minder
.
Range
();
var
receiver
=
new
Minder
.
Receiver
(
this
,
sel
,
range
);
var
keyboarder
=
new
Minder
.
keyboarder
(
receiver
);
this
.
receiver
=
receiver
;
//鼠标被点击,并未太抬起时为真
var
mouseDownStatus
=
false
;
var
lastEvtPosition
,
dir
=
1
;
//当前是否有选区存在
var
selectionReadyShow
=
false
;
...
...
@@ -24,17 +23,16 @@ KityMinder.registerModule('TextEditModule', function() {
var
color
=
node
.
getStyle
(
'text-selection-color'
);
//准备输入状态
var
textShape
=
node
.
getTextShape
();
receiver
.
updateByMinderNode
(
node
);
sel
.
setHide
()
.
setStartOffset
(
0
)
.
setEndOffset
(
textShape
.
getContent
().
length
)
.
setEndOffset
(
receiver
.
getTxtOfContainer
().
length
)
.
setColor
(
color
);
receiver
.
setMinderNode
(
node
)
.
updateContainerRangeBySel
();
receiver
.
updateContainerRangeBySel
();
if
(
browser
.
ie
){
var
timer
=
setInterval
(
function
(){
...
...
@@ -57,7 +55,7 @@ KityMinder.registerModule('TextEditModule', function() {
km
.
textEditNode
=
function
(
node
){
inputStatusReady
(
node
);
km
.
setStatus
(
'textedit'
);
receiver
.
updateSelection
Show
();
receiver
.
updateSelection
();
};
return
{
'events'
:
{
...
...
@@ -92,27 +90,28 @@ KityMinder.registerModule('TextEditModule', function() {
if
(
node
){
var
textShape
=
node
.
getTextShape
();
textShape
.
setStyle
(
'cursor'
,
'default'
);
if
(
this
.
isSingleSelect
()
&&
node
.
isSelected
())
{
var
textGroup
=
node
.
getTextGroup
();
textGroup
.
setStyle
(
'cursor'
,
'default'
);
sel
.
collapse
(
true
);
sel
.
setColor
(
node
.
getStyle
(
'text-selection-color'
));
receiver
.
set
MinderNode
(
node
)
.
setCurrentIndex
(
e
.
getPosition
(
this
.
getRenderContainer
()))
.
updateBy
MinderNode
(
node
)
.
updateIndexByMouse
(
e
.
getPosition
(
node
.
getRenderContainer
()))
.
setRange
(
range
)
.
setReady
();
lastEvtPosition
=
e
.
getPosition
(
this
.
getRenderContainer
());
if
(
selectionReadyShow
){
textShape
.
setStyle
(
'cursor'
,
'text'
);
receiver
.
updateSelection
();
textGroup
.
setStyle
(
'cursor'
,
'text'
);
sel
.
setShowStatus
();
setTimeout
(
function
()
{
sel
.
setShow
();
sel
.
collapse
(
true
)
.
updatePosition
(
receiver
.
getOffsetByIndex
())
.
setShow
();
},
200
);
km
.
setStatus
(
'textedit'
);
...
...
@@ -166,9 +165,8 @@ KityMinder.registerModule('TextEditModule', function() {
node
.
getTextShape
().
setStyle
(
'cursor'
,
'text'
);
//
node.getTextShape().setStyle('cursor', 'text');
receiver
.
updateSelection
();
//必须再次focus,要不不能呼出键盘
if
(
browser
.
ipad
){
...
...
@@ -176,24 +174,22 @@ KityMinder.registerModule('TextEditModule', function() {
}
setTimeout
(
function
()
{
sel
.
setShow
();
sel
.
collapse
(
true
)
.
updatePosition
(
receiver
.
getOffsetByIndex
())
.
setShow
();
},
200
);
lastEvtPosition
=
e
.
getPosition
(
this
.
getRenderContainer
());
km
.
setStatus
(
'textedit'
);
return
;
}
//当选中节点后,输入状态准备
if
(
sel
.
isHide
()){
inputStatusReady
(
e
.
getTargetNode
());
}
else
{
//当有光标时,要同步选区
if
(
!
sel
.
collapsed
){
receiver
.
updateContainerRangeBySel
();
}
...
...
@@ -205,22 +201,21 @@ KityMinder.registerModule('TextEditModule', function() {
},
'textedit.beforemousemove inputready.beforemousemove'
:
function
(
e
)
{
if
(
browser
.
ipad
){
return
;
}
//ipad下不做框选
if
(
mouseDownStatus
&&
receiver
.
isReady
()
&&
selectionReadyShow
)
{
var
node
=
e
.
getTargetNode
();
e
.
stopPropagationImmediately
();
var
offset
=
e
.
getPosition
(
this
.
getRenderContainer
());
dir
=
offset
.
x
>
lastEvtPosition
.
x
?
1
:
(
offset
.
x
<
lastEvtPosition
.
x
?
-
1
:
dir
);
receiver
.
updateSelectionByMousePosition
(
offset
,
dir
)
.
updateSelection
Show
(
dir
)
var
offset
=
e
.
getPosition
(
node
.
getRenderContainer
());
receiver
.
updateSelectionByMousePosition
(
offset
)
.
updateSelection
(
offset
)
.
updateContainerRangeBySel
();
lastEvtPosition
=
e
.
getPosition
(
this
.
getRenderContainer
());
}
else
if
(
mouseDownStatus
&&
!
selectionReadyShow
){
//第一次点中,第二次再次点中进行拖拽
...
...
@@ -231,12 +226,13 @@ KityMinder.registerModule('TextEditModule', function() {
'normal.dblclick textedit.dblclick inputready.dblclick'
:
function
(
e
)
{
var
node
=
e
.
getTargetNode
();
if
(
node
){
inputStatusReady
(
e
.
getTargetNode
()
);
inputStatusReady
(
node
);
km
.
setStatus
(
'textedit'
);
receiver
.
updateSelection
Show
();
receiver
.
updateSelection
();
}
},
...
...
@@ -259,7 +255,7 @@ KityMinder.registerModule('TextEditModule', function() {
};
if
(
cmds
[
e
.
commandName
])
{
inputStatusReady
(
km
.
getSelectedNode
());
receiver
.
updateSelection
Show
();
receiver
.
updateSelection
();
return
;
}
...
...
@@ -270,9 +266,7 @@ KityMinder.registerModule('TextEditModule', function() {
},
'layoutfinish'
:
function
(
e
){
if
(
e
.
node
===
receiver
.
minderNode
&&
(
this
.
getStatus
()
==
'textedit'
||
this
.
getStatus
()
==
'inputready'
)
)
{
//&& selectionReadyShow
receiver
.
setBaseOffset
()
.
setContainerStyle
();
receiver
.
setContainerStyle
();
}
},
'selectionclear'
:
function
()
{
...
...
@@ -287,13 +281,13 @@ KityMinder.registerModule('TextEditModule', function() {
},
'blur'
:
function
()
{
receiver
.
clear
();
!
/
\?
debug#
?
/
.
test
(
location
.
href
)
&&
receiver
.
clear
();
},
'textedit.import'
:
function
()
{
km
.
setStatus
(
'normal'
);
receiver
.
clear
();
},
'textedit.mousewheel'
:
function
()
{
'
inputready.mousewheel
textedit.mousewheel'
:
function
()
{
receiver
.
setContainerStyle
();
}
...
...
src/module/editor.keyboard.js
0 → 100644
View file @
e3d55a0f
//接收者
Minder
.
keyboarder
=
kity
.
createClass
(
'keyboarder'
,
function
(){
return
{
constructor
:
function
(
re
)
{
this
.
re
=
re
;
this
.
container
=
re
.
container
;
this
.
selection
=
re
.
selection
;
this
.
range
=
re
.
range
;
this
.
km
=
re
.
km
;
this
.
lastMinderNode
=
null
;
this
.
isTypeText
=
false
;
this
.
_initEvent
();
},
//给接受容器绑定事件
_initEvent
:
function
(){
var
me
=
this
;
if
(
browser
.
ipad
)
{
utils
.
listen
(
this
.
container
,
'keydown keypress keyup input'
,
function
(
e
)
{
me
.
_handleEvents
.
call
(
me
,
new
MinderEvent
(
e
.
type
==
'keyup'
?
'beforekeyup'
:
e
.
type
,
e
));
if
(
e
.
type
==
'keyup'
){
if
(
me
.
km
.
getStatus
()
==
'normal'
){
me
.
km
.
fire
(
'keyup'
,
e
);
}
}
});
}
this
.
km
.
on
(
'inputready.beforekeyup '
+
'inputready.beforekeydown '
+
'textedit.beforekeyup '
+
'normal.keydown '
+
'normal.keyup '
+
'textedit.beforekeydown '
+
'textedit.keypress '
+
'textedit.paste'
,
utils
.
proxy
(
this
.
_handleEvents
,
this
));
},
_handleEvents
:
function
(
e
){
switch
(
e
.
type
)
{
case
'input'
:
this
.
_input
(
e
);
break
;
case
'beforekeydown'
:
this
.
_beforeKeydown
(
e
);
break
;
case
'beforekeyup'
:
this
.
_beforeKeyup
(
e
);
break
;
case
'keyup'
:
this
.
_keyup
(
e
);
}
},
_setTextToContainer
:
function
(
keyCode
){
var
me
=
this
;
//同步节点
me
.
minderNode
=
me
.
re
.
minderNode
;
clearTimeout
(
me
.
timer
);
if
(
!
me
.
range
.
hasNativeRange
())
{
return
;
}
if
(
keymap
.
controlKeys
[
keyCode
]){
return
;
}
//当第一次输入内容时进行保存
if
(
me
.
lastMinderNode
!==
me
.
minderNode
&&
!
keymap
.
notContentChange
[
keyCode
]){
me
.
km
.
fire
(
'saveScene'
,{
inputStatus
:
true
});
me
.
lastMinderNode
=
me
.
minderNode
;
}
var
text
=
me
.
re
.
getTxtOfContainer
();
// //#46 修复在ff下定位到文字后方空格光标不移动问题
// if (browser.gecko && /\s$/.test(text)) {
// text += '\u200b';
// }
//重新渲染节点
me
.
minderNode
.
setText
(
text
);
me
.
re
.
setContainerStyle
();
me
.
minderNode
.
getRenderContainer
().
bringTop
();
me
.
minderNode
.
render
();
//移动光标不做layout
if
(
!
keymap
.
notContentChange
[
keyCode
]){
clearTimeout
(
me
.
inputTextTimer
);
me
.
inputTextTimer
=
setTimeout
(
function
(){
me
.
km
.
layout
(
300
);
},
250
);
}
me
.
re
.
updateTextOffsetData
()
.
updateRange
()
.
updateSelectionByRange
();
me
.
selection
.
updateOffsetByTextData
(
me
.
re
.
textData
)
.
updatePosition
()
.
setHoldShow
();
me
.
timer
=
setTimeout
(
function
()
{
if
(
me
.
selection
.
isShow
()){
me
.
selection
.
setShow
();
}
},
200
);
me
.
km
.
setStatus
(
'textedit'
);
},
_input
:
function
(
e
){
var
me
=
this
;
if
(
browser
.
ipad
)
{
setTimeout
(
function
()
{
me
.
_setTextToContainer
();
});
}
},
_beforeKeydown
:
function
(
e
){
var
me
=
this
;
var
orgEvt
=
e
.
originEvent
;
var
keyCode
=
orgEvt
.
keyCode
;
this
.
isTypeText
=
keyCode
==
229
||
keyCode
===
0
;
switch
(
keyCode
)
{
case
keymap
.
Enter
:
if
(
e
.
originEvent
.
shiftKey
){
me
.
_handlerEnterkey
();
e
.
preventDefault
();
return
false
;
}
case
keymap
.
Tab
:
if
(
this
.
selection
.
isShow
()){
this
.
re
.
clear
();
this
.
km
.
setStatus
(
'inputready'
);
clearTimeout
(
me
.
inputTextTimer
);
e
.
preventDefault
();
}
else
{
this
.
km
.
setStatus
(
'normal'
);
this
.
km
.
fire
(
'contentchange'
);
}
return
;
case
keymap
.
left
:
case
keymap
.
right
:
case
keymap
.
up
:
case
keymap
.
down
:
case
keymap
.
Backspace
:
case
keymap
.
Del
:
case
keymap
[
'/'
]:
if
(
this
.
selection
.
isHide
()){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
break
;
case
keymap
.
Control
:
case
keymap
.
Alt
:
case
keymap
.
Cmd
:
case
keymap
.
F2
:
if
(
this
.
selection
.
isHide
()
&&
this
.
km
.
getStatus
()
!=
'textedit'
){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
}
if
(
e
.
originEvent
.
ctrlKey
||
e
.
originEvent
.
metaKey
)
{
//选中节点时的复制粘贴,要变成normal
if
(
this
.
selection
.
isHide
()
&&
{
86
:
1
,
88
:
1
,
67
:
1
}[
keyCode
]){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
//粘贴
if
(
keyCode
==
keymap
.
v
)
{
setTimeout
(
function
()
{
me
.
range
.
updateNativeRange
().
insertNode
(
$
(
'<span>$$_kityminder_bookmark_$$</span>'
)[
0
]);
me
.
container
.
innerHTML
=
utils
.
unhtml
(
me
.
container
.
textContent
.
replace
(
/
[\u
200b
\t\r\n]
/g
,
''
));
var
index
=
me
.
container
.
textContent
.
indexOf
(
'$$_kityminder_bookmark_$$'
);
me
.
container
.
textContent
=
me
.
container
.
textContent
.
replace
(
'$$_kityminder_bookmark_$$'
,
''
);
me
.
range
.
setStart
(
me
.
container
.
firstChild
,
index
).
collapse
(
true
).
select
();
me
.
_setTextToContainer
(
keyCode
);
},
100
);
return
;
}
//剪切
if
(
keyCode
==
keymap
.
x
)
{
setTimeout
(
function
()
{
me
.
_setTextToContainer
(
keyCode
);
},
100
);
return
;
}
}
//针对不能连续删除做处理
if
(
keymap
.
Del
==
keyCode
||
keymap
.
Backspace
==
keyCode
)
me
.
_setTextToContainer
(
keyCode
);
},
_beforeKeyup
:
function
(
e
){
var
me
=
this
;
var
orgEvt
=
e
.
originEvent
;
var
keyCode
=
orgEvt
.
keyCode
;
switch
(
keyCode
)
{
case
keymap
.
Enter
:
case
keymap
.
Tab
:
case
keymap
.
F2
:
if
(
browser
.
ipad
){
if
(
this
.
selection
.
isShow
()){
this
.
clear
();
this
.
km
.
setStatus
(
'inputready'
);
clearTimeout
(
me
.
inputTextTimer
);
e
.
preventDefault
();
}
else
{
this
.
km
.
setStatus
(
'normal'
);
this
.
km
.
fire
(
'contentchange'
);
}
return
;
}
if
(
keymap
.
Enter
==
keyCode
&&
(
this
.
isTypeText
||
browser
.
mac
&&
browser
.
gecko
))
{
me
.
_setTextToContainer
(
keyCode
);
}
if
(
this
.
keydownNode
===
this
.
minderNode
)
{
this
.
rollbackStatus
();
this
.
clear
();
}
e
.
preventDefault
();
return
;
case
keymap
.
Del
:
case
keymap
.
Backspace
:
case
keymap
.
Spacebar
:
if
(
browser
.
ipad
){
if
(
this
.
selection
.
isHide
()){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
}
me
.
_setTextToContainer
(
keyCode
);
return
;
}
if
(
this
.
isTypeText
)
{
me
.
_setTextToContainer
(
keyCode
);
return
;
}
if
(
browser
.
mac
&&
browser
.
gecko
){
me
.
_setTextToContainer
(
keyCode
);
return
;
}
me
.
_setTextToContainer
(
keyCode
);
return
true
;
},
_keyup
:
function
(
e
){
var
me
=
this
;
var
orgEvt
=
e
.
originEvent
;
var
keyCode
=
orgEvt
.
keyCode
;
var
node
=
this
.
km
.
getSelectedNode
();
if
(
this
.
km
.
getStatus
()
==
'normal'
&&
node
&&
this
.
selection
.
isHide
()){
if
(
node
&&
this
.
km
.
isSingleSelect
()
&&
node
.
isSelected
())
{
this
.
selection
.
setHide
()
.
setStartOffset
(
0
)
.
setEndOffset
(
this
.
re
.
getTxtOfContainer
().
length
)
.
setColor
(
node
.
getStyle
(
'text-selection-color'
));
this
.
re
.
updateByMinderNode
(
node
)
.
updateContainerRangeBySel
();
if
(
browser
.
ie
){
var
timer
=
setInterval
(
function
(){
var
nativeRange
=
me
.
range
.
nativeSel
.
getRangeAt
(
0
);
if
(
!
nativeRange
||
nativeRange
.
collapsed
){
me
.
range
.
select
();
}
else
{
clearInterval
(
timer
);
}
});
}
this
.
km
.
setStatus
(
'inputready'
);
}
}
},
//处理软回车操作
_handlerEnterkey
:
function
(){
var
rng
=
this
.
range
;
var
br
=
document
.
createElement
(
'br'
);
var
me
=
this
;
if
(
!
rng
.
collapsed
){
rng
.
deleteContents
();
}
rng
.
insertNode
(
br
);
rng
.
setStartAfter
(
br
);
rng
.
collapse
(
true
);
rng
.
select
();
me
.
_setTextToContainer
(
keymap
.
Enter
);
}
};
}());
\ No newline at end of file
src/module/editor.range.js
View file @
e3d55a0f
Minder
.
Range
=
kity
.
createClass
(
'Range'
,{
constructor
:
function
(){
this
.
nativeRange
=
document
.
createRange
();
this
.
nativeSel
=
window
.
getSelection
();
},
hasNativeRange
:
function
(){
return
this
.
nativeSel
.
rangeCount
!==
0
;
},
select
:
function
(){
var
start
=
this
.
nativeRange
.
startContainer
;
if
(
start
.
nodeType
==
1
&&
start
.
childNodes
.
length
===
0
){
var
char
=
document
.
createTextNode
(
'
\
u200b'
);
start
.
appendChild
(
char
);
this
.
nativeRange
.
setStart
(
char
,
1
);
this
.
nativeRange
.
collapse
(
true
);
}
try
{
this
.
nativeSel
.
removeAllRanges
();
}
catch
(
e
){
Minder
.
Range
=
kity
.
createClass
(
'Range'
,
function
(){
function
getOffset
(
rng
,
dir
){
var
node
=
rng
[
dir
+
'Container'
],
offset
=
rng
[
dir
+
'Offset'
],
rOffset
=
0
;
if
(
node
.
nodeType
==
1
){
//默认不会出现得不到子节点的情况
node
=
node
.
childNodes
[
offset
];
if
(
node
.
nodeType
==
3
){
offset
=
0
;
}
}
utils
.
each
(
rng
.
container
.
childNodes
,
function
(
index
,
n
){
if
(
n
===
node
){
if
(
n
.
nodeType
==
1
){
return
false
;
}
else
{
rOffset
+=
offset
;
return
false
;
}
}
rOffset
+=
(
n
.
nodeType
==
1
?
1
:
utils
.
clearWhitespace
(
n
.
nodeValue
).
length
);
});
return
rOffset
;
}
function
setBoundary
(
rng
,
offset
,
dir
){
var
rOffset
=
0
,
cont
=
rng
.
container
;
utils
.
each
(
cont
.
childNodes
,
function
(
index
,
node
){
if
(
node
.
nodeType
==
1
){
this
.
nativeSel
.
addRange
(
this
.
nativeRange
);
return
this
;
},
setStart
:
function
(
node
,
index
){
try
{
this
.
nativeRange
.
setStart
(
node
,
index
);
}
catch
(
error
){
console
.
log
(
error
);
}
rOffset
++
;
if
(
rOffset
==
offset
){
return
this
;
},
setEnd
:
function
(
node
,
index
){
this
.
nativeRange
.
setEnd
(
node
,
index
);
return
this
;
},
getStart
:
function
(){
var
range
=
this
.
nativeSel
.
getRangeAt
(
0
);
return
{
startContainer
:
range
.
startContainer
,
startOffset
:
range
.
startOffset
};
},
getStartOffset
:
function
(){
return
this
.
nativeRange
.
startOffset
;
},
getEndOffset
:
function
(){
return
this
.
nativeRange
.
endOffset
;
},
collapse
:
function
(
toStart
){
this
.
nativeRange
.
collapse
(
toStart
===
true
);
return
this
;
},
isCollapsed
:
function
(){
return
this
.
nativeRange
.
collapsed
;
},
insertNode
:
function
(
node
){
this
.
nativeRange
.
insertNode
(
node
);
return
this
;
},
updateNativeRange
:
function
(){
rng
[
'set'
+
dir
](
cont
,
index
);
return
false
;
}
return
;
}
this
.
nativeRange
=
this
.
nativeSel
.
getRangeAt
(
0
);
return
this
;
var
currentLength
=
utils
.
clearWhitespace
(
node
.
nodeValue
).
length
;
if
(
rOffset
+
currentLength
>=
offset
){
rng
[
'set'
+
dir
](
node
,
offset
-
rOffset
);
return
false
;
}
rOffset
+=
currentLength
;
});
}
return
{
constructor
:
function
(
container
){
this
.
nativeRange
=
document
.
createRange
();
this
.
nativeSel
=
window
.
getSelection
();
this
.
startContainer
=
this
.
endContainer
=
this
.
startOffset
=
this
.
endOffset
=
null
;
this
.
collapsed
=
false
;
this
.
container
=
container
||
null
;
},
hasNativeRange
:
function
(){
return
this
.
nativeSel
.
rangeCount
!==
0
;
},
deleteContents
:
function
(){
this
.
nativeRange
.
deleteContents
();
return
this
.
_updateBoundary
();
},
select
:
function
(){
var
start
=
this
.
nativeRange
.
startContainer
;
if
(
start
.
nodeType
==
1
&&
start
.
childNodes
.
length
===
0
){
var
char
=
document
.
createTextNode
(
'
\
u200b'
);
start
.
appendChild
(
char
);
this
.
nativeRange
.
setStart
(
char
,
1
);
this
.
nativeRange
.
collapse
(
true
);
}
try
{
this
.
nativeSel
.
removeAllRanges
();
}
catch
(
e
){
}
this
.
nativeSel
.
addRange
(
this
.
nativeRange
);
return
this
;
},
_updateBoundary
:
function
(){
var
nRange
=
this
.
nativeRange
;
this
.
startContainer
=
nRange
.
startContainer
;
this
.
endContainer
=
nRange
.
endContainer
;
this
.
startOffset
=
nRange
.
startOffset
;
this
.
endOffset
=
nRange
.
endOffset
;
this
.
collapsed
=
nRange
.
collapsed
;
return
this
;
},
setStartOffset
:
function
(
offset
){
setBoundary
(
this
,
offset
,
'Start'
);
return
this
;
},
setEndOffset
:
function
(
offset
){
setBoundary
(
this
,
offset
,
'End'
);
return
this
;
},
setStart
:
function
(
node
,
offset
){
this
.
nativeRange
.
setStart
(
node
,
offset
);
this
.
_updateBoundary
();
return
this
;
},
setStartAfter
:
function
(
node
){
return
this
.
setStart
(
node
.
parentNode
,
utils
.
getNodeIndex
(
node
)
+
1
);
},
setEnd
:
function
(
node
,
offset
){
this
.
nativeRange
.
setEnd
(
node
,
offset
);
this
.
_updateBoundary
();
return
this
;
},
update
:
function
(){
this
.
updateNativeRange
()
.
_updateBoundary
();
return
this
;
},
getStart
:
function
(){
this
.
update
();
return
{
startContainer
:
this
.
startContainer
,
startOffset
:
this
.
startOffset
};
},
getStartOffset
:
function
(){
return
getOffset
(
this
,
'start'
);
},
getEndOffset
:
function
(){
return
getOffset
(
this
,
'end'
);
},
collapse
:
function
(
toStart
){
this
.
nativeRange
.
collapse
(
toStart
===
true
);
this
.
_updateBoundary
();
return
this
;
},
isCollapsed
:
function
(){
this
.
_updateBoundary
();
return
this
.
collapsed
;
},
insertNode
:
function
(
node
){
this
.
nativeRange
.
insertNode
(
node
);
return
this
.
_updateBoundary
();
},
updateNativeRange
:
function
(){
this
.
nativeRange
=
this
.
nativeSel
.
getRangeAt
(
0
);
return
this
;
},
clear
:
function
(){
this
.
nativeSel
.
removeAllRanges
();
return
this
;
}
});
\ No newline at end of file
};
}());
\ No newline at end of file
src/module/editor.receiver.js
View file @
e3d55a0f
...
...
@@ -6,49 +6,40 @@ Minder.Receiver = kity.createClass('Receiver', {
this
.
selection
.
setHide
();
}
if
(
this
.
range
)
{
this
.
range
.
nativeSel
.
removeAllRanges
();
this
.
range
.
clear
();
}
this
.
index
=
0
;
this
.
isTypeText
=
false
;
this
.
lastMinderNode
=
null
;
return
this
;
},
constructor
:
function
(
km
,
sel
,
range
)
{
var
me
=
this
;
//初始化接收者
this
.
setKityMinder
(
km
);
//创建接收者容器
var
_div
=
document
.
createElement
(
'div'
);
_div
.
setAttribute
(
'contenteditable'
,
true
);
_div
.
className
=
'km_receiver'
;
this
.
container
=
_div
;
utils
.
addCssRule
(
'km_receiver_css'
,
' .km_receiver{white-space:nowrap;position:absolute;padding:0;margin:0;word-wrap:break-word;'
+
(
/
\?
debug#
?
/
.
test
(
location
.
href
)?
''
:
'clip:rect(1em 1em 1em 1em);'
));
if
(
browser
.
ipad
)
{
utils
.
listen
(
this
.
container
,
'keydown keypress keyup input'
,
function
(
e
)
{
me
.
keyboardEvents
.
call
(
me
,
new
MinderEvent
(
e
.
type
==
'keyup'
?
'beforekeyup'
:
e
.
type
,
e
));
if
(
e
.
type
==
'keyup'
){
if
(
me
.
km
.
getStatus
()
==
'normal'
){
me
.
km
.
fire
(
'keyup'
,
e
);
}
}
});
}
utils
.
addCssRule
(
'km_receiver_css'
,
' .km_receiver{white-space:nowrap;position:absolute;padding:0;margin:0;word-wrap:break-word;'
+
(
/
\?
debug#
?
/
.
test
(
location
.
href
)?
''
:
'clip:rect(1em 1em 1em 1em);'
));
this
.
km
.
on
(
'inputready.beforekeyup inputready.beforekeydown textedit.beforekeyup normal.keydown normal.keyup textedit.beforekeydown textedit.keypress textedit.paste'
,
utils
.
proxy
(
this
.
keyboardEvents
,
this
));
this
.
timer
=
null
;
this
.
index
=
0
;
this
.
selection
=
sel
;
this
.
range
=
range
;
this
.
range
.
container
=
_div
;
},
setRange
:
function
(
range
,
index
)
{
this
.
index
=
index
||
this
.
index
;
var
text
=
this
.
container
.
firstChild
;
this
.
range
=
range
;
range
.
setStart
(
text
||
this
.
container
,
this
.
index
)
range
.
setStartOffset
(
this
.
index
);
range
.
collapse
(
true
);
var
me
=
this
;
...
...
@@ -58,39 +49,22 @@ Minder.Receiver = kity.createClass('Receiver', {
});
return
this
;
},
setTextShape
:
function
(
textShape
)
{
if
(
!
textShape
)
{
textShape
=
new
kity
.
Text
();
}
this
.
textShape
=
textShape
;
// techird: add cache
if
(
textShape
.
_lastContent
!=
textShape
.
getContent
())
{
this
.
container
.
innerHTML
=
utils
.
unhtml
(
textShape
.
getContent
());
textShape
.
_lastContent
=
textShape
.
getContent
();
}
return
this
;
},
setTextShapeSize
:
function
(
size
)
{
this
.
textShape
.
setSize
(
size
);
setTextGroup
:
function
(
textGroup
)
{
this
.
textGroup
=
textGroup
;
return
this
;
},
getTextShapeHeight
:
function
()
{
var
height
=
this
.
textShape
.
getRenderBox
().
height
;
return
height
||
this
.
minderNode
.
_lastTextShapeBox
.
height
;
},
setKityMinder
:
function
(
km
)
{
this
.
km
=
km
;
return
this
;
},
setMinderNode
:
function
(
node
)
{
this
.
minderNode
=
node
;
updateByMinderNode
:
function
(
node
){
this
.
setMinderNode
(
node
);
//追加selection到节点
this
.
_addSelection
();
//更新minderNode下的textshape
this
.
setTextShape
(
node
.
getTextShape
());
//更新textshape的baseOffset
this
.
setBaseOffset
();
//更新minderNode下的textGroup
this
.
setTextGroup
(
node
.
getTextGroup
());
//更新接受容器的样式
this
.
setContainerStyle
();
//更新textOffsetData数据
...
...
@@ -99,472 +73,215 @@ Minder.Receiver = kity.createClass('Receiver', {
this
.
setSelectionHeight
();
//更新接收容器内容
this
.
setContainerTxt
();
return
this
;
},
setMinderNode
:
function
(
node
)
{
this
.
minderNode
=
node
;
this
.
selection
.
setMinderNode
(
node
);
return
this
;
},
_addSelection
:
function
(){
if
(
this
.
selection
.
container
)
this
.
selection
.
remove
();
if
(
this
.
selection
.
container
){
this
.
selection
.
remove
();
}
this
.
minderNode
.
getRenderContainer
().
addShape
(
this
.
selection
);
return
this
;
},
getMinderNode
:
function
(){
return
this
.
minderNode
;
},
keyboardEvents
:
function
(
e
)
{
var
me
=
this
;
var
orgEvt
=
e
.
originEvent
;
var
keyCode
=
orgEvt
.
keyCode
;
function
setTextToContainer
()
{
clearTimeout
(
me
.
timer
);
if
(
!
me
.
range
.
hasNativeRange
())
{
return
;
}
if
(
keymap
.
controlKeys
[
keyCode
]){
return
;
}
//当第一次输入内容时进行保存
if
(
me
.
lastMinderNode
!==
me
.
minderNode
&&
!
keymap
.
notContentChange
[
keyCode
]){
me
.
km
.
fire
(
'saveScene'
,{
inputStatus
:
true
});
me
.
lastMinderNode
=
me
.
minderNode
;
}
var
text
=
me
.
container
.
textContent
.
replace
(
/
[\u
200b
\t\r\n]
/g
,
''
);
//#46 修复在ff下定位到文字后方空格光标不移动问题
if
(
browser
.
gecko
&&
/
\s
$/
.
test
(
text
))
{
text
+=
'
\
u200b'
;
}
me
.
minderNode
.
setText
(
text
);
me
.
setContainerStyle
();
me
.
minderNode
.
getRenderContainer
().
bringTop
();
me
.
minderNode
.
render
();
//移动光标不做layout
if
(
!
keymap
.
notContentChange
[
keyCode
]){
clearTimeout
(
me
.
inputTextTimer
);
me
.
inputTextTimer
=
setTimeout
(
function
(){
me
.
km
.
layout
(
300
);
},
250
);
}
me
.
textShape
=
me
.
minderNode
.
getRenderer
(
'TextRenderer'
).
getRenderShape
();
me
.
setBaseOffset
();
me
.
updateTextOffsetData
();
me
.
updateRange
();
me
.
updateSelectionByRange
();
me
.
updateSelectionShow
();
me
.
timer
=
setTimeout
(
function
()
{
if
(
me
.
selection
.
isShow
())
me
.
selection
.
setShow
();
},
200
);
me
.
km
.
setStatus
(
'textedit'
);
}
switch
(
e
.
type
)
{
case
'input'
:
if
(
browser
.
ipad
)
{
setTimeout
(
function
()
{
setTextToContainer
();
});
}
break
;
case
'beforekeydown'
:
this
.
isTypeText
=
keyCode
==
229
||
keyCode
===
0
;
switch
(
keyCode
)
{
case
keymap
.
Enter
:
case
keymap
.
Tab
:
if
(
this
.
selection
.
isShow
()){
this
.
clear
();
this
.
km
.
setStatus
(
'inputready'
);
clearTimeout
(
me
.
inputTextTimer
);
e
.
preventDefault
();
this
.
km
.
fire
(
'contentchange'
);
}
else
{
this
.
km
.
setStatus
(
'normal'
);
}
return
;
case
keymap
.
left
:
case
keymap
.
right
:
case
keymap
.
up
:
case
keymap
.
down
:
case
keymap
.
Backspace
:
case
keymap
.
Del
:
case
keymap
[
'/'
]:
if
(
this
.
selection
.
isHide
()){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
break
;
case
keymap
.
Control
:
case
keymap
.
Alt
:
case
keymap
.
Cmd
:
case
keymap
.
F2
:
if
(
this
.
selection
.
isHide
()
&&
this
.
km
.
getStatus
()
!=
'textedit'
){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
}
if
(
e
.
originEvent
.
ctrlKey
||
e
.
originEvent
.
metaKey
)
{
//选中节点时的复制粘贴,要变成normal
if
(
this
.
selection
.
isHide
()
&&
{
86
:
1
,
88
:
1
,
67
:
1
}[
keyCode
]){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
//粘贴
if
(
keyCode
==
keymap
.
v
)
{
setTimeout
(
function
()
{
me
.
range
.
updateNativeRange
().
insertNode
(
$
(
'<span>$$_kityminder_bookmark_$$</span>'
)[
0
]);
me
.
container
.
innerHTML
=
utils
.
unhtml
(
me
.
container
.
textContent
.
replace
(
/
[\u
200b
\t\r\n]
/g
,
''
));
var
index
=
me
.
container
.
textContent
.
indexOf
(
'$$_kityminder_bookmark_$$'
);
me
.
container
.
textContent
=
me
.
container
.
textContent
.
replace
(
'$$_kityminder_bookmark_$$'
,
''
);
me
.
range
.
setStart
(
me
.
container
.
firstChild
,
index
).
collapse
(
true
).
select
();
setTextToContainer
(
keyCode
);
},
100
);
return
;
}
//剪切
if
(
keyCode
==
keymap
.
x
)
{
setTimeout
(
function
()
{
setTextToContainer
(
keyCode
);
},
100
);
return
;
}
}
//针对不能连续删除做处理
if
(
keymap
.
Del
==
keyCode
||
keymap
.
Backspace
==
keyCode
)
setTextToContainer
(
keyCode
);
break
;
case
'beforekeyup'
:
switch
(
keyCode
)
{
case
keymap
.
Enter
:
case
keymap
.
Tab
:
case
keymap
.
F2
:
if
(
browser
.
ipad
){
if
(
this
.
selection
.
isShow
()){
this
.
clear
();
this
.
km
.
setStatus
(
'inputready'
);
clearTimeout
(
me
.
inputTextTimer
);
e
.
preventDefault
();
}
else
{
this
.
km
.
setStatus
(
'normal'
);
}
return
;
}
if
(
keymap
.
Enter
==
keyCode
&&
(
this
.
isTypeText
||
browser
.
mac
&&
browser
.
gecko
))
{
setTextToContainer
(
keyCode
);
}
if
(
this
.
keydownNode
===
this
.
minderNode
)
{
this
.
rollbackStatus
();
this
.
clear
();
}
e
.
preventDefault
();
return
;
case
keymap
.
Del
:
case
keymap
.
Backspace
:
case
keymap
.
Spacebar
:
if
(
browser
.
ipad
){
if
(
this
.
selection
.
isHide
()){
this
.
km
.
setStatus
(
'normal'
);
return
;
}
}
setTextToContainer
(
keyCode
);
return
;
}
if
(
this
.
isTypeText
)
{
setTextToContainer
(
keyCode
);
return
;
}
if
(
browser
.
mac
&&
browser
.
gecko
){
setTextToContainer
(
keyCode
);
return
;
}
setTextToContainer
(
keyCode
);
return
true
;
case
'keyup'
:
var
node
=
this
.
km
.
getSelectedNode
();
if
(
this
.
km
.
getStatus
()
==
'normal'
&&
node
&&
this
.
selection
.
isHide
()){
if
(
node
&&
this
.
km
.
isSingleSelect
()
&&
node
.
isSelected
())
{
var
color
=
node
.
getStyle
(
'text-selection-color'
);
//准备输入状态
var
textShape
=
node
.
getTextShape
();
this
.
selection
.
setHide
()
.
setStartOffset
(
0
)
.
setEndOffset
(
textShape
.
getContent
().
length
)
.
setColor
(
color
);
this
.
setMinderNode
(
node
)
.
updateContainerRangeBySel
();
if
(
browser
.
ie
){
var
timer
=
setInterval
(
function
(){
var
nativeRange
=
this
.
range
.
nativeSel
.
getRangeAt
(
0
);
if
(
!
nativeRange
||
nativeRange
.
collapsed
){
this
.
range
.
select
();
}
else
{
clearInterval
(
timer
);
}
});
}
this
.
km
.
setStatus
(
'inputready'
);
}
}
}
},
updateIndex
:
function
()
{
this
.
index
=
this
.
range
.
getStart
().
startOffset
;
return
this
;
},
updateTextOffsetData
:
function
()
{
this
.
getTextOffsetData
();
this
.
index
=
this
.
range
.
getStartOffset
();
return
this
;
},
setSelection
:
function
(
selection
)
{
this
.
selection
=
selection
;
return
this
;
},
updateSelection
:
function
()
{
this
.
selection
.
setShowHold
();
this
.
selection
.
bringTop
();
//更新模拟选区的范围
this
.
selection
.
setStartOffset
(
this
.
index
).
collapse
(
true
);
if
(
this
.
index
==
this
.
textData
.
length
)
{
if
(
this
.
index
===
0
)
{
this
.
selection
.
setPosition
(
this
.
getBaseOffset
());
}
else
{
this
.
selection
.
setPosition
({
x
:
this
.
textData
[
this
.
index
-
1
].
x
+
this
.
textData
[
this
.
index
-
1
].
width
,
y
:
this
.
textData
[
this
.
index
-
1
].
y
});
}
}
else
{
this
.
selection
.
setPosition
(
this
.
textData
[
this
.
index
]);
}
updateSelection
:
function
(
offset
)
{
this
.
selection
.
update
(
this
.
textData
,
offset
);
return
this
;
},
get
BaseOffset
:
function
(
refer
)
{
return
this
.
textShape
.
getRenderBox
(
refer
||
this
.
km
.
getRenderContainer
()
);
get
OffsetByIndex
:
function
(
index
)
{
return
utils
.
getValueByIndex
(
this
.
textData
,
index
!==
undefined
?
index
:
this
.
index
);
},
setBaseOffset
:
function
()
{
this
.
offset
=
this
.
textShape
.
getRenderBox
(
this
.
km
.
getRenderContainer
());
return
this
;
getBaseOffset
:
function
()
{
return
this
.
textGroup
.
getRenderBox
(
'screen'
);
},
setContainerStyle
:
function
()
{
var
text
ShapeBox
=
this
.
getBaseOffset
(
'screen'
);
var
text
GroupBox
=
this
.
getBaseOffset
(
);
this
.
container
.
style
.
cssText
=
';left:'
+
(
browser
.
ipad
?
'-'
:
''
)
+
text
ShapeBox
.
x
+
'px;top:'
+
(
textShapeBox
.
y
+
(
/
\?
debug#
?
/
.
test
(
location
.
href
)?
30
:
0
))
+
'px;width:'
+
text
ShapeBox
.
width
+
'px;height:'
+
textShape
Box
.
height
+
'px;'
;
text
GroupBox
.
x
+
'px;top:'
+
(
textGroupBox
.
y
+
(
/
\?
debug#
?
/
.
test
(
location
.
href
)?
this
.
textGroup
.
getItems
().
length
*
this
.
getlineHeight
()
:
0
))
+
'px;width:'
+
text
GroupBox
.
width
+
'px;height:'
+
textGroup
Box
.
height
+
'px;'
;
return
this
;
},
getTextOffsetData
:
function
()
{
var
text
=
this
.
textShape
.
getContent
();
updateTextOffsetData
:
function
()
{
var
me
=
this
;
var
lineHeight
=
this
.
minderNode
.
getStyle
(
'line-height'
)
*
(
this
.
minderNode
.
getData
(
'font-size'
)
||
this
.
minderNode
.
getStyle
(
'font-size'
));
var
offsetHeight
=
(
me
.
textGroup
.
getShapes
().
length
*
lineHeight
)
/
2
;
var
box
;
this
.
textData
=
[];
for
(
var
i
=
0
,
l
=
text
.
length
;
i
<
l
;
i
++
)
{
try
{
box
=
this
.
textShape
.
getExtentOfChar
(
i
);
}
catch
(
e
)
{
console
.
log
(
e
);
}
me
.
textGroup
.
eachItem
(
function
(
index
,
textShape
){
me
.
textData
[
index
]
=
[];
var
currentLineTop
=
index
*
lineHeight
+
2
;
var
text
=
textShape
.
getContent
();
this
.
textData
.
push
({
x
:
box
.
x
,
y
:
box
.
y
,
width
:
box
.
width
,
height
:
box
.
height
});
}
if
(
this
.
textData
.
length
===
0
){
var
lastBox
=
this
.
minderNode
.
_lastTextShapeBox
;
this
.
textData
.
push
({
x
:
lastBox
.
x
,
y
:
lastBox
.
y
,
width
:
0
,
height
:
lastBox
.
height
});
}
for
(
var
i
=
0
,
l
=
text
.
length
;
i
<
l
;
i
++
)
{
try
{
box
=
textShape
.
getExtentOfChar
(
i
);
}
catch
(
e
)
{
console
.
log
(
e
);
}
me
.
textData
[
index
].
push
({
x
:
box
.
x
,
y
:
currentLineTop
-
offsetHeight
,
width
:
box
.
width
,
height
:
box
.
height
});
}
if
(
text
.
length
===
0
){
me
.
textData
[
index
].
push
({
x
:
0
,
y
:
currentLineTop
-
offsetHeight
,
width
:
0
,
height
:
lineHeight
});
}
});
return
this
;
},
setCurrentIndex
:
function
(
offset
)
{
getlineHeight
:
function
(){
return
this
.
minderNode
.
getStyle
(
'line-height'
)
*
(
this
.
minderNode
.
getData
(
'font-size'
)
||
this
.
minderNode
.
getStyle
(
'font-size'
));
},
updateIndexByMouse
:
function
(
offset
)
{
var
me
=
this
;
this
.
getTextOffsetData
();
var
hadChanged
=
false
;
//要剪掉基数
this
.
_getRelativeValue
(
offset
);
if
(
this
.
textData
.
length
==
1
&&
this
.
textData
[
0
].
width
===
0
){
me
.
index
=
0
;
return
this
;
}
utils
.
each
(
this
.
textData
,
function
(
i
,
v
)
{
//点击开始之前
if
(
i
===
0
&&
offset
.
x
<=
v
.
x
)
{
me
.
index
=
0
;
return
false
;
}
if
(
offset
.
x
>=
v
.
x
&&
offset
.
x
<=
v
.
x
+
v
.
width
)
{
if
(
offset
.
x
-
v
.
x
>
v
.
width
/
2
)
{
me
.
index
=
i
+
1
;
//更新文本字符坐标
me
.
updateTextOffsetData
();
}
else
{
me
.
index
=
i
;
this
.
index
=
0
;
}
hadChanged
=
true
;
return
false
;
}
if
(
i
==
me
.
textData
.
length
-
1
&&
offset
.
x
>=
v
.
x
)
{
me
.
index
=
me
.
textData
.
length
;
var
lineHeight
=
this
.
getlineHeight
();
utils
.
each
(
this
.
textData
,
function
(
l
,
arr
){
var
first
=
arr
[
0
];
//确定行号
if
(
first
.
y
<=
offset
.
y
&&
first
.
y
+
lineHeight
>=
offset
.
y
){
utils
.
each
(
arr
,
function
(
i
,
v
){
//点击开始之前
if
(
i
===
0
&&
offset
.
x
<=
v
.
x
)
{
return
false
;
}
if
(
offset
.
x
>=
v
.
x
&&
offset
.
x
<=
v
.
x
+
v
.
width
)
{
if
(
offset
.
x
-
v
.
x
>
v
.
width
/
2
)
{
me
.
index
+=
i
+
1
;
}
else
{
me
.
index
+=
i
;
}
return
false
;
}
if
(
i
==
arr
.
length
-
1
&&
offset
.
x
>=
v
.
x
)
{
me
.
index
+=
arr
.
length
;
return
false
;
}
});
return
false
;
}
else
{
me
.
index
+=
arr
.
length
+
(
arr
.
length
==
1
&&
arr
[
0
].
width
===
0
?
0
:
1
);
return
;
}
});
this
.
selection
.
setStartOffset
(
this
.
index
).
collapse
(
true
);
return
this
;
},
setSelectionHeight
:
function
()
{
this
.
selection
.
setHeight
(
this
.
getTextShapeHeight
());
this
.
selection
.
setHeight
((
this
.
minderNode
.
getData
(
'font-size'
)
||
this
.
minderNode
.
getStyle
(
'font-size'
))
*
1
);
return
this
;
},
_getRelativeValue
:
function
(
offset
){
offset
.
x
=
offset
.
x
-
this
.
offset
.
x
;
offset
.
y
=
offset
.
y
-
this
.
offset
.
y
;
},
updateSelectionByMousePosition
:
function
(
offset
,
dir
)
{
//要剪掉基数
this
.
_getRelativeValue
(
offset
);
updateSelectionByMousePosition
:
function
(
offset
,
dir
)
{
var
me
=
this
;
utils
.
each
(
this
.
textData
,
function
(
i
,
v
)
{
//点击开始之前
if
(
i
===
0
&&
offset
.
x
<=
v
.
x
)
{
me
.
selection
.
setStartOffset
(
0
);
return
false
;
}
var
result
=
0
;
var
lineHeight
=
this
.
getlineHeight
();
utils
.
each
(
this
.
textData
,
function
(
l
,
arr
){
var
first
=
arr
[
0
];
//确定行号
if
(
first
.
y
<=
offset
.
y
&&
first
.
y
+
lineHeight
>=
offset
.
y
){
utils
.
each
(
arr
,
function
(
i
,
v
){
//点击开始之前
if
(
i
===
0
&&
offset
.
x
<=
v
.
x
)
{
return
false
;
}
if
(
offset
.
x
>=
v
.
x
&&
offset
.
x
<=
v
.
x
+
v
.
width
)
{
if
(
i
==
me
.
textData
.
length
-
1
&&
offset
.
x
>=
v
.
x
)
{
me
.
selection
.
setEndOffset
(
me
.
textData
.
length
);
return
false
;
}
if
(
offset
.
x
>=
v
.
x
&&
offset
.
x
<=
v
.
x
+
v
.
width
)
{
result
+=
i
;
if
(
offset
.
x
-
v
.
x
>
v
.
width
/
2
)
{
if
(
me
.
index
==
i
)
{
if
(
i
===
0
)
{
me
.
selection
.
setStartOffset
(
i
);
}
if
(
offset
.
x
<=
v
.
x
+
v
.
width
/
2
)
{
me
.
selection
.
collapse
(
true
);
}
else
{
me
.
selection
.
setEndOffset
(
i
+
((
me
.
selection
.
endOffset
>
i
||
dir
==
1
)
&&
i
!=
me
.
textData
.
length
-
1
?
1
:
0
));
}
result
+=
1
;
}
}
else
if
(
i
>
me
.
index
)
{
me
.
selection
.
setStartOffset
(
me
.
index
);
me
.
selection
.
setEndOffset
(
i
+
1
);
}
else
{
if
(
dir
==
1
)
{
me
.
selection
.
setStartOffset
(
i
+
(
offset
.
x
>=
v
.
x
+
v
.
width
/
2
&&
i
!=
me
.
textData
.
length
-
1
?
1
:
0
));
}
else
{
me
.
selection
.
setStartOffset
(
i
);
return
false
;
}
if
(
i
==
arr
.
length
-
1
&&
offset
.
x
>=
v
.
x
)
{
result
+=
arr
.
length
;
me
.
selection
.
setEndOffset
(
me
.
index
);
}
return
false
;
}
});
return
false
;
}
else
{
result
+=
arr
.
length
+
(
arr
.
length
==
1
&&
arr
[
0
].
width
===
0
?
0
:
1
);
return
;
}
});
return
this
;
},
updateSelectionShow
:
function
()
{
var
startOffset
=
this
.
textData
[
this
.
selection
.
startOffset
],
endOffset
=
this
.
textData
[
this
.
selection
.
endOffset
],
width
=
0
;
if
(
this
.
selection
.
collapsed
)
{
if
(
startOffset
===
undefined
){
var
tmpOffset
=
this
.
textData
[
this
.
textData
.
length
-
1
];
tmpOffset
=
utils
.
clone
(
tmpOffset
);
tmpOffset
.
x
=
tmpOffset
.
x
+
tmpOffset
.
width
;
startOffset
=
tmpOffset
;
}
this
.
selection
.
updateShow
(
startOffset
,
2
);
return
this
;
}
if
(
!
endOffset
)
{
try
{
var
lastOffset
=
this
.
textData
[
this
.
textData
.
length
-
1
];
width
=
lastOffset
.
x
-
startOffset
.
x
+
lastOffset
.
width
;
}
catch
(
e
)
{
console
.
log
(
e
);
}
if
(
result
<
me
.
index
){
this
.
selection
.
setStartOffset
(
result
);
this
.
selection
.
setEndOffset
(
me
.
index
);
}
else
{
width
=
endOffset
.
x
-
startOffset
.
x
;
}
}
else
if
(
result
==
me
.
index
){
this
.
selection
.
updateShow
(
startOffset
,
width
);
this
.
selection
.
setStartOffset
(
result
).
collapse
(
true
);
}
else
{
this
.
selection
.
setStartOffset
(
me
.
index
);
this
.
selection
.
setEndOffset
(
result
);
}
return
this
;
},
updateRange
:
function
()
{
this
.
range
.
update
NativeRange
();
this
.
range
.
update
();
return
this
;
},
updateContainerRangeBySel
:
function
(){
var
me
=
this
;
var
node
=
this
.
container
.
firstChild
;
if
(
!
node
){
node
=
this
.
container
;
}
this
.
range
.
setStart
(
node
,
this
.
selection
.
startOffset
);
this
.
range
.
setEnd
(
node
,
this
.
selection
.
endOffset
);
this
.
range
.
setStartOffset
(
this
.
selection
.
startOffset
);
this
.
range
.
setEndOffset
(
this
.
selection
.
endOffset
);
if
(
browser
.
gecko
){
this
.
container
.
focus
();
setTimeout
(
function
(){
...
...
@@ -585,7 +302,17 @@ Minder.Receiver = kity.createClass('Receiver', {
return
this
;
},
setContainerTxt
:
function
(
txt
)
{
this
.
container
.
textContent
=
txt
||
this
.
textShape
.
getContent
();
if
(
txt
){
txt
=
txt
.
replace
(
/
[\n]
/g
,
'<br
\
/>'
);
}
else
{
txt
=
''
;
this
.
textGroup
.
eachItem
(
function
(
i
,
item
){
txt
+=
item
.
getContent
()
+
'<br/>'
;
});
}
this
.
container
.
innerHTML
=
txt
;
return
this
;
},
setReady
:
function
(){
...
...
@@ -599,5 +326,17 @@ Minder.Receiver = kity.createClass('Receiver', {
},
focus
:
function
(){
this
.
container
.
focus
();
},
getTxtOfContainer
:
function
(){
var
result
=
''
,
cont
=
this
.
container
;
utils
.
each
(
cont
.
childNodes
,
function
(
i
,
n
){
if
(
n
.
nodeType
==
3
){
result
+=
n
.
nodeValue
.
replace
(
/
[\u
200b
]
/g
,
''
);
}
else
{
if
(
n
!==
cont
.
lastChild
)
result
+=
'
\
n'
;
}
});
return
result
;
}
});
\ No newline at end of file
src/module/editor.selection.js
View file @
e3d55a0f
//模拟光标
Minder
.
Selection
=
kity
.
createClass
(
'Selection'
,
{
base
:
kity
.
Rect
,
base
:
kity
.
Group
,
constructor
:
function
(
height
,
color
,
width
)
{
this
.
callBase
();
this
.
height
=
height
||
20
;
...
...
@@ -14,14 +14,85 @@ Minder.Selection = kity.createClass( 'Selection', {
this
.
setOpacity
(
0.5
);
this
.
setStyle
(
'cursor'
,
'text'
);
this
.
_show
=
false
;
this
.
offset
=
[];
},
setMinderNode
:
function
(
node
){
this
.
minderNode
=
node
;
},
setColor
:
function
(
color
){
this
.
fill
(
color
);
},
updateOffsetByTextData
:
function
(
data
,
offset
){
if
(
this
.
collapsed
){
this
.
offset
=
utils
.
getValueByIndex
(
data
,
this
.
startOffset
);
return
this
;
}
else
{
var
arrOffset
=
[],
tmpOffset
=
{},
startOffset
=
this
.
startOffset
,
endOffset
=
this
.
endOffset
,
cIndex
=
0
;
utils
.
each
(
data
,
function
(
l
,
arr
){
tmpOffset
=
{
width
:
0
,
x
:
0
,
y
:
0
};
utils
.
each
(
arr
,
function
(
i
,
o
){
if
(
cIndex
>=
startOffset
&&
cIndex
<=
endOffset
){
if
(
i
===
0
||
cIndex
===
startOffset
){
tmpOffset
.
x
=
o
.
x
;
tmpOffset
.
y
=
o
.
y
;
tmpOffset
.
width
=
i
===
0
&&
offset
&&
offset
.
x
<=
o
.
x
&&
cIndex
!=
startOffset
?
0
:
o
.
width
;
}
else
if
(
cIndex
<
endOffset
){
tmpOffset
.
width
+=
o
.
width
;
}
else
if
(
cIndex
===
endOffset
){
return
false
;
}
}
cIndex
++
;
});
if
(
tmpOffset
.
x
!==
undefined
)
{
arrOffset
.
push
(
tmpOffset
);
}
if
(
cIndex
===
endOffset
)
{
return
false
;
}
if
(
arr
.
length
==
1
&&
arr
[
0
].
width
===
0
)
return
;
cIndex
++
;
});
this
.
offset
=
arrOffset
;
return
this
;
}
},
updatePosition
:
function
(
offset
){
var
me
=
this
;
this
.
clear
();
offset
=
offset
||
this
.
offset
;
if
(
this
.
collapsed
){
var
rect
=
new
kity
.
Rect
().
fill
(
null
).
stroke
(
null
).
setWidth
(
2
).
setHeight
(
this
.
height
);
rect
.
setPosition
(
Math
.
round
(
offset
.
x
)
-
0.5
,
Math
.
round
(
offset
.
y
)
-
1.5
);
this
.
addShape
(
rect
);
}
else
{
utils
.
each
(
offset
,
function
(
i
,
v
){
var
rect
=
new
kity
.
Rect
().
fill
(
null
).
stroke
(
null
).
setWidth
(
v
.
width
).
setHeight
(
me
.
height
);
rect
.
setPosition
(
Math
.
round
(
v
.
x
)
-
0.5
,
Math
.
round
(
v
.
y
)
-
1.5
);
me
.
addShape
(
rect
);
});
}
return
this
;
},
collapse
:
function
(
toStart
){
this
.
setOpacity
(
1
);
this
.
width
=
2
;
this
.
collapsed
=
true
;
if
(
toStart
){
this
.
endOffset
=
this
.
startOffset
;
...
...
@@ -52,24 +123,12 @@ Minder.Selection = kity.createClass( 'Selection', {
this
.
setOpacity
(
0.5
);
return
this
;
},
updateShow
:
function
(
offset
,
width
){
if
(
width
){
this
.
setShowHold
();
}
this
.
setPosition
(
offset
).
setWidth
(
width
);
this
.
bringTop
();
return
this
;
},
setPosition
:
function
(
offset
)
{
try
{
// 这两个是神奇的 0.5 —— SVG 要边缘锐利,你需要一些对齐
this
.
x
=
Math
.
round
(
offset
.
x
)
-
0.5
;
this
.
y
=
Math
.
round
(
offset
.
y
)
-
1.5
;
}
catch
(
e
)
{
console
.
log
(
e
);
update
:
function
(
data
,
offset
){
if
(
data
){
this
.
updateOffsetByTextData
(
data
,
offset
);
}
this
.
update
();
this
.
updatePosition
();
this
.
setShow
();
return
this
;
},
setHeight
:
function
(
height
)
{
...
...
@@ -82,13 +141,13 @@ Minder.Selection = kity.createClass( 'Selection', {
this
.
_show
=
false
;
return
this
;
},
setShowHold
:
function
()
{
clearInterval
(
this
.
timer
);
this
.
setStyle
(
'display'
,
''
);
this
.
_show
=
true
;
setHoldShow
:
function
(){
this
.
setStyle
(
'display'
,
''
);
clearInterval
(
this
.
timer
);
return
this
;
},
setShow
:
function
()
{
this
.
bringTop
();
clearInterval
(
this
.
timer
);
var
me
=
this
,
state
=
''
;
...
...
@@ -104,10 +163,15 @@ Minder.Selection = kity.createClass( 'Selection', {
}
return
this
;
},
setShowStatus
:
function
(){
this
.
_show
=
true
;
return
this
;
},
isShow
:
function
(){
return
this
.
_show
;
},
isHide
:
function
(){
return
!
this
.
_show
;
}
}
);
\ No newline at end of file
src/module/font.js
View file @
e3d55a0f
...
...
@@ -3,16 +3,18 @@ KityMinder.registerModule("fontmodule", function() {
return
node
.
getData
(
name
)
||
node
.
getStyle
(
name
);
}
KityMinder
.
TextRenderer
.
registerStyleHook
(
function
(
node
,
text
)
{
KityMinder
.
TextRenderer
.
registerStyleHook
(
function
(
node
,
text
Group
)
{
var
dataColor
=
node
.
getData
(
'color'
);
var
selectedColor
=
node
.
getStyle
(
'selected-color'
);
var
styleColor
=
node
.
getStyle
(
'color'
);
text
.
fill
(
dataColor
||
(
node
.
isSelected
()
&&
selectedColor
?
selectedColor
:
styleColor
));
text
Group
.
fill
(
dataColor
||
(
node
.
isSelected
()
&&
selectedColor
?
selectedColor
:
styleColor
));
text
.
setFont
({
family
:
getNodeDataOrStyle
(
node
,
'font-family'
),
size
:
getNodeDataOrStyle
(
node
,
'font-size'
)
textGroup
.
eachItem
(
function
(
index
,
item
){
item
.
setFont
({
'family'
:
getNodeDataOrStyle
(
node
,
'font-family'
),
'size'
:
getNodeDataOrStyle
(
node
,
'font-size'
)
});
});
});
...
...
src/module/text.js
View file @
e3d55a0f
...
...
@@ -4,39 +4,61 @@ var TextRenderer = KityMinder.TextRenderer = kity.createClass('TextRenderer', {
base
:
Renderer
,
create
:
function
()
{
return
new
kity
.
Text
()
.
setId
(
KityMinder
.
uuid
(
'node_text'
))
.
setVerticalAlign
(
'middle'
)
.
setAttr
(
'text-rendering'
,
'inherit'
);
return
new
kity
.
Group
().
setId
(
KityMinder
.
uuid
(
'node_text'
));
},
update
:
function
(
text
,
node
)
{
update
:
function
(
text
Group
,
node
)
{
var
t
mpText
=
node
.
getText
(
);
var
t
extArr
=
node
.
getText
(
true
);
this
.
setTextStyle
(
node
,
text
.
setContent
(
tmpText
));
var
lineHeight
=
node
.
getStyle
(
'line-height'
);
var
fontSize
=
node
.
getData
(
'font-size'
)
||
node
.
getStyle
(
'font-size'
);
var
height
=
textArr
.
length
*
node
.
getStyle
(
'line-height'
)
*
(
node
.
getData
(
'font-size'
)
||
node
.
getStyle
(
'font-size'
))
/
2
;
var
rBox
=
new
kity
.
Box
(),
r
=
Math
.
round
;
this
.
setTextStyle
(
node
,
textGroup
);
for
(
var
i
=
0
,
text
,
textShape
;
(
text
=
textArr
[
i
],
textShape
=
textGroup
.
getItem
(
i
),
text
!==
undefined
||
textShape
!==
undefined
);
i
++
){
if
(
text
===
undefined
&&
textShape
){
textGroup
.
removeItem
(
i
);
}
else
{
if
(
text
!==
undefined
&&!
textShape
){
textShape
=
new
kity
.
Text
()
.
setVerticalAlign
(
'top'
)
.
setAttr
(
'text-rendering'
,
'inherit'
);
textGroup
.
addItem
(
textShape
);
}
textShape
.
setContent
(
text
);
if
(
tmpText
.
length
||
!
this
.
_lastBox
){
var
box
=
text
.
getBoundaryBox
();
var
r
=
Math
.
round
;
if
(
kity
.
Browser
.
ie
)
{
box
.
y
+=
1
;
}
this
.
_lastBox
=
{
x
:
r
(
box
.
x
),
y
:
r
(
box
.
y
),
width
:
r
(
box
.
width
),
height
:
r
(
box
.
height
)
};
}
else
{
this
.
_lastBox
.
width
=
0
;
}
var
lastBox
=
this
.
_lastBox
;
node
.
_lastTextShapeBox
=
lastBox
;
this
.
setTextStyle
(
node
,
textGroup
);
textGroup
.
eachItem
(
function
(
i
,
textShape
){
var
y
=
i
*
fontSize
*
lineHeight
-
height
;
textShape
.
setY
(
y
);
rBox
=
rBox
.
merge
(
new
kity
.
Box
(
0
,
y
,
textShape
.
getBoundaryBox
().
width
,
fontSize
));
});
var
nBox
=
new
kity
.
Box
(
r
(
rBox
.
x
),
r
(
rBox
.
y
),
r
(
rBox
.
width
),
r
(
rBox
.
height
));
node
.
_currentTextGroupBox
=
nBox
;
return
function
()
{
return
n
ew
kity
.
Box
(
lastBox
.
x
,
lastBox
.
y
,
lastBox
.
width
,
lastBox
.
height
)
;
return
n
Box
;
};
},
...
...
@@ -58,7 +80,7 @@ utils.extend(TextRenderer, {
});
kity
.
extendClass
(
MinderNode
,{
getText
Shape
:
function
()
{
getText
Group
:
function
()
{
return
this
.
getRenderer
(
'TextRenderer'
).
getRenderShape
();
}
});
...
...
src/theme/default.js
View file @
e3d55a0f
...
...
@@ -51,5 +51,6 @@ KityMinder.registerTheme('classic', {
'order-hint-path-color'
:
'#0f0'
,
'order-hint-path-width'
:
1
,
'text-selection-color'
:
'rgb(27,171,255)'
'text-selection-color'
:
'rgb(27,171,255)'
,
'line-height'
:
1.5
});
\ No newline at end of file
src/theme/fresh.js
View file @
e3d55a0f
...
...
@@ -54,7 +54,8 @@
'order-hint-path-color'
:
hsl
(
h
,
100
,
25
),
'order-hint-path-width'
:
1
,
'text-selection-color'
:
hsl
(
h
,
100
,
20
)
'text-selection-color'
:
hsl
(
h
,
100
,
20
),
'line-height'
:
1.5
};
}
...
...
src/theme/snow.js
View file @
e3d55a0f
...
...
@@ -47,5 +47,6 @@ KityMinder.registerTheme('snow', {
'order-hint-path-color'
:
'#0f0'
,
'order-hint-path-width'
:
1
,
'text-selection-color'
:
'rgb(27,171,255)'
'text-selection-color'
:
'rgb(27,171,255)'
,
'line-height'
:
1.5
});
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment