cross-channel
Version:
Cross window messaging
155 lines (136 loc) • 4.48 kB
JavaScript
var MessageEvent = require('../../types/message-event.js')
var Message = require('../../types/message.js')
var generateRandomKey = require('../../utils/generate-random-key.js')
var getAllWindows = require('../../utils/frames.js').getAll
var environment = require('../../utils/environment.js')
/*
Known issues:
1. From NW to child window - NO
2. From child window to NW - NO
3. From child frame to child window - NO
4. From child window to child frame - NO
5. <iframe nwfaketop> disables message bubbling to the parent frame
*/
var global = environment.global
function getGUI(window) {
return window && window.nwDispatcher.requireNwGui()
}
function whenGuiReadyThen(callback) {
var gui = getGUI(global.window)
if (gui) {
callback(gui)
return
}
var timerId = setInterval(function () {
gui = getGUI(global.window)
if (gui) {
clearInterval(timerId)
callback(gui)
}
}, 4)
}
function getNWWindowThen(callback) {
whenGuiReadyThen(function (gui) {
var nwWindow = gui.Window.get()
callback(nwWindow)
})
}
function Transport(name) {
var transport = this
// this.port - computed value
this.origin = '*' //location = window.location, location && (location.origin || (location.protocol + '//' + location.host)) || '*'
this.listener = null
this.name = name
this.key = generateRandomKey()
this.nwLoadedListener = function () {
var listener = transport.listener
var port = transport.port
if (listener) {
//port.removeEventListener(Transport.EVENT_TYPE, listener)
port.addEventListener(Transport.EVENT_TYPE, listener)
}
}
getNWWindowThen(function (nwWindow) {
//listen when page is refreshed
nwWindow.on('loaded', transport.nwLoadedListener)
})
}
Transport.supported = Boolean(environment.is.node && environment.is.nodeWebkit)
Transport.EVENT_TYPE = 'message'
Transport.prototype = {
constructor: Transport,
send: function (data) {
var transport = this
var origin = this.origin
var message = new Message(data, this)
getNWWindowThen(function (nwWindow) {
var browserWindow = transport.port
var topBrowserWindow = browserWindow.top
var browserFrames = getAllWindows(topBrowserWindow)
// try {
// if (global.__nwWindowsStore) {
// browserFrames = Object.keys(global.__nwWindowsStore)
// .map(function(id) {
// return global.__nwWindowsStore[id];
// })
// .map(function(nwWindow) {
// var browserWindow = nwWindow.window;
// return getAllWindows(browserWindow.top)
// })
// .reduce(function(allBrowserWindows, browserWindows) {
// return allBrowserWindows.concat(browserWindows)
// }, [])
// }
// }
// catch (err) {
// setTimeout(console.error.bind(console, err), 4000)
//
// }
var index = -1
while (++index in browserFrames) {
//.replace(/'/g, '\\\'')
nwWindow.eval(browserFrames[index].frameElement || null, 'window.postMessage(' + JSON.stringify(message.asJSON()) + ', "' + origin + '")')
}
})
},
onMessageEvent: function (handler) {
var transport = this
function listener(e) {
var window = this
var nativeMessageEventWorks = window.MessageEvent && window.MessageEvent.length
var event = nativeMessageEventWorks ? (new window.MessageEvent(Transport.EVENT_TYPE, e)) : e //fixes crashes in NWjs, when read `e.data`
var messageEvent = new MessageEvent(event)
if (
('key' in messageEvent)
&& ('sourceChannel' in messageEvent)
&& transport.name === messageEvent.sourceChannel //events on the same channel
&& transport.key !== messageEvent.key //skip returned back events
) {
handler(messageEvent)
}
}
getNWWindowThen(function () {
var port = transport.port
port.removeEventListener(Transport.EVENT_TYPE, transport.listener)
port.addEventListener(Transport.EVENT_TYPE, listener)
transport.listener = listener
})
},
close: function () {
var transport = this
getNWWindowThen(function (nwWindow) {
transport.port.removeEventListener(Transport.EVENT_TYPE, transport.listener)
transport.listener = null
nwWindow.removeListener('loaded', transport.nwLoadedListener)
})
}
}
//computed `this.port`
Object.defineProperty(Transport.prototype, 'port', {
get: function () {
return global.window
},
set: function (value) { }
})
module.exports = Transport