Sunday, September 30, 2007

Getting browser's progress status

Ever wonder how to correctly get the page's progress of the browser (loading, transferring, waiting, etc)? Well here it is:

There are several states that can be detected using this interface
  • onStateChange
  • onLocationChange
  • onProgressChange
  • onStatusChange
  • onSecurityChange
  • onLinkIconAvailable
even though their names can seem self-explanatory, you better check the full documentation.

1) create an object that will withhold the Progress Listener Interface

var oProgressListener = new Object(); //on top of all codes, or with global scope


2) get the Progress Listener interface and assign preliminary values.

wpl = Components.interfaces.nsIWebProgressListener;

//I'm still not very sure what this function does :D
oProgressListener.QueryInterface = function(aIID) {
if (aIID.equals(oProgressListener.wpl) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports)) return this;
throw Components.results.NS_NOINTERFACE;

}


3) assign appropriate functions to the state you wants to:

//detect URL changes
oProgressListener.onLocationChange = function(aProgress, aRequest, aURI) {

alert('my URL was changed');
return 0;

}

//detect the starting of loading a new page / document
oProgressListener.onStateChange = function(aProgress, aRequest, aFlag, aStatus) {
if (aFlag & oProgressListener.wpl.STATE_IS_DOCUMENT){
alert('New page is being loaded');
}
}

//detect when a page is fully loaded
if (aFlag & oProgressListener.wpl.STATE_STOP) {
if ( aFlag & oProgressListener.wpl.STATE_IS_DOCUMENT ) {
alert('New page has finished loading');
}
}


4) Associate the progress listener for a "browser" to a listener object

browser.addProgressListener( oProgressListener,
Components.interfaces.nsIWebProgress.NOTIFY_STATE_WINDOW);

How to put log messages in Firefox's Error Console

Found out about how to add comments/logs to Firefox built-in Error Console. Really helps in debugging process.

1) get the Console Service component

var ConsSrv = Components.classes['@mozilla.org/consoleservice;1'].getService(Components.interfaces.nsIConsoleService);


2) write your logs!

ConsSrv.logStringMessage('here is my logs.. Hello!!!!');

Friday, September 21, 2007

Change multiple textbox value simultenously

Ever tried duplicating values from one main textbox to another (in XUL)? or to many others? Right after every keypresses from the user? Well, the JavaScript way is to call the onchange / onkeypress / onkeydown / onkeyup event for the main textbox, and when the event occurs, duplicate it's content to the target textboxes.

Well, this is not the same in case of XUL textboxes. Using onchange / onkeypress / onkeydown / onkeyup will always get the second latest char, as illustrated in this example:

Main textbox
-------------------------
| 12345 |
-------------------------

Duplicating textbox
-------------------------
| 1234 |
-------------------------

So the correct way is to use the oninput event handler, then you'll get the latest update from the main textbox.

Sample code:

<textbox id="main" oninput="duplicateValue()" />
<textbox id="duplicate" />

function duplicateValue()
{
var main = document.getElementById('main');
var duplicate = document.getElementById('duplicate');

duplicate.value = main.value;

}

Running multiple instances of firefox

Here is a very helpful article that elaborates (with pictures) on how to run multiple instances of Firefox(es) at the same time. This may be a requirement if you are trying to develop a Firefox extension and need to test it on 2 or more Firefox windows at the same time.

ref:
http://lifehacker.com/software/firefox/geek-to-live--manage-multiple-firefox-profiles-231646.php

Concatenating Object with String using eval()

eval() is a neat function that evaluates a string and executes it as if it was script
code.

Consider this code:

function displayItem(itemNo){
var item1 = "111";
var item2 = "222";
var item3 = "333";

eval("alert(item"+itemNo+")"); // the 'item' variable is concatenated with the parameter passed
}

and when call with this statement:

displayItem(1);

it will alert:

111

or in other case:

displayItem(3);

it will alert:

333

Getting X node value

Consider the following stanza:

<message>
<body>bar</body>
<x xmlns="myns">
<content>foo</content>
</x>
</message>

which is then passed to a function called getFoo(message), that will extract the value of <content>. I was having trouble getting that value using message.stanza.x.content, so I found an alternative way, by parsing the xml stanza through xml string.


What we need to do:


//declare a namespace var to make things easier...to read
ns = "myns";

//get the <x> node only
var x = message.stanza.ns::x;

//extracting the position value
var foovalue = loadXMLString(x);

//function to parse through XML String .. from w3schools.com
function loadXMLString(XMLtext)
{
//alert(XMLtext);
var parser=new DOMParser();
var doc=parser.parseFromString(XMLtext,"text/xml");

// documentElement always represents the root node
var x=doc.documentElement;

return x.childNodes[1].childNodes[0].nodeValue; //the <content> value..... Why so many childNodes? see below.


}

Why so many childNodes?

Even though the xml string we extracted (<x> node only) will be something like this:

<x xmlns="myns">
<content>foo</content>
</x>

In plain eyes, it looks like <x> have only 1 child node (content), but instead it has 3 nodes actually. The real stanza would be something like this:

<x xmlns="myns">
--- invisible textnode ---
<content>foo</content>
--- invisible textnode ---
</x>

you can prove this by displaying the nodeType for all the children:

x.childNodes[0].nodeType; // text
x.childNodes[1].nodeType; // element (<content>)
x.childNodes[2].nodeType; // text

ref:
http://www.w3schools.com/dom/dom_parser.asp
http://truetalkdev.blogspot.com/2007/06/sps-chat-events-stanzas.html

Tuesday, September 4, 2007

Get the previous sibling of a node

Consider this DOM tree:

<book>
<title>Magic Mayhem</title>
<author>Merlin</author>
<publisher>King Arthur Inc.</publisher>
</book>

and you would like to know who is the TITLE of the book, by passing the AUTHOR node to a function, i.e: getSibling(node); . You may use a handy function called element.previousSibling but there is matters to consider.

Must use a loop
The correct way (in IE & Mozilla) to get the previous sibling of a certain node is by using a loop that iterates through the child nodes:

function get_previoussibling(n)
{
//n = <author>
var x=n.previousSibling;
while (x.nodeType!=1)
{
x=x.previousSibling;
}
return x;
}

The nodeType = 1 will only be TRUE if the element is an element node (not a textnode or any other nodes). So the loop will keep on iterating until it find the correct element node (<title>) and returns that node. However, this may requires hevery processing when we have thousands of child nodes. Hence, if you are sure and know where is the place [index] of the child node you want, you may try this instead:

//n = <author>
var prevSibling = document.getElementById(n).parentNode.childNodes[0]; //returns <title> --- no loops required.

ref:
http://www.w3schools.com/dom/prop_element_previoussibling.asp

Detecting mouse over event

I was trying to register an event handler with a div's onmouseover event, there's something interesting that I found.

div.onmouseover = alert('yatta!');
- this event will be triggered every time the div is appended to another element (weird?), because u cant trigger a function with params with this statement.

div.setAttribute("onmouseover", "alert('yatta!');");
- this event will be triggered only when the mouse is over the div