function not being called first time script runs - javascript

I am new to JavaScript and I have beginners grip on the concepts I have a function that gets the label from a kml and displays it on screen (some of the clustering part of this function was supplied by someone on S/O). it works perfectly for all the kmls that are loaded except the First one.
I am sure that the problem is something to do with a variable and its scope, but for the life of me i cannot see where or how I am getting an error, I correction to the code would be a great help, but correction to my understanding (or lack there of) just as helpful.
many thanks in adavance
here is the code
EDIT
1) I have changes the function getlabel a number of times and the changes are only seen on kmls loaded outside of the first ajax call shown below. I don’t for the life of em understand why this is happening. It may be a context issue, however this is beyond my understanding of the topic
var tripid=1;
var myStyles;
var cfarmerid;
var navigate=true;
var edit=false;
var vectors;
var polyControl;
var bound=false;
var mycluster;
var label=" ";
$(document).ready(function(){
$.ajax({
type: "POST",url: "temp.php",dataType: "json",
error: function(e){
alert('Error: '+e);
},
success: function (data) {
if(data[0]==="not"){
window.location = "http://www.g4ema.com/index.html";
}
maxlat=data[0];
maxlon=data[1];
minlat=data[2];
minlon=data[3];
tripid=parseInt(data[4]);
var bbox=new OpenLayers.Bounds();
bbox.extend(new OpenLayers.LonLat(minlon,minlat));
bbox.extend(new OpenLayers.LonLat(maxlat,maxlon));
bbox.toBBOX();
map = new OpenLayers.Map("map");
//var layer= new OpenLayers.Layer.OSM();
mycluster = new OpenLayers.Strategy.Cluster(
{
threshold: 2, // single clusters are shown as features
shouldCluster: function(cluster, feature)
{
if (feature.geometry.CLASS_NAME === "OpenLayers.Geometry.Point" &&
cluster.cluster[0].geometry.CLASS_NAME === "OpenLayers.Geometry.Point") {
return OpenLayers.Strategy.Cluster.prototype.shouldCluster.apply(this, arguments);
} else {
return false;
}
}
});
var layer = new OpenLayers.Layer.Google(
"Google Hybrid",
{type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20});
layer.wrapDateLine=false;
map.addLayer(layer);
myStyles = new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
strokeColor: "#00ffff",
strokeWidth:5,
strokeOpacity:1,
fillColor:"#003399",
fillOpacity: 1,
labelYOffset: 15,
pointRadius: 4,
label:"${getLabel}",
fontColor:"#ff0000"
}, {
context: {
getLabel: function (f) {
label=" ";
if (f.cluster) { // is a cluster
if (f.cluster[0].attributes.label!==" ") {
label= " " + f.attributes.count + " " +
f.cluster[0].attributes.label;
} else {
label= " " ;//+ f.attributes.count + "init";
}
} else { // is not cluster
if (f.attributes.label!==" ") {
label= " " + f.attributes.label;
}else{
label=" ";
}
}
if(!label){label=" ";}
return label;
}
}
})
});
kmlLayer = new OpenLayers.Layer.Vector("Trip", {
styleMap: myStyles,
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.Fixed(),mycluster],
protocol: new OpenLayers.Protocol.HTTP({
params:{ tripid:tripid},
url: "kml2.php",
readWithPOST:true,
//{userid:userid,tripid:tripid},
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true
})
})
});
map.addLayer(kmlLayer);
var clat=(parseFloat(minlat)+parseFloat(maxlat))/2;
var clon=(parseFloat(minlon)+parseFloat(maxlon))/2;
var lonlat = new OpenLayers.LonLat(clon,clat).transform(new OpenLayers.Projection("EPSG:4326"),new OpenLayers.Projection("EPSG:900913"));
map.setCenter(lonlat);
map.zoomTo(15);

