馃悕馃悕馃悕
at dev 243 lines 6.7 kB view raw
1let transmitters: { [id: string]: Transmitter } = {}; 2 3let receivers: { [id: string]: Receiver } = {}; 4 5let workspaces: { [id: string]: Workspace } = {}; 6 7function registerWorkspace(element: Element, renderWires: Function | null = null) { 8 if (workspaces[element.id] === undefined) { 9 workspaces[element.id] = { 10 id: element.id, 11 element, 12 transmitters: {}, 13 receivers: {}, 14 renderWires 15 }; 16 } else { 17 if (renderWires !== null) { 18 workspaces[element.id].renderWires = renderWires; 19 } 20 } 21} 22 23export interface Workspace { 24 id: string; 25 element: Element; 26 transmitters: { [id: string]: Transmitter; }; 27 receivers: { [id: string]: Receiver; }; 28 renderWires: Function | null; 29} 30 31export interface Transmitter { 32 id: string; 33 element: Element; 34 rerender: Function; 35 schemas: string[]; 36 connections: Receiver[]; 37 workspace: Workspace | null; 38 dirty: boolean; 39} 40 41export interface Receiver { 42 id: string; 43 element: Element; 44 schemas: string[]; 45 onSignal: Function; 46 connections: Transmitter[]; 47 workspace: Workspace | null; 48 dirty: boolean; 49} 50 51function registerTransmitter(id: string, element: HTMLElement, rerender: Function, schemas: string[], connections: Receiver[]): void { 52 let transmitter: Transmitter = { id, element, rerender, schemas, connections, workspace: null, dirty: true }; 53 54 transmitters[id] = transmitter; 55 56 let workspaceElement = seekParent(element, prefixes.workspace); 57 if (workspaceElement === null) { 58 return; 59 } 60 61 if (workspaces[workspaceElement.id] === undefined) { 62 registerWorkspace(workspaceElement); 63 } 64 65 workspaces[workspaceElement.id].transmitters[id] = transmitter; 66 transmitter.workspace = workspaces[workspaceElement.id]; 67} 68 69function registerReceiver(id: string, element: HTMLElement, schemas: string[], onSignal: Function, connections: Transmitter[]) { 70 let receiver: Receiver = { id, element, schemas, onSignal, connections, workspace: null, dirty: true }; 71 72 receivers[id] = receiver; 73 74 let workspace = seekParent(element, prefixes.workspace); 75 if (workspace === null) { 76 return; 77 } 78 79 if (workspaces[workspace.id] === undefined) { 80 registerWorkspace(workspace); 81 } 82 83 workspaces[workspace.id].receivers[id] = receiver; 84 receiver.workspace = workspaces[workspace.id]; 85} 86 87function removeWorkspace(id: string) { 88 let workspace = workspaces[id]; 89 for (const transmitterId in workspace.transmitters) { 90 removeTransmitter(transmitterId, true); 91 } 92 for (const receiverId in workspace.receivers) { 93 removeReceiver(receiverId, true); 94 } 95 delete workspaces[id]; 96} 97 98function removeTransmitter(id: string, skipWorkspace: boolean = false) { 99 let transmitter = transmitters[id]; 100 101 if (transmitter === undefined) { 102 // This happens sometimes because onDestroy gets called before onMount for some transmitters and receivers when the app starts up. 103 return; 104 } 105 106 for (const receiver of transmitter.connections) { 107 let index = receiver.connections.indexOf(transmitter); 108 receiver.connections.splice(index, 1); 109 receiver.dirty = true; 110 } 111 112 if (!skipWorkspace && transmitter.workspace !== null) { 113 delete transmitter.workspace.transmitters[id]; 114 } 115 116 delete transmitters[id]; 117} 118 119function removeReceiver(id: string, skipWorkspace: boolean = false) { 120 let receiver = receivers[id]; 121 122 if (receiver === undefined) { 123 // This happens sometimes because onDestroy gets called before onMount for some transmitters and receivers when the app starts up. 124 return; 125 } 126 127 for (const transmitter of receiver.connections) { 128 let index = transmitter.connections.indexOf(receiver); 129 transmitter.connections.splice(index, 1); 130 transmitter.dirty = true; 131 } 132 133 if (!skipWorkspace && receiver.workspace !== null) { 134 delete receiver.workspace.receivers[id]; 135 } 136 137 delete receivers[id]; 138} 139 140function seekParent(element: Element, idPrefix: string): Element | null { 141 if (element === undefined) { return null; } 142 let currentElement = element.parentElement; 143 144 while (currentElement) { 145 if (currentElement.id.startsWith(idPrefix)) { 146 return currentElement; 147 } 148 149 currentElement = currentElement.parentElement; 150 } 151 152 return null; 153} 154 155function connect(transmitterId: string, receiverId: string) { 156 let transmitter = transmitters[transmitterId]; 157 let receiver = receivers[receiverId]; 158 159 transmitter.connections.push(receiver); 160 receiver.connections.push(transmitter); 161 162 transmitter.dirty = true; 163 receiver.dirty = true; 164 165 if (transmitter.workspace?.renderWires !== null) { 166 transmitter.workspace?.renderWires(); 167 } 168 169 if (receiver.workspace?.renderWires !== null) { 170 if (receiver.workspace !== transmitter.workspace) { 171 receiver.workspace?.renderWires(); 172 } 173 } 174 175} 176 177function childTransceivers(element: Element) { 178 let receivers: string[] = []; 179 let transmitters: string[] = []; 180 181 if (element === undefined) return { receivers, transmitters }; 182 183 Array.from(element.children).forEach(child => { 184 if (child.id.startsWith(prefixes.receiver)) { 185 receivers.push(child.id); 186 } 187 if (child.id.startsWith(prefixes.transmitter)) { 188 transmitters.push(child.id); 189 } 190 let recurseResult = childTransceivers(child); 191 receivers.push(...recurseResult.receivers); 192 transmitters.push(...recurseResult.transmitters); 193 }); 194 195 return { receivers, transmitters }; 196} 197 198function idAtLocation(x: number, y: number, idPrefix: string): string | null { 199 var stack = []; 200 var el; 201 var result = null; 202 do { 203 el = document.elementFromPoint(x, y); 204 if (el === null) { 205 break; 206 } 207 if (el.id.startsWith(idPrefix)) { 208 result = el.id; 209 break; 210 } 211 stack.push(el); 212 el.classList.add('pointerEventsNone'); 213 }while(el && el.tagName !== 'HTML'); 214 215 // clean up 216 for(var i = 0; i < stack.length; i += 1) 217 stack[i].classList.remove('pointerEventsNone'); 218 219 return result; 220} 221 222let prefixes = { 223 workspace: "WORKSPACE", 224 transmitter: "TRANSMITTER", 225 receiver: "RECEIVER" 226} 227 228export default { 229 receivers, 230 transmitters, 231 workspaces, 232 prefixes, 233 connect, 234 registerWorkspace, 235 registerTransmitter, 236 registerReceiver, 237 removeWorkspace, 238 removeTransmitter, 239 removeReceiver, 240 seekParent, 241 childTransceivers, 242 idAtLocation 243}