forked from LinusBorg/portal-vue
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwormhole.ts
116 lines (107 loc) · 3.37 KB
/
wormhole.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import Vue from 'vue'
import { freeze, inBrowser, stableSort } from '../utils'
import {
Transports,
Transport,
TransportInput,
TransportVector,
VMRegister,
} from '../types'
const transports: Transports = {}
const targets: VMRegister = {}
const sources: VMRegister = {}
export const Wormhole = Vue.extend({
data: () => ({
transports,
targets,
sources,
trackInstances: inBrowser,
}),
methods: {
open(transport: TransportInput) {
if (!inBrowser) return
const { to, from, passengers, order = Infinity } = transport
if (!to || !from || !passengers) return
const newTransport = {
to,
from,
passengers: freeze<object>(passengers),
order,
} as Transport
const keys = Object.keys(this.transports)
if (keys.indexOf(to) === -1) {
Vue.set(this.transports, to, [])
}
const currentIndex = this.$_getTransportIndex(newTransport)
// Copying the array here so that the PortalTarget change event will actually contain two distinct arrays
const newTransports = this.transports[to].slice(0)
if (currentIndex === -1) {
newTransports.push(newTransport)
} else {
newTransports[currentIndex] = newTransport
}
this.transports[to] = stableSort<Transport>(
newTransports,
(a: Transport, b: Transport) => a.order - b.order
)
},
close(transport: TransportVector, force = false) {
const { to, from } = transport
if (!to || (!from && force === false)) return
if (!this.transports[to]) {
return
}
if (force) {
this.transports[to] = []
} else {
const index = this.$_getTransportIndex(transport)
if (index >= 0) {
// Copying the array here so that the PortalTarget change event will actually contain two distinct arrays
const newTransports = this.transports[to].slice(0)
newTransports.splice(index, 1)
this.transports[to] = newTransports
}
}
},
registerTarget(target: string, vm: Vue, force?: boolean): void {
if (!inBrowser) return
if (this.trackInstances && !force && this.targets[target]) {
console.warn(`[portal-vue]: Target ${target} already exists`)
}
this.$set(this.targets, target, Object.freeze([vm]))
},
unregisterTarget(target: string) {
this.$delete(this.targets, target)
},
registerSource(source: string, vm: Vue, force?: boolean): void {
if (!inBrowser) return
if (this.trackInstances && !force && this.sources[source]) {
console.warn(`[portal-vue]: source ${source} already exists`)
}
this.$set(this.sources, source, Object.freeze([vm]))
},
unregisterSource(source: string) {
this.$delete(this.sources, source)
},
hasTarget(to: string) {
return !!(this.targets[to] && this.targets[to][0])
},
hasSource(to: string) {
return !!(this.sources[to] && this.sources[to][0])
},
hasContentFor(to: string) {
return !!this.transports[to] && !!this.transports[to].length
},
// Internal
$_getTransportIndex({ to, from }: TransportVector): number {
for (const i in this.transports[to]) {
if (this.transports[to][i].from === from) {
return +i
}
}
return -1
},
},
})
const wormhole = new Wormhole(transports)
export { wormhole }