First of all, I don't see the advantage of declaring the label variable with global scope in the context of the code you've shared. Since you're returning a label from the getLabel function then I think you should just declare var label; at the top of the getLabel function and return the value of that local variable from the function.
Second, the only way I can see that "undefined" would be returned from getLabel is if f.attributes.label is undefined. I would try a code block such as:
} else { // is not cluster
if (f.attributes.label != null && typeof(f.attributes.label != "undefined") {
// if (f.attributes.label) { // alternate simpler if statement
label= " " + f.attributes.label;
} else {
label = " ";
}
}

For anyone looking this with the same problem,
The above code is faultless, the reason this wasn't working is I was calling another function later in the $document.ready() and this was refining the mycluster variable. I am very sorry for those you have looked at this and couldn't see the problem.
but the above code will work FINE

Related

Error upon reassigned function call, why?

I'm working with NW.js, in order to create a local websocket-client. I have the principle working, at the moment I'm refactoring my code to be more object oriented.
Websockclient.prototype.connect = function() {
if (!("WebSocket" in window)) {
alert("WebSocket is NOT supported!");
} else {
uri = "ws://" + this.host + ":" + this.port;
this.ws = new WebSocket(uri);
this.ws.onopen = function(evt) { this.onOpen(evt); }
}
};
Websockclient.prototype.log = function(message) {
if (this.logEn == true) {
console.log(message);
}
};
Websockclient.prototype.onOpen = function(evt) {
this.log("connected");
this.ws.send("Client says Hi!");
};
The connection open's correctly, however something fails in the Websockclient.prototype.onOpen function call. The error output is as follows:
[31910:31910:0530/115015:ERROR:edid_parser.cc(181)] invalid EDID:
human unreadable char in name
chrome-extension://oimdoepkkglchafiooagncfokloigedg/app/lib/websockclient.js:29
this.ws.onopen = function(evt) { this.onOpen(evt); }
TypeError: this.onOpen is not a function
at WebSocket.ws.onopen (chrome-> > extension://oimdoepkkglchafiooagncfokloigedg/app/lib/websockclient.js:29:47)
It looks like I have a mistake in the following:
this.ws.onopen = function(evt) { this.onOpen(evt); }
(NB: this is line nr. 29 in file websockclient.js)
I think this assignment is incorrect, but I'm a bit stuck here. Can somebody can please explain what I'm missing here.
thx to #Pimmol's comment I've solved the problem, The following line:
this.ws.onopen = function(evt) { this.onOpen(evt); }
Needed to be changed to the following:
this.ws.onopen = this.onOpen.bind(this);
For more info, see the following documentation:
"The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called."

Unreliable behaviour in Node.js

I have a Node.js application that, upon initialisation, reads two tables from an SQL database and reconstructs their relationship in memory. They're used for synchronously looking up data that changes (very) infrequently.
Problem: Sometimes I can't access the data, even though the application reports successfully loading it.
Code:
constants.js
module.exports = {
ready: function () { return false; }
};
var log = sysLog('core', 'constants')
, Geo = require('../models/geo.js');
var _ready = false
, _countries = []
, _carriers = [];
function reload() {
_ready = false;
var index = Object.create(null);
return Geo.Country.find().map(function (country) {
var obj = country.toPlainObject()
, id = obj.id;
delete obj.id;
index[id] = obj;
return Object.freeze(obj);
}).then(function (countries) {
log.debug('Loaded ' + countries.length + ' countries');
_countries = countries;
return Geo.Carrier.Descriptor.find().map(function (carrier) {
var obj = carrier.toPlainObject();
if (obj.country) {
obj.country = index[obj.country];
}
return Object.freeze(obj);
}).then(function (carriers) {
log.debug('Loaded ' + carriers.length + ' carriers');
_carriers = carriers;
});
}).finally(function () {
_ready = true;
});
}
reload().catch(function (err) {
log.crit({ message: 'Could not load constants', reason: err });
process.exit(-42);
}).done();
module.exports = {
reload : reload,
ready : function () { return _ready; },
countries : function () { return _countries; },
carriers : function () { return _carriers; }
};
utils.js
var log = sysLog('core', 'utils')
, constants = require('./constants');
module.exports = {
getCountryByISO: function(iso) {
if (!iso) {
return;
}
if ('string' != typeof iso) {
throw new Error('getCountryByISO requires a string');
}
if (!constants.ready()) {
throw new UnavailableError('Try again in a few seconds');
}
switch (iso.length) {
case 2:
return _.findWhere(constants.countries(), { 'iso2' : iso.toUpperCase() });
case 3:
return _.findWhere(constants.countries(), { 'iso3' : iso.toUpperCase() });
default:
throw new Error('getCountryByISO requires a 2 or 3 letter ISO code');
}
},
getCarrierByCode: function(code) {
if (!code) {
return;
}
if ('string' != typeof code) {
throw new Error('getCarrierByCode requires a string');
}
if (!constants.ready()) {
throw new UnavailableError('Try again in a few seconds');
}
return _.findWhere(constants.carriers(), { 'code' : code });
},
getCarrierByHandle: function(handle) {
if (!handle) {
return;
}
if ('string' != typeof handle) {
throw new Error('getCarrierByHandle requires a string');
}
if (!constants.ready()) {
throw new UnavailableError('Try again in a few seconds');
}
return _.findWhere(constants.carriers(), { 'handle' : handle });
}
};
Use case
if (data.handle) {
carrier = utils.getCarrierByHandle(data.handle);
if (_.isEmpty(carrier)) {
throw new InternalError('Unknown carrier', { handle: data.handle });
}
}
What's going on: All errors are logged; as soon as I see an error (i.e. "Unknown carrier") in the logs, I check the SQL database to see if it should've been recognised. That has always been the case so far, so I check the debug log to see if data was loaded. I always see "Loaded X countries" and "Loaded Y carriers" with correct values and no sign of "Could not load constants" or any other kind of trouble.
This happens around 10% of the time I start the application and the problem persists (i.e. didn't seem to go away after 12+ hours) and seems to occur regardless of input, leading me to think that the data isn't referenced correctly.
Questions:
Is there something wrong in constants.js or am I doing something very obviously wrong? I've tried setting it up for cyclical loading (even though I am not aware of that happening in this case).
Why can't I (sometimes) access my data?
What can I do to figure out what's wrong?
Is there any way I can work around this? Is there anything else I could to achieve the desired behaviour? Hard-coding the data in constants.js is excluded.
Additional information:
constants.reload() is never actually called from outside of constants.js.
constants.js is required only in utils.js.
utils.js is required in app.js (application entry); all files required before it do not require it.
SQL access is done through an in-house library built on top of knex.js and bluebird; so far it's been very stable.
Versions:
Node.js v0.10.33
underscore 1.7.0
bluebird 2.3.11
knex 0.6.22
}).finally(function () {
_ready = true;
});
Code in a finally will always get called, regardless of if an error was thrown up the promise chain. Additionally, your reload().catch(/* ... */) clause will never be reached, because finally swallows the error.
Geo.Country.find() or Geo.Carrier.Descriptor.find() could throw an error, and _ready would still be set to true, and the problem of your countries and carriers not being set would persist.
This problem would not have occurred if you had designed your system without a ready call, as I described in my previous post. Hopefully this informs you that the issue here is really beyond finally swallowing a catch. The real issue is relying on side-effects; the modification of free variables results in brittle systems, especially when asynchrony is involved. I highly recommend against it.
Try this
var log = sysLog('core', 'constants');
var Geo = require('../models/geo.js');
var index;
var _countries;
var _carriers;
function reload() {
index = Object.create(null);
_countries = Geo.Country.find().map(function (country) {
var obj = country.toPlainObject();
var id = obj.id;
delete obj.id;
index[id] = obj;
return Object.freeze(obj);
});
_carriers = _countries.then(function(countries) {
return Geo.Carrier.Descriptor.find().map(function (carrier) {
var obj = carrier.toPlainObject();
if (obj.country) {
obj.country = index[obj.country];
}
return Object.freeze(obj);
});
});
return _carriers;
}
reload().done();
module.exports = {
reload : reload,
countries : function () { return _countries; },
carriers : function () { return _carriers; }
};
constants.reload() is never actually called from outside of
constants.js.
That's your issue. constants.reload() reads from a database, which is an aysnchronous process. Node's require() is a synchronous process. At the time constants.js is required in utils.js and the module.exports value is returned, your database query is still running. And at whatever point in time that app.js reaches the point where it calls a method from the utils module, that query could still be running, resulting in the error.
You could say that requiring utils.js has the side-effect of requiring constants.js, which has the side-effect of executing a database query, which has the side-effect of concurrently modifying the free variables _countries and _carriers.
Initialize _countries and _carriers as unresolved promises. Have reload() resolve them. Make the utils.js api async.
promises.js:
// ...
var Promise = require('bluebird');
var countriesResolve
, carriersResolve;
var _ready = false
, _countries = new Promise(function (resolve) {
countriesResolve = resolve;
})
, _carriers = new Promise(function (resolve) {
carriersResolve = resolve;
});
function reload() {
_ready = false;
var index = Object.create(null);
return Geo.Country.find().map(function (country) {
// ...
}).then(function (countries) {
log.debug('Loaded ' + countries.length + ' countries');
countriesResolve(countries);
return Geo.Carrier.Descriptor.find().map(function (carrier) {
// ...
}).then(function (carriers) {
log.debug('Loaded ' + carriers.length + ' carriers');
carriersResolve(carriers);
});
}).finally(function () {
_ready = true;
});
}
reload().catch(function (err) {
log.crit({ message: 'Could not load constants', reason: err });
process.exit(-42);
}).done();
module.exports = {
reload : reload,
ready : function () { return _ready; },
countries : function () { return _countries; },
carriers : function () { return _carriers; }
};
utils.js
getCarrierByHandle: function(handle) {
// ...
return constants.carriers().then(function (carriers) {
return _.findWhere(carriers, { 'handle' : handle });
});
}
Use case:
utils.getCarrierByHandle(data.handle).then(function (carrier) {
if (_.isEmpty(carrier)) {
throw new InternalError('Unknown carrier', { handle: data.handle });
}
}).then(function () {
// ... next step in application logic
});
This design will also eliminate the need for a ready method.
Alternatively, you could call constants.reload() on initialization and hang all possibly-dependent operations until it completes. This approach would also obsolete the ready method.
What can I do to figure out what's wrong?
You could have analyzed your logs and observed that "Loaded X countries" and "Loaded Y carriers" were sometimes written after "Unknown carrier", helping you realize that the success of utils.getCarrierByHandle() was a race condition.

How to call inner function in Openlayer?

I have trouble about selecting the feature layer based on its attribute. I got this code below but it says:
Uncaught TypeError: Cannot read property 'features' of undefined
here's my code:
var init = function () { // A function that will initialize and execute all the declared variables
var geographic = new OpenLayers.Projection("EPSG:4326"); // Setting the standard geographic projection
var mercator = new OpenLayers.Projection("EPSG:3857"); // Setting the universal geographic projection
map = new OpenLayers.Map('map'); // Creating & initializing map constructor
var base_osm = new OpenLayers.Layer.OSM("OpenStreetMap"); // Setting OpenStreetMap as a BaseMap
map.addControl(
new OpenLayers.Control.MousePosition({
prefix: '<small style="color:blue">',
suffix: '</small>',
numDigits: 2,
emptyString: '<small style="color:red">' + 'Mouse is not over map.' +'</small>'
})
);
var layer_agao = new OpenLayers.Layer.Vector("Agao");
map.addLayers([layer_agao, base_osm]); // Adding the vector layer to the map
map.addControl(new OpenLayers.Control.LayerSwitcher());
selectControl = new OpenLayers.Control.SelectFeature(layer_agao, {
onSelect: onFeatureSelect, onUnselect: onFeatureUnselect
});
map.addControl(selectControl);
selectControl.activate();
map.setCenter(new OpenLayers.LonLat(13975400.3513, 999830.692078),16);
var format_agao = new OpenLayers.Format.GeoJSON(); //initializing and calling the rendered GeoJSON Layer from views.py
var feat_agao = format_agao.read({{agao_transform|safe}});
layer_agao.addFeatures(feat_agao);
layer_agao.events.on({
featureselected: function(event) {
var feature = event.feature;
var area = feature.geometry.getArea();
var id = feature.attributes.newpin;
var output = "Land Pin: " + id + "<br/>" + "Area: " + area.toFixed(12);
document.getElementById("status").innerHTML = output;
}
});
init.showparcel();
}
init.showparcel = function (getpin){
for(var f=0;f<layer_agao.features.length;f++) {
if(layer_agao.features[f].attributes.newpin == getpin) {
selectControl.select(layer_agao.features[f]);
break;
}
}
}
I also read about getfeaturesbyattribute, but i can't find any example. So, is there other way to call the specific feature layer on click (event)? This is for my searching...
You would need to use the getFeaturesByAttribute or track features in your own index with their FID as the index of that object, and then use getFeatureByFid.
I usually prefer to track them in my own object or hashtable and then reference by FID.
In your example I would pull in an unique id on the attribs that you can search yourself outside of openlayers, and then use the getFeaturesByAttribute to reference the unique id that you know exist. If that doesn't may sense hit me up in the comments.
vlayer.getFeaturesByAttribute("fid", target)[0]
http://dev.openlayers.org/docs/files/OpenLayers/Layer/Vector-js.html#OpenLayers.Layer.Vector.getFeaturesByAttribute
The correct way to add a listener to a Vector.Layer is layer.events.register(type, obj, listener) as shown in the comments in the source: http://trac.osgeo.org/openlayers/browser/trunk/openlayers/lib/OpenLayers/Layer/Vector.js. Note, the listener for featureselected is passed the selected feature, not the event as you have it.
So, in your case:
layer_agao.events.on('featureselected', null, function(feature){
//do something with the feature
var area = feature.geometry.getArea();
var id = feature.attributes.newpin;
var output = "Land Pin: " + id + "<br/>" + "Area: " + area.toFixed(12);
document.getElementById("status").innerHTML = output;
});
getFeaturesByAttribute doesn't look like it is what you need, based on your code sample, though it is useful in specific cases.

Simpy cannot iterate over javascript object?

I have scoured the other question/answer for this and implemented everything and I still cannot access the values of the object. Here's the code I am using:
function apply_voucher(voucher) {
var dates = $.parseJSON($("[name='dates']").val());
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
if(voucher.length > 0)
{
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_yes_no.push('yes');
voucher_reduction.push(result.voucher_reduction);
} else {
voucher_yes_no.push('no');
}
}, 'json');
});
// check if there are any yes's in the array
if('yes' in voucher_yes_no) {
console.log("no yes's");
} else {
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}
}
}
Apologies for the constant console logging - I'm just trying to track everything to make sure it's all doing what it should. The console output I get from this is below:
...which shows the object containing one value, "1.01" and my console.log of the typeof it to make sure it is actually an object (as I thought I was going mad at one point). After this there is nothing from inside the for-in loop. I have tried jquery's $.each() also to no avail. I can't understand why nothing I'm trying is working!
It does not work because the Ajax call is asynchronous!
You are reading the values BEFORE it is populated!
Move the code in and watch it magically start working since it will run after you actually populate the Array!
function apply_voucher(voucher) {
var room_id = "169";
var dates = $.parseJSON($("[name='dates']").val());
var voucher_reduction = new Array();
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
}
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}, 'json');
}
From what it looks like, you plan on making that Ajax call in a loop. For this you need to wait for all of the requests to be done. You need to use when() and then(). It is answered in another question: https://stackoverflow.com/a/9865124/14104
Just to say for future viewers that changing the way I did this to use proper deferred objects and promises, which blew my head up for a while, but I got there! Thanks for all the help, particularly #epascarello for pointing me in the right direction :) As soon as I started doing it this way the arrays began behaving like arrays again as well, hooray!
Here's the final code:
function apply_voucher(voucher) {
var booking_id = $("[name='booking_id']").val();
var dates = $.parseJSON($("[name='dates']").val());
if(voucher.length > 0) {
var data = []; // the ids coming back from serviceA
var deferredA = blah(data, voucher, dates); // has to add the ids to data
deferredA.done(function() { // if blah successful...
var voucher_yes_no = data[0];
var voucher_reduction = data[1];
if(voucher_yes_no.indexOf("yes") !== -1)
{
console.log("at least one yes!");
// change value of voucher_reduction field
var reduction_total = 0;
for(var i = 0; i < voucher_reduction.length; i++) {
reduction_total += voucher_reduction[i];
}
console.log(reduction_total);
}
else
{
console.log("there are no yes's");
}
});
}
}
function blah(data, voucher, dates) {
var dfd = $.Deferred();
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
var cycles = 0;
var dates_length = 0;
for(var prop in dates) {
++dates_length;
}
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
voucher_yes_no.push('yes');
} else {
voucher_yes_no.push('no');
}
++cycles;
if(cycles == dates_length) {
data.push(voucher_yes_no);
data.push(voucher_reduction);
dfd.resolve();
}
}, 'json');
});
return dfd.promise();
}
Can you show how voucher_reduction is defined?
I am wondering where the second line of the debug output comes from, the one starting with '0'.
in this line:
console.log(vouncher_reduction[prop]);
^
The name of the variable is wrong (then) and probably that is breaking your code.
I think there are no problem with your loop.
But perhaps with your object.
Are you sure what properties has enumerable ?
Try to execute this to check :
Object.getOwnPropertyDescriptor(voucher_reduction,'0');
If it return undefined, the property was not exist.

