Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
9be3eb53
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
9be3eb53
编写于
8月 21, 2019
作者:
P
Pine
提交者:
GitHub
8月 21, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #79538 from microsoft/pine/openerservice
Refactor OpenerService. Fix #79487
上级
3b911340
82839c60
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
256 addition
and
245 deletion
+256
-245
src/vs/editor/browser/services/openerService.ts
src/vs/editor/browser/services/openerService.ts
+28
-76
src/vs/editor/standalone/browser/standaloneEditor.ts
src/vs/editor/standalone/browser/standaloneEditor.ts
+1
-10
src/vs/editor/test/browser/services/openerService.test.ts
src/vs/editor/test/browser/services/openerService.test.ts
+101
-142
src/vs/platform/opener/common/opener.ts
src/vs/platform/opener/common/opener.ts
+11
-0
src/vs/workbench/contrib/url/common/url.contribution.ts
src/vs/workbench/contrib/url/common/url.contribution.ts
+115
-17
未找到文件。
src/vs/editor/browser/services/openerService.ts
浏览文件 @
9be3eb53
...
...
@@ -4,41 +4,39 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
{
Disposable
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
LinkedList
}
from
'
vs/base/common/linkedList
'
;
import
{
parse
}
from
'
vs/base/common/marshalling
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
*
as
resources
from
'
vs/base/common/resources
'
;
import
{
equalsIgnoreCase
}
from
'
vs/base/common/strings
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
ICodeEditorService
}
from
'
vs/editor/browser/services/codeEditorService
'
;
import
{
CommandsRegistry
,
ICommandService
}
from
'
vs/platform/commands/common/commands
'
;
import
{
IOpenerService
,
IOpener
}
from
'
vs/platform/opener/common/opener
'
;
import
{
equalsIgnoreCase
}
from
'
vs/base/common/strings
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
LinkedList
}
from
'
vs/base/common/linkedList
'
;
import
{
IDialogService
}
from
'
vs/platform/dialogs/common/dialogs
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
Severity
from
'
vs/base/common/severity
'
;
import
{
ServiceIdentifier
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IOpener
,
IOpenerService
,
IValidator
}
from
'
vs/platform/opener/common/opener
'
;
export
class
OpenerService
implements
IOpenerService
{
export
class
OpenerService
extends
Disposable
implements
IOpenerService
{
_serviceBrand
!
:
ServiceIdentifier
<
any
>
;
private
readonly
_opener
=
new
LinkedList
<
IOpener
>
();
private
readonly
_openers
=
new
LinkedList
<
IOpener
>
();
private
readonly
_validators
=
new
LinkedList
<
IValidator
>
();
constructor
(
@
ICodeEditorService
private
readonly
_editorService
:
ICodeEditorService
,
@
ICommandService
private
readonly
_commandService
:
ICommandService
,
@
IStorageService
private
readonly
_storageService
:
IStorageService
,
@
IDialogService
private
readonly
_dialogService
:
IDialogService
,
@
IProductService
private
readonly
_productService
:
IProductService
)
{
//
super
();
}
registerOpener
(
opener
:
IOpener
):
IDisposable
{
const
remove
=
this
.
_opener
.
push
(
opener
);
const
remove
=
this
.
_openers
.
push
(
opener
);
return
{
dispose
:
remove
};
}
registerValidator
(
validator
:
IValidator
):
IDisposable
{
const
remove
=
this
.
_validators
.
push
(
validator
);
return
{
dispose
:
remove
};
}
...
...
@@ -47,8 +45,16 @@ export class OpenerService implements IOpenerService {
if
(
!
resource
.
scheme
)
{
return
Promise
.
resolve
(
false
);
}
// check with contributed validators
for
(
const
validator
of
this
.
_validators
.
toArray
())
{
if
(
!
(
await
validator
.
shouldOpen
(
resource
)))
{
return
false
;
}
}
// check with contributed openers
for
(
const
opener
of
this
.
_opener
.
toArray
())
{
for
(
const
opener
of
this
.
_opener
s
.
toArray
())
{
const
handled
=
await
opener
.
open
(
resource
,
options
);
if
(
handled
)
{
return
true
;
...
...
@@ -60,7 +66,7 @@ export class OpenerService implements IOpenerService {
private
_doOpen
(
resource
:
URI
,
options
?:
{
openToSide
?:
boolean
,
openExternal
?:
boolean
}):
Promise
<
boolean
>
{
const
{
scheme
,
authority
,
path
,
query
,
fragment
}
=
resource
;
const
{
scheme
,
path
,
query
,
fragment
}
=
resource
;
if
(
equalsIgnoreCase
(
scheme
,
Schemas
.
mailto
)
||
(
options
&&
options
.
openExternal
))
{
// open default mail application
...
...
@@ -68,48 +74,8 @@ export class OpenerService implements IOpenerService {
}
if
(
equalsIgnoreCase
(
scheme
,
Schemas
.
http
)
||
equalsIgnoreCase
(
scheme
,
Schemas
.
https
))
{
let
trustedDomains
:
string
[]
=
[
'
https://code.visualstudio.com
'
];
try
{
const
trustedDomainsSrc
=
this
.
_storageService
.
get
(
'
http.trustedDomains
'
,
StorageScope
.
GLOBAL
);
if
(
trustedDomainsSrc
)
{
trustedDomains
=
JSON
.
parse
(
trustedDomainsSrc
);
}
}
catch
(
err
)
{
}
const
domainToOpen
=
`
${
scheme
}
://
${
authority
}
`
;
if
(
isDomainTrusted
(
domainToOpen
,
trustedDomains
))
{
return
this
.
_doOpenExternal
(
resource
);
}
else
{
return
this
.
_dialogService
.
show
(
Severity
.
Info
,
localize
(
'
openExternalLinkAt
'
,
'
Do you want {0} to open the external website?
\n
{1}
'
,
this
.
_productService
.
nameShort
,
resource
.
toString
(
true
)
),
[
localize
(
'
openLink
'
,
'
Open Link
'
),
localize
(
'
cancel
'
,
'
Cancel
'
),
localize
(
'
configureTrustedDomains
'
,
'
Configure Trusted Domains
'
)
],
{
cancelId
:
1
}).
then
((
choice
)
=>
{
if
(
choice
===
0
)
{
return
this
.
_doOpenExternal
(
resource
);
}
else
if
(
choice
===
2
)
{
return
this
.
_commandService
.
executeCommand
(
'
workbench.action.configureTrustedDomains
'
,
domainToOpen
).
then
((
pickedDomains
:
string
[])
=>
{
if
(
pickedDomains
.
indexOf
(
domainToOpen
)
!==
-
1
)
{
return
this
.
_doOpenExternal
(
resource
);
}
return
Promise
.
resolve
(
false
);
});
}
return
Promise
.
resolve
(
false
);
});
}
// open link in default browser
return
this
.
_doOpenExternal
(
resource
);
}
else
if
(
equalsIgnoreCase
(
scheme
,
Schemas
.
command
))
{
// run command or bail out if command isn't known
if
(
!
CommandsRegistry
.
getCommand
(
path
))
{
...
...
@@ -158,22 +124,8 @@ export class OpenerService implements IOpenerService {
return
Promise
.
resolve
(
true
);
}
}
/**
* Check whether a domain like https://www.microsoft.com matches
* the list of trusted domains.
*/
function
isDomainTrusted
(
domain
:
string
,
trustedDomains
:
string
[])
{
for
(
let
i
=
0
;
i
<
trustedDomains
.
length
;
i
++
)
{
if
(
trustedDomains
[
i
]
===
'
*
'
)
{
return
true
;
}
if
(
trustedDomains
[
i
]
===
domain
)
{
return
true
;
}
dispose
()
{
this
.
_validators
.
clear
();
}
return
false
;
}
src/vs/editor/standalone/browser/standaloneEditor.ts
浏览文件 @
9be3eb53
...
...
@@ -38,9 +38,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import
{
IOpenerService
}
from
'
vs/platform/opener/common/opener
'
;
import
{
IAccessibilityService
}
from
'
vs/platform/accessibility/common/accessibility
'
;
import
{
clearAllFontInfos
}
from
'
vs/editor/browser/config/configuration
'
;
import
{
IDialogService
}
from
'
vs/platform/dialogs/common/dialogs
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
import
{
IStorageService
}
from
'
vs/platform/storage/common/storage
'
;
type
Omit
<
T
,
K
extends
keyof
T
>
=
Pick
<
T
,
Exclude
<
keyof
T
,
K
>>
;
...
...
@@ -54,13 +51,7 @@ function withAllStandaloneServices<T extends editorCommon.IEditor>(domElement: H
}
if
(
!
services
.
has
(
IOpenerService
))
{
services
.
set
(
IOpenerService
,
new
OpenerService
(
services
.
get
(
ICodeEditorService
),
services
.
get
(
ICommandService
),
services
.
get
(
IStorageService
),
services
.
get
(
IDialogService
),
services
.
get
(
IProductService
)
));
services
.
set
(
IOpenerService
,
new
OpenerService
(
services
.
get
(
ICodeEditorService
),
services
.
get
(
ICommandService
)));
}
let
result
=
callback
(
services
);
...
...
src/vs/editor/test/browser/services/openerService.test.ts
浏览文件 @
9be3eb53
...
...
@@ -7,18 +7,13 @@ import { URI } from 'vs/base/common/uri';
import
{
OpenerService
}
from
'
vs/editor/browser/services/openerService
'
;
import
{
TestCodeEditorService
}
from
'
vs/editor/test/browser/editorTestServices
'
;
import
{
CommandsRegistry
,
ICommandService
,
NullCommandService
}
from
'
vs/platform/commands/common/commands
'
;
import
{
deepClone
}
from
'
vs/base/common/objects
'
;
import
{
IDialogService
}
from
'
vs/platform/dialogs/common/dialogs
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
import
{
IStorageService
}
from
'
vs/platform/storage/common/storage
'
;
suite
(
'
OpenerService
'
,
function
()
{
const
editorService
=
new
TestCodeEditorService
();
let
lastCommand
:
{
id
:
string
,
args
:
any
[]
}
|
undefined
;
let
lastCommand
:
{
id
:
string
;
args
:
any
[]
}
|
undefined
;
const
commandService
=
new
class
implements
ICommandService
{
const
commandService
=
new
(
class
implements
ICommandService
{
_serviceBrand
:
any
;
onWillExecuteCommand
=
()
=>
({
dispose
:
()
=>
{
}
});
onDidExecuteCommand
=
()
=>
({
dispose
:
()
=>
{
}
});
...
...
@@ -26,80 +21,20 @@ suite('OpenerService', function () {
lastCommand
=
{
id
,
args
};
return
Promise
.
resolve
(
undefined
);
}
};
function
getStorageService
(
trustedDomainsSetting
:
string
[])
{
let
_settings
=
deepClone
(
trustedDomainsSetting
);
return
new
class
implements
IStorageService
{
get
=
()
=>
JSON
.
stringify
(
_settings
);
store
=
(
key
:
string
,
val
:
string
)
=>
_settings
=
JSON
.
parse
(
val
);
// Don't care
_serviceBrand
:
any
;
onDidChangeStorage
=
()
=>
({
dispose
:
()
=>
{
}
});
onWillSaveState
=
()
=>
({
dispose
:
()
=>
{
}
});
getBoolean
=
()
=>
true
;
getNumber
=
()
=>
0
;
remove
=
()
=>
{
};
logStorage
=
()
=>
{
};
};
}
function
getDialogService
()
{
return
new
class
implements
IDialogService
{
_showInvoked
=
0
;
show
=
()
=>
{
this
.
_showInvoked
++
;
return
Promise
.
resolve
({}
as
any
);
}
get
confirmInvoked
()
{
return
this
.
_showInvoked
;
}
// Don't care
_serviceBrand
:
any
;
confirm
=
()
=>
{
return
Promise
.
resolve
({}
as
any
);
}
};
}
function
getProductService
():
IProductService
{
return
new
class
{
nameShort
:
'
VS Code
'
;
_serviceBrand
:
any
;
}
as
IProductService
;
}
})();
setup
(
function
()
{
lastCommand
=
undefined
;
});
test
(
'
delegate to editorService, scheme:///fff
'
,
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
NullCommandService
,
getStorageService
([]),
getDialogService
(),
getProductService
()
);
const
openerService
=
new
OpenerService
(
editorService
,
NullCommandService
);
openerService
.
open
(
URI
.
parse
(
'
another:///somepath
'
));
assert
.
equal
(
editorService
.
lastInput
!
.
options
!
.
selection
,
undefined
);
});
test
(
'
delegate to editorService, scheme:///fff#L123
'
,
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
NullCommandService
,
getStorageService
([]),
getDialogService
(),
getProductService
()
);
const
openerService
=
new
OpenerService
(
editorService
,
NullCommandService
);
openerService
.
open
(
URI
.
parse
(
'
file:///somepath#L23
'
));
assert
.
equal
(
editorService
.
lastInput
!
.
options
!
.
selection
!
.
startLineNumber
,
23
);
...
...
@@ -121,14 +56,7 @@ suite('OpenerService', function () {
});
test
(
'
delegate to editorService, scheme:///fff#123,123
'
,
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
NullCommandService
,
getStorageService
([]),
getDialogService
(),
getProductService
()
);
const
openerService
=
new
OpenerService
(
editorService
,
NullCommandService
);
openerService
.
open
(
URI
.
parse
(
'
file:///somepath#23
'
));
assert
.
equal
(
editorService
.
lastInput
!
.
options
!
.
selection
!
.
startLineNumber
,
23
);
...
...
@@ -146,14 +74,7 @@ suite('OpenerService', function () {
});
test
(
'
delegate to commandsService, command:someid
'
,
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
commandService
,
getStorageService
([]),
getDialogService
(),
getProductService
()
);
const
openerService
=
new
OpenerService
(
editorService
,
commandService
);
const
id
=
`aCommand
${
Math
.
random
()}
`
;
CommandsRegistry
.
registerCommand
(
id
,
function
()
{
});
...
...
@@ -174,69 +95,107 @@ suite('OpenerService', function () {
assert
.
equal
(
lastCommand
!
.
args
[
1
],
true
);
});
test
(
'
links are protected by dialog.show
'
,
function
()
{
const
dialogService
=
getDialogService
();
const
openerService
=
new
OpenerService
(
editorService
,
commandService
,
getStorageService
([]),
dialogService
,
getProductService
()
);
openerService
.
open
(
URI
.
parse
(
'
https://www.microsoft.com
'
));
assert
.
equal
(
dialogService
.
confirmInvoked
,
1
);
test
(
'
links are protected by validators
'
,
async
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
commandService
);
openerService
.
registerValidator
({
shouldOpen
:
()
=>
Promise
.
resolve
(
false
)
});
const
httpResult
=
await
openerService
.
open
(
URI
.
parse
(
'
https://www.microsoft.com
'
));
const
httpsResult
=
await
openerService
.
open
(
URI
.
parse
(
'
https://www.microsoft.com
'
));
assert
.
equal
(
httpResult
,
false
);
assert
.
equal
(
httpsResult
,
false
);
});
test
(
'
links
on the whitelisted domains can be opened without dialog.show
'
,
function
()
{
const
dialogService
=
getDialogService
(
);
const
openerService
=
new
OpenerService
(
editorService
,
commandService
,
getStorageService
([
'
https://microsoft.com
'
]),
dialogService
,
getProductService
()
)
;
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com
'
));
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com/
'
)
);
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com/en-us/
'
));
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com/en-us/?foo=bar
'
));
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com/en-us/?foo=bar#baz
'
)
);
assert
.
equal
(
dialogService
.
confirmInvoked
,
0
);
test
(
'
links
validated by validators go to openers
'
,
async
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
commandService
);
openerService
.
registerValidator
({
shouldOpen
:
()
=>
Promise
.
resolve
(
true
)
});
let
openCount
=
0
;
openerService
.
registerOpener
({
open
:
(
resource
:
URI
)
=>
{
openCount
++
;
return
Promise
.
resolve
(
true
);
}
}
);
await
openerService
.
open
(
URI
.
parse
(
'
http://microsoft.com
'
));
assert
.
equal
(
openCount
,
1
);
await
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com
'
));
assert
.
equal
(
openCount
,
2
);
});
test
(
'
variations of links are protected by dialog confirmation
'
,
function
()
{
const
dialogService
=
getDialogService
();
const
openerService
=
new
OpenerService
(
editorService
,
commandService
,
getStorageService
([
'
https://microsoft.com
'
]),
dialogService
,
getProductService
()
);
test
(
'
links validated by multiple validators
'
,
async
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
commandService
);
openerService
.
open
(
URI
.
parse
(
'
http://microsoft.com
'
));
openerService
.
open
(
URI
.
parse
(
'
https://www.microsoft.com
'
));
let
v1
=
0
;
openerService
.
registerValidator
({
shouldOpen
:
()
=>
{
v1
++
;
return
Promise
.
resolve
(
true
);
}
});
assert
.
equal
(
dialogService
.
confirmInvoked
,
2
);
let
v2
=
0
;
openerService
.
registerValidator
({
shouldOpen
:
()
=>
{
v2
++
;
return
Promise
.
resolve
(
true
);
}
});
let
openCount
=
0
;
openerService
.
registerOpener
({
open
:
(
resource
:
URI
)
=>
{
openCount
++
;
return
Promise
.
resolve
(
true
);
}
});
await
openerService
.
open
(
URI
.
parse
(
'
http://microsoft.com
'
));
assert
.
equal
(
openCount
,
1
);
assert
.
equal
(
v1
,
1
);
assert
.
equal
(
v2
,
1
);
await
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com
'
));
assert
.
equal
(
openCount
,
2
);
assert
.
equal
(
v1
,
2
);
assert
.
equal
(
v2
,
2
);
});
test
(
'
* removes all link protection
'
,
function
()
{
const
dialogService
=
getDialogService
();
const
openerService
=
new
OpenerService
(
editorService
,
commandService
,
getStorageService
([
'
*
'
]),
dialogService
,
getProductService
()
);
openerService
.
open
(
URI
.
parse
(
'
https://code.visualstudio.com/
'
));
openerService
.
open
(
URI
.
parse
(
'
https://www.microsoft.com
'
));
openerService
.
open
(
URI
.
parse
(
'
https://www.github.com
'
));
assert
.
equal
(
dialogService
.
confirmInvoked
,
0
);
test
(
'
links invalidated by first validator do not continue validating
'
,
async
function
()
{
const
openerService
=
new
OpenerService
(
editorService
,
commandService
);
let
v1
=
0
;
openerService
.
registerValidator
({
shouldOpen
:
()
=>
{
v1
++
;
return
Promise
.
resolve
(
false
);
}
});
let
v2
=
0
;
openerService
.
registerValidator
({
shouldOpen
:
()
=>
{
v2
++
;
return
Promise
.
resolve
(
true
);
}
});
let
openCount
=
0
;
openerService
.
registerOpener
({
open
:
(
resource
:
URI
)
=>
{
openCount
++
;
return
Promise
.
resolve
(
true
);
}
});
await
openerService
.
open
(
URI
.
parse
(
'
http://microsoft.com
'
));
assert
.
equal
(
openCount
,
0
);
assert
.
equal
(
v1
,
1
);
assert
.
equal
(
v2
,
0
);
await
openerService
.
open
(
URI
.
parse
(
'
https://microsoft.com
'
));
assert
.
equal
(
openCount
,
0
);
assert
.
equal
(
v1
,
2
);
assert
.
equal
(
v2
,
0
);
});
});
src/vs/platform/opener/common/opener.ts
浏览文件 @
9be3eb53
...
...
@@ -14,6 +14,10 @@ export interface IOpener {
open
(
resource
:
URI
,
options
?:
{
openExternal
?:
boolean
}):
Promise
<
boolean
>
;
}
export
interface
IValidator
{
shouldOpen
(
resource
:
URI
):
Promise
<
boolean
>
;
}
export
interface
IOpenerService
{
_serviceBrand
:
any
;
...
...
@@ -23,6 +27,12 @@ export interface IOpenerService {
*/
registerOpener
(
opener
:
IOpener
):
IDisposable
;
/**
* Register a participant that can validate if the URI resource be opened.
* validators are run before openers.
*/
registerValidator
(
validator
:
IValidator
):
IDisposable
;
/**
* Opens a resource, like a webaddress, a document uri, or executes command.
*
...
...
@@ -36,5 +46,6 @@ export interface IOpenerService {
export
const
NullOpenerService
:
IOpenerService
=
Object
.
freeze
({
_serviceBrand
:
undefined
,
registerOpener
()
{
return
{
dispose
()
{
}
};
},
registerValidator
()
{
return
{
dispose
()
{
}
};
},
open
()
{
return
Promise
.
resolve
(
false
);
},
});
src/vs/workbench/contrib/url/common/url.contribution.ts
浏览文件 @
9be3eb53
...
...
@@ -14,17 +14,24 @@ import { Action } from 'vs/base/common/actions';
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
{
CommandsRegistry
}
from
'
vs/platform/commands/common/commands
'
;
import
{
ServicesAccessor
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IWorkbenchContribution
,
IWorkbenchContributionsRegistry
,
Extensions
as
WorkbenchExtensions
}
from
'
vs/workbench/common/contributions
'
;
import
{
LifecyclePhase
}
from
'
vs/platform/lifecycle/common/lifecycle
'
;
import
{
IDialogService
}
from
'
vs/platform/dialogs/common/dialogs
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
import
{
IOpenerService
}
from
'
vs/platform/opener/common/opener
'
;
import
{
equalsIgnoreCase
}
from
'
vs/base/common/strings
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
Severity
from
'
vs/base/common/severity
'
;
export
class
OpenUrlAction
extends
Action
{
static
readonly
ID
=
'
workbench.action.url.openUrl
'
;
static
readonly
LABEL
=
localize
(
'
openUrl
'
,
"
Open URL
"
);
static
readonly
LABEL
=
localize
(
'
openUrl
'
,
'
Open URL
'
);
constructor
(
id
:
string
,
label
:
string
,
@
IURLService
private
readonly
urlService
:
IURLService
,
@
IQuickInputService
private
readonly
quickInputService
:
IQuickInputService
,
@
IQuickInputService
private
readonly
quickInputService
:
IQuickInputService
)
{
super
(
id
,
label
);
}
...
...
@@ -45,7 +52,7 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
const
VSCODE_DOMAIN
=
'
https://code.visualstudio.com
'
;
const
configureTrustedDomainsHandler
=
(
const
configureTrustedDomainsHandler
=
async
(
quickInputService
:
IQuickInputService
,
storageService
:
IStorageService
,
domainToConfigure
?:
string
...
...
@@ -66,7 +73,7 @@ const configureTrustedDomainsHandler = (
type
:
'
item
'
,
label
:
d
,
id
:
d
,
picked
:
true
,
picked
:
true
};
});
...
...
@@ -91,23 +98,24 @@ const configureTrustedDomainsHandler = (
specialQuickPickItems
.
push
(
<
IQuickPickItem
>
domainToConfigureItem
);
}
const
quickPickItems
:
(
IQuickPickItem
|
IQuickPickSeparator
)[]
=
domainQuickPickItems
.
length
===
0
?
specialQuickPickItems
:
[...
specialQuickPickItems
,
{
type
:
'
separator
'
},
...
domainQuickPickItems
];
const
quickPickItems
:
(
IQuickPickItem
|
IQuickPickSeparator
)[]
=
domainQuickPickItems
.
length
===
0
?
specialQuickPickItems
:
[...
specialQuickPickItems
,
{
type
:
'
separator
'
},
...
domainQuickPickItems
];
return
quickInputService
.
pick
(
quickPickItems
,
{
const
pickedResult
=
await
quickInputService
.
pick
(
quickPickItems
,
{
canPickMany
:
true
,
activeItem
:
domainToConfigureItem
}).
then
(
result
=>
{
if
(
result
)
{
const
pickedDomains
=
result
.
map
(
r
=>
r
.
id
);
storageService
.
store
(
'
http.trustedDomains
'
,
JSON
.
stringify
(
pickedDomains
),
StorageScope
.
GLOBAL
);
});
return
pickedDomains
;
}
if
(
pickedResult
)
{
const
pickedDomains
:
string
[]
=
pickedResult
.
map
(
r
=>
r
.
id
!
);
storageService
.
store
(
'
http.trustedDomains
'
,
JSON
.
stringify
(
pickedDomains
),
StorageScope
.
GLOBAL
);
return
[];
});
return
pickedDomains
;
}
return
[];
};
const
configureTrustedDomainCommand
=
{
...
...
@@ -131,3 +139,93 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
title
:
configureTrustedDomainCommand
.
description
.
description
}
});
class
OpenerValidatorContributions
implements
IWorkbenchContribution
{
constructor
(
@
IOpenerService
private
readonly
_openerService
:
IOpenerService
,
@
IStorageService
private
readonly
_storageService
:
IStorageService
,
@
IDialogService
private
readonly
_dialogService
:
IDialogService
,
@
IProductService
private
readonly
_productService
:
IProductService
,
@
IQuickInputService
private
readonly
_quickInputService
:
IQuickInputService
)
{
this
.
_openerService
.
registerValidator
({
shouldOpen
:
r
=>
this
.
validateLink
(
r
)
});
}
async
validateLink
(
resource
:
URI
):
Promise
<
boolean
>
{
const
{
scheme
,
authority
}
=
resource
;
if
(
!
equalsIgnoreCase
(
scheme
,
Schemas
.
http
)
&&
!
equalsIgnoreCase
(
scheme
,
Schemas
.
https
))
{
return
true
;
}
let
trustedDomains
:
string
[]
=
[
VSCODE_DOMAIN
];
try
{
const
trustedDomainsSrc
=
this
.
_storageService
.
get
(
'
http.trustedDomains
'
,
StorageScope
.
GLOBAL
);
if
(
trustedDomainsSrc
)
{
trustedDomains
=
JSON
.
parse
(
trustedDomainsSrc
);
}
}
catch
(
err
)
{
}
const
domainToOpen
=
`
${
scheme
}
://
${
authority
}
`
;
if
(
isDomainTrusted
(
domainToOpen
,
trustedDomains
))
{
return
true
;
}
else
{
const
choice
=
await
this
.
_dialogService
.
show
(
Severity
.
Info
,
localize
(
'
openExternalLinkAt
'
,
'
Do you want {0} to open the external website?
\n
{1}
'
,
this
.
_productService
.
nameShort
,
resource
.
toString
(
true
)
),
[
localize
(
'
openLink
'
,
'
Open Link
'
),
localize
(
'
cancel
'
,
'
Cancel
'
),
localize
(
'
configureTrustedDomains
'
,
'
Configure Trusted Domains
'
)
],
{
cancelId
:
1
}
);
// Open Link
if
(
choice
===
0
)
{
return
true
;
}
// Configure Trusted Domains
else
if
(
choice
===
2
)
{
const
pickedDomains
=
await
configureTrustedDomainsHandler
(
this
.
_quickInputService
,
this
.
_storageService
,
domainToOpen
);
if
(
pickedDomains
.
indexOf
(
domainToOpen
)
!==
-
1
)
{
return
true
;
}
return
false
;
}
return
false
;
}
}
}
Registry
.
as
<
IWorkbenchContributionsRegistry
>
(
WorkbenchExtensions
.
Workbench
).
registerWorkbenchContribution
(
OpenerValidatorContributions
,
LifecyclePhase
.
Restored
);
/**
* Check whether a domain like https://www.microsoft.com matches
* the list of trusted domains.
*/
function
isDomainTrusted
(
domain
:
string
,
trustedDomains
:
string
[])
{
for
(
let
i
=
0
;
i
<
trustedDomains
.
length
;
i
++
)
{
if
(
trustedDomains
[
i
]
===
'
*
'
)
{
return
true
;
}
if
(
trustedDomains
[
i
]
===
domain
)
{
return
true
;
}
}
return
false
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录