Firefox SDK: How to make trigger for certain domain - firefox-addon

I need to catch requests on sites with URLs *.net and take some actions (stop request and put HTML code from disk, but this I can do). How do I catch these requests?
I tried to use progress listeners, but something is wrong:
const STATE_START = Ci.nsIWebProgressListener.STATE_START;
var myListener = {
QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
"nsISupportsWeakReference"]),
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {
if (aFlag & STATE_START) {
// actions
}
}

use nsIHTTPChannel and observer service. copy paste it. however .net can be included in resources like javascript things, if you want to test if its specfically a window you have to check for some load flags of LOAD_INITIAL_DOCUMENT_URI, also will want to chec
Cu.import('resource://gre/modules/Services.jsm');
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (httpChannel.loadFlags & httpChannel.LOAD_INITIAL_DOCUMENT_URI) {
//ok continue because loadFlags is a document
} else {
//its not a document, probably a resource like a js file image or css or something, but maybe could be ajax call
return;
}
if (requestURL.indexOf('.net')) {
var goodies = loadContextGoodies(httpChannel);
if (goodies) {
httpChannel.cancel(Cr.NS_BINDING_ABORTED);
goodies.contentWindow.location = self.data.url('pages/test.html');
} else {
//dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
}
}
return;
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {}
}
} catch (ex0) {}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
if (aTab == null) {
return null;
}
else {
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}

Related

Scorm files, Ruby on Rails

