Skip to content

Commit cfb738b

Browse files
authored
Merge pull request SolidOS#284 from solid/acl-control-cleanup
acl-control cleanup
2 parents 616bf6f + 03b880c commit cfb738b

3 files changed

Lines changed: 114 additions & 55 deletions

File tree

src/acl/acl-control.ts

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import { DataBrowserContext } from 'pane-registry'
1313
import { AccessController } from './access-controller'
1414
import { getClasses } from '../jss'
1515
import { styles } from './styles'
16-
import * as debug from '../debug'
16+
import { log, warn } from '../debug'
17+
18+
let global: Window = window
19+
const preventBrowserDropEventsDone = Symbol('prevent double triggering of drop event')
1720

1821
/**
1922
* See https://coshx.com/preventing-drag-and-drop-disasters-with-a-chrome-userscript
@@ -28,40 +31,37 @@ import * as debug from '../debug'
2831
* @returns void
2932
*/
3033
export function preventBrowserDropEvents (document: HTMLDocument): void {
31-
debug.log('preventBrowserDropEvents called.')
32-
const global: any = window
34+
log('preventBrowserDropEvents called.')
3335
if (typeof global !== 'undefined') {
34-
if (global.preventBrowserDropEventsDone) return
35-
global.preventBrowserDropEventsDone = true
36-
}
37-
38-
function preventDrag (e) {
39-
e.stopPropagation()
40-
e.preventDefault()
41-
}
42-
43-
function handleDrop (e) {
44-
if (e.dataTransfer.files.length > 0) {
45-
if (
46-
!confirm(
47-
'Are you sure you want to drop this file here? ' +
48-
'(Cancel opens it in a new tab)'
49-
)
50-
) {
51-
e.stopPropagation()
52-
e.preventDefault()
53-
debug.log(
54-
'@@@@ document-level DROP suppressed: ' + e.dataTransfer.dropEffect
55-
)
56-
}
57-
}
36+
if (global[preventBrowserDropEventsDone]) return
37+
global[preventBrowserDropEventsDone] = true
5838
}
5939

6040
document.addEventListener('drop', handleDrop, false)
6141
document.addEventListener('dragenter', preventDrag, false)
6242
document.addEventListener('dragover', preventDrag, false)
6343
}
6444

45+
/** @internal */
46+
export function preventDrag (e) {
47+
e.stopPropagation()
48+
e.preventDefault()
49+
}
50+
51+
/** @internal */
52+
export function handleDrop (e) {
53+
if (e.dataTransfer.files.length > 0) {
54+
if (
55+
!global.confirm('Are you sure you want to drop this file here? (Cancel opens it in a new tab)')
56+
) {
57+
e.stopPropagation()
58+
e.preventDefault()
59+
log('@@@@ document-level DROP suppressed: ' + e.dataTransfer.dropEffect
60+
)
61+
}
62+
}
63+
}
64+
6565
/**
6666
* Get a folder's own filename in the directory tree. Also works for
6767
* domain names; the URL protocol ('https://') acts as the tree root
@@ -181,7 +181,7 @@ async function loadController (
181181
return resolve(getController(prospectiveDefaultHolder))
182182
} catch (error) {
183183
// No need to show this error in status, but good to warn about it in console
184-
debug.warn(error)
184+
warn(error)
185185
}
186186
}
187187
return resolve(getController())
@@ -212,3 +212,8 @@ function hasProtectedAcl (targetDoc: NamedNode): boolean {
212212
// Hopefully we'll find a better, standardized solution to this - https://github.com/solid/specification/issues/37
213213
return targetDoc.uri === targetDoc.site().uri
214214
}
215+
216+
/** @internal */
217+
export function setGlobalWindow (window: Window) {
218+
global = window
219+
}

test/unit/acl/acl-control.test.ts

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { DataBrowserContext } from 'pane-registry'
33
import { sym, graph, namedNode } from 'rdflib'
44
import { JSDOM } from 'jsdom'
55
import {
6-
ACLControlBox5,
7-
preventBrowserDropEvents,
6+
ACLControlBox5, handleDrop,
7+
preventBrowserDropEvents, preventDrag, setGlobalWindow,
88
shortNameForFolder
99
} from '../../../src/acl/acl-control'
1010

@@ -14,9 +14,6 @@ const window = new JSDOM('<!DOCTYPE html><p>Hello world</p>').window
1414
const dom = window.document
1515

