jQuery Plugin Overwriting Parameters - javascript

This may be a very mundane question, but this is the first jQuery plugin that I have written and I'm a bit fuzzy on understanding the scope rules in JavaScript.
I'm trying to write an simple jQuery plugin that wraps around the Stack Overflow API. I'm starting off by trying to work with the Flair API.
I wanted to make the plugin as configurable as possible so that you can easily pass it the domain and user id, and generate multiple Flairs.
var superUser = $.jStackOverflow.flair({domain:"superuser.com", id: 30162, parentId:'#su-flair'});
var stackOverflow = $.jStackOverflow.flair({domain:"stackoverflow.com", id: 55954, parentId:'#so-flair'});
The problem is, when it makes the second call, it's somehow using the correct domain and id parameters, but the parentId field that it's using in the callback function to create the HTML is using the first parameter.
You can see the plugin here and the HTML here

UPDATED
DEMO: http://jsbin.com/epeti3/5
/* 16/02/2012 02.04.38 */
(function($) {
$.fn.jStackOverflow = function(options) {
var opts = $.extend({},
$.fn.jStackOverflow.defaults, options);
return this.each(function() {
$this = $(this);
var opt = $.meta ? $.extend({},
opts, $this.data()) : opts;
var result;
var id = this.id;
var flair = $.fn.jStackOverflow.flair(opt, id);
$this.html(flair);
});
};
$.fn.jStackOverflow.setApis = function(options) {
var apis = options.protocol + options.domain + options.gTLD + "/users/flair/" + options.id + "." + options.format;
if (options.makeCallbacks) {
apis += "?callback=?";
}
return apis;
};
$.fn.jStackOverflow.flair = function(options, id) {
var api = $.fn.jStackOverflow.setApis(options);
if (options.makeCallbacks) {
result = $.getJSON(api,
function(data) {
$.fn.jStackOverflow.flairCallback(data, options, id);
});
}
return result;
};
$.fn.jStackOverflow.flairCallback = function(data, options, id) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
$('<div class="' + key + '"></div>').html(key + ' : ' +data[key]).appendTo('#' + id);
}
}
};
$.fn.jStackOverflow.defaults = {
protocol: 'http://',
domain: 'stackoverflow',
gTLD: '.com',
format: 'json',
makeCallbacks: true
};
})(jQuery);
use:
<div id="so-flair"></div>
$(function() {
$('#so-flair').jStackOverflow({domain:"stackoverflow", id: 91130 });
});

The problem is that you only have a single instance of your plugin. This means that the two calls to $.jStackOverflow.flair() interfere with each other as both manipulate interal data of a single object.
Check for a demo what happens if there is some delay between the two calls (click the two buttons at the bottom)
http://jsbin.com/esovu (to edit http://jsbin.com/esovu/edit
Suddenly it starts working. So you need to investigate how to write a plugin which supports multiple instances on a single page.
You can pick any "good" jQuery plugin which multiple instances support to check how to do it.
e.g. jQuery Carousel.
Check how the lines interact to allow creating multiple Carousel instances on one page (code taken from jQuery Carousel source)
$.fn.jcarousel = function(o) { //this would match your `jStackOverflow`
return this.each(function() { //for each matched element return a new carousel
new $jc(this, o);
});
};
...
var defaults = {
...
};
...
$.jcarousel = function(e, o) { //the acutal constructor
...
}
...
$jc.fn.extend({
...
});

Related

Uncaught SyntaxError: Unexpected token : (jquery)

The error comes after the word init: before the function. I'm newer to coding and not sure what the problem is. This is jquery.
init: function (options) {
var self = this, o = this.options, c = o.classes, d = $(document), i;
// Set up the cart configuration.
$.extend(true, o, options);
// Set up the storage method.
this.saveCart = this.setStorageMethod(o.storage);
if (this.saveCart) {
this.webstore();
// Get the shopping cart.
o.properties = $.merge([ c.id, c.stock, c.price, c.quantity, o.title ], o.properties);
this.saveCart(true);
if (this.cart.timeout === null) {
this.cart.timeout = this.timeout(true);
}
// Build the shopping cart.
$.each(this.carts, function (cart) {
d.delegate(cart + ' .' + c.remove, 'click', 'remove', $.proxy(self.listen, self));
d.delegate(cart + ' :input', 'change', 'cart-options', $.proxy(self.listen, self));
self.buildCart(cart);
});
// Update total amounts.
this.updateTotals();
o.ready.call(this);
}
}
If you want a function named 'init' Just put it after function like so:
function init(options) { }
Unless you're wanting to create your own jQuery function via prototyping:
jQuery.fn.extend({
init: function(options){}
})
Read more on the documentation here: https://api.jquery.com/jquery.fn.extend/