I have implemented a scorm api in my platform (LMS), for this I have used Ruby on rails, the Scorm gem and the javascript api.
Everything works correctly and the scorm contents are displayed with satisfaction. I do not have much experience in Scorm content, but there is a zip file that they sent me of type scorm, which when it is uploaded to the platform that I am using, it takes a long time to load and execute. when I test this file on Scorm cloud, the content runs normally. The problem is that the platform does not generate any error.
why can this happen?
bugs in my code? or optimization of the Scorm zip file?
The other scorm contents work normally, but this specific one, I have no idea why. I can not think of anything
any ideas? Thank you
this is de api js:
<html>
<head>
<title>VS SCORM - RTE API</title>
<script language="javascript">
function createRequest() {
// this is the object that we're going to (try to) create
var request;
// does the browser have native support for
// the XMLHttpRequest object
try {
request = new XMLHttpRequest();
}
// it failed so it's likely to be Internet Explorer which
// uses a different way to do this
catch (tryIE) {
// try to see if it's a newer version of Internet Explorer
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
}
// that didn't work so ...
catch (tryOlderIE) {
// maybe it's an older version of Internet Explorer
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
// even that didn't work (sigh)
catch (failed) {
alert("Error creating XMLHttpRequest");
}
}
}
return request;
}
//var debug = true;
var debug = false;
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
// ------------------------------------------
// SCORM RTE Functions - Initialization
// ------------------------------------------
function LMSInitialize(dummyString) {
// create request object
var req = createRequest();
// code to prevent caching
var d = new Date();
// set up request parameters - uses GET method
req.open('GET','/scorm/initializesco?code='+d.getTime(),false);
// submit to the server for processing
req.send(null);
// process returned data - error condition
if (req.status != 200) {
alert('Problem with Request');
return "";
}
// process returned data - OK
else {
return "true";
}
}
// ------------------------------------------
// SCORM RTE Functions - Getting and Setting Values
// ------------------------------------------
//function LMSGetValue(varname) {
// if (debug) {
// alert('*** LMSGetValue varname='+varname
// +' varvalue=value ***');
// }
// return "value";
//}
function LMSGetValue(varname) {
// create request object
var req = createRequest();
// set up request parameters - uses GET method
req.open('GET','/scorm/getValue?varname='+urlencode(varname)
+'&code='+Math.random(),false);
// submit to the server for processing
req.send(null);
//alert('LMSGetValue() - ' + req.responseText);
// process returned data - error condition
if (req.status != 200) {
alert('LMSGetValue() - Problem with Request');
return "";
}
// process returned data - OK
else {
return req.responseText.replace("\n","");
}
}
/*
function LMSSetValue(varname,varvalue) {
if (debug) {
alert('*** LMSSetValue varname='+varname
+' varvalue='+varvalue+' ***');
}
return "true";
}
*/
function LMSSetValue(varname,varvalue) {
// create request object
var req = createRequest();
// set up request parameters - uses combined GET and POST
//req.open('POST','nav/setValue?varname='+urlencode(varname)
// +'&code='+Math.random(),false);
// set up request parameters - uses combined GET and POST
req.open('POST','/scorm/setValue?varname='+urlencode(varname)
+'&code='+Math.random(),false);
// send header information along with the POST data
var params = 'varvalue='+urlencode(varvalue);
req.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
//req.setRequestHeader("Content-length", params.length);
//req.setRequestHeader("Connection", "close");
// submit to the server for processing
req.send(params);
// process returned data - error condition
if (req.status != 200) {
alert('LMSSetValue() - Problem with Request');
return "false";
}
// process returned data - OK
else {
return "true";
}
}
function LMSCommit(dummyString) {
LMSGetValue('');
if (debug)
{
//alert('*** LMSCommit ***');
}
return "true";
}
function LMSFinish(dummyString) {
// create request object
var req = createRequest();
// code to prevent caching
var d = new Date();
// set up request parameters - uses GET method
req.open('GET','/scorm/finishsco?code='+d.getTime(),false);
// submit to the server for processing
req.send(null);
// process returned data - error condition
if (req.status != 200) {
alert('Problem with Request');
return "";
}
// process returned data - OK
else {
return "true";
}
}
// ------------------------------------------
// SCORM RTE Functions - Error Handling
// ------------------------------------------
function LMSGetLastError() {
if (debug) { alert('*** LMSGetLastError ***'); }
sleep(1000);
return 0;
}
function LMSGetDiagnostic(errorCode) {
if (debug) {
alert('*** LMSGetDiagnostic errorCode='+errorCode+' ***');
}
return "diagnostic string";
}
function LMSGetErrorString(errorCode) {
if (debug) {
alert('*** LMSGetErrorString errorCode='+errorCode+' ***');
}
return "error string";
}
function urlencode( str ) {
//
// Ref: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_urlencode/
//
var histogram = {}, unicodeStr='', hexEscStr='';
var ret = (str+'').toString();
var replacer = function(search, replace, str) {
var tmp_arr = [];
tmp_arr = str.split(search);
return tmp_arr.join(replace);
};
// The histogram is identical to the one in urldecode.
histogram["'"] = '%27';
histogram['('] = '%28';
histogram[')'] = '%29';
histogram['*'] = '%2A';
histogram['~'] = '%7E';
histogram['!'] = '%21';
histogram['%20'] = '+';
histogram['\u00DC'] = '%DC';
histogram['\u00FC'] = '%FC';
histogram['\u00C4'] = '%D4';
histogram['\u00E4'] = '%E4';
histogram['\u00D6'] = '%D6';
histogram['\u00F6'] = '%F6';
histogram['\u00DF'] = '%DF';
histogram['\u20AC'] = '%80';
histogram['\u0081'] = '%81';
histogram['\u201A'] = '%82';
histogram['\u0192'] = '%83';
histogram['\u201E'] = '%84';
histogram['\u2026'] = '%85';
histogram['\u2020'] = '%86';
histogram['\u2021'] = '%87';
histogram['\u02C6'] = '%88';
histogram['\u2030'] = '%89';
histogram['\u0160'] = '%8A';
histogram['\u2039'] = '%8B';
histogram['\u0152'] = '%8C';
histogram['\u008D'] = '%8D';
histogram['\u017D'] = '%8E';
histogram['\u008F'] = '%8F';
histogram['\u0090'] = '%90';
histogram['\u2018'] = '%91';
histogram['\u2019'] = '%92';
histogram['\u201C'] = '%93';
histogram['\u201D'] = '%94';
histogram['\u2022'] = '%95';
histogram['\u2013'] = '%96';
histogram['\u2014'] = '%97';
histogram['\u02DC'] = '%98';
histogram['\u2122'] = '%99';
histogram['\u0161'] = '%9A';
histogram['\u203A'] = '%9B';
histogram['\u0153'] = '%9C';
histogram['\u009D'] = '%9D';
histogram['\u017E'] = '%9E';
histogram['\u0178'] = '%9F';
// Begin with encodeURIComponent, which most resembles PHP's encoding functions
ret = encodeURIComponent(ret);
for (unicodeStr in histogram) {
hexEscStr = histogram[unicodeStr];
ret = replacer(unicodeStr, hexEscStr, ret); // Custom replace. No regexing
}
// Uppercase for full PHP compatibility
return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
return "%"+m2.toUpperCase();
});
}
</script>
</head>
<body>
<p>
</body>
</html>
You're using blocking GET/SET requests (XHR async=false) to your backend for every LMSGetValue call. Some courses are much more aggressive about how many things they get and set at launch/initialization time. Most SCORM implementations do the heavy lifting in JS (all GET value processing never touches a server, most commonly) and only go to the backend for user state storage, often at a commit or some storage frequency. If that's the issue, there's no way to fix it that doesn't involve rewriting your interface to do all the SCORM logic client-side instead of server-side, as you can't switch to using async GET calls since LMSGetValue expects the return to be the value needed.

