mirror of
https://github.com/Hopiu/postal.js.git
synced 2026-04-26 09:34:47 +00:00
Created Replay panel, refactored bus/postal, re-organized file structure, etc.
This commit is contained in:
parent
f96f4eb485
commit
e3bd1d64fe
30 changed files with 1156 additions and 697 deletions
|
|
@ -1,4 +0,0 @@
|
|||
src/misc.js
|
||||
src/MessageCaptor.js
|
||||
src/ReplayContext.js
|
||||
src/Postal.js
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
src/misc.js
|
||||
src/MessageCaptor.js
|
||||
src/ReplayContext.js
|
||||
src/Bus.js
|
||||
src/Postal.js
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
var postal = global.postal = new Postal();
|
||||
global.postal = postal;
|
||||
|
||||
postal.DEFAULT_EXCHANGE = DEFAULT_EXCHANGE;
|
||||
postal.SYSTEM_EXCHANGE = SYSTEM_EXCHANGE;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
var postal = new Postal();
|
||||
|
||||
postal.DEFAULT_EXCHANGE = DEFAULT_EXCHANGE;
|
||||
postal.SYSTEM_EXCHANGE = SYSTEM_EXCHANGE;
|
||||
postal.NORMAL_MODE = NORMAL_MODE;
|
||||
|
|
|
|||
2
build/boilerplate/replay_footer.txt
Normal file
2
build/boilerplate/replay_footer.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
})(window);
|
||||
2
build/boilerplate/replay_header.txt
Normal file
2
build/boilerplate/replay_header.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
(function(global, undefined) {
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
./linux-build-node.sh
|
||||
./linux-build-browser.sh
|
||||
./linux-build-browser.sh
|
||||
./linux-build-browser-replay.sh
|
||||
14
build/linux-build-browser-replay.sh
Executable file
14
build/linux-build-browser-replay.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
|
||||
OutFile='output/browser/postal.replay.js'
|
||||
|
||||
cp version-header.js $OutFile
|
||||
|
||||
cat ./boilerplate/replay_header.txt >> $OutFile
|
||||
|
||||
# Combine the source files
|
||||
while read line; do
|
||||
cat ../$line >> $OutFile
|
||||
done < source-browser-replay.txt
|
||||
|
||||
cat ./boilerplate/replay_footer.txt >> $OutFile
|
||||
|
|
@ -9,6 +9,6 @@ cat ./boilerplate/browser_header.txt >> $OutFile
|
|||
# Combine the source files
|
||||
while read line; do
|
||||
cat ../$line >> $OutFile
|
||||
done < SourceManifest-browser.txt
|
||||
done < source-browser-postal.txt
|
||||
|
||||
cat ./boilerplate/browser_footer.txt >> $OutFile
|
||||
|
|
@ -35,104 +35,7 @@ var isArray = function(value) {
|
|||
}
|
||||
};
|
||||
|
||||
var MessageCaptor = function(plugUp, unPlug) {
|
||||
var _grabMsg = function(data) {
|
||||
// We need to ignore system messages, since they could involve captures, replays, etc.
|
||||
if(data.exchange !== SYSTEM_EXCHANGE) {
|
||||
this.messages.push(data);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
plugUp(_grabMsg);
|
||||
|
||||
this.messages = [];
|
||||
|
||||
this.save = function(batchId, description) {
|
||||
unPlug(_grabMsg);
|
||||
var captureStore = amplify.store(POSTAL_MSG_STORE_KEY);
|
||||
if(!captureStore) {
|
||||
captureStore = {};
|
||||
}
|
||||
captureStore[batchId] = {
|
||||
batchId: batchId,
|
||||
description: description,
|
||||
messages: this.messages
|
||||
};
|
||||
amplify.store(POSTAL_MSG_STORE_KEY, captureStore);
|
||||
};
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "captor.save", function(data) {
|
||||
this.save(data.batchId || new Date().toString(),
|
||||
data.description || "Captured Message Batch");
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
var ReplayContext = function (publish, subscribe) {
|
||||
var _batch,
|
||||
_continue = true,
|
||||
_loadMessages = function(batchId) {
|
||||
var msgStore = amplify.store(POSTAL_MSG_STORE_KEY),
|
||||
targetBatch = msgStore[batchId];
|
||||
if(targetBatch) {
|
||||
targetBatch.messages.forEach(function(msg) {
|
||||
msg.timeStamp = new Date(msg.timeStamp);
|
||||
});
|
||||
_batch = targetBatch;
|
||||
}
|
||||
},
|
||||
_replayImmediate = function() {
|
||||
while(_batch.messages.length > 0) {
|
||||
if(_continue) {
|
||||
_advanceNext();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
_advanceNext = function() {
|
||||
var msg = _batch.messages.shift();
|
||||
publish(msg.exchange, msg.topic, msg.data);
|
||||
},
|
||||
_replayRealTime = function() {
|
||||
if(_continue && _batch.messages.length > 0) {
|
||||
if(_batch.messages.length > 1) {
|
||||
var span = _batch.messages[1].timeStamp - _batch.messages[0].timeStamp;
|
||||
_advanceNext();
|
||||
setTimeout(_replayRealTime, span);
|
||||
}
|
||||
else {
|
||||
_advanceNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.load", function(data) {
|
||||
_continue = false;
|
||||
_loadMessages(data);
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.immediate", function() {
|
||||
_continue = true;
|
||||
_replayImmediate();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.advanceNext", function() {
|
||||
_continue = true;
|
||||
_advanceNext();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.realTime", function() {
|
||||
_continue = true;
|
||||
_replayRealTime();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.stop", function() {
|
||||
_continue = false;
|
||||
});
|
||||
};
|
||||
|
||||
var Postal = function() {
|
||||
var Bus = function() {
|
||||
var _regexify = function(topic) {
|
||||
if(!this.cache[topic]) {
|
||||
this.cache[topic] = topic.replace(".", "\.").replace("*", ".*");
|
||||
|
|
@ -146,42 +49,69 @@ var Postal = function() {
|
|||
(topic.indexOf("*") !== -1 && comparison.search(_regexify(topic)) !== -1);
|
||||
}
|
||||
return this.cache[topic + '_' + comparison];
|
||||
}.bind(this),
|
||||
_publish = function(exchange, topic, data) {
|
||||
this.wireTaps.forEach(function(tap) {
|
||||
tap({
|
||||
exchange: exchange,
|
||||
topic: topic,
|
||||
data: data,
|
||||
timeStamp: new Date()
|
||||
});
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
_forEachKeyValue(this.subscriptions[exchange],function(subTpc, subs) {
|
||||
if(_isTopicMatch(topic, subTpc)) {
|
||||
subs.forEach(function(sub) {
|
||||
if(typeof sub.callback === 'function') {
|
||||
sub.callback(data);
|
||||
sub.onFired();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}.bind(this),
|
||||
_mode = NORMAL_MODE,
|
||||
_replayContext,
|
||||
_captor;
|
||||
this.context = undefined;
|
||||
|
||||
this.cache = {};
|
||||
|
||||
this.getMode = function() { return _mode; };
|
||||
|
||||
this.wireTaps = [];
|
||||
|
||||
this.subscriptions = {};
|
||||
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
|
||||
this.publish = function(exchange, topic, data) {
|
||||
this.wireTaps.forEach(function(tap) {
|
||||
tap({
|
||||
exchange: exchange,
|
||||
topic: topic,
|
||||
data: data,
|
||||
timeStamp: new Date()
|
||||
});
|
||||
});
|
||||
|
||||
_forEachKeyValue(this.subscriptions[exchange],function(subTpc, subs) {
|
||||
if(_isTopicMatch(topic, subTpc)) {
|
||||
subs.forEach(function(sub) {
|
||||
if(typeof sub.callback === 'function') {
|
||||
sub.callback.apply(sub.context, [data]);
|
||||
sub.onFired();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.mode = NORMAL_MODE;
|
||||
|
||||
this[NORMAL_MODE] = {
|
||||
setup: function() {
|
||||
this.mode = NORMAL_MODE;
|
||||
this.context = undefined;
|
||||
},
|
||||
teardown: function() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
this.init = function() {
|
||||
this[NORMAL_MODE]();
|
||||
var systemEx = this.subscriptions[SYSTEM_EXCHANGE] || {};
|
||||
this.subscriptions = {};
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
this.subscriptions[SYSTEM_EXCHANGE] = systemEx;
|
||||
this.cache = {};
|
||||
this.wireTaps = [];
|
||||
};
|
||||
};
|
||||
|
||||
var bus = new Bus();
|
||||
|
||||
var Postal = function() {
|
||||
|
||||
this.getMode = function() { return bus.mode; };
|
||||
|
||||
/*
|
||||
options object has the following optional members:
|
||||
{
|
||||
|
|
@ -196,10 +126,10 @@ var Postal = function() {
|
|||
_topicList, // we allow multiple topics to be subscribed in one call.,
|
||||
_once = false,
|
||||
_subData = {
|
||||
callback: function() { /* placeholder noop */ },
|
||||
callback: function() { /* placeholder no-op */ },
|
||||
priority: 50,
|
||||
context: null,
|
||||
onFired: function() { /* noop */ }
|
||||
onFired: function() { /* placeholder no-op */ }
|
||||
},
|
||||
_idx,
|
||||
_found;
|
||||
|
|
@ -237,26 +167,26 @@ var Postal = function() {
|
|||
}.bind(this);
|
||||
}
|
||||
|
||||
if(!this.subscriptions[_exchange]) {
|
||||
this.subscriptions[_exchange] = {};
|
||||
if(!bus.subscriptions[_exchange]) {
|
||||
bus.subscriptions[_exchange] = {};
|
||||
}
|
||||
|
||||
_topicList.forEach(function(tpc) {
|
||||
if(!this.subscriptions[_exchange][tpc]) {
|
||||
this.subscriptions[_exchange][tpc] = [_subData];
|
||||
if(!bus.subscriptions[_exchange][tpc]) {
|
||||
bus.subscriptions[_exchange][tpc] = [_subData];
|
||||
}
|
||||
else {
|
||||
_idx = this.subscriptions[_exchange][tpc].length - 1;
|
||||
if(this.subscriptions[_exchange][tpc].filter(function(sub) { return sub === callback; }).length === 0) {
|
||||
_idx = bus.subscriptions[_exchange][tpc].length - 1;
|
||||
if(bus.subscriptions[_exchange][tpc].filter(function(sub) { return sub === callback; }).length === 0) {
|
||||
for(; _idx >= 0; _idx--) {
|
||||
if(this.subscriptions[_exchange][tpc][_idx].priority <= _subData.priority) {
|
||||
this.subscriptions[_exchange][tpc].splice(_idx + 1, 0, _subData);
|
||||
if(bus.subscriptions[_exchange][tpc][_idx].priority <= _subData.priority) {
|
||||
bus.subscriptions[_exchange][tpc].splice(_idx + 1, 0, _subData);
|
||||
_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!_found) {
|
||||
this.subscriptions[_exchange][tpc].unshift(_subData);
|
||||
bus.subscriptions[_exchange][tpc].unshift(_subData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -286,12 +216,12 @@ var Postal = function() {
|
|||
}
|
||||
|
||||
_topicList.forEach(function(tpc) {
|
||||
if(this.subscriptions[_exchange][tpc]) {
|
||||
var _len = this.subscriptions[_exchange][tpc].length,
|
||||
if(bus.subscriptions[_exchange][tpc]) {
|
||||
var _len = bus.subscriptions[_exchange][tpc].length,
|
||||
_idx = 0;
|
||||
for ( ; _idx < _len; _idx++ ) {
|
||||
if (this.subscriptions[_exchange][tpc][_idx].callback === callback) {
|
||||
this.subscriptions[_exchange][tpc].splice( _idx, 1 );
|
||||
if (bus.subscriptions[_exchange][tpc][_idx].callback === callback) {
|
||||
bus.subscriptions[_exchange][tpc].splice( _idx, 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -324,46 +254,54 @@ var Postal = function() {
|
|||
_topicList = topic.split(/\s/);
|
||||
_data = data || {};
|
||||
}
|
||||
if(_mode !== REPLAY_MODE || (_mode === REPLAY_MODE && _exchange === SYSTEM_EXCHANGE)) {
|
||||
if(bus.mode !== REPLAY_MODE || (bus.mode === REPLAY_MODE && _exchange === SYSTEM_EXCHANGE)) {
|
||||
|
||||
_topicList.forEach(function(tpc){
|
||||
_publish(_exchange, tpc, _data);
|
||||
bus.publish(_exchange, tpc, _data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.reset = function() {
|
||||
bus.init();
|
||||
};
|
||||
|
||||
this.addBusBehavior = function(behaviorName, setup, teardown) {
|
||||
if(!bus[behaviorName]) {
|
||||
bus[behaviorName] = {};
|
||||
}
|
||||
bus[behaviorName].setup = function() {
|
||||
bus.mode = behaviorName;
|
||||
setup(bus);
|
||||
};
|
||||
if(teardown) {
|
||||
bus[behaviorName].teardown = function() { teardown(bus); }
|
||||
}
|
||||
else {
|
||||
bus[behaviorName].teardown = function() { /* no-op */ }
|
||||
}
|
||||
};
|
||||
|
||||
this.subscribe(SYSTEM_EXCHANGE, "mode.set", function(data) {
|
||||
if(data.mode) {
|
||||
switch(data.mode) {
|
||||
case REPLAY_MODE:
|
||||
_mode = REPLAY_MODE;
|
||||
_replayContext = new ReplayContext(_publish.bind(this), this.subscribe.bind(this));
|
||||
_captor = undefined;
|
||||
break;
|
||||
case CAPTURE_MODE:
|
||||
_mode = CAPTURE_MODE;
|
||||
_captor = new MessageCaptor(function(callback){
|
||||
this.wireTaps.push(callback);
|
||||
}.bind(this),
|
||||
function(callback) {
|
||||
var idx = this.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
this.wireTaps.splice(idx,1);
|
||||
}
|
||||
}.bind(this));
|
||||
break;
|
||||
default:
|
||||
_mode = NORMAL_MODE;
|
||||
_replayContext = undefined;
|
||||
_captor = undefined;
|
||||
break;
|
||||
}
|
||||
if(data.mode && bus[data.mode]) {
|
||||
bus[bus.mode].teardown();
|
||||
bus[data.mode].setup(data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.addWireTap = function(callback) {
|
||||
bus.wireTaps.push(callback);
|
||||
return function() {
|
||||
var idx = bus.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
bus.wireTaps.splice(idx,1);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var postal = global.postal = new Postal();
|
||||
var postal = new Postal();
|
||||
global.postal = postal;
|
||||
|
||||
postal.DEFAULT_EXCHANGE = DEFAULT_EXCHANGE;
|
||||
postal.SYSTEM_EXCHANGE = SYSTEM_EXCHANGE;
|
||||
|
|
|
|||
238
build/output/browser/postal.replay.js
Normal file
238
build/output/browser/postal.replay.js
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
postal.js
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.0.1
|
||||
*/
|
||||
|
||||
(function(global, undefined) {
|
||||
|
||||
var _forEachKeyValue = function(object, callback) {
|
||||
for(var x in object) {
|
||||
if(object.hasOwnProperty(x)) {
|
||||
callback(x, object[x]);
|
||||
}
|
||||
}
|
||||
},
|
||||
_subscriptions = [];
|
||||
|
||||
var ReplayContext = function (bus) {
|
||||
var _batch,
|
||||
_continue = true,
|
||||
_loadMessages = function(batchId) {
|
||||
var msgStore = amplify.store(postal.POSTAL_MSG_STORE_KEY),
|
||||
targetBatch;
|
||||
|
||||
if(msgStore[window.location.pathname] && msgStore[window.location.pathname][batchId]) {
|
||||
targetBatch = msgStore[window.location.pathname][batchId];
|
||||
targetBatch.messages.forEach(function(msg) {
|
||||
msg.timeStamp = new Date(msg.timeStamp);
|
||||
});
|
||||
_batch = msgStore[window.location.pathname][batchId];
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.batchLoaded", { batchId: batchId,
|
||||
description: targetBatch.description,
|
||||
msgCount: targetBatch.messages.length });
|
||||
}
|
||||
},
|
||||
_batchListCache = [],
|
||||
_remoteConfigured = false,
|
||||
_replayImmediate = function() {
|
||||
if(_batch) {
|
||||
while(_batch.messages.length > 0) {
|
||||
if(_continue) {
|
||||
_advanceNext();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_advanceNext = function() {
|
||||
if(_batch && _batch.messages.length > 0) {
|
||||
var msg = _batch.messages.shift();
|
||||
bus.publish(msg.exchange, msg.topic, msg.data);
|
||||
}
|
||||
},
|
||||
_replayRealTime = function() {
|
||||
if(_continue && _batch && _batch.messages.length > 0) {
|
||||
if(_batch.messages.length > 1) {
|
||||
var span = _batch.messages[1].timeStamp - _batch.messages[0].timeStamp;
|
||||
_advanceNext();
|
||||
setTimeout(_replayRealTime, span);
|
||||
}
|
||||
else {
|
||||
_advanceNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.init = function() {
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.immediate", function() {
|
||||
_continue = true;
|
||||
_replayImmediate();
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.advanceNext", function() {
|
||||
_continue = true;
|
||||
_advanceNext();
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.realTime", function() {
|
||||
_continue = true;
|
||||
_replayRealTime();
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.stop", function() {
|
||||
_continue = false;
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.loadBatch", function(data) {
|
||||
if(data.batchId) {
|
||||
_continue = false;
|
||||
_loadMessages(data.batchId);
|
||||
}
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.refreshLocal", function(data){
|
||||
var local = amplify.store(postal.POSTAL_MSG_STORE_KEY) || {},
|
||||
batches = [];
|
||||
if(local && local[window.location.pathname]) {
|
||||
_forEachKeyValue(local[window.location.pathname], function(k, v) {
|
||||
batches.push({ batchId: v.batchId,
|
||||
description: v.description,
|
||||
messageCount: v.messages.length,
|
||||
source: "local"
|
||||
});
|
||||
});
|
||||
}
|
||||
_batchListCache = _batchListCache.filter(function(x) { return x.source !== "local"; })
|
||||
.concat(batches);
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.batchList", _batchListCache);
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.refreshRemote", function(data) {
|
||||
if(_remoteConfigured) {
|
||||
amplify.request("getRemoteCaptures", function(data) {
|
||||
if(data.batches) {
|
||||
_batchListCache = _batchListCache.filter(function(x) { return x.source !== 'remote'; });
|
||||
_batchListCache = _batchListCache.concat(data.batches.map(function(x) {
|
||||
x.source = "remote";
|
||||
return x;
|
||||
}));
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.batchList", _batchListCache);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.remote.config", function(data) {
|
||||
if(amplify) {
|
||||
amplify.request.define("getRemoteCaptures", "ajax", {
|
||||
"url": data.url,
|
||||
"dataType": "json",
|
||||
"type": data.method,
|
||||
"contentType" : "application/json"
|
||||
});
|
||||
_remoteConfigured = true;
|
||||
}
|
||||
else {
|
||||
throw "Amplify.js is required in order to access remote captured batches."
|
||||
}
|
||||
}));
|
||||
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.refreshLocal");
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.refreshRemote");
|
||||
};
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
// Adding replay functionality to the bus.....
|
||||
postal.addBusBehavior(postal.REPLAY_MODE,
|
||||
function(bus) {
|
||||
postal.replay.render();
|
||||
return new ReplayContext(bus);
|
||||
},
|
||||
function(bus) {
|
||||
postal.replay.hide();
|
||||
_subscriptions.forEach(function(remove) { remove(); });
|
||||
});
|
||||
|
||||
var ReplayPanel = function() {
|
||||
var _rendered = false,
|
||||
_style = '.postal-replay-wrapper { font-family: Tahoma, Arial; font-size: 10pt; float: left; vertical-align: middle; margin: 0px; padding: 0px; position: fixed; left: 0px; top: 0px; width: 100%; background-color: steelblue; color: white; } .postal-replay-title { float: left; margin-top: 4px; margin-left: 5px; margin-right: 15px; font-weight: bold; font-size: 11pt; height: 100%; } .postal-replay-button { float: left; } .postal-replay-dropdown { width: 150px; } .postal-replay-load { float: right; } .postal-replay-load select { float: left; margin-right: 10px; } #currentBatch { margin-top: 4px; margin-left: 20px; font-size: 10pt; font-weight: bold; float: left; } .postal-replay-exit { margin-left:35px; }',
|
||||
_html = '<div class="postal-replay-title">Postal Replay</div> <input class="postal-replay-button" type="button" id="btnRealTime" value="Play" alt="Real Time Playback" onclick="postal.replay.replayRealTime()"> <input class="postal-replay-button" type="button" id="btnStop" value="Stop" onclick="postal.replay.replayStop()"> <input class="postal-replay-button" type="button" id="btnAdvance" value="Step" alt="Advances to Next Msg (manual progression)" onclick="postal.replay.replayAdvance()"> <input class="postal-replay-button" type="button" id="btnImmediate" value="Immediate" alt="Replays all Messages Immediately" onclick="postal.replay.replayImmediate()"> <div id="currentBatch"></div> <div class="postal-replay-load"> <select class="postal-replay-dropdown" id="drpBatches"></select> <input class="postal-replay-button" type="button" id="btnLoad" value="Load Batch" onclick="postal.replay.loadBatch()"> <input class="postal-replay-button postal-replay-exit" type="button" id="btnExitReplay" value="Exit Replay Mode" onclick="postal.replay.exitReplay()"></div>';
|
||||
|
||||
this.exitReplay = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "mode.set", { mode: postal.NORMAL_MODE });
|
||||
};
|
||||
|
||||
this.replayRealTime = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.realTime");
|
||||
};
|
||||
|
||||
this.replayImmediate = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.immediate");
|
||||
};
|
||||
|
||||
this.replayAdvance = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.advanceNext");
|
||||
};
|
||||
|
||||
this.replayStop = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.stop");
|
||||
};
|
||||
|
||||
this.loadBatch = function() {
|
||||
var batchId = document.getElementById("drpBatches").value;
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.loadBatch", { batchId: batchId });
|
||||
};
|
||||
|
||||
postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.batchLoaded", function(data) {
|
||||
var text = "Replaying: " + data.batchId + " (" + data.description + ") " + data.msgCount + " message(s)";
|
||||
document.getElementById("currentBatch").innerText = text;
|
||||
});
|
||||
|
||||
postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.batchList", function(data) {
|
||||
var dropDown = document.getElementById("drpBatches"),
|
||||
optElem;
|
||||
dropDown.options.remove();
|
||||
if(data) {
|
||||
data.forEach(function(item) {
|
||||
optElem = document.createElement("option");
|
||||
optElem.value = item.batchId;
|
||||
optElem.text = item.batchId
|
||||
dropDown.options.add(optElem);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.render = function() {
|
||||
if(!_rendered){
|
||||
var style = document.createElement("style");
|
||||
style.innerText = _style;
|
||||
document.getElementsByTagName("head")[0].appendChild(style);
|
||||
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.setAttribute("class", "postal-replay-wrapper");
|
||||
wrapper.setAttribute("id", "replay-wrapper");
|
||||
wrapper.innerHTML = _html;
|
||||
document.body.appendChild(wrapper);
|
||||
_rendered = true;
|
||||
}
|
||||
else {
|
||||
document.getElementById("replay-wrapper").hidden = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.hide = function() {
|
||||
document.getElementById("replay-wrapper").hidden = true;
|
||||
};
|
||||
};
|
||||
|
||||
postal.replay = new ReplayPanel();
|
||||
|
||||
|
||||
})(window);
|
||||
|
|
@ -33,104 +33,7 @@ var isArray = function(value) {
|
|||
}
|
||||
};
|
||||
|
||||
var MessageCaptor = function(plugUp, unPlug) {
|
||||
var _grabMsg = function(data) {
|
||||
// We need to ignore system messages, since they could involve captures, replays, etc.
|
||||
if(data.exchange !== SYSTEM_EXCHANGE) {
|
||||
this.messages.push(data);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
plugUp(_grabMsg);
|
||||
|
||||
this.messages = [];
|
||||
|
||||
this.save = function(batchId, description) {
|
||||
unPlug(_grabMsg);
|
||||
var captureStore = amplify.store(POSTAL_MSG_STORE_KEY);
|
||||
if(!captureStore) {
|
||||
captureStore = {};
|
||||
}
|
||||
captureStore[batchId] = {
|
||||
batchId: batchId,
|
||||
description: description,
|
||||
messages: this.messages
|
||||
};
|
||||
amplify.store(POSTAL_MSG_STORE_KEY, captureStore);
|
||||
};
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "captor.save", function(data) {
|
||||
this.save(data.batchId || new Date().toString(),
|
||||
data.description || "Captured Message Batch");
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
var ReplayContext = function (publish, subscribe) {
|
||||
var _batch,
|
||||
_continue = true,
|
||||
_loadMessages = function(batchId) {
|
||||
var msgStore = amplify.store(POSTAL_MSG_STORE_KEY),
|
||||
targetBatch = msgStore[batchId];
|
||||
if(targetBatch) {
|
||||
targetBatch.messages.forEach(function(msg) {
|
||||
msg.timeStamp = new Date(msg.timeStamp);
|
||||
});
|
||||
_batch = targetBatch;
|
||||
}
|
||||
},
|
||||
_replayImmediate = function() {
|
||||
while(_batch.messages.length > 0) {
|
||||
if(_continue) {
|
||||
_advanceNext();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
_advanceNext = function() {
|
||||
var msg = _batch.messages.shift();
|
||||
publish(msg.exchange, msg.topic, msg.data);
|
||||
},
|
||||
_replayRealTime = function() {
|
||||
if(_continue && _batch.messages.length > 0) {
|
||||
if(_batch.messages.length > 1) {
|
||||
var span = _batch.messages[1].timeStamp - _batch.messages[0].timeStamp;
|
||||
_advanceNext();
|
||||
setTimeout(_replayRealTime, span);
|
||||
}
|
||||
else {
|
||||
_advanceNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.load", function(data) {
|
||||
_continue = false;
|
||||
_loadMessages(data);
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.immediate", function() {
|
||||
_continue = true;
|
||||
_replayImmediate();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.advanceNext", function() {
|
||||
_continue = true;
|
||||
_advanceNext();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.realTime", function() {
|
||||
_continue = true;
|
||||
_replayRealTime();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.stop", function() {
|
||||
_continue = false;
|
||||
});
|
||||
};
|
||||
|
||||
var Postal = function() {
|
||||
var Bus = function() {
|
||||
var _regexify = function(topic) {
|
||||
if(!this.cache[topic]) {
|
||||
this.cache[topic] = topic.replace(".", "\.").replace("*", ".*");
|
||||
|
|
@ -144,42 +47,69 @@ var Postal = function() {
|
|||
(topic.indexOf("*") !== -1 && comparison.search(_regexify(topic)) !== -1);
|
||||
}
|
||||
return this.cache[topic + '_' + comparison];
|
||||
}.bind(this),
|
||||
_publish = function(exchange, topic, data) {
|
||||
this.wireTaps.forEach(function(tap) {
|
||||
tap({
|
||||
exchange: exchange,
|
||||
topic: topic,
|
||||
data: data,
|
||||
timeStamp: new Date()
|
||||
});
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
_forEachKeyValue(this.subscriptions[exchange],function(subTpc, subs) {
|
||||
if(_isTopicMatch(topic, subTpc)) {
|
||||
subs.forEach(function(sub) {
|
||||
if(typeof sub.callback === 'function') {
|
||||
sub.callback(data);
|
||||
sub.onFired();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}.bind(this),
|
||||
_mode = NORMAL_MODE,
|
||||
_replayContext,
|
||||
_captor;
|
||||
this.context = undefined;
|
||||
|
||||
this.cache = {};
|
||||
|
||||
this.getMode = function() { return _mode; };
|
||||
|
||||
this.wireTaps = [];
|
||||
|
||||
this.subscriptions = {};
|
||||
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
|
||||
this.publish = function(exchange, topic, data) {
|
||||
this.wireTaps.forEach(function(tap) {
|
||||
tap({
|
||||
exchange: exchange,
|
||||
topic: topic,
|
||||
data: data,
|
||||
timeStamp: new Date()
|
||||
});
|
||||
});
|
||||
|
||||
_forEachKeyValue(this.subscriptions[exchange],function(subTpc, subs) {
|
||||
if(_isTopicMatch(topic, subTpc)) {
|
||||
subs.forEach(function(sub) {
|
||||
if(typeof sub.callback === 'function') {
|
||||
sub.callback.apply(sub.context, [data]);
|
||||
sub.onFired();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.mode = NORMAL_MODE;
|
||||
|
||||
this[NORMAL_MODE] = {
|
||||
setup: function() {
|
||||
this.mode = NORMAL_MODE;
|
||||
this.context = undefined;
|
||||
},
|
||||
teardown: function() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
this.init = function() {
|
||||
this[NORMAL_MODE]();
|
||||
var systemEx = this.subscriptions[SYSTEM_EXCHANGE] || {};
|
||||
this.subscriptions = {};
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
this.subscriptions[SYSTEM_EXCHANGE] = systemEx;
|
||||
this.cache = {};
|
||||
this.wireTaps = [];
|
||||
};
|
||||
};
|
||||
|
||||
var bus = new Bus();
|
||||
|
||||
var Postal = function() {
|
||||
|
||||
this.getMode = function() { return bus.mode; };
|
||||
|
||||
/*
|
||||
options object has the following optional members:
|
||||
{
|
||||
|
|
@ -194,10 +124,10 @@ var Postal = function() {
|
|||
_topicList, // we allow multiple topics to be subscribed in one call.,
|
||||
_once = false,
|
||||
_subData = {
|
||||
callback: function() { /* placeholder noop */ },
|
||||
callback: function() { /* placeholder no-op */ },
|
||||
priority: 50,
|
||||
context: null,
|
||||
onFired: function() { /* noop */ }
|
||||
onFired: function() { /* placeholder no-op */ }
|
||||
},
|
||||
_idx,
|
||||
_found;
|
||||
|
|
@ -235,26 +165,26 @@ var Postal = function() {
|
|||
}.bind(this);
|
||||
}
|
||||
|
||||
if(!this.subscriptions[_exchange]) {
|
||||
this.subscriptions[_exchange] = {};
|
||||
if(!bus.subscriptions[_exchange]) {
|
||||
bus.subscriptions[_exchange] = {};
|
||||
}
|
||||
|
||||
_topicList.forEach(function(tpc) {
|
||||
if(!this.subscriptions[_exchange][tpc]) {
|
||||
this.subscriptions[_exchange][tpc] = [_subData];
|
||||
if(!bus.subscriptions[_exchange][tpc]) {
|
||||
bus.subscriptions[_exchange][tpc] = [_subData];
|
||||
}
|
||||
else {
|
||||
_idx = this.subscriptions[_exchange][tpc].length - 1;
|
||||
if(this.subscriptions[_exchange][tpc].filter(function(sub) { return sub === callback; }).length === 0) {
|
||||
_idx = bus.subscriptions[_exchange][tpc].length - 1;
|
||||
if(bus.subscriptions[_exchange][tpc].filter(function(sub) { return sub === callback; }).length === 0) {
|
||||
for(; _idx >= 0; _idx--) {
|
||||
if(this.subscriptions[_exchange][tpc][_idx].priority <= _subData.priority) {
|
||||
this.subscriptions[_exchange][tpc].splice(_idx + 1, 0, _subData);
|
||||
if(bus.subscriptions[_exchange][tpc][_idx].priority <= _subData.priority) {
|
||||
bus.subscriptions[_exchange][tpc].splice(_idx + 1, 0, _subData);
|
||||
_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!_found) {
|
||||
this.subscriptions[_exchange][tpc].unshift(_subData);
|
||||
bus.subscriptions[_exchange][tpc].unshift(_subData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -284,12 +214,12 @@ var Postal = function() {
|
|||
}
|
||||
|
||||
_topicList.forEach(function(tpc) {
|
||||
if(this.subscriptions[_exchange][tpc]) {
|
||||
var _len = this.subscriptions[_exchange][tpc].length,
|
||||
if(bus.subscriptions[_exchange][tpc]) {
|
||||
var _len = bus.subscriptions[_exchange][tpc].length,
|
||||
_idx = 0;
|
||||
for ( ; _idx < _len; _idx++ ) {
|
||||
if (this.subscriptions[_exchange][tpc][_idx].callback === callback) {
|
||||
this.subscriptions[_exchange][tpc].splice( _idx, 1 );
|
||||
if (bus.subscriptions[_exchange][tpc][_idx].callback === callback) {
|
||||
bus.subscriptions[_exchange][tpc].splice( _idx, 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -322,47 +252,53 @@ var Postal = function() {
|
|||
_topicList = topic.split(/\s/);
|
||||
_data = data || {};
|
||||
}
|
||||
if(_mode !== REPLAY_MODE || (_mode === REPLAY_MODE && _exchange === SYSTEM_EXCHANGE)) {
|
||||
if(bus.mode !== REPLAY_MODE || (bus.mode === REPLAY_MODE && _exchange === SYSTEM_EXCHANGE)) {
|
||||
|
||||
_topicList.forEach(function(tpc){
|
||||
_publish(_exchange, tpc, _data);
|
||||
bus.publish(_exchange, tpc, _data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.reset = function() {
|
||||
bus.init();
|
||||
};
|
||||
|
||||
this.addBusBehavior = function(behaviorName, setup, teardown) {
|
||||
if(!bus[behaviorName]) {
|
||||
bus[behaviorName] = {};
|
||||
}
|
||||
bus[behaviorName].setup = function() {
|
||||
bus.mode = behaviorName;
|
||||
setup(bus);
|
||||
};
|
||||
if(teardown) {
|
||||
bus[behaviorName].teardown = function() { teardown(bus); }
|
||||
}
|
||||
else {
|
||||
bus[behaviorName].teardown = function() { /* no-op */ }
|
||||
}
|
||||
};
|
||||
|
||||
this.subscribe(SYSTEM_EXCHANGE, "mode.set", function(data) {
|
||||
if(data.mode) {
|
||||
switch(data.mode) {
|
||||
case REPLAY_MODE:
|
||||
_mode = REPLAY_MODE;
|
||||
_replayContext = new ReplayContext(_publish.bind(this), this.subscribe.bind(this));
|
||||
_captor = undefined;
|
||||
break;
|
||||
case CAPTURE_MODE:
|
||||
_mode = CAPTURE_MODE;
|
||||
_captor = new MessageCaptor(function(callback){
|
||||
this.wireTaps.push(callback);
|
||||
}.bind(this),
|
||||
function(callback) {
|
||||
var idx = this.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
this.wireTaps.splice(idx,1);
|
||||
}
|
||||
}.bind(this));
|
||||
break;
|
||||
default:
|
||||
_mode = NORMAL_MODE;
|
||||
_replayContext = undefined;
|
||||
_captor = undefined;
|
||||
break;
|
||||
}
|
||||
if(data.mode && bus[data.mode]) {
|
||||
bus[bus.mode].teardown();
|
||||
bus[data.mode].setup(data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.addWireTap = function(callback) {
|
||||
bus.wireTaps.push(callback);
|
||||
return function() {
|
||||
var idx = bus.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
bus.wireTaps.splice(idx,1);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var postal = new Postal();
|
||||
|
||||
postal.DEFAULT_EXCHANGE = DEFAULT_EXCHANGE;
|
||||
postal.SYSTEM_EXCHANGE = SYSTEM_EXCHANGE;
|
||||
postal.NORMAL_MODE = NORMAL_MODE;
|
||||
|
|
|
|||
3
build/source-browser-postal.txt
Normal file
3
build/source-browser-postal.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
src/misc.js
|
||||
src/Bus.js
|
||||
src/Postal.js
|
||||
2
build/source-browser-replay.txt
Normal file
2
build/source-browser-replay.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
src/replay/ReplayContext.js
|
||||
src/replay/ReplayPanel.js
|
||||
|
|
@ -4,7 +4,7 @@ QUnit.specify("postal.js", function(){
|
|||
describe("broker", function(){
|
||||
describe("When publishing a message to a specific one level topic", function() {
|
||||
describe("with one recipient", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageReceived: false
|
||||
};
|
||||
|
|
@ -17,7 +17,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
describe("with two recipients", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var ObjA = function() {
|
||||
this.messageReceived = false;
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
describe("When publishing a message to a specific multi-level topic", function() {
|
||||
describe("with one recipient", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageReceived: false
|
||||
};
|
||||
|
|
@ -61,7 +61,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
describe("with two recipients", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var ObjA = function() {
|
||||
this.messageReceived = false;
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
describe("When publishing a wildcard message to a multi-level topic", function() {
|
||||
describe("with one recipient", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageReceived: false
|
||||
};
|
||||
|
|
@ -105,7 +105,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
describe("with two recipients", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var ObjA = function() {
|
||||
this.messageReceived = false;
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
describe("When unsubscribing using provided callback", function() {
|
||||
describe("with one callback", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
|
|
@ -151,7 +151,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
describe("with two callbacks", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var ObjA = function() {
|
||||
var _unsubscribe;
|
||||
|
||||
|
|
@ -197,10 +197,9 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("When publishing a message on a specific exchange", function(){
|
||||
describe("With a valid exchange", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
|
|
@ -215,7 +214,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
describe("With an invalid exchange", function() {
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
|
|
@ -231,7 +230,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
describe("With multiple active exchanges", function() {
|
||||
describe("Publishing only to one exchange", function(){
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
|
|
@ -255,7 +254,7 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
describe("Publishing to multiple exchanges", function(){
|
||||
postal = new Postal();
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
|
|
@ -283,154 +282,5 @@ QUnit.specify("postal.js", function(){
|
|||
});
|
||||
});
|
||||
});
|
||||
describe("With Mode Change Messages", function(){
|
||||
describe("Change To Replay", function() {
|
||||
postal = new Postal();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
mode;
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: REPLAY_MODE });
|
||||
mode = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only once", function(){
|
||||
assert(objA.messageCount).equals(1);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(REPLAY_MODE);
|
||||
});
|
||||
});
|
||||
describe("Change To Replay & Back to Normal", function() {
|
||||
postal = new Postal();
|
||||
var mode,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
mode2;
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: REPLAY_MODE });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
mode = postal.getMode();
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: NORMAL_MODE });
|
||||
mode2 = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only twice", function(){
|
||||
assert(objA.messageCount).equals(2);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(REPLAY_MODE);
|
||||
});
|
||||
|
||||
it("broker should report normal mode", function() {
|
||||
assert(mode2).equals(NORMAL_MODE);
|
||||
});
|
||||
});
|
||||
describe("Change To Replay & Then to Capture", function() {
|
||||
postal = new Postal();
|
||||
var mode,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
mode2;
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: REPLAY_MODE });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
mode = postal.getMode();
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: CAPTURE_MODE });
|
||||
mode2 = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only twice", function(){
|
||||
assert(objA.messageCount).equals(2);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(REPLAY_MODE);
|
||||
});
|
||||
|
||||
it("broker should report capture mode", function() {
|
||||
assert(mode2).equals(CAPTURE_MODE);
|
||||
});
|
||||
});
|
||||
describe("Change To Capture & Then to Normal", function() {
|
||||
postal = new Postal();
|
||||
var mode,
|
||||
mode2,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: CAPTURE_MODE });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
mode = postal.getMode();
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: NORMAL_MODE });
|
||||
mode2 = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only 3x", function(){
|
||||
assert(objA.messageCount).equals(3);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(CAPTURE_MODE);
|
||||
});
|
||||
|
||||
it("broker should report capture mode", function() {
|
||||
assert(mode2).equals(NORMAL_MODE);
|
||||
});
|
||||
});
|
||||
describe("Change To Capture", function() {
|
||||
postal = new Postal();
|
||||
var mode,
|
||||
savedBatch,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
objB = {
|
||||
messageCount: 0
|
||||
};
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
var unsubscribeB = postal.subscribe("MyExchangeB", "Test.*", function() { objB.messageCount++; });
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: CAPTURE_MODE });
|
||||
mode = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish("MyExchangeB", "Test.Topic", {});
|
||||
postal.publish("MyExchangeB", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
postal.publish(SYSTEM_EXCHANGE, "captor.save", { batchId: "MyMsgBatch", description: "Just a Test" });
|
||||
savedBatch = amplify.store(POSTAL_MSG_STORE_KEY)["MyMsgBatch"];
|
||||
|
||||
it("the subscription callback for objA should be invoked only twice", function(){
|
||||
assert(objA.messageCount).equals(2);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(CAPTURE_MODE);
|
||||
});
|
||||
|
||||
it("captured message batch should exist", function() {
|
||||
assert(savedBatch !== undefined).isTrue();
|
||||
})
|
||||
|
||||
it("captured message batch should have 4 messages", function() {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
74
spec/broker.withCapture.spec.js
Normal file
74
spec/broker.withCapture.spec.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
QUnit.specify("postal.js", function(){
|
||||
describe("broker", function(){
|
||||
describe("With Mode Change Messages", function(){
|
||||
describe("Change To Capture & Then to Normal", function() {
|
||||
postal = new Postal();
|
||||
var mode,
|
||||
mode2,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
};
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: CAPTURE_MODE });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
mode = postal.getMode();
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: NORMAL_MODE });
|
||||
mode2 = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only 3x", function(){
|
||||
assert(objA.messageCount).equals(3);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(CAPTURE_MODE);
|
||||
});
|
||||
|
||||
it("broker should report capture mode", function() {
|
||||
assert(mode2).equals(NORMAL_MODE);
|
||||
});
|
||||
});
|
||||
describe("Change To Capture", function() {
|
||||
postal = new Postal();
|
||||
var mode,
|
||||
savedBatch,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
objB = {
|
||||
messageCount: 0
|
||||
};
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
var unsubscribeB = postal.subscribe("MyExchangeB", "Test.*", function() { objB.messageCount++; });
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: CAPTURE_MODE });
|
||||
mode = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish("MyExchangeB", "Test.Topic", {});
|
||||
postal.publish("MyExchangeB", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
postal.publish(SYSTEM_EXCHANGE, "captor.save", { batchId: "MyMsgBatch", description: "Just a Test" });
|
||||
savedBatch = amplify.store(POSTAL_MSG_STORE_KEY)["MyMsgBatch"];
|
||||
|
||||
it("the subscription callback for objA should be invoked only twice", function(){
|
||||
assert(objA.messageCount).equals(2);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(CAPTURE_MODE);
|
||||
});
|
||||
|
||||
it("captured message batch should exist", function() {
|
||||
assert(savedBatch !== undefined).isTrue();
|
||||
})
|
||||
|
||||
it("captured message batch should have 4 messages", function() {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
56
spec/broker.withReplay.spec.js
Normal file
56
spec/broker.withReplay.spec.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
QUnit.specify("postal.js", function(){
|
||||
describe("broker", function(){
|
||||
describe("With Mode Change Messages", function(){
|
||||
describe("Change To Replay", function() {
|
||||
postal.reset();
|
||||
var objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
mode;
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: REPLAY_MODE });
|
||||
mode = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only once", function(){
|
||||
assert(objA.messageCount).equals(1);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(REPLAY_MODE);
|
||||
});
|
||||
});
|
||||
describe("Change To Replay & Back to Normal", function() {
|
||||
postal.reset();
|
||||
var mode,
|
||||
objA = {
|
||||
messageCount: 0
|
||||
},
|
||||
mode2;
|
||||
var unsubscribeA = postal.subscribe("MyExchangeA", "Test.*", function() { objA.messageCount++; });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: REPLAY_MODE });
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
mode = postal.getMode();
|
||||
postal.publish(SYSTEM_EXCHANGE, "mode.set", { mode: NORMAL_MODE });
|
||||
mode2 = postal.getMode();
|
||||
postal.publish("MyExchangeA", "Test.Topic", {});
|
||||
unsubscribeA();
|
||||
|
||||
it("the subscription callback for objA should be invoked only twice", function(){
|
||||
assert(objA.messageCount).equals(2);
|
||||
});
|
||||
|
||||
it("broker should report replay mode", function() {
|
||||
assert(mode).equals(REPLAY_MODE);
|
||||
});
|
||||
|
||||
it("broker should report normal mode", function() {
|
||||
assert(mode2).equals(NORMAL_MODE);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
22
spec/postal.core.html
Normal file
22
spec/postal.core.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="../lib/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="../lib/qunit.js"></script>
|
||||
<script type="text/javascript" src="../lib/pavlov.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.core.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.store.js"></script>
|
||||
<script type="text/javascript" src="../src/misc.js"></script>
|
||||
<script type="text/javascript" src="../src/Bus.js"></script>
|
||||
<script type="text/javascript" src="../src/Postal.js"></script>
|
||||
<script type="text/javascript" src="broker.spec.js"></script>
|
||||
<link rel="stylesheet" href="../lib/qunit.css" type="text/css" media="screen" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header"></h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
</body>
|
||||
</html>
|
||||
24
spec/postal.withCapture.html
Normal file
24
spec/postal.withCapture.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="../lib/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="../lib/qunit.js"></script>
|
||||
<script type="text/javascript" src="../lib/pavlov.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.core.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.store.js"></script>
|
||||
<script type="text/javascript" src="../src/misc.js"></script>
|
||||
<script type="text/javascript" src="../src/Bus.js"></script>
|
||||
<script type="text/javascript" src="../src/Postal.js"></script>
|
||||
<script type="text/javascript" src="../src/MessageCaptor.js"></script>
|
||||
<script type="text/javascript" src="broker.withCapture.spec.js"></script>
|
||||
<script type="text/javascript" src="broker.spec.js"></script>
|
||||
<link rel="stylesheet" href="../lib/qunit.css" type="text/css" media="screen" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header"></h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
</body>
|
||||
</html>
|
||||
26
spec/postal.withCapture_Replay.html
Normal file
26
spec/postal.withCapture_Replay.html
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="../lib/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="../lib/qunit.js"></script>
|
||||
<script type="text/javascript" src="../lib/pavlov.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.core.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.store.js"></script>
|
||||
<script type="text/javascript" src="../src/misc.js"></script>
|
||||
<script type="text/javascript" src="../src/Bus.js"></script>
|
||||
<script type="text/javascript" src="../src/Postal.js"></script>
|
||||
<script type="text/javascript" src="../src/replay/ReplayContext.js"></script>
|
||||
<script type="text/javascript" src="../src/MessageCaptor.js"></script>
|
||||
<script type="text/javascript" src="broker.withCapture.spec.js"></script>
|
||||
<script type="text/javascript" src="broker.withReplay.spec.js"></script>
|
||||
<script type="text/javascript" src="broker.spec.js"></script>
|
||||
<link rel="stylesheet" href="../lib/qunit.css" type="text/css" media="screen" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header"></h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
</body>
|
||||
</html>
|
||||
24
spec/postal.withReplay.html
Normal file
24
spec/postal.withReplay.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="../lib/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="../lib/qunit.js"></script>
|
||||
<script type="text/javascript" src="../lib/pavlov.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.core.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.store.js"></script>
|
||||
<script type="text/javascript" src="../src/misc.js"></script>
|
||||
<script type="text/javascript" src="../src/Bus.js"></script>
|
||||
<script type="text/javascript" src="../src/Postal.js"></script>
|
||||
<script type="text/javascript" src="../src/replay/ReplayContext.js"></script>
|
||||
<script type="text/javascript" src="broker.withReplay.spec.js"></script>
|
||||
<script type="text/javascript" src="broker.spec.js"></script>
|
||||
<link rel="stylesheet" href="../lib/qunit.css" type="text/css" media="screen" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header"></h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,26 +1,19 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="../lib/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="../lib/qunit.js"></script>
|
||||
<script type="text/javascript" src="../lib/pavlov.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.core.js"></script>
|
||||
<script type="text/javascript" src="../lib/amplify.store.js"></script>
|
||||
<script type="text/javascript" src="../src/misc.js"></script>
|
||||
<script type="text/javascript" src="../src/Postal.js"></script>
|
||||
<script type="text/javascript" src="../src/ReplayContext.js"></script>
|
||||
<script type="text/javascript" src="../src/MessageCaptor.js"></script>
|
||||
<script type="text/javascript">
|
||||
var postal = new Postal();
|
||||
</script>
|
||||
<script type="text/javascript" src="broker.spec.js"></script>
|
||||
<link rel="stylesheet" href="../lib/qunit.css" type="text/css" media="screen" />
|
||||
<script type="text/javascript">
|
||||
var core = window.open("postal.core.html","core");
|
||||
core.focus();
|
||||
var wCapture = window.open("postal.withCapture.html","wCapture");
|
||||
wCapture.focus();
|
||||
var wReplay = window.open("postal.withReplay.html","wReplay");
|
||||
wReplay.focus();
|
||||
var wCaptureReplay = window.open("postal.withCapture_Replay.html","wCaptureReplay");
|
||||
wCaptureReplay.focus();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header"></h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
73
src/Bus.js
Normal file
73
src/Bus.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
var Bus = function() {
|
||||
var _regexify = function(topic) {
|
||||
if(!this.cache[topic]) {
|
||||
this.cache[topic] = topic.replace(".", "\.").replace("*", ".*");
|
||||
}
|
||||
return this.cache[topic];
|
||||
}.bind(this),
|
||||
_isTopicMatch = function(topic, comparison) {
|
||||
if(!this.cache[topic + '_' + comparison]) {
|
||||
this.cache[topic + '_' + comparison] = topic === comparison ||
|
||||
(comparison.indexOf("*") !== -1 && topic.search(_regexify(comparison)) !== -1) ||
|
||||
(topic.indexOf("*") !== -1 && comparison.search(_regexify(topic)) !== -1);
|
||||
}
|
||||
return this.cache[topic + '_' + comparison];
|
||||
}.bind(this);
|
||||
|
||||
this.context = undefined;
|
||||
|
||||
this.cache = {};
|
||||
|
||||
this.wireTaps = [];
|
||||
|
||||
this.subscriptions = {};
|
||||
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
|
||||
this.publish = function(exchange, topic, data) {
|
||||
this.wireTaps.forEach(function(tap) {
|
||||
tap({
|
||||
exchange: exchange,
|
||||
topic: topic,
|
||||
data: data,
|
||||
timeStamp: new Date()
|
||||
});
|
||||
});
|
||||
|
||||
_forEachKeyValue(this.subscriptions[exchange],function(subTpc, subs) {
|
||||
if(_isTopicMatch(topic, subTpc)) {
|
||||
subs.forEach(function(sub) {
|
||||
if(typeof sub.callback === 'function') {
|
||||
sub.callback.apply(sub.context, [data]);
|
||||
sub.onFired();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.mode = NORMAL_MODE;
|
||||
|
||||
this[NORMAL_MODE] = {
|
||||
setup: function() {
|
||||
this.mode = NORMAL_MODE;
|
||||
this.context = undefined;
|
||||
},
|
||||
teardown: function() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
this.init = function() {
|
||||
this[NORMAL_MODE]();
|
||||
var systemEx = this.subscriptions[SYSTEM_EXCHANGE] || {};
|
||||
this.subscriptions = {};
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
this.subscriptions[SYSTEM_EXCHANGE] = systemEx;
|
||||
this.cache = {};
|
||||
this.wireTaps = [];
|
||||
};
|
||||
};
|
||||
|
||||
var bus = new Bus();
|
||||
|
||||
8
src/Diagnostics.js
Normal file
8
src/Diagnostics.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
postal.addWireTap(function(data) {
|
||||
try {
|
||||
console.log(JSON.stringify(data || {}));
|
||||
}
|
||||
catch(exception) {
|
||||
console.log("(Unable to show JSON data)");
|
||||
}
|
||||
});
|
||||
|
|
@ -1,32 +1,74 @@
|
|||
var MessageCaptor = function(plugUp, unPlug) {
|
||||
var MessageCaptor = function(bus) {
|
||||
var _grabMsg = function(data) {
|
||||
// We need to ignore system messages, since they could involve captures, replays, etc.
|
||||
if(data.exchange !== SYSTEM_EXCHANGE) {
|
||||
this.messages.push(data);
|
||||
}
|
||||
}.bind(this);
|
||||
}.bind(this),
|
||||
_remoteConfigured = false;
|
||||
|
||||
plugUp(_grabMsg);
|
||||
this.plugUp = function() {
|
||||
bus.wireTaps.push(_grabMsg);
|
||||
};
|
||||
|
||||
this.unPlug = function(callback) {
|
||||
var idx = bus.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
bus.wireTaps.splice(idx,1);
|
||||
}
|
||||
};
|
||||
|
||||
this.messages = [];
|
||||
|
||||
this.save = function(batchId, description) {
|
||||
unPlug(_grabMsg);
|
||||
var captureStore = amplify.store(POSTAL_MSG_STORE_KEY);
|
||||
if(!captureStore) {
|
||||
captureStore = {};
|
||||
this.save = function(location, batchId, description) {
|
||||
this.unPlug(_grabMsg);
|
||||
var batch = {
|
||||
batchId: batchId,
|
||||
description: description,
|
||||
messages: this.messages
|
||||
};
|
||||
if(location === 'remote') {
|
||||
amplify.request("saveRemoteCapture", batch, function(data) {
|
||||
postal.publish(SYSTEM_EXCHANGE, "replay.store.refreshRemote");
|
||||
});
|
||||
}
|
||||
else {
|
||||
var captureStore = amplify.store(POSTAL_MSG_STORE_KEY);
|
||||
if(!captureStore) {
|
||||
captureStore = {};
|
||||
}
|
||||
if(!captureStore[window.location.pathname]) {
|
||||
captureStore[window.location.pathname] = {};
|
||||
}
|
||||
captureStore[window.location.pathname][batchId] = batch;
|
||||
amplify.store(POSTAL_MSG_STORE_KEY, captureStore);
|
||||
postal.publish(SYSTEM_EXCHANGE, "replay.store.refreshLocal");
|
||||
}
|
||||
captureStore[batchId] = {
|
||||
batchId: batchId,
|
||||
description: description,
|
||||
messages: this.messages
|
||||
};
|
||||
amplify.store(POSTAL_MSG_STORE_KEY, captureStore);
|
||||
};
|
||||
|
||||
this.plugUp();
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "captor.save", function(data) {
|
||||
this.save(data.batchId || new Date().toString(),
|
||||
this.save(data.location || "local",
|
||||
data.batchId || new Date().toString(),
|
||||
data.description || "Captured Message Batch");
|
||||
}.bind(this));
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "captor.remote.config", function(data) {
|
||||
if(amplify) {
|
||||
amplify.request.define("saveRemoteCapture", "ajax", {
|
||||
"url": data.url,
|
||||
"dataType": "json",
|
||||
"type": data.method,
|
||||
"contentType" : "application/json"
|
||||
});
|
||||
_remoteConfigured = true;
|
||||
}
|
||||
else {
|
||||
throw "Amplify.js is required in order to save captured batches to a remote location."
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Adding replay functionality to the bus.....
|
||||
postal.addBusBehavior(CAPTURE_MODE, function(bus) { return new MessageCaptor(bus); });
|
||||
|
|
|
|||
141
src/Postal.js
141
src/Postal.js
|
|
@ -1,52 +1,6 @@
|
|||
var Postal = function() {
|
||||
var _regexify = function(topic) {
|
||||
if(!this.cache[topic]) {
|
||||
this.cache[topic] = topic.replace(".", "\.").replace("*", ".*");
|
||||
}
|
||||
return this.cache[topic];
|
||||
}.bind(this),
|
||||
_isTopicMatch = function(topic, comparison) {
|
||||
if(!this.cache[topic + '_' + comparison]) {
|
||||
this.cache[topic + '_' + comparison] = topic === comparison ||
|
||||
(comparison.indexOf("*") !== -1 && topic.search(_regexify(comparison)) !== -1) ||
|
||||
(topic.indexOf("*") !== -1 && comparison.search(_regexify(topic)) !== -1);
|
||||
}
|
||||
return this.cache[topic + '_' + comparison];
|
||||
}.bind(this),
|
||||
_publish = function(exchange, topic, data) {
|
||||
this.wireTaps.forEach(function(tap) {
|
||||
tap({
|
||||
exchange: exchange,
|
||||
topic: topic,
|
||||
data: data,
|
||||
timeStamp: new Date()
|
||||
});
|
||||
});
|
||||
|
||||
_forEachKeyValue(this.subscriptions[exchange],function(subTpc, subs) {
|
||||
if(_isTopicMatch(topic, subTpc)) {
|
||||
subs.forEach(function(sub) {
|
||||
if(typeof sub.callback === 'function') {
|
||||
sub.callback(data);
|
||||
sub.onFired();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}.bind(this),
|
||||
_mode = NORMAL_MODE,
|
||||
_replayContext,
|
||||
_captor;
|
||||
|
||||
this.cache = {};
|
||||
|
||||
this.getMode = function() { return _mode; };
|
||||
|
||||
this.wireTaps = [];
|
||||
|
||||
this.subscriptions = {};
|
||||
|
||||
this.subscriptions[DEFAULT_EXCHANGE] = {};
|
||||
this.getMode = function() { return bus.mode; };
|
||||
|
||||
/*
|
||||
options object has the following optional members:
|
||||
|
|
@ -62,10 +16,10 @@ var Postal = function() {
|
|||
_topicList, // we allow multiple topics to be subscribed in one call.,
|
||||
_once = false,
|
||||
_subData = {
|
||||
callback: function() { /* placeholder noop */ },
|
||||
callback: function() { /* placeholder no-op */ },
|
||||
priority: 50,
|
||||
context: null,
|
||||
onFired: function() { /* noop */ }
|
||||
onFired: function() { /* placeholder no-op */ }
|
||||
},
|
||||
_idx,
|
||||
_found;
|
||||
|
|
@ -103,26 +57,26 @@ var Postal = function() {
|
|||
}.bind(this);
|
||||
}
|
||||
|
||||
if(!this.subscriptions[_exchange]) {
|
||||
this.subscriptions[_exchange] = {};
|
||||
if(!bus.subscriptions[_exchange]) {
|
||||
bus.subscriptions[_exchange] = {};
|
||||
}
|
||||
|
||||
_topicList.forEach(function(tpc) {
|
||||
if(!this.subscriptions[_exchange][tpc]) {
|
||||
this.subscriptions[_exchange][tpc] = [_subData];
|
||||
if(!bus.subscriptions[_exchange][tpc]) {
|
||||
bus.subscriptions[_exchange][tpc] = [_subData];
|
||||
}
|
||||
else {
|
||||
_idx = this.subscriptions[_exchange][tpc].length - 1;
|
||||
if(this.subscriptions[_exchange][tpc].filter(function(sub) { return sub === callback; }).length === 0) {
|
||||
_idx = bus.subscriptions[_exchange][tpc].length - 1;
|
||||
if(bus.subscriptions[_exchange][tpc].filter(function(sub) { return sub === callback; }).length === 0) {
|
||||
for(; _idx >= 0; _idx--) {
|
||||
if(this.subscriptions[_exchange][tpc][_idx].priority <= _subData.priority) {
|
||||
this.subscriptions[_exchange][tpc].splice(_idx + 1, 0, _subData);
|
||||
if(bus.subscriptions[_exchange][tpc][_idx].priority <= _subData.priority) {
|
||||
bus.subscriptions[_exchange][tpc].splice(_idx + 1, 0, _subData);
|
||||
_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!_found) {
|
||||
this.subscriptions[_exchange][tpc].unshift(_subData);
|
||||
bus.subscriptions[_exchange][tpc].unshift(_subData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,12 +106,12 @@ var Postal = function() {
|
|||
}
|
||||
|
||||
_topicList.forEach(function(tpc) {
|
||||
if(this.subscriptions[_exchange][tpc]) {
|
||||
var _len = this.subscriptions[_exchange][tpc].length,
|
||||
if(bus.subscriptions[_exchange][tpc]) {
|
||||
var _len = bus.subscriptions[_exchange][tpc].length,
|
||||
_idx = 0;
|
||||
for ( ; _idx < _len; _idx++ ) {
|
||||
if (this.subscriptions[_exchange][tpc][_idx].callback === callback) {
|
||||
this.subscriptions[_exchange][tpc].splice( _idx, 1 );
|
||||
if (bus.subscriptions[_exchange][tpc][_idx].callback === callback) {
|
||||
bus.subscriptions[_exchange][tpc].splice( _idx, 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -190,41 +144,50 @@ var Postal = function() {
|
|||
_topicList = topic.split(/\s/);
|
||||
_data = data || {};
|
||||
}
|
||||
if(_mode !== REPLAY_MODE || (_mode === REPLAY_MODE && _exchange === SYSTEM_EXCHANGE)) {
|
||||
if(bus.mode !== REPLAY_MODE || (bus.mode === REPLAY_MODE && _exchange === SYSTEM_EXCHANGE)) {
|
||||
|
||||
_topicList.forEach(function(tpc){
|
||||
_publish(_exchange, tpc, _data);
|
||||
bus.publish(_exchange, tpc, _data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.reset = function() {
|
||||
bus.init();
|
||||
};
|
||||
|
||||
this.addBusBehavior = function(behaviorName, setup, teardown) {
|
||||
if(!bus[behaviorName]) {
|
||||
bus[behaviorName] = {};
|
||||
}
|
||||
bus[behaviorName].setup = function() {
|
||||
bus.mode = behaviorName;
|
||||
setup(bus);
|
||||
};
|
||||
if(teardown) {
|
||||
bus[behaviorName].teardown = function() { teardown(bus); }
|
||||
}
|
||||
else {
|
||||
bus[behaviorName].teardown = function() { /* no-op */ }
|
||||
}
|
||||
};
|
||||
|
||||
this.subscribe(SYSTEM_EXCHANGE, "mode.set", function(data) {
|
||||
if(data.mode) {
|
||||
switch(data.mode) {
|
||||
case REPLAY_MODE:
|
||||
_mode = REPLAY_MODE;
|
||||
_replayContext = new ReplayContext(_publish.bind(this), this.subscribe.bind(this));
|
||||
_captor = undefined;
|
||||
break;
|
||||
case CAPTURE_MODE:
|
||||
_mode = CAPTURE_MODE;
|
||||
_captor = new MessageCaptor(function(callback){
|
||||
this.wireTaps.push(callback);
|
||||
}.bind(this),
|
||||
function(callback) {
|
||||
var idx = this.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
this.wireTaps.splice(idx,1);
|
||||
}
|
||||
}.bind(this));
|
||||
break;
|
||||
default:
|
||||
_mode = NORMAL_MODE;
|
||||
_replayContext = undefined;
|
||||
_captor = undefined;
|
||||
break;
|
||||
}
|
||||
if(data.mode && bus[data.mode]) {
|
||||
bus[bus.mode].teardown();
|
||||
bus[data.mode].setup(data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.addWireTap = function(callback) {
|
||||
bus.wireTaps.push(callback);
|
||||
return function() {
|
||||
var idx = bus.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
bus.wireTaps.splice(idx,1);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
var postal = new Postal();
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
var ReplayContext = function (publish, subscribe) {
|
||||
var _batch,
|
||||
_continue = true,
|
||||
_loadMessages = function(batchId) {
|
||||
var msgStore = amplify.store(POSTAL_MSG_STORE_KEY),
|
||||
targetBatch = msgStore[batchId];
|
||||
if(targetBatch) {
|
||||
targetBatch.messages.forEach(function(msg) {
|
||||
msg.timeStamp = new Date(msg.timeStamp);
|
||||
});
|
||||
_batch = targetBatch;
|
||||
}
|
||||
},
|
||||
_replayImmediate = function() {
|
||||
while(_batch.messages.length > 0) {
|
||||
if(_continue) {
|
||||
_advanceNext();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
_advanceNext = function() {
|
||||
var msg = _batch.messages.shift();
|
||||
publish(msg.exchange, msg.topic, msg.data);
|
||||
},
|
||||
_replayRealTime = function() {
|
||||
if(_continue && _batch.messages.length > 0) {
|
||||
if(_batch.messages.length > 1) {
|
||||
var span = _batch.messages[1].timeStamp - _batch.messages[0].timeStamp;
|
||||
_advanceNext();
|
||||
setTimeout(_replayRealTime, span);
|
||||
}
|
||||
else {
|
||||
_advanceNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.load", function(data) {
|
||||
_continue = false;
|
||||
_loadMessages(data);
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.immediate", function() {
|
||||
_continue = true;
|
||||
_replayImmediate();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.advanceNext", function() {
|
||||
_continue = true;
|
||||
_advanceNext();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.realTime", function() {
|
||||
_continue = true;
|
||||
_replayRealTime();
|
||||
});
|
||||
|
||||
postal.subscribe(SYSTEM_EXCHANGE, "replay.stop", function() {
|
||||
_continue = false;
|
||||
});
|
||||
};
|
||||
|
||||
153
src/replay/ReplayContext.js
Normal file
153
src/replay/ReplayContext.js
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
var _forEachKeyValue = function(object, callback) {
|
||||
for(var x in object) {
|
||||
if(object.hasOwnProperty(x)) {
|
||||
callback(x, object[x]);
|
||||
}
|
||||
}
|
||||
},
|
||||
_subscriptions = [];
|
||||
|
||||
var ReplayContext = function (bus) {
|
||||
var _batch,
|
||||
_continue = true,
|
||||
_loadMessages = function(batchId) {
|
||||
var msgStore = amplify.store(postal.POSTAL_MSG_STORE_KEY),
|
||||
targetBatch;
|
||||
|
||||
if(msgStore[window.location.pathname] && msgStore[window.location.pathname][batchId]) {
|
||||
targetBatch = msgStore[window.location.pathname][batchId];
|
||||
targetBatch.messages.forEach(function(msg) {
|
||||
msg.timeStamp = new Date(msg.timeStamp);
|
||||
});
|
||||
_batch = msgStore[window.location.pathname][batchId];
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.batchLoaded", { batchId: batchId,
|
||||
description: targetBatch.description,
|
||||
msgCount: targetBatch.messages.length });
|
||||
}
|
||||
},
|
||||
_batchListCache = [],
|
||||
_remoteConfigured = false,
|
||||
_replayImmediate = function() {
|
||||
if(_batch) {
|
||||
while(_batch.messages.length > 0) {
|
||||
if(_continue) {
|
||||
_advanceNext();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_advanceNext = function() {
|
||||
if(_batch && _batch.messages.length > 0) {
|
||||
var msg = _batch.messages.shift();
|
||||
bus.publish(msg.exchange, msg.topic, msg.data);
|
||||
}
|
||||
},
|
||||
_replayRealTime = function() {
|
||||
if(_continue && _batch && _batch.messages.length > 0) {
|
||||
if(_batch.messages.length > 1) {
|
||||
var span = _batch.messages[1].timeStamp - _batch.messages[0].timeStamp;
|
||||
_advanceNext();
|
||||
setTimeout(_replayRealTime, span);
|
||||
}
|
||||
else {
|
||||
_advanceNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.init = function() {
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.immediate", function() {
|
||||
_continue = true;
|
||||
_replayImmediate();
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.advanceNext", function() {
|
||||
_continue = true;
|
||||
_advanceNext();
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.realTime", function() {
|
||||
_continue = true;
|
||||
_replayRealTime();
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.stop", function() {
|
||||
_continue = false;
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.loadBatch", function(data) {
|
||||
if(data.batchId) {
|
||||
_continue = false;
|
||||
_loadMessages(data.batchId);
|
||||
}
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.refreshLocal", function(data){
|
||||
var local = amplify.store(postal.POSTAL_MSG_STORE_KEY) || {},
|
||||
batches = [];
|
||||
if(local && local[window.location.pathname]) {
|
||||
_forEachKeyValue(local[window.location.pathname], function(k, v) {
|
||||
batches.push({ batchId: v.batchId,
|
||||
description: v.description,
|
||||
messageCount: v.messages.length,
|
||||
source: "local"
|
||||
});
|
||||
});
|
||||
}
|
||||
_batchListCache = _batchListCache.filter(function(x) { return x.source !== "local"; })
|
||||
.concat(batches);
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.batchList", _batchListCache);
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.refreshRemote", function(data) {
|
||||
if(_remoteConfigured) {
|
||||
amplify.request("getRemoteCaptures", function(data) {
|
||||
if(data.batches) {
|
||||
_batchListCache = _batchListCache.filter(function(x) { return x.source !== 'remote'; });
|
||||
_batchListCache = _batchListCache.concat(data.batches.map(function(x) {
|
||||
x.source = "remote";
|
||||
return x;
|
||||
}));
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.batchList", _batchListCache);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
_subscriptions.push(postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.remote.config", function(data) {
|
||||
if(amplify) {
|
||||
amplify.request.define("getRemoteCaptures", "ajax", {
|
||||
"url": data.url,
|
||||
"dataType": "json",
|
||||
"type": data.method,
|
||||
"contentType" : "application/json"
|
||||
});
|
||||
_remoteConfigured = true;
|
||||
}
|
||||
else {
|
||||
throw "Amplify.js is required in order to access remote captured batches."
|
||||
}
|
||||
}));
|
||||
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.refreshLocal");
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.refreshRemote");
|
||||
};
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
// Adding replay functionality to the bus.....
|
||||
postal.addBusBehavior(postal.REPLAY_MODE,
|
||||
function(bus) {
|
||||
postal.replay.render();
|
||||
return new ReplayContext(bus);
|
||||
},
|
||||
function(bus) {
|
||||
postal.replay.hide();
|
||||
_subscriptions.forEach(function(remove) { remove(); });
|
||||
});
|
||||
|
||||
74
src/replay/ReplayPanel.js
Normal file
74
src/replay/ReplayPanel.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
var ReplayPanel = function() {
|
||||
var _rendered = false,
|
||||
_style = '.postal-replay-wrapper { font-family: Tahoma, Arial; font-size: 10pt; float: left; vertical-align: middle; margin: 0px; padding: 0px; position: fixed; left: 0px; top: 0px; width: 100%; background-color: steelblue; color: white; } .postal-replay-title { float: left; margin-top: 4px; margin-left: 5px; margin-right: 15px; font-weight: bold; font-size: 11pt; height: 100%; } .postal-replay-button { float: left; } .postal-replay-dropdown { width: 150px; } .postal-replay-load { float: right; } .postal-replay-load select { float: left; margin-right: 10px; } #currentBatch { margin-top: 4px; margin-left: 20px; font-size: 10pt; font-weight: bold; float: left; } .postal-replay-exit { margin-left:35px; }',
|
||||
_html = '<div class="postal-replay-title">Postal Replay</div> <input class="postal-replay-button" type="button" id="btnRealTime" value="Play" alt="Real Time Playback" onclick="postal.replay.replayRealTime()"> <input class="postal-replay-button" type="button" id="btnStop" value="Stop" onclick="postal.replay.replayStop()"> <input class="postal-replay-button" type="button" id="btnAdvance" value="Step" alt="Advances to Next Msg (manual progression)" onclick="postal.replay.replayAdvance()"> <input class="postal-replay-button" type="button" id="btnImmediate" value="Immediate" alt="Replays all Messages Immediately" onclick="postal.replay.replayImmediate()"> <div id="currentBatch"></div> <div class="postal-replay-load"> <select class="postal-replay-dropdown" id="drpBatches"></select> <input class="postal-replay-button" type="button" id="btnLoad" value="Load Batch" onclick="postal.replay.loadBatch()"> <input class="postal-replay-button postal-replay-exit" type="button" id="btnExitReplay" value="Exit Replay Mode" onclick="postal.replay.exitReplay()"></div>';
|
||||
|
||||
this.exitReplay = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "mode.set", { mode: postal.NORMAL_MODE });
|
||||
};
|
||||
|
||||
this.replayRealTime = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.realTime");
|
||||
};
|
||||
|
||||
this.replayImmediate = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.immediate");
|
||||
};
|
||||
|
||||
this.replayAdvance = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.advanceNext");
|
||||
};
|
||||
|
||||
this.replayStop = function() {
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.stop");
|
||||
};
|
||||
|
||||
this.loadBatch = function() {
|
||||
var batchId = document.getElementById("drpBatches").value;
|
||||
postal.publish(postal.SYSTEM_EXCHANGE, "replay.store.loadBatch", { batchId: batchId });
|
||||
};
|
||||
|
||||
postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.batchLoaded", function(data) {
|
||||
var text = "Replaying: " + data.batchId + " (" + data.description + ") " + data.msgCount + " message(s)";
|
||||
document.getElementById("currentBatch").innerText = text;
|
||||
});
|
||||
|
||||
postal.subscribe(postal.SYSTEM_EXCHANGE, "replay.store.batchList", function(data) {
|
||||
var dropDown = document.getElementById("drpBatches"),
|
||||
optElem;
|
||||
dropDown.options.remove();
|
||||
if(data) {
|
||||
data.forEach(function(item) {
|
||||
optElem = document.createElement("option");
|
||||
optElem.value = item.batchId;
|
||||
optElem.text = item.batchId
|
||||
dropDown.options.add(optElem);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.render = function() {
|
||||
if(!_rendered){
|
||||
var style = document.createElement("style");
|
||||
style.innerText = _style;
|
||||
document.getElementsByTagName("head")[0].appendChild(style);
|
||||
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.setAttribute("class", "postal-replay-wrapper");
|
||||
wrapper.setAttribute("id", "replay-wrapper");
|
||||
wrapper.innerHTML = _html;
|
||||
document.body.appendChild(wrapper);
|
||||
_rendered = true;
|
||||
}
|
||||
else {
|
||||
document.getElementById("replay-wrapper").hidden = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.hide = function() {
|
||||
document.getElementById("replay-wrapper").hidden = true;
|
||||
};
|
||||
};
|
||||
|
||||
postal.replay = new ReplayPanel();
|
||||
|
||||
13
src/replay/panel.html
Normal file
13
src/replay/panel.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script type="text/javascript" src="../../build/output/browser/postal.js"></script>
|
||||
<script type="text/javascript" src="../Diagnostics.js"></script>
|
||||
<script type="text/javascript" src="ReplayPanel.js"></script>
|
||||
</head>
|
||||
<body onload="postal.replay.render();">
|
||||
<span>Test</span>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue