Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
75a39c83
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
75a39c83
编写于
1月 09, 2019
作者:
J
João Moreno
提交者:
GitHub
1月 09, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #66291 from Microsoft/joao/tree-dnd
Implement List & new Tree drag and drop
上级
65281379
a0092214
变更
22
隐藏空白更改
内联
并排
Showing
22 changed file
with
696 addition
and
154 deletion
+696
-154
src/vs/base/browser/dnd.ts
src/vs/base/browser/dnd.ts
+14
-1
src/vs/base/browser/dom.ts
src/vs/base/browser/dom.ts
+16
-1
src/vs/base/browser/ui/list/list.css
src/vs/base/browser/ui/list/list.css
+9
-0
src/vs/base/browser/ui/list/list.ts
src/vs/base/browser/ui/list/list.ts
+31
-0
src/vs/base/browser/ui/list/listView.ts
src/vs/base/browser/ui/list/listView.ts
+327
-44
src/vs/base/browser/ui/list/listWidget.ts
src/vs/base/browser/ui/list/listWidget.ts
+101
-49
src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
+0
-1
src/vs/base/browser/ui/tree/abstractTree.ts
src/vs/base/browser/ui/tree/abstractTree.ts
+86
-6
src/vs/base/browser/ui/tree/asyncDataTree.ts
src/vs/base/browser/ui/tree/asyncDataTree.ts
+17
-0
src/vs/base/browser/ui/tree/indexTreeModel.ts
src/vs/base/browser/ui/tree/indexTreeModel.ts
+4
-0
src/vs/base/browser/ui/tree/objectTreeModel.ts
src/vs/base/browser/ui/tree/objectTreeModel.ts
+5
-0
src/vs/base/browser/ui/tree/tree.ts
src/vs/base/browser/ui/tree/tree.ts
+24
-1
src/vs/base/parts/tree/browser/tree.ts
src/vs/base/parts/tree/browser/tree.ts
+1
-5
src/vs/base/parts/tree/browser/treeDefaults.ts
src/vs/base/parts/tree/browser/treeDefaults.ts
+4
-3
src/vs/base/parts/tree/browser/treeDnd.ts
src/vs/base/parts/tree/browser/treeDnd.ts
+11
-11
src/vs/base/parts/tree/browser/treeView.ts
src/vs/base/parts/tree/browser/treeView.ts
+8
-10
src/vs/editor/contrib/suggest/media/suggest.css
src/vs/editor/contrib/suggest/media/suggest.css
+10
-1
src/vs/editor/contrib/suggest/suggestWidget.ts
src/vs/editor/contrib/suggest/suggestWidget.ts
+17
-6
src/vs/platform/list/browser/listService.ts
src/vs/platform/list/browser/listService.ts
+6
-9
src/vs/workbench/browser/dnd.ts
src/vs/workbench/browser/dnd.ts
+2
-2
src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
...ench/parts/files/electron-browser/views/explorerViewer.ts
+2
-2
src/vs/workbench/parts/files/electron-browser/views/openEditorsView.ts
...nch/parts/files/electron-browser/views/openEditorsView.ts
+1
-2
未找到文件。
src/vs/base/browser/dnd.ts
浏览文件 @
75a39c83
...
...
@@ -83,4 +83,17 @@ export function applyDragImage(event: DragEvent, label: string, clazz: string):
// Removes the element when the DND operation is done
setTimeout
(()
=>
document
.
body
.
removeChild
(
dragImage
),
0
);
}
}
\ No newline at end of file
}
export
interface
IDragAndDropData
{
update
(
dataTransfer
:
DataTransfer
):
void
;
getData
():
any
;
}
export
interface
IStaticDND
{
CurrentDragAndDropData
:
IDragAndDropData
|
undefined
;
}
export
const
StaticDND
:
IStaticDND
=
{
CurrentDragAndDropData
:
undefined
};
\ No newline at end of file
src/vs/base/browser/dom.ts
浏览文件 @
75a39c83
...
...
@@ -11,7 +11,7 @@ import { TimeoutTimer } from 'vs/base/common/async';
import
{
CharCode
}
from
'
vs/base/common/charCode
'
;
import
{
onUnexpectedError
}
from
'
vs/base/common/errors
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
Disposable
,
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
Disposable
,
IDisposable
,
dispose
,
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
{
coalesce
}
from
'
vs/base/common/arrays
'
;
...
...
@@ -1157,3 +1157,18 @@ export function windowOpenNoOpener(url: string): void {
}
}
}
export
function
animate
(
fn
:
()
=>
void
):
IDisposable
{
const
step
=
()
=>
{
fn
();
stepDisposable
=
scheduleAtNextAnimationFrame
(
step
);
};
let
stepDisposable
=
scheduleAtNextAnimationFrame
(
step
);
return
toDisposable
(()
=>
stepDisposable
.
dispose
());
}
export
function
timeout
(
fn
:
()
=>
void
,
millis
:
number
):
IDisposable
{
const
timer
=
setTimeout
(
fn
,
millis
);
return
toDisposable
(()
=>
clearTimeout
(
timer
));
}
\ No newline at end of file
src/vs/base/browser/ui/list/list.css
浏览文件 @
75a39c83
...
...
@@ -52,4 +52,13 @@
/* Focus */
.monaco-list.element-focused
,
.monaco-list.selection-single
,
.monaco-list.selection-multiple
{
outline
:
0
!important
;
}
/* Dnd */
.monaco-list-drag-image
{
display
:
inline-block
;
padding
:
1px
7px
;
border-radius
:
10px
;
font-size
:
12px
;
position
:
absolute
;
}
\ No newline at end of file
src/vs/base/browser/ui/list/list.ts
浏览文件 @
75a39c83
...
...
@@ -7,6 +7,7 @@ import { GestureEvent } from 'vs/base/browser/touch';
import
{
IKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
export
interface
IListVirtualDelegate
<
T
>
{
getHeight
(
element
:
T
):
number
;
...
...
@@ -46,6 +47,12 @@ export interface IListGestureEvent<T> {
index
:
number
|
undefined
;
}
export
interface
IListDragEvent
<
T
>
{
browserEvent
:
DragEvent
;
element
:
T
|
undefined
;
index
:
number
|
undefined
;
}
export
interface
IListContextMenuEvent
<
T
>
{
browserEvent
:
UIEvent
;
element
:
T
|
undefined
;
...
...
@@ -62,6 +69,30 @@ export interface IKeyboardNavigationLabelProvider<T> {
mightProducePrintableCharacter
?(
event
:
IKeyboardEvent
):
boolean
;
}
export
const
enum
ListDragOverEffect
{
Copy
,
Move
}
export
interface
IListDragOverReaction
{
accept
:
boolean
;
effect
?:
ListDragOverEffect
;
feedback
?:
number
[];
// use -1 for entire list
}
export
const
ListDragOverReactions
=
{
reject
():
IListDragOverReaction
{
return
{
accept
:
false
};
},
accept
():
IListDragOverReaction
{
return
{
accept
:
true
};
},
};
export
interface
IListDragAndDrop
<
T
>
{
getDragURI
(
element
:
T
):
string
|
null
;
getDragLabel
?(
elements
:
T
[]):
string
|
undefined
;
onDragStart
(
data
:
IDragAndDropData
,
originalEvent
:
DragEvent
):
void
;
onDragOver
(
data
:
IDragAndDropData
,
targetElement
:
T
|
undefined
,
targetIndex
:
number
|
undefined
,
originalEvent
:
DragEvent
):
boolean
|
IListDragOverReaction
;
drop
(
data
:
IDragAndDropData
,
targetElement
:
T
|
undefined
,
targetIndex
:
number
|
undefined
,
originalEvent
:
DragEvent
):
void
;
}
/**
* Use this renderer when you want to re-render elements on account of
* an event firing.
...
...
src/vs/base/browser/ui/list/listView.ts
浏览文件 @
75a39c83
...
...
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import
{
getOrDefault
}
from
'
vs/base/common/objects
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
IDisposable
,
dispose
,
Disposable
,
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
Gesture
,
EventType
as
TouchEventType
,
GestureEvent
}
from
'
vs/base/browser/touch
'
;
import
*
as
DOM
from
'
vs/base/browser/dom
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
...
...
@@ -12,14 +12,15 @@ import { domEvent } from 'vs/base/browser/event';
import
{
ScrollableElement
}
from
'
vs/base/browser/ui/scrollbar/scrollableElement
'
;
import
{
ScrollEvent
,
ScrollbarVisibility
,
INewScrollDimensions
}
from
'
vs/base/common/scrollable
'
;
import
{
RangeMap
,
shift
}
from
'
./rangeMap
'
;
import
{
IListVirtualDelegate
,
IListRenderer
,
IListMouseEvent
,
IListTouchEvent
,
IListGestureEvent
}
from
'
./list
'
;
import
{
IListVirtualDelegate
,
IListRenderer
,
IListMouseEvent
,
IListTouchEvent
,
IListGestureEvent
,
IListDragEvent
,
IListDragAndDrop
,
ListDragOverEffect
}
from
'
./list
'
;
import
{
RowCache
,
IRow
}
from
'
./rowCache
'
;
import
{
isWindows
}
from
'
vs/base/common/platform
'
;
import
*
as
browser
from
'
vs/base/browser/browser
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
import
{
memoize
}
from
'
vs/base/common/decorators
'
;
import
{
DragMouseEvent
}
from
'
vs/base/browser/mouseEvent
'
;
import
{
Range
,
IRange
}
from
'
vs/base/common/range
'
;
import
{
equals
,
distinct
}
from
'
vs/base/common/arrays
'
;
import
{
DataTransfers
,
StaticDND
,
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
function
canUseTranslate3d
():
boolean
{
if
(
browser
.
isFirefox
)
{
...
...
@@ -41,9 +42,17 @@ interface IItem<T> {
size
:
number
;
hasDynamicHeight
:
boolean
;
renderWidth
:
number
|
undefined
;
uri
:
string
|
undefined
;
dropTarget
:
boolean
;
dragStartDisposable
:
IDisposable
;
}
export
interface
IListViewOptions
{
export
interface
IListViewDragAndDrop
<
T
>
extends
IListDragAndDrop
<
T
>
{
getDragElements
(
element
:
T
):
T
[];
}
export
interface
IListViewOptions
<
T
>
{
readonly
dnd
?:
IListViewDragAndDrop
<
T
>
;
readonly
useShadows
?:
boolean
;
readonly
verticalScrollMode
?:
ScrollbarVisibility
;
readonly
setRowLineHeight
?:
boolean
;
...
...
@@ -55,9 +64,94 @@ const DefaultOptions = {
useShadows
:
true
,
verticalScrollMode
:
ScrollbarVisibility
.
Auto
,
setRowLineHeight
:
true
,
supportDynamicHeights
:
false
supportDynamicHeights
:
false
,
dnd
:
{
getDragElements
(
e
)
{
return
[
e
];
},
getDragURI
()
{
return
null
;
},
onDragStart
():
void
{
},
onDragOver
()
{
return
false
;
},
drop
()
{
}
}
};
export
class
ElementsDragAndDropData
<
T
>
implements
IDragAndDropData
{
private
elements
:
T
[];
constructor
(
elements
:
T
[])
{
this
.
elements
=
elements
;
}
public
update
(
dataTransfer
:
DataTransfer
):
void
{
// no-op
}
public
getData
():
any
{
return
this
.
elements
;
}
}
export
class
ExternalElementsDragAndDropData
<
T
>
implements
IDragAndDropData
{
private
elements
:
T
[];
constructor
(
elements
:
T
[])
{
this
.
elements
=
elements
;
}
public
update
(
dataTransfer
:
DataTransfer
):
void
{
// no-op
}
public
getData
():
any
{
return
this
.
elements
;
}
}
export
class
DesktopDragAndDropData
implements
IDragAndDropData
{
private
types
:
any
[];
private
files
:
any
[];
constructor
()
{
this
.
types
=
[];
this
.
files
=
[];
}
public
update
(
dataTransfer
:
DataTransfer
):
void
{
if
(
dataTransfer
.
types
)
{
this
.
types
=
[...
dataTransfer
.
types
];
}
if
(
dataTransfer
.
files
)
{
this
.
files
=
[];
for
(
let
i
=
0
;
i
<
dataTransfer
.
files
.
length
;
i
++
)
{
const
file
=
dataTransfer
.
files
.
item
(
i
);
if
(
file
&&
(
file
.
size
||
file
.
type
))
{
this
.
files
.
push
(
file
);
}
}
}
}
public
getData
():
any
{
return
{
types
:
this
.
types
,
files
:
this
.
files
};
}
}
function
equalsDragFeedback
(
f1
:
number
[]
|
undefined
,
f2
:
number
[]
|
undefined
):
boolean
{
if
(
Array
.
isArray
(
f1
)
&&
Array
.
isArray
(
f2
))
{
return
equals
(
f1
,
f2
!
);
}
return
f1
===
f2
;
}
export
class
ListView
<
T
>
implements
ISpliceable
<
T
>
,
IDisposable
{
readonly
domNode
:
HTMLElement
;
...
...
@@ -76,22 +170,37 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private
_scrollHeight
:
number
;
private
scrollableElementUpdateDisposable
:
IDisposable
|
null
=
null
;
private
splicing
=
false
;
private
drag
AndDropScrollInterval
:
number
;
private
drag
AndDropScrollTimeout
:
number
;
private
drag
AndDrop
MouseY
:
number
;
private
drag
OverAnimationDisposable
:
IDisposable
|
undefined
;
private
drag
OverAnimationStopDisposable
:
IDisposable
=
Disposable
.
None
;
private
drag
Over
MouseY
:
number
;
private
setRowLineHeight
:
boolean
;
private
supportDynamicHeights
:
boolean
;
private
dnd
:
IListViewDragAndDrop
<
T
>
;
private
currentDragData
:
IDragAndDropData
|
undefined
;
private
currentDragFeedback
:
number
[]
|
undefined
;
private
currentDragFeedbackDisposable
:
IDisposable
=
Disposable
.
None
;
private
onDragLeaveTimeout
:
IDisposable
=
Disposable
.
None
;
private
disposables
:
IDisposable
[];
private
_onDidChangeContentHeight
=
new
Emitter
<
number
>
();
readonly
onDidChangeContentHeight
:
Event
<
number
>
=
Event
.
latch
(
this
.
_onDidChangeContentHeight
.
event
);
get
contentHeight
():
number
{
return
this
.
rangeMap
.
size
;
}
// private _onDragStart = new Emitter<{ element: T, uri: string, event: DragEvent }>();
// readonly onDragStart = this._onDragStart.event;
// readonly onDragOver: Event<IListDragEvent<T>>;
// readonly onDragLeave: Event<void>;
// readonly onDrop: Event<IListDragEvent<T>>;
// readonly onDragEnd: Event<void>;
constructor
(
container
:
HTMLElement
,
private
virtualDelegate
:
IListVirtualDelegate
<
T
>
,
renderers
:
IListRenderer
<
any
/* TODO@joao */
,
any
>
[],
options
:
IListViewOptions
=
DefaultOptions
options
:
IListViewOptions
<
T
>
=
DefaultOptions
)
{
this
.
items
=
[];
this
.
itemId
=
0
;
...
...
@@ -134,11 +243,14 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
domEvent
(
this
.
scrollableElement
.
getDomNode
(),
'
scroll
'
)
(
e
=>
(
e
.
target
as
HTMLElement
).
scrollTop
=
0
,
null
,
this
.
disposables
);
const
onDragOver
=
Event
.
map
(
domEvent
(
this
.
rowsContainer
,
'
dragover
'
),
e
=>
new
DragMouseEvent
(
e
));
onDragOver
(
this
.
onDragOver
,
this
,
this
.
disposables
);
Event
.
map
(
domEvent
(
this
.
domNode
,
'
dragover
'
),
e
=>
this
.
toDragEvent
(
e
))(
this
.
onDragOver
,
this
,
this
.
disposables
);
Event
.
map
(
domEvent
(
this
.
domNode
,
'
drop
'
),
e
=>
this
.
toDragEvent
(
e
))(
this
.
onDrop
,
this
,
this
.
disposables
);
domEvent
(
this
.
domNode
,
'
dragleave
'
)(
this
.
onDragLeave
,
this
,
this
.
disposables
);
domEvent
(
window
,
'
dragend
'
)(
this
.
onDragEnd
,
this
,
this
.
disposables
);
this
.
setRowLineHeight
=
getOrDefault
(
options
,
o
=>
o
.
setRowLineHeight
,
DefaultOptions
.
setRowLineHeight
);
this
.
supportDynamicHeights
=
getOrDefault
(
options
,
o
=>
o
.
supportDynamicHeights
,
DefaultOptions
.
supportDynamicHeights
);
this
.
dnd
=
getOrDefault
<
IListViewOptions
<
T
>
,
IListViewDragAndDrop
<
T
>>
(
options
,
o
=>
o
.
dnd
,
DefaultOptions
.
dnd
);
this
.
layout
();
}
...
...
@@ -178,7 +290,10 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
size
:
this
.
virtualDelegate
.
getHeight
(
element
),
hasDynamicHeight
:
!!
this
.
virtualDelegate
.
hasDynamicHeight
&&
this
.
virtualDelegate
.
hasDynamicHeight
(
element
),
renderWidth
:
undefined
,
row
:
null
row
:
null
,
uri
:
undefined
,
dropTarget
:
false
,
dragStartDisposable
:
Disposable
.
None
}));
let
deleted
:
IItem
<
T
>
[];
...
...
@@ -354,6 +469,15 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
const
renderer
=
this
.
renderers
.
get
(
item
.
templateId
);
renderer
.
renderElement
(
item
.
element
,
index
,
item
.
row
.
templateData
);
const
uri
=
this
.
dnd
.
getDragURI
(
item
.
element
);
item
.
dragStartDisposable
.
dispose
();
if
(
uri
)
{
item
.
row
.
domNode
!
.
draggable
=
true
;
const
onDragStart
=
domEvent
(
item
.
row
.
domNode
!
,
'
dragstart
'
);
item
.
dragStartDisposable
=
onDragStart
(
event
=>
this
.
onDragStart
(
item
.
element
,
uri
,
event
));
}
}
private
updateItemInDOM
(
item
:
IItem
<
T
>
,
index
:
number
):
void
{
...
...
@@ -368,10 +492,13 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
item
.
row
!
.
domNode
!
.
setAttribute
(
'
data-last-element
'
,
index
===
this
.
length
-
1
?
'
true
'
:
'
false
'
);
item
.
row
!
.
domNode
!
.
setAttribute
(
'
aria-setsize
'
,
`
${
this
.
length
}
`
);
item
.
row
!
.
domNode
!
.
setAttribute
(
'
aria-posinset
'
,
`
${
index
+
1
}
`
);
DOM
.
toggleClass
(
item
.
row
!
.
domNode
!
,
'
drop-target
'
,
item
.
dropTarget
);
}
private
removeItemFromDOM
(
index
:
number
):
void
{
const
item
=
this
.
items
[
index
];
item
.
dragStartDisposable
.
dispose
();
const
renderer
=
this
.
renderers
.
get
(
item
.
templateId
);
if
(
renderer
.
disposeElement
)
{
...
...
@@ -444,6 +571,13 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
return
{
browserEvent
,
index
,
element
};
}
private
toDragEvent
(
browserEvent
:
DragEvent
):
IListDragEvent
<
T
>
{
const
index
=
this
.
getItemIndexFromEventTarget
(
browserEvent
.
target
||
null
);
const
item
=
typeof
index
===
'
undefined
'
?
undefined
:
this
.
items
[
index
];
const
element
=
item
&&
item
.
element
;
return
{
browserEvent
,
index
,
element
};
}
private
onScroll
(
e
:
ScrollEvent
):
void
{
try
{
this
.
render
(
e
.
scrollTop
,
e
.
height
);
...
...
@@ -464,55 +598,204 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this
.
scrollTop
-=
event
.
translationY
;
}
private
onDragOver
(
event
:
DragMouseEvent
):
void
{
this
.
setupDragAndDropScrollInterval
();
this
.
dragAndDropMouseY
=
event
.
posy
;
// DND
private
onDragStart
(
element
:
T
,
uri
:
string
,
event
:
DragEvent
):
void
{
if
(
!
event
.
dataTransfer
)
{
return
;
}
const
elements
=
this
.
dnd
.
getDragElements
(
element
);
event
.
dataTransfer
.
effectAllowed
=
'
copyMove
'
;
event
.
dataTransfer
.
setData
(
DataTransfers
.
RESOURCES
,
JSON
.
stringify
([
uri
]));
if
(
event
.
dataTransfer
.
setDragImage
)
{
let
label
:
string
|
undefined
;
if
(
this
.
dnd
.
getDragLabel
)
{
label
=
this
.
dnd
.
getDragLabel
(
elements
);
}
if
(
typeof
label
===
'
undefined
'
)
{
label
=
String
(
elements
.
length
);
}
const
dragImage
=
DOM
.
$
(
'
.monaco-list-drag-image
'
);
dragImage
.
textContent
=
label
;
document
.
body
.
appendChild
(
dragImage
);
event
.
dataTransfer
.
setDragImage
(
dragImage
,
-
10
,
-
10
);
setTimeout
(()
=>
document
.
body
.
removeChild
(
dragImage
),
0
);
}
this
.
currentDragData
=
new
ElementsDragAndDropData
(
elements
);
StaticDND
.
CurrentDragAndDropData
=
new
ExternalElementsDragAndDropData
(
elements
);
this
.
dnd
.
onDragStart
(
this
.
currentDragData
,
event
);
}
private
setupDragAndDropScrollInterval
():
void
{
const
viewTop
=
DOM
.
getTopLeftOffset
(
this
.
domNode
).
top
;
private
onDragOver
(
event
:
IListDragEvent
<
T
>
):
boolean
{
this
.
onDragLeaveTimeout
.
dispose
();
this
.
setupDragAndDropScrollTopAnimation
(
event
.
browserEvent
);
if
(
!
event
.
browserEvent
.
dataTransfer
)
{
return
false
;
}
if
(
!
this
.
dragAndDropScrollInterval
)
{
this
.
dragAndDropScrollInterval
=
window
.
setInterval
(()
=>
{
if
(
this
.
dragAndDropMouseY
===
undefined
)
{
return
;
// Drag over from outside
if
(
!
this
.
currentDragData
)
{
if
(
StaticDND
.
CurrentDragAndDropData
)
{
// Drag over from another list
this
.
currentDragData
=
StaticDND
.
CurrentDragAndDropData
;
}
else
{
// Drag over from the desktop
if
(
!
event
.
browserEvent
.
dataTransfer
.
types
)
{
return
false
;
}
let
diff
=
this
.
dragAndDropMouseY
-
viewTop
;
let
scrollDiff
=
0
;
let
upperLimit
=
this
.
renderHeight
-
35
;
this
.
currentDragData
=
new
DesktopDragAndDropData
();
}
}
const
result
=
this
.
dnd
.
onDragOver
(
this
.
currentDragData
,
event
.
element
,
event
.
index
,
event
.
browserEvent
);
const
canDrop
=
typeof
result
===
'
boolean
'
?
result
:
result
.
accept
;
if
(
!
canDrop
)
{
return
false
;
}
event
.
browserEvent
.
dataTransfer
.
dropEffect
=
(
typeof
result
!==
'
boolean
'
&&
result
.
effect
===
ListDragOverEffect
.
Copy
)
?
'
copy
'
:
'
move
'
;
let
feedback
:
number
[];
if
(
diff
<
35
)
{
scrollDiff
=
Math
.
max
(
-
14
,
0.2
*
(
diff
-
35
));
}
else
if
(
diff
>
upperLimit
)
{
scrollDiff
=
Math
.
min
(
14
,
0.2
*
(
diff
-
upperLimit
));
if
(
typeof
result
!==
'
boolean
'
&&
result
.
feedback
)
{
feedback
=
result
.
feedback
;
}
else
{
if
(
typeof
event
.
index
===
'
undefined
'
)
{
feedback
=
[
-
1
];
}
else
{
feedback
=
[
event
.
index
];
}
}
// sanitize feedback list
feedback
=
distinct
(
feedback
).
filter
(
i
=>
i
>=
-
1
&&
i
<
this
.
length
).
sort
();
feedback
=
feedback
[
0
]
===
-
1
?
[
-
1
]
:
feedback
;
if
(
feedback
.
length
===
0
)
{
throw
new
Error
(
'
Invalid empty feedback list
'
);
}
if
(
equalsDragFeedback
(
this
.
currentDragFeedback
,
feedback
))
{
return
true
;
}
this
.
currentDragFeedback
=
feedback
;
this
.
currentDragFeedbackDisposable
.
dispose
();
if
(
feedback
[
0
]
===
-
1
)
{
// entire list feedback
DOM
.
addClass
(
this
.
domNode
,
'
drop-target
'
);
this
.
currentDragFeedbackDisposable
=
toDisposable
(()
=>
DOM
.
removeClass
(
this
.
domNode
,
'
drop-target
'
));
}
else
{
for
(
const
index
of
feedback
)
{
const
item
=
this
.
items
[
index
]
!
;
item
.
dropTarget
=
true
;
if
(
item
.
row
&&
item
.
row
.
domNode
)
{
DOM
.
addClass
(
item
.
row
.
domNode
,
'
drop-target
'
);
}
}
this
.
scrollTop
+=
scrollDiff
;
},
10
);
this
.
currentDragFeedbackDisposable
=
toDisposable
(()
=>
{
for
(
const
index
of
feedback
)
{
const
item
=
this
.
items
[
index
]
!
;
item
.
dropTarget
=
false
;
this
.
cancelDragAndDropScrollTimeout
();
if
(
item
.
row
&&
item
.
row
.
domNode
)
{
DOM
.
removeClass
(
item
.
row
.
domNode
,
'
drop-target
'
);
}
}
});
}
return
true
;
}
this
.
dragAndDropScrollTimeout
=
window
.
setTimeout
(()
=>
{
this
.
cancelDragAndDropScrollInterval
();
this
.
dragAndDropScrollTimeout
=
-
1
;
},
1000
);
private
onDragLeave
():
void
{
this
.
onDragLeaveTimeout
.
dispose
();
this
.
onDragLeaveTimeout
=
DOM
.
timeout
(()
=>
this
.
clearDragOverFeedback
(),
100
);
}
private
onDrop
(
event
:
IListDragEvent
<
T
>
):
void
{
const
dragData
=
this
.
currentDragData
;
this
.
teardownDragAndDropScrollTopAnimation
();
this
.
clearDragOverFeedback
();
this
.
currentDragData
=
undefined
;
StaticDND
.
CurrentDragAndDropData
=
undefined
;
if
(
!
dragData
||
!
event
.
browserEvent
.
dataTransfer
)
{
return
;
}
event
.
browserEvent
.
preventDefault
();
dragData
.
update
(
event
.
browserEvent
.
dataTransfer
);
this
.
dnd
.
drop
(
dragData
,
event
.
element
,
event
.
index
,
event
.
browserEvent
);
}
private
cancelDragAndDropScrollInterval
():
void
{
if
(
this
.
dragAndDropScrollInterval
)
{
window
.
clearInterval
(
this
.
dragAndDropScrollInterval
);
this
.
dragAndDropScrollInterval
=
-
1
;
private
onDragEnd
():
void
{
this
.
teardownDragAndDropScrollTopAnimation
();
this
.
clearDragOverFeedback
();
this
.
currentDragData
=
undefined
;
StaticDND
.
CurrentDragAndDropData
=
undefined
;
}
private
clearDragOverFeedback
():
void
{
this
.
currentDragFeedback
=
undefined
;
this
.
currentDragFeedbackDisposable
.
dispose
();
this
.
currentDragFeedbackDisposable
=
Disposable
.
None
;
}
// DND scroll top animation
private
setupDragAndDropScrollTopAnimation
(
event
:
DragEvent
):
void
{
if
(
!
this
.
dragOverAnimationDisposable
)
{
const
viewTop
=
DOM
.
getTopLeftOffset
(
this
.
domNode
).
top
;
this
.
dragOverAnimationDisposable
=
DOM
.
animate
(
this
.
animateDragAndDropScrollTop
.
bind
(
this
,
viewTop
));
}
this
.
dragOverAnimationStopDisposable
.
dispose
();
this
.
dragOverAnimationStopDisposable
=
DOM
.
timeout
(()
=>
{
if
(
this
.
dragOverAnimationDisposable
)
{
this
.
dragOverAnimationDisposable
.
dispose
();
this
.
dragOverAnimationDisposable
=
undefined
;
}
},
1000
);
this
.
dragOverMouseY
=
event
.
pageY
;
}
private
animateDragAndDropScrollTop
(
viewTop
:
number
):
void
{
if
(
this
.
dragOverMouseY
===
undefined
)
{
return
;
}
this
.
cancelDragAndDropScrollTimeout
();
const
diff
=
this
.
dragOverMouseY
-
viewTop
;
const
upperLimit
=
this
.
renderHeight
-
35
;
if
(
diff
<
35
)
{
this
.
scrollTop
+=
Math
.
max
(
-
14
,
Math
.
floor
(
0.3
*
(
diff
-
35
)));
}
else
if
(
diff
>
upperLimit
)
{
this
.
scrollTop
+=
Math
.
min
(
14
,
Math
.
floor
(
0.3
*
(
diff
-
upperLimit
)));
}
}
private
cancelDragAndDropScrollTimeout
():
void
{
if
(
this
.
dragAndDropScrollTimeout
)
{
window
.
clearTimeout
(
this
.
dragAndDropScrollTimeout
);
this
.
dragAndDropScrollTimeout
=
-
1
;
private
teardownDragAndDropScrollTopAnimation
():
void
{
this
.
dragOverAnimationStopDisposable
.
dispose
();
if
(
this
.
dragOverAnimationDisposable
)
{
this
.
dragOverAnimationDisposable
.
dispose
();
this
.
dragOverAnimationDisposable
=
undefined
;
}
}
...
...
src/vs/base/browser/ui/list/listWidget.ts
浏览文件 @
75a39c83
...
...
@@ -16,8 +16,8 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import
{
StandardKeyboardEvent
,
IKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
{
Event
,
Emitter
,
EventBufferer
}
from
'
vs/base/common/event
'
;
import
{
domEvent
}
from
'
vs/base/browser/event
'
;
import
{
IListVirtualDelegate
,
IListRenderer
,
IListEvent
,
IListContextMenuEvent
,
IListMouseEvent
,
IListTouchEvent
,
IListGestureEvent
,
IIdentityProvider
,
IKeyboardNavigationLabelProvider
}
from
'
./list
'
;
import
{
ListView
,
IListViewOptions
}
from
'
./listView
'
;
import
{
IListVirtualDelegate
,
IListRenderer
,
IListEvent
,
IListContextMenuEvent
,
IListMouseEvent
,
IListTouchEvent
,
IListGestureEvent
,
IIdentityProvider
,
IKeyboardNavigationLabelProvider
,
IListDragAndDrop
,
IListDragOverReaction
}
from
'
./list
'
;
import
{
ListView
,
IListViewOptions
,
IListViewDragAndDrop
}
from
'
./listView
'
;
import
{
Color
}
from
'
vs/base/common/color
'
;
import
{
mixin
}
from
'
vs/base/common/objects
'
;
import
{
ScrollbarVisibility
}
from
'
vs/base/common/scrollable
'
;
...
...
@@ -25,6 +25,7 @@ import { ISpliceable } from 'vs/base/common/sequence';
import
{
CombinedSpliceable
}
from
'
vs/base/browser/ui/list/splice
'
;
import
{
clamp
}
from
'
vs/base/common/numbers
'
;
import
{
matchesPrefix
}
from
'
vs/base/common/filters
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
interface
ITraitChangeEvent
{
indexes
:
number
[];
...
...
@@ -212,7 +213,7 @@ class TraitSpliceable<T> implements ISpliceable<T> {
splice
(
start
:
number
,
deleteCount
:
number
,
elements
:
T
[]):
void
{
if
(
!
this
.
identityProvider
)
{
return
this
.
trait
.
splice
(
start
,
deleteCount
,
elements
.
map
(
e
=>
false
));
return
this
.
trait
.
splice
(
start
,
deleteCount
,
elements
.
map
(
()
=>
false
));
}
const
pastElementsWithTrait
=
this
.
trait
.
get
().
map
(
i
=>
this
.
identityProvider
!
.
getId
(
this
.
view
.
element
(
i
)).
toString
());
...
...
@@ -477,7 +478,7 @@ class MouseController<T> implements IDisposable {
constructor
(
private
list
:
List
<
T
>
,
private
view
:
ListView
<
T
>
,
private
options
:
IListOptions
<
T
>
=
{}
options
:
IListOptions
<
T
>
=
{}
)
{
this
.
multipleSelectionSupport
=
!
(
options
.
multipleSelectionSupport
===
false
);
...
...
@@ -488,6 +489,7 @@ class MouseController<T> implements IDisposable {
this
.
openController
=
options
.
openController
||
DefaultOpenController
;
view
.
onMouseDown
(
this
.
onMouseDown
,
this
,
this
.
disposables
);
view
.
onContextMenu
(
this
.
onContextMenu
,
this
,
this
.
disposables
);
view
.
onMouseClick
(
this
.
onPointer
,
this
,
this
.
disposables
);
view
.
onMouseDblClick
(
this
.
onDoubleClick
,
this
,
this
.
disposables
);
view
.
onTouchStart
(
this
.
onMouseDown
,
this
,
this
.
disposables
);
...
...
@@ -516,13 +518,17 @@ class MouseController<T> implements IDisposable {
}
private
onMouseDown
(
e
:
IListMouseEvent
<
T
>
|
IListTouchEvent
<
T
>
):
void
{
if
(
this
.
options
.
focusOnMouseDown
===
false
)
{
e
.
browserEvent
.
preventDefault
();
e
.
browserEvent
.
stopPropagation
();
}
else
if
(
document
.
activeElement
!==
e
.
browserEvent
.
target
)
{
if
(
document
.
activeElement
!==
e
.
browserEvent
.
target
)
{
this
.
view
.
domNode
.
focus
();
}
}
private
onContextMenu
(
e
:
IListMouseEvent
<
T
>
|
IListTouchEvent
<
T
>
):
void
{
const
focus
=
typeof
e
.
index
===
'
undefined
'
?
[]
:
[
e
.
index
];
this
.
list
.
setFocus
(
focus
,
e
.
browserEvent
);
}
private
onPointer
(
e
:
IListMouseEvent
<
T
>
):
void
{
let
reference
=
this
.
list
.
getFocus
()[
0
];
const
selection
=
this
.
list
.
getSelection
();
reference
=
reference
===
undefined
?
selection
[
0
]
:
reference
;
...
...
@@ -539,15 +545,13 @@ class MouseController<T> implements IDisposable {
return
this
.
changeSelection
(
e
,
reference
);
}
if
(
selection
.
every
(
s
=>
s
!==
focus
))
{
this
.
list
.
setFocus
([
focus
],
e
.
browserEvent
);
}
if
(
this
.
multipleSelectionSupport
&&
this
.
isSelectionChangeEvent
(
e
))
{
return
this
.
changeSelection
(
e
,
reference
);
}
if
(
this
.
options
.
selectOnMouseDown
&&
!
isMouseRightClick
(
e
.
browserEvent
))
{
this
.
list
.
setFocus
([
focus
],
e
.
browserEvent
);
if
(
!
isMouseRightClick
(
e
.
browserEvent
))
{
this
.
list
.
setSelection
([
focus
],
e
.
browserEvent
);
if
(
this
.
openController
.
shouldOpen
(
e
.
browserEvent
))
{
...
...
@@ -556,21 +560,6 @@ class MouseController<T> implements IDisposable {
}
}
private
onPointer
(
e
:
IListMouseEvent
<
T
>
):
void
{
if
(
this
.
multipleSelectionSupport
&&
this
.
isSelectionChangeEvent
(
e
))
{
return
;
}
if
(
!
this
.
options
.
selectOnMouseDown
)
{
const
focus
=
this
.
list
.
getFocus
();
this
.
list
.
setSelection
(
focus
,
e
.
browserEvent
);
if
(
this
.
openController
.
shouldOpen
(
e
.
browserEvent
))
{
this
.
list
.
open
(
focus
,
e
.
browserEvent
);
}
}
}
private
onDoubleClick
(
e
:
IListMouseEvent
<
T
>
):
void
{
if
(
this
.
multipleSelectionSupport
&&
this
.
isSelectionChangeEvent
(
e
))
{
return
;
...
...
@@ -670,11 +659,17 @@ export class DefaultStyleController implements IStyleController {
}
if
(
styles
.
listFocusAndSelectionBackground
)
{
content
.
push
(
`.monaco-list
${
suffix
}
:focus .monaco-list-row.selected.focused { background-color:
${
styles
.
listFocusAndSelectionBackground
}
; }`
);
content
.
push
(
`
.monaco-list-drag-image,
.monaco-list
${
suffix
}
:focus .monaco-list-row.selected.focused { background-color:
${
styles
.
listFocusAndSelectionBackground
}
; }
`
);
}
if
(
styles
.
listFocusAndSelectionForeground
)
{
content
.
push
(
`.monaco-list
${
suffix
}
:focus .monaco-list-row.selected.focused { color:
${
styles
.
listFocusAndSelectionForeground
}
; }`
);
content
.
push
(
`
.monaco-list-drag-image,
.monaco-list
${
suffix
}
:focus .monaco-list-row.selected.focused { color:
${
styles
.
listFocusAndSelectionForeground
}
; }
`
);
}
if
(
styles
.
listInactiveFocusBackground
)
{
...
...
@@ -704,7 +699,10 @@ export class DefaultStyleController implements IStyleController {
}
if
(
styles
.
listFocusOutline
)
{
content
.
push
(
`.monaco-list
${
suffix
}
:focus .monaco-list-row.focused { outline: 1px solid
${
styles
.
listFocusOutline
}
; outline-offset: -1px; }`
);
content
.
push
(
`
.monaco-list-drag-image,
.monaco-list
${
suffix
}
:focus .monaco-list-row.focused { outline: 1px solid
${
styles
.
listFocusOutline
}
; outline-offset: -1px; }
`
);
}
if
(
styles
.
listInactiveFocusOutline
)
{
...
...
@@ -715,6 +713,13 @@ export class DefaultStyleController implements IStyleController {
content
.
push
(
`.monaco-list
${
suffix
}
.monaco-list-row:hover { outline: 1px dashed
${
styles
.
listHoverOutline
}
; outline-offset: -1px; }`
);
}
if
(
styles
.
listDropBackground
)
{
content
.
push
(
`
.monaco-list
${
suffix
}
.drop-target,
.monaco-list
${
suffix
}
.monaco-list-row.drop-target { background-color:
${
styles
.
listDropBackground
}
!important; color: inherit !important; }
`
);
}
const
newStyles
=
content
.
join
(
'
\n
'
);
if
(
newStyles
!==
this
.
styleElement
.
innerHTML
)
{
this
.
styleElement
.
innerHTML
=
newStyles
;
...
...
@@ -722,20 +727,24 @@ export class DefaultStyleController implements IStyleController {
}
}
export
interface
IListOptions
<
T
>
extends
IListViewOptions
,
IListStyles
{
identityProvider
?:
IIdentityProvider
<
T
>
;
keyboardNavigationLabelProvider
?:
IKeyboardNavigationLabelProvider
<
T
>
;
ariaLabel
?:
string
;
mouseSupport
?:
boolean
;
selectOnMouseDown
?:
boolean
;
focusOnMouseDown
?:
boolean
;
keyboardSupport
?:
boolean
;
verticalScrollMode
?:
ScrollbarVisibility
;
multipleSelectionSupport
?:
boolean
;
multipleSelectionController
?:
IMultipleSelectionController
<
T
>
;
openController
?:
IOpenController
;
styleController
?:
IStyleController
;
accessibilityProvider
?:
IAccessibilityProvider
<
T
>
;
export
interface
IListOptions
<
T
>
extends
IListStyles
{
readonly
identityProvider
?:
IIdentityProvider
<
T
>
;
readonly
dnd
?:
IListDragAndDrop
<
T
>
;
readonly
keyboardNavigationLabelProvider
?:
IKeyboardNavigationLabelProvider
<
T
>
;
readonly
ariaLabel
?:
string
;
readonly
keyboardSupport
?:
boolean
;
readonly
multipleSelectionSupport
?:
boolean
;
readonly
multipleSelectionController
?:
IMultipleSelectionController
<
T
>
;
readonly
openController
?:
IOpenController
;
readonly
styleController
?:
IStyleController
;
readonly
accessibilityProvider
?:
IAccessibilityProvider
<
T
>
;
// list view options
readonly
useShadows
?:
boolean
;
readonly
verticalScrollMode
?:
ScrollbarVisibility
;
readonly
setRowLineHeight
?:
boolean
;
readonly
supportDynamicHeights
?:
boolean
;
readonly
mouseSupport
?:
boolean
;
}
export
interface
IListStyles
{
...
...
@@ -768,10 +777,16 @@ const defaultStyles: IListStyles = {
listDropBackground
:
Color
.
fromHex
(
'
#383B3D
'
)
};
const
DefaultOptions
:
IListOptions
<
any
>
=
{
const
DefaultOptions
=
{
keyboardSupport
:
true
,
mouseSupport
:
true
,
multipleSelectionSupport
:
true
multipleSelectionSupport
:
true
,
dnd
:
{
getDragURI
()
{
return
null
;
},
onDragStart
():
void
{
},
onDragOver
()
{
return
false
;
},
drop
()
{
}
}
};
// TODO@Joao: move these utils into a SortedArray class
...
...
@@ -926,6 +941,37 @@ class AccessibiltyRenderer<T> implements IListRenderer<T, HTMLElement> {
}
}
class
ListViewDragAndDrop
<
T
>
implements
IListViewDragAndDrop
<
T
>
{
constructor
(
private
list
:
List
<
T
>
,
private
dnd
:
IListDragAndDrop
<
T
>
)
{
}
getDragElements
(
element
:
T
):
T
[]
{
const
selection
=
this
.
list
.
getSelectedElements
();
const
elements
=
selection
.
indexOf
(
element
)
>
-
1
?
selection
:
[
element
];
return
elements
;
}
getDragURI
(
element
:
T
):
string
|
null
{
return
this
.
dnd
.
getDragURI
(
element
);
}
getDragLabel
?(
elements
:
T
[]):
string
|
undefined
{
return
this
.
dnd
.
getDragLabel
&&
this
.
dnd
.
getDragLabel
(
elements
);
}
onDragStart
(
data
:
IDragAndDropData
,
originalEvent
:
DragEvent
):
void
{
this
.
dnd
.
onDragStart
(
data
,
originalEvent
);
}
onDragOver
(
data
:
IDragAndDropData
,
targetElement
:
T
,
targetIndex
:
number
,
originalEvent
:
DragEvent
):
boolean
|
IListDragOverReaction
{
return
this
.
dnd
.
onDragOver
(
data
,
targetElement
,
targetIndex
,
originalEvent
);
}
drop
(
data
:
IDragAndDropData
,
targetElement
:
T
,
targetIndex
:
number
,
originalEvent
:
DragEvent
):
void
{
this
.
dnd
.
drop
(
data
,
targetElement
,
targetIndex
,
originalEvent
);
}
}
export
class
List
<
T
>
implements
ISpliceable
<
T
>
,
IDisposable
{
private
static
InstanceCount
=
0
;
...
...
@@ -936,10 +982,11 @@ export class List<T> implements ISpliceable<T>, IDisposable {
private
eventBufferer
=
new
EventBufferer
();
private
view
:
ListView
<
T
>
;
private
spliceable
:
ISpliceable
<
T
>
;
protected
disposables
:
IDisposable
[];
private
styleElement
:
HTMLStyleElement
;
private
styleController
:
IStyleController
;
protected
disposables
:
IDisposable
[];
@
memoize
get
onFocusChange
():
Event
<
IListEvent
<
T
>>
{
return
Event
.
map
(
this
.
eventBufferer
.
wrapEvent
(
this
.
focus
.
onChange
),
e
=>
this
.
toListEvent
(
e
));
}
...
...
@@ -1034,7 +1081,12 @@ export class List<T> implements ISpliceable<T>, IDisposable {
renderers
=
renderers
.
map
(
r
=>
new
PipelineRenderer
(
r
.
templateId
,
[...
baseRenderers
,
r
]));
this
.
view
=
new
ListView
(
container
,
virtualDelegate
,
renderers
,
options
);
const
viewOptions
:
IListViewOptions
<
T
>
=
{
...
options
,
dnd
:
options
.
dnd
&&
new
ListViewDragAndDrop
(
this
,
options
.
dnd
)
};
this
.
view
=
new
ListView
(
container
,
virtualDelegate
,
renderers
,
viewOptions
);
this
.
view
.
domNode
.
setAttribute
(
'
role
'
,
'
tree
'
);
DOM
.
addClass
(
this
.
view
.
domNode
,
this
.
idPrefix
);
this
.
view
.
domNode
.
tabIndex
=
0
;
...
...
src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
浏览文件 @
75a39c83
...
...
@@ -731,7 +731,6 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate<I
this
.
selectList
=
new
List
(
this
.
selectDropDownListContainer
,
this
,
[
this
.
listRenderer
],
{
ariaLabel
:
this
.
selectBoxOptions
.
ariaLabel
,
useShadows
:
false
,
selectOnMouseDown
:
false
,
verticalScrollMode
:
ScrollbarVisibility
.
Visible
,
keyboardSupport
:
false
,
mouseSupport
:
false
...
...
src/vs/base/browser/ui/tree/abstractTree.ts
浏览文件 @
75a39c83
...
...
@@ -4,17 +4,95 @@
*--------------------------------------------------------------------------------------------*/
import
'
vs/css!./media/tree
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
IDisposable
,
dispose
,
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IListOptions
,
List
,
IListStyles
}
from
'
vs/base/browser/ui/list/listWidget
'
;
import
{
IListVirtualDelegate
,
IListRenderer
,
IListMouseEvent
,
IListEvent
,
IListContextMenuEvent
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
append
,
$
,
toggleClass
}
from
'
vs/base/browser/dom
'
;
import
{
IListVirtualDelegate
,
IListRenderer
,
IListMouseEvent
,
IListEvent
,
IListContextMenuEvent
,
IListDragAndDrop
,
IListDragOverReaction
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
append
,
$
,
toggleClass
,
timeout
}
from
'
vs/base/browser/dom
'
;
import
{
Event
,
Relay
}
from
'
vs/base/common/event
'
;
import
{
StandardKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
{
KeyCode
}
from
'
vs/base/common/keyCodes
'
;
import
{
ITreeModel
,
ITreeNode
,
ITreeRenderer
,
ITreeEvent
,
ITreeMouseEvent
,
ITreeContextMenuEvent
,
ITreeFilter
,
ITreeNavigator
,
ICollapseStateChangeEvent
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ITreeModel
,
ITreeNode
,
ITreeRenderer
,
ITreeEvent
,
ITreeMouseEvent
,
ITreeContextMenuEvent
,
ITreeFilter
,
ITreeNavigator
,
ICollapseStateChangeEvent
,
ITreeDragAndDrop
,
TreeDragOverBubble
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
import
{
range
}
from
'
vs/base/common/arrays
'
;
function
asListOptions
<
T
,
TFilterData
>
(
options
?:
IAbstractTreeOptions
<
T
,
TFilterData
>
):
IListOptions
<
ITreeNode
<
T
,
TFilterData
>>
|
undefined
{
class
TreeNodeListDragAndDrop
<
T
,
TFilterData
,
TRef
>
implements
IListDragAndDrop
<
ITreeNode
<
T
,
TFilterData
>>
{
private
autoExpandNode
:
ITreeNode
<
T
,
TFilterData
>
|
undefined
;
private
autoExpandDisposable
:
IDisposable
=
Disposable
.
None
;
constructor
(
private
modelProvider
:
()
=>
ITreeModel
<
T
,
TFilterData
,
TRef
>
,
private
dnd
:
ITreeDragAndDrop
<
T
>
)
{
}
getDragURI
(
node
:
ITreeNode
<
T
,
TFilterData
>
):
string
|
null
{
return
this
.
dnd
.
getDragURI
(
node
.
element
);
}
getDragLabel
(
nodes
:
ITreeNode
<
T
,
TFilterData
>
[]):
string
|
undefined
{
return
this
.
dnd
.
getDragLabel
&&
this
.
dnd
.
getDragLabel
(
nodes
.
map
(
node
=>
node
.
element
));
}
onDragStart
(
data
:
IDragAndDropData
,
originalEvent
:
DragEvent
):
void
{
this
.
dnd
.
onDragStart
(
data
,
originalEvent
);
}
onDragOver
(
data
:
IDragAndDropData
,
targetNode
:
ITreeNode
<
T
,
TFilterData
>
|
undefined
,
targetIndex
:
number
|
undefined
,
originalEvent
:
DragEvent
,
raw
=
true
):
boolean
|
IListDragOverReaction
{
const
result
=
this
.
dnd
.
onDragOver
(
data
,
targetNode
&&
targetNode
.
element
,
targetIndex
,
originalEvent
);
const
didChangeAutoExpandNode
=
this
.
autoExpandNode
!==
targetNode
;
if
(
didChangeAutoExpandNode
)
{
this
.
autoExpandDisposable
.
dispose
();
this
.
autoExpandNode
=
targetNode
;
}
if
(
typeof
targetNode
===
'
undefined
'
)
{
return
result
;
}
if
(
didChangeAutoExpandNode
&&
typeof
result
!==
'
boolean
'
&&
result
.
autoExpand
)
{
this
.
autoExpandDisposable
=
timeout
(()
=>
{
const
model
=
this
.
modelProvider
();
const
ref
=
model
.
getNodeLocation
(
targetNode
);
if
(
model
.
isCollapsed
(
ref
))
{
model
.
setCollapsed
(
ref
,
false
);
}
this
.
autoExpandNode
=
undefined
;
},
500
);
}
if
(
typeof
result
===
'
boolean
'
||
!
result
.
accept
||
typeof
result
.
bubble
===
'
undefined
'
)
{
if
(
!
raw
)
{
const
accept
=
typeof
result
===
'
boolean
'
?
result
:
result
.
accept
;
const
effect
=
typeof
result
===
'
boolean
'
?
undefined
:
result
.
effect
;
return
{
accept
,
effect
,
feedback
:
[
targetIndex
!
]
};
}
return
result
;
}
if
(
result
.
bubble
===
TreeDragOverBubble
.
Up
)
{
const
parentNode
=
targetNode
.
parent
;
const
model
=
this
.
modelProvider
();
const
parentIndex
=
parentNode
&&
model
.
getListIndex
(
model
.
getNodeLocation
(
parentNode
));
return
this
.
onDragOver
(
data
,
parentNode
,
parentIndex
,
originalEvent
,
false
);
}
const
model
=
this
.
modelProvider
();
const
ref
=
model
.
getNodeLocation
(
targetNode
);
const
start
=
model
.
getListIndex
(
ref
);
const
length
=
model
.
getListRenderCount
(
ref
);
return
{
...
result
,
feedback
:
range
(
start
,
start
+
length
)
};
}
drop
(
data
:
IDragAndDropData
,
targetNode
:
ITreeNode
<
T
,
TFilterData
>
|
undefined
,
targetIndex
:
number
|
undefined
,
originalEvent
:
DragEvent
):
void
{
this
.
dnd
.
drop
(
data
,
targetNode
&&
targetNode
.
element
,
targetIndex
,
originalEvent
);
}
}
function
asListOptions
<
T
,
TFilterData
,
TRef
>
(
modelProvider
:
()
=>
ITreeModel
<
T
,
TFilterData
,
TRef
>
,
options
?:
IAbstractTreeOptions
<
T
,
TFilterData
>
):
IListOptions
<
ITreeNode
<
T
,
TFilterData
>>
|
undefined
{
return
options
&&
{
...
options
,
identityProvider
:
options
.
identityProvider
&&
{
...
...
@@ -22,6 +100,7 @@ function asListOptions<T, TFilterData>(options?: IAbstractTreeOptions<T, TFilter
return
options
.
identityProvider
!
.
getId
(
el
.
element
);
}
},
dnd
:
options
.
dnd
&&
new
TreeNodeListDragAndDrop
(
modelProvider
,
options
.
dnd
),
multipleSelectionController
:
options
.
multipleSelectionController
&&
{
isSelectionSingleChangeEvent
(
e
)
{
return
options
.
multipleSelectionController
!
.
isSelectionSingleChangeEvent
({
...
e
,
element
:
e
.
element
}
as
any
);
...
...
@@ -181,6 +260,7 @@ function asTreeContextMenuEvent<T>(event: IListContextMenuEvent<ITreeNode<T, any
export
interface
IAbstractTreeOptions
<
T
,
TFilterData
=
void
>
extends
IListOptions
<
T
>
{
collapseByDefault
?:
boolean
;
// defaults to false
filter
?:
ITreeFilter
<
T
,
TFilterData
>
;
readonly
dnd
?:
ITreeDragAndDrop
<
T
>
;
}
export
abstract
class
AbstractTree
<
T
,
TFilterData
,
TRef
>
implements
IDisposable
{
...
...
@@ -221,7 +301,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
const
treeRenderers
=
renderers
.
map
(
r
=>
new
TreeRenderer
<
T
,
TFilterData
,
any
>
(
r
,
onDidChangeCollapseStateRelay
.
event
));
this
.
disposables
.
push
(...
treeRenderers
);
this
.
view
=
new
List
(
container
,
treeDelegate
,
treeRenderers
,
asListOptions
(
options
));
this
.
view
=
new
List
(
container
,
treeDelegate
,
treeRenderers
,
asListOptions
(
()
=>
this
.
model
,
options
));
this
.
model
=
this
.
createModel
(
this
.
view
,
options
);
onDidChangeCollapseStateRelay
.
input
=
this
.
model
.
onDidChangeCollapseState
;
...
...
src/vs/base/browser/ui/tree/asyncDataTree.ts
浏览文件 @
75a39c83
...
...
@@ -130,6 +130,23 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
return
options
.
identityProvider
!
.
getId
(
el
.
element
as
T
);
}
},
dnd
:
options
.
dnd
&&
{
getDragURI
(
node
)
{
return
options
.
dnd
!
.
getDragURI
(
node
.
element
as
T
);
},
getDragLabel
:
options
.
dnd
!
.
getDragLabel
&&
((
nodes
)
=>
{
return
options
.
dnd
!
.
getDragLabel
!
(
nodes
.
map
(
node
=>
node
.
element
as
T
));
}),
onDragStart
(
data
,
originalEvent
)
{
return
options
.
dnd
!
.
onDragStart
(
data
,
originalEvent
);
},
onDragOver
(
data
,
targetNode
,
targetIndex
,
originalEvent
)
{
return
options
.
dnd
!
.
onDragOver
(
data
,
targetNode
&&
targetNode
.
element
as
T
,
targetIndex
,
originalEvent
);
},
drop
(
data
,
targetNode
,
targetIndex
,
originalEvent
)
{
return
options
.
dnd
!
.
drop
(
data
,
targetNode
&&
targetNode
.
element
as
T
,
targetIndex
,
originalEvent
);
}
},
multipleSelectionController
:
options
.
multipleSelectionController
&&
{
isSelectionSingleChangeEvent
(
e
)
{
return
options
.
multipleSelectionController
!
.
isSelectionSingleChangeEvent
({
...
e
,
element
:
e
.
element
}
as
any
);
...
...
src/vs/base/browser/ui/tree/indexTreeModel.ts
浏览文件 @
75a39c83
...
...
@@ -127,6 +127,10 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
this
.
getTreeNodeWithListIndex
(
location
).
listIndex
;
}
getListRenderCount
(
location
:
number
[]):
number
{
return
this
.
getTreeNode
(
location
).
renderNodeCount
;
}
isCollapsible
(
location
:
number
[]):
boolean
{
return
this
.
getTreeNode
(
location
).
collapsible
;
}
...
...
src/vs/base/browser/ui/tree/objectTreeModel.ts
浏览文件 @
75a39c83
...
...
@@ -123,6 +123,11 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
return
this
.
model
.
getListIndex
(
location
);
}
getListRenderCount
(
element
:
T
):
number
{
const
location
=
this
.
getElementLocation
(
element
);
return
this
.
model
.
getListRenderCount
(
location
);
}
isCollapsible
(
element
:
T
):
boolean
{
const
location
=
this
.
getElementLocation
(
element
);
return
this
.
model
.
isCollapsible
(
location
);
...
...
src/vs/base/browser/ui/tree/tree.ts
浏览文件 @
75a39c83
...
...
@@ -5,7 +5,8 @@
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
Iterator
}
from
'
vs/base/common/iterator
'
;
import
{
IListRenderer
,
AbstractListRenderer
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
IListRenderer
,
AbstractListRenderer
,
IListDragOverReaction
,
IListDragAndDrop
,
ListDragOverEffect
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
export
const
enum
TreeVisibility
{
...
...
@@ -100,6 +101,7 @@ export interface ITreeModel<T, TFilterData, TRef> {
readonly
onDidChangeRenderNodeCount
:
Event
<
ITreeNode
<
T
,
TFilterData
>>
;
getListIndex
(
location
:
TRef
):
number
;
getListRenderCount
(
location
:
TRef
):
number
;
getNode
(
location
?:
TRef
):
ITreeNode
<
T
,
any
>
;
getNodeLocation
(
node
:
ITreeNode
<
T
,
any
>
):
TRef
;
getParentNodeLocation
(
location
:
TRef
):
TRef
;
...
...
@@ -154,6 +156,27 @@ export interface IAsyncDataSource<TInput, T> {
getChildren
(
element
:
TInput
|
T
):
T
[]
|
Promise
<
T
[]
>
;
}
export
const
enum
TreeDragOverBubble
{
Down
,
Up
}
export
interface
ITreeDragOverReaction
extends
IListDragOverReaction
{
bubble
?:
TreeDragOverBubble
;
autoExpand
?:
boolean
;
}
export
const
TreeDragOverReactions
=
{
acceptBubbleUp
():
ITreeDragOverReaction
{
return
{
accept
:
true
,
bubble
:
TreeDragOverBubble
.
Up
};
},
acceptBubbleDown
(
autoExpand
=
false
):
ITreeDragOverReaction
{
return
{
accept
:
true
,
bubble
:
TreeDragOverBubble
.
Down
,
autoExpand
};
},
acceptCopyBubbleUp
():
ITreeDragOverReaction
{
return
{
accept
:
true
,
bubble
:
TreeDragOverBubble
.
Up
,
effect
:
ListDragOverEffect
.
Copy
};
},
acceptCopyBubbleDown
(
autoExpand
=
false
):
ITreeDragOverReaction
{
return
{
accept
:
true
,
bubble
:
TreeDragOverBubble
.
Down
,
effect
:
ListDragOverEffect
.
Copy
,
autoExpand
};
}
};
export
interface
ITreeDragAndDrop
<
T
>
extends
IListDragAndDrop
<
T
>
{
onDragOver
(
data
:
IDragAndDropData
,
targetElement
:
T
|
undefined
,
targetIndex
:
number
|
undefined
,
originalEvent
:
DragEvent
):
boolean
|
ITreeDragOverReaction
;
}
/**
* Use this renderer when you want to re-render elements on account of
* an event firing.
...
...
src/vs/base/parts/tree/browser/tree.ts
浏览文件 @
75a39c83
...
...
@@ -12,6 +12,7 @@ import { Event } from 'vs/base/common/event';
import
{
IAction
,
IActionItem
}
from
'
vs/base/common/actions
'
;
import
{
Color
}
from
'
vs/base/common/color
'
;
import
{
IItemCollapseEvent
,
IItemExpandEvent
}
from
'
vs/base/parts/tree/browser/treeModel
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
export
interface
ITree
{
...
...
@@ -593,11 +594,6 @@ export const DRAG_OVER_ACCEPT_BUBBLE_DOWN = (autoExpand = false) => ({ accept: t
export
const
DRAG_OVER_ACCEPT_BUBBLE_UP_COPY
:
IDragOverReaction
=
{
accept
:
true
,
bubble
:
DragOverBubble
.
BUBBLE_UP
,
effect
:
DragOverEffect
.
COPY
};
export
const
DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY
=
(
autoExpand
=
false
)
=>
({
accept
:
true
,
bubble
:
DragOverBubble
.
BUBBLE_DOWN
,
effect
:
DragOverEffect
.
COPY
,
autoExpand
});
export
interface
IDragAndDropData
{
update
(
event
:
Mouse
.
DragMouseEvent
):
void
;
getData
():
any
;
}
export
interface
IDragAndDrop
{
/**
...
...
src/vs/base/parts/tree/browser/treeDefaults.ts
浏览文件 @
75a39c83
...
...
@@ -12,6 +12,7 @@ import * as dom from 'vs/base/browser/dom';
import
*
as
mouse
from
'
vs/base/browser/mouseEvent
'
;
import
{
IKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
*
as
_
from
'
vs/base/parts/tree/browser/tree
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
import
{
KeyCode
,
KeyMod
,
Keybinding
,
SimpleKeybinding
,
createSimpleKeybinding
}
from
'
vs/base/common/keyCodes
'
;
export
interface
IKeyBindingCallback
{
...
...
@@ -434,15 +435,15 @@ export class DefaultDragAndDrop implements _.IDragAndDrop {
return
null
;
}
public
onDragStart
(
tree
:
_
.
ITree
,
data
:
_
.
IDragAndDropData
,
originalEvent
:
mouse
.
DragMouseEvent
):
void
{
public
onDragStart
(
tree
:
_
.
ITree
,
data
:
IDragAndDropData
,
originalEvent
:
mouse
.
DragMouseEvent
):
void
{
return
;
}
public
onDragOver
(
tree
:
_
.
ITree
,
data
:
_
.
IDragAndDropData
,
targetElement
:
any
,
originalEvent
:
mouse
.
DragMouseEvent
):
_
.
IDragOverReaction
|
null
{
public
onDragOver
(
tree
:
_
.
ITree
,
data
:
IDragAndDropData
,
targetElement
:
any
,
originalEvent
:
mouse
.
DragMouseEvent
):
_
.
IDragOverReaction
|
null
{
return
null
;
}
public
drop
(
tree
:
_
.
ITree
,
data
:
_
.
IDragAndDropData
,
targetElement
:
any
,
originalEvent
:
mouse
.
DragMouseEvent
):
void
{
public
drop
(
tree
:
_
.
ITree
,
data
:
IDragAndDropData
,
targetElement
:
any
,
originalEvent
:
mouse
.
DragMouseEvent
):
void
{
return
;
}
}
...
...
src/vs/base/parts/tree/browser/treeDnd.ts
浏览文件 @
75a39c83
...
...
@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
_
from
'
vs/base/parts/tree/browser/tree
'
;
import
*
as
Mouse
from
'
vs/base/browser/mouseEvent
'
;
import
{
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
export
class
ElementsDragAndDropData
implements
_
.
IDragAndDropData
{
export
class
ElementsDragAndDropData
implements
IDragAndDropData
{
private
elements
:
any
[];
...
...
@@ -14,7 +14,7 @@ export class ElementsDragAndDropData implements _.IDragAndDropData {
this
.
elements
=
elements
;
}
public
update
(
event
:
Mouse
.
DragMouseEvent
):
void
{
public
update
(
dataTransfer
:
DataTransfer
):
void
{
// no-op
}
...
...
@@ -23,7 +23,7 @@ export class ElementsDragAndDropData implements _.IDragAndDropData {
}
}
export
class
ExternalElementsDragAndDropData
implements
_
.
IDragAndDropData
{
export
class
ExternalElementsDragAndDropData
implements
IDragAndDropData
{
private
elements
:
any
[];
...
...
@@ -31,7 +31,7 @@ export class ExternalElementsDragAndDropData implements _.IDragAndDropData {
this
.
elements
=
elements
;
}
public
update
(
event
:
Mouse
.
DragMouseEvent
):
void
{
public
update
(
dataTransfer
:
DataTransfer
):
void
{
// no-op
}
...
...
@@ -40,7 +40,7 @@ export class ExternalElementsDragAndDropData implements _.IDragAndDropData {
}
}
export
class
DesktopDragAndDropData
implements
_
.
IDragAndDropData
{
export
class
DesktopDragAndDropData
implements
IDragAndDropData
{
private
types
:
any
[];
private
files
:
any
[];
...
...
@@ -50,15 +50,15 @@ export class DesktopDragAndDropData implements _.IDragAndDropData {
this
.
files
=
[];
}
public
update
(
event
:
Mouse
.
DragMouseEvent
):
void
{
if
(
event
.
dataTransfer
.
types
)
{
public
update
(
dataTransfer
:
DataTransfer
):
void
{
if
(
dataTransfer
.
types
)
{
this
.
types
=
[];
Array
.
prototype
.
push
.
apply
(
this
.
types
,
event
.
dataTransfer
.
types
);
Array
.
prototype
.
push
.
apply
(
this
.
types
,
dataTransfer
.
types
as
any
);
}
if
(
event
.
dataTransfer
.
files
)
{
if
(
dataTransfer
.
files
)
{
this
.
files
=
[];
Array
.
prototype
.
push
.
apply
(
this
.
files
,
event
.
dataTransfer
.
files
);
Array
.
prototype
.
push
.
apply
(
this
.
files
,
dataTransfer
.
files
as
any
);
this
.
files
=
this
.
files
.
filter
(
f
=>
f
.
size
||
f
.
type
);
}
...
...
src/vs/base/parts/tree/browser/treeView.ts
浏览文件 @
75a39c83
...
...
@@ -21,7 +21,7 @@ import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
import
*
as
_
from
'
vs/base/parts/tree/browser/tree
'
;
import
{
KeyCode
}
from
'
vs/base/common/keyCodes
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
DataTransfers
}
from
'
vs/base/browser/dnd
'
;
import
{
DataTransfers
,
StaticDND
,
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
import
{
DefaultTreestyler
}
from
'
./treeDefaults
'
;
import
{
Delayer
,
timeout
}
from
'
vs/base/common/async
'
;
...
...
@@ -410,8 +410,6 @@ export class TreeView extends HeightMap {
private
static
counter
:
number
=
0
;
private
instance
:
number
;
private
static
currentExternalDragAndDropData
:
_
.
IDragAndDropData
=
null
;
private
context
:
IViewContext
;
private
modelListeners
:
Lifecycle
.
IDisposable
[];
private
model
:
Model
.
TreeModel
;
...
...
@@ -438,7 +436,7 @@ export class TreeView extends HeightMap {
private
isRefreshing
=
false
;
private
refreshingPreviousChildrenIds
:
{
[
id
:
string
]:
string
[]
}
=
{};
private
currentDragAndDropData
:
_
.
IDragAndDropData
;
private
currentDragAndDropData
:
IDragAndDropData
;
private
currentDropElement
:
any
;
private
currentDropElementReaction
:
_
.
IDragOverReaction
;
private
currentDropTarget
:
ViewItem
;
...
...
@@ -1399,7 +1397,7 @@ export class TreeView extends HeightMap {
}
this
.
currentDragAndDropData
=
new
dnd
.
ElementsDragAndDropData
(
elements
);
TreeView
.
currentExternal
DragAndDropData
=
new
dnd
.
ExternalElementsDragAndDropData
(
elements
);
StaticDND
.
Current
DragAndDropData
=
new
dnd
.
ExternalElementsDragAndDropData
(
elements
);
this
.
context
.
dnd
.
onDragStart
(
this
.
context
.
tree
,
this
.
currentDragAndDropData
,
new
Mouse
.
DragMouseEvent
(
e
));
}
...
...
@@ -1482,8 +1480,8 @@ export class TreeView extends HeightMap {
if
(
!
this
.
currentDragAndDropData
)
{
// just started dragging
if
(
TreeView
.
currentExternal
DragAndDropData
)
{
this
.
currentDragAndDropData
=
TreeView
.
currentExternal
DragAndDropData
;
if
(
StaticDND
.
Current
DragAndDropData
)
{
this
.
currentDragAndDropData
=
StaticDND
.
Current
DragAndDropData
;
}
else
{
if
(
!
event
.
dataTransfer
.
types
)
{
return
false
;
...
...
@@ -1493,7 +1491,7 @@ export class TreeView extends HeightMap {
}
}
this
.
currentDragAndDropData
.
update
(
event
);
this
.
currentDragAndDropData
.
update
(
(
event
.
browserEvent
as
DragEvent
).
dataTransfer
);
let
element
:
any
;
let
item
:
Model
.
Item
=
viewItem
.
model
;
...
...
@@ -1581,7 +1579,7 @@ export class TreeView extends HeightMap {
if
(
this
.
currentDropElement
)
{
let
event
=
new
Mouse
.
DragMouseEvent
(
e
);
event
.
preventDefault
();
this
.
currentDragAndDropData
.
update
(
event
);
this
.
currentDragAndDropData
.
update
(
(
event
.
browserEvent
as
DragEvent
).
dataTransfer
);
this
.
context
.
dnd
.
drop
(
this
.
context
.
tree
,
this
.
currentDragAndDropData
,
this
.
currentDropElement
,
event
);
this
.
onDragEnd
(
e
);
}
...
...
@@ -1598,7 +1596,7 @@ export class TreeView extends HeightMap {
this
.
cancelDragAndDropScrollInterval
();
this
.
currentDragAndDropData
=
null
;
TreeView
.
currentExternalDragAndDropData
=
null
;
StaticDND
.
CurrentDragAndDropData
=
undefined
;
this
.
currentDropElement
=
null
;
this
.
currentDropTarget
=
null
;
this
.
dragAndDropMouseY
=
null
;
...
...
src/vs/editor/contrib/suggest/media/suggest.css
浏览文件 @
75a39c83
...
...
@@ -56,7 +56,14 @@
height
:
100%
;
}
.monaco-editor
.suggest-widget
.monaco-list
{
-webkit-user-select
:
none
;
-khtml-user-select
:
none
;
-moz-user-select
:
-moz-none
;
-ms-user-select
:
none
;
-o-user-select
:
none
;
user-select
:
none
;
}
/** Styles for each row in the list element **/
...
...
@@ -68,6 +75,8 @@
background-repeat
:
no-repeat
;
background-position
:
2px
2px
;
white-space
:
nowrap
;
cursor
:
pointer
;
touch-action
:
none
;
}
.monaco-editor
.suggest-widget
.monaco-list
.monaco-list-row
>
.contents
{
...
...
src/vs/editor/contrib/suggest/suggestWidget.ts
浏览文件 @
75a39c83
...
...
@@ -11,7 +11,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import
{
onUnexpectedError
}
from
'
vs/base/common/errors
'
;
import
{
IDisposable
,
dispose
,
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
addClass
,
append
,
$
,
hide
,
removeClass
,
show
,
toggleClass
,
getDomNodePagePosition
,
hasClass
}
from
'
vs/base/browser/dom
'
;
import
{
IListVirtualDelegate
,
IListEvent
,
IListRenderer
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
IListVirtualDelegate
,
IListEvent
,
IListRenderer
,
IListMouseEvent
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
List
}
from
'
vs/base/browser/ui/list/listWidget
'
;
import
{
DomScrollableElement
}
from
'
vs/base/browser/ui/scrollbar/scrollableElement
'
;
import
{
IKeybindingService
}
from
'
vs/platform/keybinding/common/keybinding
'
;
...
...
@@ -470,9 +470,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this
.
list
=
new
List
(
this
.
listElement
,
this
,
[
renderer
],
{
useShadows
:
false
,
selectOnMouseDown
:
true
,
focusOnMouseDown
:
false
,
openController
:
{
shouldOpen
:
()
=>
false
}
openController
:
{
shouldOpen
:
()
=>
false
},
mouseSupport
:
false
});
this
.
toDispose
=
[
...
...
@@ -482,6 +481,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
}),
themeService
.
onThemeChange
(
t
=>
this
.
onThemeChange
(
t
)),
editor
.
onDidLayoutChange
(()
=>
this
.
onEditorLayoutChange
()),
this
.
list
.
onMouseDown
(
e
=>
this
.
onListMouseDown
(
e
)),
this
.
list
.
onSelectionChange
(
e
=>
this
.
onListSelection
(
e
)),
this
.
list
.
onFocusChange
(
e
=>
this
.
onListFocus
(
e
)),
this
.
editor
.
onDidChangeCursorSelection
(()
=>
this
.
onCursorSelectionChanged
())
...
...
@@ -510,18 +510,29 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
}
}
private
onListMouseDown
(
e
:
IListMouseEvent
<
CompletionItem
>
):
void
{
if
(
typeof
e
.
element
===
'
undefined
'
||
typeof
e
.
index
===
'
undefined
'
)
{
return
;
}
this
.
select
(
e
.
element
,
e
.
index
);
}
private
onListSelection
(
e
:
IListEvent
<
CompletionItem
>
):
void
{
if
(
!
e
.
elements
.
length
)
{
return
;
}
this
.
select
(
e
.
elements
[
0
],
e
.
indexes
[
0
]);
}
private
select
(
item
:
CompletionItem
,
index
:
number
):
void
{
const
completionModel
=
this
.
completionModel
;
if
(
!
completionModel
)
{
return
;
}
const
item
=
e
.
elements
[
0
];
const
index
=
e
.
indexes
[
0
];
item
.
resolve
(
CancellationToken
.
None
).
then
(()
=>
{
this
.
onDidSelectEmitter
.
fire
({
item
,
index
,
model
:
completionModel
});
alert
(
nls
.
localize
(
'
suggestionAriaAccepted
'
,
"
{0}, accepted
"
,
item
.
completion
.
label
));
...
...
src/vs/platform/list/browser/listService.ts
浏览文件 @
75a39c83
...
...
@@ -162,22 +162,24 @@ class WorkbenchOpenController implements IOpenController {
}
function
toWorkbenchListOptions
<
T
>
(
options
:
IListOptions
<
T
>
,
configurationService
:
IConfigurationService
,
keybindingService
:
IKeybindingService
):
IListOptions
<
T
>
{
const
result
=
{
...
options
};
if
(
options
.
multipleSelectionSupport
!==
false
&&
!
options
.
multipleSelectionController
)
{
options
.
multipleSelectionController
=
new
MultipleSelectionController
(
configurationService
);
result
.
multipleSelectionController
=
new
MultipleSelectionController
(
configurationService
);
}
options
.
openController
=
new
WorkbenchOpenController
(
configurationService
,
options
.
openController
);
result
.
openController
=
new
WorkbenchOpenController
(
configurationService
,
options
.
openController
);
if
(
options
.
keyboardNavigationLabelProvider
)
{
const
tlp
=
options
.
keyboardNavigationLabelProvider
;
options
.
keyboardNavigationLabelProvider
=
{
result
.
keyboardNavigationLabelProvider
=
{
getKeyboardNavigationLabel
(
e
)
{
return
tlp
.
getKeyboardNavigationLabel
(
e
);
},
mightProducePrintableCharacter
(
e
)
{
return
keybindingService
.
mightProducePrintableCharacter
(
e
);
}
};
}
return
options
;
return
result
;
}
let
sharedListStyleSheet
:
HTMLStyleElement
;
...
...
@@ -234,7 +236,6 @@ export class WorkbenchList<T> extends List<T> {
super
(
container
,
delegate
,
renderers
,
{
keyboardSupport
:
false
,
selectOnMouseDown
:
true
,
styleController
:
new
DefaultStyleController
(
getSharedListStyleSheet
()),
...
computeStyles
(
themeService
.
getTheme
(),
defaultListStyles
),
...
toWorkbenchListOptions
(
options
,
configurationService
,
keybindingService
)
...
...
@@ -310,7 +311,6 @@ export class WorkbenchPagedList<T> extends PagedList<T> {
super
(
container
,
delegate
,
renderers
,
{
keyboardSupport
:
false
,
selectOnMouseDown
:
true
,
styleController
:
new
DefaultStyleController
(
getSharedListStyleSheet
()),
...
computeStyles
(
themeService
.
getTheme
(),
defaultListStyles
),
...
toWorkbenchListOptions
(
options
,
configurationService
,
keybindingService
)
...
...
@@ -903,7 +903,6 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
)
{
super
(
container
,
delegate
,
renderers
,
{
keyboardSupport
:
false
,
selectOnMouseDown
:
true
,
styleController
:
new
DefaultStyleController
(
getSharedListStyleSheet
()),
...
computeStyles
(
themeService
.
getTheme
(),
defaultListStyles
),
...
toWorkbenchListOptions
(
options
,
configurationService
,
keybindingService
)
...
...
@@ -980,7 +979,6 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
)
{
super
(
container
,
delegate
,
renderers
,
dataSource
,
{
keyboardSupport
:
false
,
selectOnMouseDown
:
true
,
styleController
:
new
DefaultStyleController
(
getSharedListStyleSheet
()),
...
computeStyles
(
themeService
.
getTheme
(),
defaultListStyles
),
...
toWorkbenchListOptions
(
options
,
configurationService
,
keybindingService
)
...
...
@@ -1052,7 +1050,6 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
)
{
super
(
container
,
delegate
,
renderers
,
dataSource
,
{
keyboardSupport
:
false
,
selectOnMouseDown
:
true
,
styleController
:
new
DefaultStyleController
(
getSharedListStyleSheet
()),
...
computeStyles
(
themeService
.
getTheme
(),
defaultListStyles
),
...
toWorkbenchListOptions
(
options
,
configurationService
,
keybindingService
)
...
...
src/vs/workbench/browser/dnd.ts
浏览文件 @
75a39c83
...
...
@@ -15,12 +15,12 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un
import
{
DefaultEndOfLine
}
from
'
vs/editor/common/model
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IEditorViewState
}
from
'
vs/editor/common/editorCommon
'
;
import
{
DataTransfers
}
from
'
vs/base/browser/dnd
'
;
import
{
DataTransfers
,
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
import
{
DefaultDragAndDrop
}
from
'
vs/base/parts/tree/browser/treeDefaults
'
;
import
{
DragMouseEvent
}
from
'
vs/base/browser/mouseEvent
'
;
import
{
normalizeDriveLetter
}
from
'
vs/base/common/labels
'
;
import
{
MIME_BINARY
}
from
'
vs/base/common/mime
'
;
import
{
ITree
,
IDragAndDropData
}
from
'
vs/base/parts/tree/browser/tree
'
;
import
{
ITree
}
from
'
vs/base/parts/tree/browser/tree
'
;
import
{
isWindows
}
from
'
vs/base/common/platform
'
;
import
{
coalesce
}
from
'
vs/base/common/arrays
'
;
import
{
ServicesAccessor
,
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
...
...
src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
浏览文件 @
75a39c83
...
...
@@ -23,7 +23,7 @@ import { IFilesConfiguration, SortOrder } from 'vs/workbench/parts/files/common/
import
{
ITextFileService
}
from
'
vs/workbench/services/textfile/common/textfiles
'
;
import
{
FileOperationError
,
FileOperationResult
,
IFileService
,
FileKind
}
from
'
vs/platform/files/common/files
'
;
import
{
DuplicateFileAction
,
AddFilesAction
,
IEditableData
,
IFileViewletState
,
FileCopiedContext
}
from
'
vs/workbench/parts/files/electron-browser/fileActions
'
;
import
{
IDataSource
,
ITree
,
IAccessibilityProvider
,
IRenderer
,
ContextMenuEvent
,
ISorter
,
IFilter
,
IDrag
AndDropData
,
IDrag
OverReaction
,
DRAG_OVER_ACCEPT_BUBBLE_DOWN
,
DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY
,
DRAG_OVER_ACCEPT_BUBBLE_UP
,
DRAG_OVER_ACCEPT_BUBBLE_UP_COPY
,
DRAG_OVER_REJECT
}
from
'
vs/base/parts/tree/browser/tree
'
;
import
{
IDataSource
,
ITree
,
IAccessibilityProvider
,
IRenderer
,
ContextMenuEvent
,
ISorter
,
IFilter
,
IDragOverReaction
,
DRAG_OVER_ACCEPT_BUBBLE_DOWN
,
DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY
,
DRAG_OVER_ACCEPT_BUBBLE_UP
,
DRAG_OVER_ACCEPT_BUBBLE_UP_COPY
,
DRAG_OVER_REJECT
}
from
'
vs/base/parts/tree/browser/tree
'
;
import
{
DesktopDragAndDropData
,
ExternalElementsDragAndDropData
}
from
'
vs/base/parts/tree/browser/treeDnd
'
;
import
{
ClickBehavior
}
from
'
vs/base/parts/tree/browser/treeDefaults
'
;
import
{
ExplorerItem
,
NewStatPlaceholder
,
Model
}
from
'
vs/workbench/parts/files/common/explorerModel
'
;
...
...
@@ -46,7 +46,7 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common
import
{
extractResources
,
SimpleFileResourceDragAndDrop
,
CodeDataTransfers
,
fillResourceDataTransfers
}
from
'
vs/workbench/browser/dnd
'
;
import
{
WorkbenchTree
,
WorkbenchTreeController
}
from
'
vs/platform/list/browser/listService
'
;
import
{
IClipboardService
}
from
'
vs/platform/clipboard/common/clipboardService
'
;
import
{
DataTransfers
}
from
'
vs/base/browser/dnd
'
;
import
{
DataTransfers
,
IDragAndDropData
}
from
'
vs/base/browser/dnd
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
{
IWorkspaceFolderCreationData
}
from
'
vs/platform/workspaces/common/workspaces
'
;
import
{
rtrim
}
from
'
vs/base/common/strings
'
;
...
...
src/vs/workbench/parts/files/electron-browser/views/openEditorsView.ts
浏览文件 @
75a39c83
...
...
@@ -222,8 +222,7 @@ export class OpenEditorsView extends ViewletPanel {
new
EditorGroupRenderer
(
this
.
keybindingService
,
this
.
instantiationService
,
this
.
editorGroupService
),
new
OpenEditorRenderer
(
this
.
listLabels
,
getSelectedElements
,
this
.
instantiationService
,
this
.
keybindingService
,
this
.
configurationService
,
this
.
editorGroupService
)
],
{
identityProvider
:
{
getId
:
(
element
:
OpenEditor
|
IEditorGroup
)
=>
element
instanceof
OpenEditor
?
element
.
getId
()
:
element
.
id
.
toString
()
},
selectOnMouseDown
:
false
/* disabled to better support DND */
identityProvider
:
{
getId
:
(
element
:
OpenEditor
|
IEditorGroup
)
=>
element
instanceof
OpenEditor
?
element
.
getId
()
:
element
.
id
.
toString
()
}
})
as
WorkbenchList
<
OpenEditor
|
IEditorGroup
>
;
this
.
disposables
.
push
(
this
.
list
);
this
.
disposables
.
push
(
this
.
listLabels
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录