How to make a Firefox addon listen to xmlhttprequests from a page?

Background
I have an existing extension designed to accompany a browser-based game (The extension is mine, the game is not). The extension had been scraping the pages as they came in for the data it needed and making ajax requests for taking any actions.
Problem
The game developers recently changed a number of actions on the site to use ajax requests and I am thus far unable to get the data from those requests.
What I have so far
function TracingListener() {
}
TracingListener.prototype =
{
originalListener: null,
receivedData: [], // array for incoming data.
onDataAvailable: function(request, context, inputStream, offset, count)
{
var binaryInputStream = CCIN("#mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream");
var storageStream = CCIN("#mozilla.org/storagestream;1", "nsIStorageStream");
binaryInputStream.setInputStream(inputStream);
storageStream.init(8192, count, null);
var binaryOutputStream = CCIN("#mozilla.org/binaryoutputstream;1",
"nsIBinaryOutputStream");
binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));
// Copy received data as they come.
var data = binaryInputStream.readBytes(count);
this.receivedData.push(data);
binaryOutputStream.writeBytes(data, count);
this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
},
onStartRequest: function(request, context) {
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode)
{
try {
if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) {
dump("\nProcessing: " + request.originalURI.spec + "\n");
var date = request.getResponseHeader("Date");
var responseSource = this.receivedData.join();
dump("\nResponse: " + responseSource + "\n");
piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date);
}
} catch(e) { dumpError(e);}
this.originalListener.onStopRequest(request, context, statusCode);
},
QueryInterface: function (aIID) {
if (aIID.equals(Ci.nsIStreamListener) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
}
}
hRO = {
observe: function(aSubject, aTopic, aData){
try {
if (aTopic == "http-on-examine-response") {
if (aSubject.originalURI && piratequesting.baseURL == aSubject.originalURI.prePath && aSubject.originalURI.path.indexOf("/index.php?ajax=") == 0) {
var newListener = new TracingListener();
aSubject.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = aSubject.setNewListener(newListener);
dump("\n\nObserver Processing: " + aSubject.originalURI.spec + "\n");
for (var i in aSubject) {
dump("\n\trequest." + i);
}
}
}
} catch (e) {
dumpError(e);
}
},
QueryInterface: function(aIID){
if (aIID.equals(Ci.nsIObserver) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
}
};
var observerService = Cc["#mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService);
observerService.addObserver(hRO, "http-on-examine-response", false);
What's happening
The above code is notified properly when an http request is processed. The uri is also available and is correct (it passes the domain/path check) but the responseSource that gets dumped is, as far as I can tell, always the contents of the first http request made after the browser opened and, obviously, not what I was expecting.
The code above comes in large part from http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/. I'm really hoping that it's just something small that I've overlooked but I've been banging my head against the desk for days on this one, and so now I turn to the wisdom of SO. Any ideas?
but the responseSource that gets
dumped is, as far as I can tell,
always the contents of the first http
request made after the browser opened
and, obviously, not what I was
expecting.
There is a problem with the code above. The "receivedData" member is declared on prototype object and have empty array assigned. This leads to every instantiation of the TracingListener class to be using the same object in memory for receivedData. Changing your code to might solve he problem:
function TracingListener() {
this.receivedData = [];
}
TracingListener.prototype =
{
originalListener: null,
receivedData: null, // array for incoming data.
/* skipped */
}
Not sure though if this will solve your original problem.

Categories