1616
describe('ACLControlBox5', () => {
17-
it('exists', () => {
18-
expect(ACLControlBox5).toBeInstanceOf(Function)
19-
})
2017
it.skip('runs', () => {
2118
expect(ACLControlBox5(
2219
sym('https://test.test'),
@@ -27,21 +24,59 @@ describe('ACLControlBox5', () => {
2724
})
2825

2926
describe('preventBrowserDropEvents', () => {
30-
it('exists', () => {
31-
expect(preventBrowserDropEvents).toBeInstanceOf(Function)
27+
let event
28+
29+
beforeAll(() => {
30+
jest.spyOn(dom, 'addEventListener')
31+
preventBrowserDropEvents(dom)
3232
})
33-
it('runs', () => {
34-
expect(preventBrowserDropEvents(dom)).toEqual(undefined)
33+
beforeEach(() => {
34+
event = {
35+
stopPropagation: jest.fn(),
36+
preventDefault: jest.fn()
37+
}
3538
})
36-
})
39+
afterAll(() => jest.restoreAllMocks())
3740

38-
describe('shortNameForFolder', () => {
39-
it('exists', () => {
40-
expect(shortNameForFolder).toBeInstanceOf(Function)
41+
it('adds event handlers for drop', () => expect(dom.addEventListener).toHaveBeenCalledWith('drop', handleDrop, false))
42+
it('adds event handlers for dragenter', () => expect(dom.addEventListener).toHaveBeenCalledWith('dragenter', preventDrag, false))
43+
it('adds event handlers for drop, dragenter and dragover', () => expect(dom.addEventListener).toHaveBeenCalledWith('dragover', preventDrag, false))
44+
45+
it('prevents adding event listeners twice', () => {
46+
preventBrowserDropEvents(dom)
47+
expect((dom.addEventListener as jest.Mock).mock.calls.length).toBe(3)
4148
})
42-
it('runs', () => {
43-
expect(shortNameForFolder(sym('https://test.test/uri'))).toEqual('uri')
49+
50+
describe('preventDrag', () => {
51+
beforeEach(() => preventDrag(event))
52+
53+
it('calls event.stopPropagation', () => expect(event.stopPropagation).toHaveBeenCalled())
54+
it('calls event.preventDefault', () => expect(event.preventDefault).toHaveBeenCalled())
4455
})
56+
57+
describe('handleDrop', () => {
58+
beforeEach(() => {
59+
setGlobalWindow(window)
60+
event.dataTransfer = { files: [{}] }
61+
window.confirm = jest.fn(() => false)
62+
handleDrop(event)
63+
})
64+
65+
it('calls window.confirm', () => expect(window.confirm).toHaveBeenCalledWith('Are you sure you want to drop this file here? (Cancel opens it in a new tab)'))
66+
67+
describe('confirm return true', () => {
68+
beforeEach(() => {
69+
window.confirm = jest.fn(() => true)
70+
handleDrop(event)
71+
})
72+
73+
it('calls event.stopPropagation', () => expect(event.stopPropagation).toHaveBeenCalled())
74+
it('calls event.preventDefault', () => expect(event.preventDefault).toHaveBeenCalled())
75+
})
76+
})
77+
})
78+
79+
describe('shortNameForFolder', () => {
4580
it('works with trailing slashes', () => {
4681
expect(shortNameForFolder(namedNode('http://example.com/some/folder/'))).toEqual('folder')
4782
})

test/unit/acl/index.test.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,38 @@ import * as AclControl from '../../../src/acl/acl-control'
44
import { acl, aclControl } from '../../../src/acl/index'
55

66
silenceDebugMessages()
7-
jest.mock('solid-auth-client')
87

9-
describe('acl/index:acl', () => {
10-
it('exports all of acl/acl', () => {
11-
for (const k in Acl) {
12-
if (k !== 'getProspectiveHolder') {
13-
expect(acl[k]).toEqual(Acl[k])
14-
}
15-
}
8+
describe('acl related APIs', () => {
9+
it('exports some methods in the acl module', () => {
10+
expect(Acl).toEqual(expect.objectContaining(acl))
11+
expect([
12+
'adoptACLDefault',
13+
'readACL',
14+
'sameACL',
15+
'ACLunion',
16+
'loadUnionACL',
17+
'ACLbyCombination',
18+
'makeACLGraph',
19+
'makeACLGraphbyCombo',
20+
'ACLToString',
21+
'comboToString',
22+
'makeACLString',
23+
'putACLObject',
24+
'putACLbyCombo',
25+
'fixIndividualCardACL',
26+
'fixIndividualACL',
27+
'setACL',
28+
'getACLorDefault',
29+
'getACL'
30+
]).toEqual(expect.arrayContaining(Object.keys(acl)))
1631
})
17-
it('exports all of acl/acl-control', () => {
18-
for (const k in AclControl) {
19-
expect(aclControl[k]).toEqual(AclControl[k])
20-
}
32+
33+
it('exposes some methods of acl-control module', () => {
34+
expect(AclControl).toEqual(expect.objectContaining(aclControl))
35+
expect([
36+
'preventBrowserDropEvents',
37+
'shortNameForFolder',
38+
'ACLControlBox5'
39+
]).toEqual(expect.arrayContaining(Object.keys(aclControl)))
2140
})
2241
})

0 commit comments

Comments
 (0)