11import { onConnect , onMessage , sendToTab } from 'crossmessaging' ;
22import updateState from 'remotedev-app/lib/store/updateState' ;
33import syncOptions from '../options/syncOptions' ;
4- import createMenu from './contextMenus' ;
54import openDevToolsWindow from './openWindow' ;
6- let connections = { } ;
5+ let panelConnections = { } ;
6+ let tabConnections = { } ;
77let catchedErrors = { } ;
8+ let unsubscribeList = { } ;
9+ let isMonitored = false ;
810
911window . syncOptions = syncOptions ; // Used in the options page
1012
1113const naMessage = { type : 'NA' } ;
1214
13- // Connect to devpanel
14- onConnect ( ( tabId ) => {
15- if ( tabId !== store . id ) return naMessage ;
16- return { } ;
17- } , { } , connections ) ;
15+ function initPanel ( msg , port ) {
16+ monitorInstances ( true ) ;
17+ panelConnections [ msg . tabId ] = port ;
18+ if ( msg . tabId !== store . id ) return naMessage ;
19+ }
20+
21+ function getId ( port ) {
22+ return port . sender . tab ? port . sender . tab . id : port . sender . id ;
23+ }
24+
25+ function initInstance ( msg , port ) {
26+ const id = getId ( port ) ;
27+ tabConnections [ id ] = port ;
28+ store . liftedStore . instances [ id ] = msg . instance ;
29+ store . id = id ;
30+ if ( typeof id === 'number' ) chrome . pageAction . show ( id ) ;
31+ if ( isMonitored ) return { type : 'START' } ;
32+ }
33+
34+ function disconnect ( port ) {
35+ if ( ! port . sender . tab && ! port . id ) {
36+ monitorInstances ( false ) ;
37+ return ;
38+ }
39+ const id = getId ( port ) ;
40+ delete tabConnections [ id ] ;
41+ if ( panelConnections [ id ] ) panelConnections [ id ] . postMessage ( naMessage ) ;
42+ if ( window . store . liftedStore . instances [ id ] ) {
43+ delete window . store . liftedStore . instances [ id ] ;
44+ window . store . liftedStore . deleteInstance ( id ) ;
45+ }
46+ }
47+
48+ onConnect ( undefined , {
49+ INIT_PANEL : initPanel ,
50+ INIT_INSTANCE : initInstance ,
51+ RELAY : ( msg , port ) => { messaging ( msg . message , port . sender ) ; }
52+ } , panelConnections , disconnect ) ;
1853
1954function handleInstancesChanged ( instance , name ) {
2055 window . store . liftedStore . instances [ instance ] = name || instance ;
@@ -24,15 +59,6 @@ function handleInstancesChanged(instance, name) {
2459function messaging ( request , sender , sendResponse ) {
2560 const tabId = sender . tab ? sender . tab . id : sender . id ;
2661 if ( tabId ) {
27- if ( request . type === 'PAGE_UNLOADED' ) {
28- handleInstancesChanged ( tabId , undefined , true ) ;
29- if ( connections [ tabId ] ) connections [ tabId ] . postMessage ( naMessage ) ;
30- if ( window . store . liftedStore . instances [ tabId ] ) {
31- delete window . store . liftedStore . instances [ tabId ] ;
32- window . store . liftedStore . deleteInstance ( tabId ) ;
33- }
34- return true ;
35- }
3662 if ( request . type === 'GET_OPTIONS' ) {
3763 syncOptions . get ( options => {
3864 sendResponse ( { options : options } ) ;
@@ -60,14 +86,9 @@ function messaging(request, sender, sendResponse) {
6086 const payload = updateState ( store , request , handleInstancesChanged , store . liftedStore . instance ) ;
6187 if ( ! payload ) return true ;
6288
63- if ( request . init ) {
64- store . id = tabId ;
65- createMenu ( sender . url , tabId ) ;
66- }
67-
68- // Relay the message to the devTools page
69- if ( tabId in connections ) {
70- connections [ tabId ] . postMessage ( request ) ;
89+ // Relay the message to the devTools panel
90+ if ( tabId in panelConnections ) {
91+ panelConnections [ tabId ] . postMessage ( request ) ;
7192 }
7293
7394 // Notify when errors occur in the app
@@ -107,9 +128,57 @@ export function toContentScript(action) {
107128 const message = { type : 'DISPATCH' , action : action } ;
108129 let id = store . liftedStore . instance ;
109130 if ( ! id || id === 'auto' ) id = store . id ;
110- if ( id in connections ) {
111- connections [ id ] . postMessage ( message ) ;
131+ if ( id in panelConnections ) {
132+ panelConnections [ id ] . postMessage ( message ) ;
112133 } else {
113- sendToTab ( Number ( id ) , message ) ;
134+ tabConnections [ id ] . postMessage ( message ) ;
114135 }
115136}
137+
138+ function monitorInstances ( shouldMonitor ) {
139+ if (
140+ ! shouldMonitor && Object . getOwnPropertyNames ( unsubscribeList ) . length !== 0
141+ || isMonitored === shouldMonitor
142+ ) return ;
143+
144+ Object . keys ( tabConnections ) . forEach ( id => {
145+ tabConnections [ id ] . postMessage ( { type : shouldMonitor ? 'START' : 'STOP' } ) ;
146+ } ) ;
147+ isMonitored = shouldMonitor ;
148+ }
149+
150+ function getTab ( cb ) {
151+ chrome . tabs . query ( {
152+ active : true ,
153+ windowId : chrome . windows . WINDOW_ID_CURRENT
154+ } , ( tab ) => {
155+ cb ( tab [ 0 ] . id ) ;
156+ } ) ;
157+ }
158+
159+ const unsubscribeMonitor = ( tabId ) => ( ) => {
160+ if ( ! unsubscribeList [ tabId ] ) return ;
161+ unsubscribeList [ tabId ] ( ) ;
162+ delete unsubscribeList [ tabId ] ;
163+ if ( Object . getOwnPropertyNames ( panelConnections ) . length === 0 ) {
164+ monitorInstances ( false ) ;
165+ }
166+ } ;
167+
168+ // Expose store to extension's windows (monitors)
169+ window . getStore = ( cb ) => {
170+ monitorInstances ( true ) ;
171+ getTab ( ( tabId ) => {
172+ cb ( {
173+ ...store ,
174+ liftedStore : {
175+ ...store . liftedStore ,
176+ subscribe ( ...args ) {
177+ const unsubscribe = store . liftedStore . subscribe ( ...args ) ;
178+ unsubscribeList [ tabId ] = unsubscribe ;
179+ return unsubscribe ;
180+ }
181+ }
182+ } , unsubscribeMonitor ( tabId ) ) ;
183+ } ) ;
184+ } ;
0 commit comments