Create or update script of given HTML

The code is getting an HTML file and configObject and according to this config object need to modify this htmlFile content(the code is working)
This is the input:
please notice that that in the firstobj of the array (there is scenario which the next attribute is not provided which say to put the new script at the bottom) the next said put the script tag after script that have ID "ui-boot"
var extendedHtmlObject = [{
type: 'script',
action: 'new',
content: 'console.log(‘hello world’);',
next: "ui-boot"
}, {
type: 'script',
id: "ui-boot",
action: 'upd',
innerElem: [{
type: 'attr',
id: 'data--ui-comersion',
content: '1.17'
}, {
type: 'attr',
id: 'src',
content: '/test/test2/-co.js'
}]
}
This is the main function:
getExtend: function(htmlContent, extendedHtmlObject) {
var self = this;
if (extendedHtmlObject) {
extendedHtmlObject.forEach(function(configs) {
switch (configs.type) {
case 'script':
htmlContent = self._handleScriptElement(htmlContent, configs);
break;
case 'head':
break;
}
});
}
return htmlContent;
},
This method determines if I need to create a new script or update existing script attributes according to the input object
_handleScriptElement: function(htmlFilecontent, configEntry) {
var oExtendedHTML = htmlFilecontent;
switch (configEntry.action) {
case 'new':
oExtendedHTML = this._createNewScript(htmlFilecontent, configEntry);
break;
case 'upd':
var sParsedHtml = this._htmlParser(oExtendedHTML);
oExtendedHTML = this._updateScript(oExtendedHTML, configEntry, sParsedHtml);
oExtendedHTML = this._convertHtmlBack(oExtendedHTML);
break;
}
return oExtendedHTML;
},
This is the method for creating new script with two option
1. the first fork need to parse the html
2. the second for doesn't.
_createNewScript: function(htmlFilecontent, configEn) {
var sScriptContent = this._createScript(configEntry.content);
if (configEn.next != null) {
var sParsedHtml = this._htmlParser(htmlFilecon);
$(sScriptContent).insertAfter(sParsedHtml.find('#' + configEn.next));
htmlFilecontent = this._convertHtmlBack(sParsedHtml);
} else {
//when the script is at the end of file
var iHeadEndTagPos = htmlFilecon.search("(| )* )*head(|*>");
htmlFilecon = htmlFilecon.substr(0, iHeadEndTagPos) + sNewScript + htmlFilecon.substr(iHeadEndTagPos);
}
return htmlFilecon;
},
This code is redundant and not efficient(I'm fairly new to JS), could I maybe improve it with JS prototype?
I want to do the parse just once in the start and the parseBack at the end(of looping the input object) but the problem is that in the createNewScript the second fork doesn't need to use the parser...
The code inside module of requireJS
update
To make it more clear, The external API have two input and one output
HTML file content
config object which determine how to update the HTML, for example to create new script (as the first object in the array
extendedHtmlObject ) or update existing script content such as
attributes values)
the output should be the extended HTML with all the modification
**update 2 **
If I can provide additional data to make it more clear please let me know what.
Maybe have a look at some of the multitude of templating systems out there.
Alternatively, simplify your html creation. If you use innerHTML to create DOM nodes, have the HTML file content just be a long string containing the full markup with placeholders for all values/classnames/etc.
eg: <script src="{{src}" id="{{id}}"></script> and then just replace all the placeholders with the values. Then you can just update the innerHTML of the target with this string.
If you use DOM node creation, document.createElement(), create all those template nodes in advance (documentFragments are really handy here). Then have one function that will check the 'extendedHtmlObject' settings and select either the node already on the page in case of update, or select your premade nodeList. Once you have the html structure as nodes, hand it off to a different function that will update all the nodes inside the structure with the new values in the 'extendedHtmlObject'. You can then append the nodes to their target.
In both cases you can juist throw the back and forth html parsing and branching away.
pseudocode:
(function myModule() {
var templates = {},
createTemplates = function() {
// Create all templates you'll use and save them.
// If you create nodes, also include a mapping from each node to its respective value
// eg: children[0] = 'label', children[1] = 'value'
},
updateTemplate = function( template, values ) {
// INNERHTML: for each placeholder 'valueName' in string template, replace placeholder by values[valueName]
// NODE CREATION: use the node mapping in the template to select each node in the template and replace its current value with values[valueName]
return template;
},
getTemplate = function( type, reference ) {
return (type === 'new') ? templates[reference] : $('#' + reference);
},
update = function( config ) {
var html = getTemplate(config.action, (config.next || config.id)),
updated = updateTemplate(html, config);
if (config.next) $('#' + config.next).insertAfter(html);
else $('#' + config.id).innerHTML = html /* OR */ $('#' + config.id).appendChild(html);
},
init = function() {
createTemplates();
};
}());
TLDR: Create new or grab existing HTML first, then update either the string or the nodes, then determine where it has to go. Make everything as general as possible.
The html creation function should be able to create any html element/update any template, not just script nodes.
The update function should not care if the html its updating existed before or is newly generated.
The function that puts the html back into the website should not be inside the creation functions.
This way you'll probably at first end up with just one big switch statement that will call the same functions with different parameters, which can easily be replaced by adding another config setting to the 'extendedHtmlObject'.
UPDATE:
I've created an example of a usable structure. It uses the DOM methods (createElement, etc) to create a new document containing the updated input string. You can change it to better match your specific input/output as much as you want. It's more of an example of how you can create anything you want with just a few general functions and alot of config settings.
This doesn't use the templetes I spoke before of though, since that would take longer to make. Just have a look at handlebars.js or mustache.js if you want templating.
But it better matches the structure you had yourself, so I hope it's easier for you then to pick the parts you like.
var originalHTML = '<script id="ui-boot" src="path/to/script/scriptname.js"></script>',
imports = {},
// IMPORTANT NOTE:
// Using a string as the body of a script element might use eval(), which should be avoided at all costs.
// Better would be to replace the 'content' config setting by a 'src' attribute and ahve the content in a seperate file you can link to.
configAry = [
{ // script-new
type: 'script',
action: 'new',
content: 'console.log(‘hello world’);',
next: "ui-boot"
},
{ // script-upd
type: 'script',
id: "ui-boot",
action: 'upd',
innerElem: [
{
type: 'attr',
id: 'data--ui-comersion',
content: '1.17'
},
{
type: 'attr',
id: 'src',
content: '/test/test2/-co.js'
}
]
}
],
// Extra helpers to make the code smaller. Replace by JQuery functions if needed.
DOM = {
'create' : function create( name ) {
return document.createElement(name);
},
// Create a new document and use the string as the body of this new document.
// This can be replaced by other functions of document.implementation if the string contains more than just the content of the document body.
'createDoc' : function createDoc( str ) {
var doc = document.implementation.createHTMLDocument('myTitle');
doc.body.innerHTML = str;
return doc;
},
'insertAfter' : function insertAfter(node, target, content ) {
target = content.querySelector(target);
if (target.nextSibling) target.nextSibling.insertBefore(node);
else target.parentNode.appendChild(node);
return content;
},
'replace' : function replace( node, target, content ) {
target = content.querySelector(target);
target.parentNode.replaceChild(node, target);
return content;
},
'update' : function update( node, textContent, attributes ) {
if (textContent) node.textContent = textContent;
return (attributes) ?
Object.keys(attributes).reduce(function( node, attr ) {
node.setAttribute(attr, attributes[attr]);
return node;
}, node) :
node;
}
},
// The actual module
moduleHTMLExtender = (function( imports ) {
var createExtension = function createExtension( extension, content ) {
switch (extension.action) {
case 'new' :
return {
'method' : 'insertAfter',
'node' : DOM.update(DOM.create(extension.type), extension.content),
'target' : '#' + extension.next
};
break;
case 'upd' :
return {
'method' : 'replace',
'node' : DOM.update(content.querySelector('#' + extension.id).cloneNode(), null, extension.innerElem.reduce(function( map, config ) {
if (config.type === 'attr') map[config.id] = config.content;
return map;
}, {})),
'target' : '#' + extension.id
}
break;
default:
return false;
break;
}
},
addExtensions = function addExtensions( content, extensions ) {
return extensions.reduce(function( content, extension ) {
return DOM[extension.method](extension.node, extension.target, content);
}, content);
},
// Returns new document as an [object Document]
extendContent = function extendContent( content, extensions ) {
var doc = DOM.createDoc(content),
toExtend = (extensions) ?
extensions.map(function( extension ) {
return createExtension(extension, doc);
}) :
null;
var res = null;
if (toExtend) return addExtensions(doc, toExtend);
else return doc;
};
// Export public interface. Replace this by your require.js code or similar.
return {
'extendContent' : extendContent
};
}( imports )),
extendedHTMLDoc = moduleHTMLExtender.extendContent(originalHTML, configAry);
console.log(extendedHTMLDoc.documentElement.outerHTML);
// output = '<html><head><title>myTitle</title></head><body><script id="ui-boot" src="/test/test2/-co.js" data--ui-comersion="1.17"></script><script>console.log(hello world);</script></body></html>';

Persist cookie form values across multiple pages

The setting: I have a form that captures$thisSearch.val(), saves it as a cookie, and pushes to an array. The form is an overlay triggered from a menu item in the header so this can appear on any page in the site.
The issue is that it only seems to save/persist the input values on/from that page it was entered on. I'm trying to collect all these values into one list.items() array that can be entered anywhere in the site.
I've tried pushing the string to the array myself instead of the add function and moved the dom around for the search form.
I can update question when I know what to specifically ask. Any pointers / concepts I should be aware of for this would be great.
var cookieList = function(cookieName) {
var cookie = $.cookie(cookieName);
var items = cookie ? cookie.split(/,/) : new Array();
return {
"add": function(val) {
items.push(val);
$.cookie(cookieName, items.join(','));
},
"items": function() {
return items;
}
}
}
var list = new cookieList("PreviousSearches");
$searchSubmit.on('click', function() {
var $thisSearch = $(this).prev().find($searchInput);
if( $thisSearch.val() == '' ) {
alert('Please enter a search term');
console.log( list );
return false;
} else {
searchTerm = $thisSearch.val()
list.add( searchTerm );
}
});
var searchTerms = list.items();
var total = searchTermsFiltered;
var searchTermsFiltered = searchTerms.filter(Boolean).slice( - 5 ).reverse();
var searchtermClean = searchTermsFiltered.join();
$.each($(searchTermsFiltered), function(i,v){
if (!window.location.origin)
window.location.origin = window.location.protocol+"//"+window.location.host;
var lastURLRaw = window.location.origin+'/bch/?s='+v;
var lastURL = lastURLRaw.replace(/ /g, '+');
listItem = '<li>'+v+'</li>';
$('.tags, .search-tags').append(listItem );
});
I found the path specifier from jquerys $.cookie in this top answer below.
$.cookie(cookieName, items.join(',') , { path: '/' }); from my code.
why are my jquery cookies not available across multiple pages?

How to work with the results of api.php using javascript?

I have searched around and can't seem to find what I'm looking for.
How can I use the results of api.php?action=query&list=allusers&augroup=sysop&aulimit=max&format=json in a javascript?
What I'm trying to do is create a script to simply change the color of usernames on the wiki if they are in certain groups, like sysop, bureaucrat, etc.
Although I'm usually pretty good at figuring these things out, I've been working on this all day and I've gotten nowhere with it. Can anyone help me out with maybe some examples or something? If it can be done with mostly jQuery that would be preferable.
Thanks in advance.
Edit: (in response to comment by ahren):
Well I started out trying to clean up and modify a script written by someone else to add more functionality/make it work as expected, but I had trouble making sense out of it:
/* HighlightUsers by Bobogoobo
* Changes color of links to specified groups and users
* TODO: redo but much better (recursive would be easier - I've learned a lot since I wrote this thing)
*/
function highlightUsers () {
"use strict";
var highlight = window.highlight || {}, selector = '', that, userstr,
indices = [],
i = 0,
user,
ns,
x,
y;
for (ns in mw.config.get('wgNamespaceIds')) {
if (i === 4) {
userstr = ns;
}
i++;
}
userstr = userstr.charAt(0).toUpperCase() + userstr.substring(1);
if (highlight['selectAll']) {
selector = 'a[href$=":';
} else {
selector = 'a[href="/wiki/' + userstr + ':';
}
for (y in highlight) {
indices.push(y);
}
for (x in highlight) {
that = highlight[x];
if (x === 'selectAll') {
continue;
} else if (x === 'users') {
for (user in that) {
$(selector + user.replace(/ /g, '_') + '"]').css({
'color': that[user],
'font-weight': 'bold'
}).attr('data-highlight-index',
$.inArray('users', indices));
}
} else {
(function (userColor, userGroup) { //JavaScript doesn't like to cooperate with me
$.getJSON('/api.php?action=query&list=allusers&augroup=' + userGroup +
'&aulimit=max&format=json', function (data) {
var stuff = data.query.allusers, //, select = '';
user;
for (user in stuff) {
//select += selector + stuff[user].name.replace(/ /g, '_') + '"], ';
$(selector + stuff[user].name.replace(/ /g, '_') + '"]').each(function () {
if (($(this).attr('data-highlight-index') || -1) < $.inArray(userGroup, indices)) {
$(this).attr('data-highlight-index', $.inArray(userGroup, indices));
$(this).css({
'color': userColor,
'font-weight': 'bold'
});
}
});
}
//select = select.substring(0, select.length - 2);
//$(select).css('color', userColor);
});
}(that, x));
}
}
}
That is my latest draft of it, I managed to accomplish a few things, like making the names bold, and correcting syntax mishaps, but I've decided I may be better off starting from scratch than trying to understand someone else's code.
i would prefer using jQuery AJAX functionality.
Usage is simple :
$.ajax({
url : 'api.php',
type : 'post',
datatype : 'json',
data : {
'list' : allusers,
'augroup' : 'sysop'
},
success : function(success_record) {
//here you can do Js dom related modifications like changing color etc.
// after php(server side) completes
}
});
I tried the AJAX solution described by Markrand, but unfortunately I wasn't able to get it to work. First off I was getting "allusers is not defined", so I wrapped it in quotes so that it wasn't treated as a var, then I had to add change 'api.php' to '/api.php' because it was becoming '/wiki/api.php' which doesn't exist, and adding the slash got it to use the base URL. It would then execute and return an object, however there was nothing useful in that object that I could use (such as an array of usernames), all it gave me was the API documentation... So I ended up doing this instead:
function highlightAdmins() {
$.getJSON('/api.php?action=query&list=allusers&augroup=sysop&aulimit=max&format=json',
function(data) {
for (var i = 0; i < data.query.allusers.length; i++) {
$('a[href$="User:' + data.query.allusers[i].name + '"]').css('color', '#FF6347');
}
});
}
This gave me an object containing the results of the query, in this case an array of sysop usernames (data.query.allusers[i].name) which I could iterate though and perform actions with.

Create Firefox Addon to Watch and modify XHR requests & reponses

Update: I guess the subject gave a wrong notion that I'm looking for an existing addon. This is a custom problem and I do NOT want an existing solution.
I wish to WRITE (or more appropriately, modify and existing) Addon.
Here's my requirement:
I want my addon to work for a particular site only
The data on the pages are encoded using a 2 way hash
A good deal of info is loaded by XHR requests, and sometimes
displayed in animated bubbles etc.
The current version of my addon parses the page via XPath
expressions, decodes the data, and replaces them
The issue comes in with those bubblified boxes that are displayed
on mouse-over event
Thus, I realized that it might be a good idea to create an XHR
bridge that could listen to all the data and decode/encode on the fly
After a couple of searches, I came across nsITraceableInterface[1][2][3]
Just wanted to know if I am on the correct path. If "yes", then kindly
provide any extra pointers and suggestions that may be appropriate;
and if "No", then.. well, please help with correct pointers :)
Thanks,
Bipin.
[1]. https://developer.mozilla.org/en/NsITraceableChannel
[2]. http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
[3]. http://www.ashita.org/howto-xhr-listening-by-a-firefox-addon/
nsITraceableChannel is indeed the way to go here. the blog posts by Jan Odvarko (softwareishard.com) and myself (ashita.org) show how to do this. You may also want to see http://www.ashita.org/implementing-an-xpcom-firefox-interface-and-creating-observers/, however it isn't really necessary to do this in an XPCOM component.
The steps are basically:
Create Object prototype implementing nsITraceableChannel; and create observer to listen to http-on-modify-request and http-on-examine-response
register observer
observer listening to the two request types adds our nsITraceableChannel object into the chain of listeners and make sure that our nsITC knows who is next in the chain
nsITC object provides three callbacks and each will be called at the appropriate stage: onStartRequest, onDataAvailable, and onStopRequest
in each of the callbacks above, our nsITC object must pass on the data to the next item in the chain
Below is actual code from a site-specific add-on I wrote that behaves very similarly to yours from what I can tell.
function TracingListener() {
//this.receivedData = [];
}
TracingListener.prototype =
{
originalListener: null,
receivedData: null, // 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);
//var data = inputStream.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.receivedData = [];
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode)
{
try
{
request.QueryInterface(Ci.nsIHttpChannel);
if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0)
{
var data = null;
if (request.requestMethod.toLowerCase() == "post")
{
var postText = this.readPostTextFromRequest(request, context);
if (postText)
data = ((String)(postText)).parseQuery();
}
var date = Date.parse(request.getResponseHeader("Date"));
var responseSource = this.receivedData.join('');
//fix leading spaces bug
responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/, "$1");
piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date, data);
}
}
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;
},
readPostTextFromRequest : function(request, context) {
try
{
var is = request.QueryInterface(Ci.nsIUploadChannel).uploadStream;
if (is)
{
var ss = is.QueryInterface(Ci.nsISeekableStream);
var prevOffset;
if (ss)
{
prevOffset = ss.tell();
ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
}
// Read data from the stream..
var charset = "UTF-8";
var text = this.readFromStream(is, charset, true);
// Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
// since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
if (ss && prevOffset == 0)
ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
return text;
}
else {
dump("Failed to Query Interface for upload stream.\n");
}
}
catch(exc)
{
dumpError(exc);
}
return null;
},
readFromStream : function(stream, charset, noClose) {
var sis = CCSV("#mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
sis.setInputStream(stream);
var segments = [];
for (var count = stream.available(); count; count = stream.available())
segments.push(sis.readBytes(count));
if (!noClose)
sis.close();
var text = segments.join("");
return text;
}
}
hRO = {
observe: function(request, aTopic, aData){
try {
if (typeof Cc == "undefined") {
var Cc = Components.classes;
}
if (typeof Ci == "undefined") {
var Ci = Components.interfaces;
}
if (aTopic == "http-on-examine-response") {
request.QueryInterface(Ci.nsIHttpChannel);
if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) {
var newListener = new TracingListener();
request.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = request.setNewListener(newListener);
}
}
} catch (e) {
dump("\nhRO error: \n\tMessage: " + e.message + "\n\tFile: " + e.fileName + " line: " + e.lineNumber + "\n");
}
},
QueryInterface: function(aIID){
if (typeof Cc == "undefined") {
var Cc = Components.classes;
}
if (typeof Ci == "undefined") {
var Ci = Components.interfaces;
}
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);
In the above code, originalListener is the listener we are inserting ourselves before in the chain. It is vital that you keep that info when creating the Tracing Listener and pass on the data in all three callbacks. Otherwise nothing will work (pages won't even load. Firefox itself is last in the chain).
Note: there are some functions called in the code above which are part of the piratequesting add-on, e.g.: parseQuery() and dumpError()
Tamper Data Add-on. See also the How to Use it page
You could try making a Greasemonkey script and overwriting the XMLHttpRequest.
The code would look something like:
function request () {
};
request.prototype.open = function (type, path, block) {
GM_xmlhttpRequest({
method: type,
url: path,
onload: function (response) {
// some code here
}
});
};
unsafeWindow.XMLHttpRequest = request;
Also note that you can turn a GM script into an addon for Firefox.

Categories

Resources