breeze observableArray binding - are properties observable?

I have a viewmodel which consists of a list(foreach loop) of DoctorPrices and when clicking on an item in the list it open up a CRUD form on the side. However when i update the values on the CRUD the observableArray that is bound to the foreach is not refreshing? (although the values are updates in the DB correctly)
From my data access module i call the following query.
function getDoctorServices(doctorId) {
var query = breeze.EntityQuery
.from('DoctorPrices')
.where('DoctorID', 'eq', doctorId).orderBy('ListOrder');
return manager.executeQueryLocally(query);
}
In my viewmodel i have the following code:
this.services = ko.computed(function() {
return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
});
services is bound using a foreach loop (not posting here as the code is simple and works)
When i click on a one of the DoctorPrices it gets the data as follows and places it in an observable:
this.selectedPrice = function (data, event) {
self.currentService(data);
self.showEdit(true);
};
I then bind selectPrice to a simple form that has the properties on it to be modified by the user. I then call manager.SaveChanges().
This results in the following problem: the value is being updated correctly but the GUI / Original List that is bound in the foreach is not being updated? Are the properties in breeze not observables? What is the best way to work with something like this.
I thought of a workaround and changing the code with something like this:
doctorList.viewModel.instance.currentDoctorID.subscribe(function() {
self.services([]);
self.services(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
});
But i feel that clearing the array in that way is sloppy and not the right way of doing things specially with long lists.
Can someone please point me in the right direction on how to bind observableArray properties properly so they are updated?
Additional code my VM Component:
function services() {
var self = this;
this.showForm = ko.observable(false);
this.currentService = ko.observable();
this.services = ko.observableArray(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
this.title = ko.observable();
doctorList.viewModel.instance.currentDoctorID.subscribe(function() {
self.services([]);
self.services(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
self.showDetails(false);
});
this.show = function (value) {
self.showForm(value);
};
this.showDetails = ko.observable(false);
this.addNewService = function() {
self.currentService(doctorServices.createService(doctorList.viewModel.instance.currentDoctorID()));
console.log(self.currentService().entityAspect.entityState);
self.showDetails(true);
};
this.showDelete = ko.computed(function() {
if (self.currentService() == null)
return false;
else if (self.currentService().entityAspect.entityState.isDetached()) {
self.title('Add new service');
return false;
} else {
self.title('Edit service');
return true;
}
});
this.deleteService = function() {
self.currentService().entityAspect.setDeleted();
doctorServices.saveChanges();
doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
};
this.closeDetails = function () {
doctorServices.manager.rejectChanges();
doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
self.showDetails(false);
};
this.selectService = function (data, event) {
self.currentService(data);
self.showDetails(true);
};
this.saveChanges = function () {
console.log(self.currentService().entityAspect.entityState);
if (self.currentService().entityAspect.entityState.isDetached()) {
doctorServices.attachEntity(self.currentService());
}
console.log(self.currentService().entityAspect.entityState);
doctorServices.saveChanges();
doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
self.currentService.notifySubscribers();
self.showDetails(true);
};
}
return {
viewModel: {
instance: new services()
},
template: servicesTemplate,
};
Below is my Breeze Data Class:
define('data/doctorServices', ['jquery', 'data/dataManager', 'knockout','mod/medappBase', 'breeze', 'breeze.savequeuing'], function ($, manager, ko,base, breeze, savequeuing) {
var services = ko.observableArray([]);
return {
attachEntity:attachEntity,
getServices: getServices,
services: services,
manager:manager,
getDoctorServices: getDoctorServices,
getServiceById: getServiceById,
createService:createService,
hasChanges: hasChanges,
saveChanges: saveChanges
};
function getServices() {
var query = breeze.EntityQuery.from("DoctorPrices");
return manager.executeQuery(query).then(function (data) {
services(data.results);
}).fail(function (data) {
console.log('fetch failed...');
console.log(data);
});;
}
function getDoctorServices(doctorId) {
var query = breeze.EntityQuery
.from('DoctorPrices')
.where('DoctorID', 'eq', doctorId).orderBy('ListOrder');
var set = manager.executeQueryLocally(query);
return set;
}
function getServiceById(serviceId) {
return manager.createEntity('DoctorPrice', serviceId);
//return manager.getEntityByKey('DoctorPrice', serviceId);
}
function handleSaveValidationError(error) {
var message = "Not saved due to validation error";
try { // fish out the first error
var firstErr = error.innerError.entityErrors[0];
message += ": " + firstErr.errorMessage;
base.addNotify('error', 'Could not save.', message);
} catch (e) { /* eat it for now */ }
return message;
}
function hasChanges() {
return manager.hasChanges();
}
function attachEntity(entity) {
manager.addEntity(entity);
}
function createService(doctorId) {
return manager.createEntity('DoctorPrice', { DoctorPricingID: breeze.core.getUuid(), DoctorID:doctorId }, breeze.EntityState.Detached);
};
function saveChanges() {
return manager.saveChanges()
.then(saveSucceeded)
.fail(saveFailed);
function saveSucceeded(saveResult) {
base.addNotify('success', 'Saved.', 'Your updates have been saved.');
}
function saveFailed(error) {
var reason = error.message;
var detail = error.detail;
if (error.innerError.entityErrors) {
reason = handleSaveValidationError(error);
} else if (detail && detail.ExceptionType &&
detail.ExceptionType.indexOf('OptimisticConcurrencyException') !== -1) {
// Concurrency error
reason =
"Another user, perhaps the server, " +
"may have deleted one or all of the settings." +
" You may have to restart the app.";
} else {
reason = "Failed to save changes: " + reason +
" You may have to restart the app.";
}
console.log(error);
console.log(reason);
}
}
});
Please note this is my frist attempt at both a data class and VM. At the moment i am relying heavily on clearing the array ([]) and using notifySubscribers to make the array refresh :(
I bet you're missing an observable somewhere. I can't tell because you keep hopping from property to property whose definition is not shown.
For example, I don't know how you defined this.currentService.
I'm confused by this:
this.services = ko.computed(function() {
return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
});
Why is it a ko.computed? Why not just make it an observable array.
self.service = ko.observableArray();
// ... later replace the inner array in one step ...
self.service(doctorServices.getDoctorServices(
doctorList.viewModel.instance.currentDoctorID()));
I urge you to follow the observability trail, confident that your Breeze entity properties are indeed observable.
vm.selectedPrice = ko.dependentObservable(function () {
return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
}, vm);
vm is ur model on which u applied bindings , try this it will work.

Firefox addon - monitoring network

If I add an nsIHttpChannel observer, is there any way I can know what initiated the HTTP request(script, iframe, image etc..)
In chrome when monitoring the network from the background page you have the request type telling you if it came from an iframe, script etc...
Don't accept this as solution yet. I hope some other people can come and help build this solution.
I know this is for sure correct:
TEST FOR: XHR - identify XHR (ajax) response while listening to http response in firefox addon
Get load context of request (like which tab, which html window, which xul window) - Firefox add-on pageMod, catch ajax done in contentScriptFile (this is marked as optional though in the code below it requires a helper function: https://gist.github.com/Noitidart/644494bdc26f996739ef )
This I think is correct, by this i mean it works in my test cases but I'm not sure if its the recommended way:
TEST FOR: Frame or full page load - Can we differentiate between frame and non-frame loads with Ci in firefox addon
This I don't know how to do so I need help from community on this:
TEST FOR image - Comment on "identify XHR (ajax) response while listening to http response in firefox addon"
Image detection can be done through the MIME type. Check channel.contentType
Solution in progress:
var myobserve = function(aSubject, aTopic, aData) {
var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
//start - test if xhr
var isXHR;
try {
var callbacks = httpChannel.notificationCallbacks;
var xhr = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null;
isXHR = !!xhr;
} catch (e) {
isXHR = false;
}
//end - test if xhr
//start - test if frame OR full page load
var isFrameLoad;
var isFullPageLoad;
if (httpChannel.loadFlags & Ci.nsIHttpChannel.LOAD_INITIAL_DOCUMENT_URI) {
isFullPageLoad = true;
isFrameLoad = false;
} else if (httpChannel.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) {
isFrameLoad = true;
isFullPageLoad = false;
}
//end - test if frame OR full page load
//start - test if image
var isImg;
var isCss;
var isJs;
var isAudio;
//can keep going here
var mimeType = httpChannel.contentType;
if (/^image/i.test(mimeType)) {
isImg = true;
}
if (/^audio/i.test(mimeType)) {
isAudio = true;
}
if (/\/css$/i.test(mimeType)) {
isCss = true;
}
if (/\/js$/i.test(mimeType)) {
isJs = true;
}
//end - test if image
//start - OPTIONAL use loadContext to get a bunch of good stuff
//must paste the function from here: https://gist.github.com/Noitidart/644494bdc26f996739ef somewhere in your code
var goodies = loadContextAndGoodies(aSubject, true);
/*
//goodies is an object that holds the following information:
var goodies = {
loadContext: loadContext,
DOMWindow: DOMWindow,
gBrowser: gBrowser,
contentWindow: contentWindow,
browser: browser,
tab: tab
};
*/
// test if resource (such as image, or whatever) is being loaded is going into a frame [can also be used as altnerative way to test if frame load or full page]
var itemDestinationIsFrame;
var itemDestinationIsTopWin;
if (goodies.contentWindow) {
if (goodies.contentWindow.frameElement) {
itemDestinationIsFrame = true;
itemDestinationIsTopWin = false;
} else {
itemDestinationIsFrame = false;
itemDestinationIsTopWin = true;
}
}
//end - OPTIONAL use loadContext to get a bunch of good stuff
}
Of course to start observing:
Services.obs.addObserver(myobserve, 'http-on-modify-request', false);
and to stop:
Services.obs.removeObserver(myobserve, 'http-on-modify-request', false);
To start observing
To start start obseving all requests do this (for example on startup of your addon)
for (var o in observers) {
observers[o].reg();
}
To stop observing
Its important to stop observring (make sure to run this at least on shutdown of addon, you dont want to leave the observer registered for memory reasons)
for (var o in observers) {
observers[o].unreg();
}

Is my implementation of unloaders proper?

I was re-reading this post here: https://stackoverflow.com/a/24473888/1828637
And got concerned about if I did things correctly. This is how I do unloading:
So I set up some stuff per window. And unload them on shutdown. (i dont unload on window close, i havent found a need to yet, as when it closes, everything i added to it goes with with the close [such as my mutation observers]).
All code below is theoretical, the mutation stuff is example, so there might be typos or bugs in it. I was wondering if the idea behind it is appropriate:
var unloadersOnShutdown = [];
var unloadersOnClose = [];
function startup() {
let DOMWindows = Services.wm.getEnumerator(null);
while (DOMWindows.hasMoreElements()) {
let aDOMWindow = DOMWindows.getNext();
var worker = new winWorker(aDOMWindow);
unloadersOnShutdown.push({DOMWindow: aDOMWindow, fn: worker.destroy});
}
}
function shutdown() {
Array.forEach.call(unloadersOnShutdown, function(obj) {
//should probably test if obj.DOMWindow exists/is open, but just put it in try-ctach
try {
obj.fn();
} catch(ex) {
//window was probably closed
console.warn('on shutdown unlaoder:', ex);
}
});
}
function winWorker(aDOMWindow) {
this.DOMWindow = aDOMWindow;
this.init();
}
winWorker.prototype = {
init: function() {
this.gMutationObserver = new this.DOMWindow.MutationObserver(gMutationFunc.bind(this));
this.myElement = this.DOMWindow.querySelector('#myXulEl');
this.gMutationObserver.observe(this.myElement, gMutationConfig);
if (this.DOMWindow.gBrowser && this.DOMWindow.gBrowser.tabContainer) {
this.onTabSelectBinded = this.onTabSelect.bind(this);
this.gBrowser.tabContainer.addEventListener('TabSelect', this.onTabSelectBinded, false);
}
},
destroy: function() {
this.gMutationObserver.disconnect();
if (this.onTabSelectBinded) {
this.gBrowser.tabContainer.removeEventListener('TabSelect', this.onTabSelectBinded, false);
}
},
onTabSelect: function() {
console.log('tab selected = ', thisDOMWindow.gBrowser.selectedTab);
}
};
var windowListener = {
onOpenWindow: function (aXULWindow) {},
onCloseWindow: function (aXULWindow) {
var DOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
for (var i=0; i<unloadersOnClose.length; i++) {
if (unloadersOnClose.DOMWindow == DOMWindow) {
try {
unloadersOnClose.fn();
} catch(ex) {
console.warn('on close unloader:', ex);
}
unloadersOnClose.splice(i, 1);
i--;
}
}
},
onWindowTitleChange: function (aXULWindow, aNewTitle) {},
}
I think one problem is me not using weak references with DOMWindows but I'm not sure.
The idea around unloaders in general seems to be OK, but very limited (to windows only).
The implementation is lacking. E.g. there is a big, fat bug:
unloadersOnShutdown.push({DOMWindow: aDOMWindow, fn: worker.destroy});
// and
obj.fn();
// or
unloadersOnClose.fn();
This will call winWorker.prototype.destroy with the wrong this.
The i++/i-- loop also looks, um... "interesting"?!
Also, keep in mind that there can be subtle leaks, so you should mind and test for Zombie compartments.
Not only can a window leak parts of your add-on (e.g. bootstrap.js) but it is also possible to leak closed windows by keeping references in your add-on. And of course, it's not just windows you need to care about, but also e.g. observers, other types of (XPCOM) listeners etc.

Performing an AJAX call from JS in asp.net MVC without Jquery

I am developing an app that will be used on an old WInCE devices where IE Embedded doesn't support Jquery, which is why I can use it. So, my question is, what is the way to perform an AJAX call from within a js file.
Code:
html
#using (Html.BeginForm("", "SomeAction", FormMethod.Post, new { id = "myId" }))
{
input field 1: <input type="text" name="somename1"><br>
}
What I need to do is call a validate routine and return a string when the user clicks enter on the somename1 input field.
Normally, this would be done with Jquery, so how do I do it without only utilizing what the MVC asp has to offer (again, the ajax might not work at all on the old browser, but I would like to give it a shot and avoid refreshing the whole page).
Step 1: Get a XMLHttp Object using:
function getXMLHttpRequest() {
var xmlHttpReq = false;
// to create XMLHttpRequest object in non-Microsoft browsers
if (window.XMLHttpRequest) {
xmlHttpReq = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (exp1) {
try {
// to create XMLHttpRequest object in older versions
// of Internet Explorer
xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (exp2) {
xmlHttpReq = false;
}
}
}
return xmlHttpReq;
}
Then do this (Just an example for downloading a file ajax request)
function myFunction(){
var xmlHttpRequest = getXMLHttpRequest();
xmlHttpRequest.onreadystatechange = getReadyStateHandler_download_file(xmlHttpRequest,file_indicator);
xmlHttpRequest.open("GET", "/wasa-app/DownloadServlet?pmuId="+pmuID+"&dlDate=" + formatted_date+"&check_flag=1"+"&file_indicator="+file_indicator, true);
xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttpRequest.send(null);
}
function getReadyStateHandler_download_file(xmlHttpRequest, fileIndicator) {
return function() {
if (xmlHttpRequest.readyState == 4) {
if (xmlHttpRequest.status == 200) {
populateSchedule();
var resp = xmlHttpRequest.responseText;
if (resp == ""){
document.getElementById("save_" + fileIndicator).disabled = false;
document.getElementById("message").innerHTML = "";
}
else{
document.getElementById("save_" + fileIndicator).disabled = true;
document.getElementById("message").innerHTML = xmlHttpRequest.responseText;
}
} else {
alert("HTTP error -- " + xmlHttpRequest.status + ": " + xmlHttpRequest.statusText);
}
}
};

Resources