Enrico Foschi’s official blog

Something about me – .NET Team Leader with an entrepreneurial mind

Archive for the ‘Tutorials’ Category

How to check with Javascript if a Firefox Add-on / Extension is installed

with 10 comments

Agglom was used to display an invitation to download the Firefox Add-on Agglomerator in the main pages to all the users.

Unfortunately, the invitation was displayed by users that already installed the Add-on too. The challenge was to check with JS if the user already had the add-on installed and, if he had it, to hide the invitation.

Surfing the web I stumbled upon this page:
http://ha.ckers.org/weird/firefox-extentions.html

Thanks to ha.ckers.org, the feature has been pretty easy to develop. What we did was to include the invitation inside a DIV with a specified id (firefoxExtension). Right after the closing tag of the DIV we appended this image:

<img src=”chrome://agglomerator/skin/icon24.png”
class=”displayNone”
onload=”if(document.getElementById(‘firefoxExtension’))
document.getElementById(‘firefoxExtension’).style.display=’none’;” />

The IMG tag loads an image that is included in Agglomerator (the icon displayed in the toolbar to save and share the current browser session). If the extension has been installed correctly, the icon will be loaded and the onload event will be fired. This is then hiding the DIV with id=firefoxExtension. If the extension is not installed, the onload event won’t be fired.

This is a quick and dirty method and should work with all almost any add-on.

Hope it helps.

Written by Enrico Foschi

August 21, 2008 at 9:14 pm

Saving your Web searches in Firefox is easier than ever

without comments

…and you can even access them wherever you are and share them with anybody.

Is just a few clicks operation with Agglomerator, the Firefox add-on from Agglom.com.

This is a web search that I just organized in less than 1 minute:

http://www.agglom.com/agglom/323/Best_cars_drawn_in_MS_Paint

This extension will add one button on the toolbar that, when clicked, will open a new window in Agglom.com with a list of all the URLs of the current opened tabs. You will be able to choose which ones you would like save and how to share them (you may share them with everybody, with your friends, keep them private or protect them with a password).

Once you save them, you’ll be able to view all the saved web contents (links, videos, images, wikipedia pages, etc…) in just one page and to share it with a Permalink.

Here is a useful video tutorial to get started with it:

Here is the link of the Firefox Extension:

Written by Enrico Foschi

July 28, 2008 at 8:38 pm

Disabling tree nodes in Flex 2

without comments

[ENGLISH]

Well, today i had to disable some tree nodes in my tree view, but i didn’t find how to. In Flex 1 I could directly use the row property in this way:

my_tree.rows[node]._alpha = 20;
my_tree.rows[node].enabled = false;
my_tree.rows[node].onPress = null;

In Flex 2, the best way is to work with XMLListCollection object properties.
So, I have created an enabled property, that has the following value:
- 1: the node is enabled
- 0: the node is disabled

Now, for disabling the node, I make a strange operation. If the node clicked is disabled, I select manually the previous selected node (or nothing if there wasn’t any node selected).
So, I have to declare a current_node_selected variable.

Then, in the click event, I have added the following instruction:

if(tree_group.selectedItem.@enabled != "1") {
   tree_group.selectedItem = current_node_selected;
}
Here is the complete code:
<![CDATA[
	var current_node_selected:Object = null;
	private function treeClick(e:Event):void {
	if(tree_group.selectedItem.@enabled != "1") {
   		 tree_group.selectedItem = current_node_selected;
	} else {
		current_node_selected = tree_group.selectedItem;
		// my actions for enabled nodes
	}
}
]>

<mx:Tree id="tree_group" change="treeClick(event)" />

[ITALIANO]

Buongiorno a tutti. Il problema di oggi era il disabilitare alcuni nodi di un tree component in Flex 2. In Flex 1 non avrei avuto problemi… avrei utilizzato un codice simile al seguente sfruttando la proprietà row:

my_tree.rows[node]._alpha = 20;
my_tree.rows[node].enabled = false;
my_tree.rows[node].onPress = null;

In Flex 2 purtroppo non posso utilizzare la stessa sintassi. La soluzione migliore che ho trovato riguarda l’utilizzo di una proprietà di ogni nodo della sorgente di dati XMLListcollection.
Ho deciso a questo punto di utilizzare la proprietà enabled (inizializzata a 1 quando il nodo è attivo).

Ora, per disabilitare il nodo, eseguo delle strane operazioni. Se il nodo cliccato è disabilitato (enabled non è uguale a 1), seleziono manualmente il nodo precedentemente selezionato (o niente se non ve ne era alcuno). Utilizzo quindi una variabile current_node_selected che memorizza continuamente il nodo appena selezionato.

Al click eseguo queste istruzioni:

if(tree_group.selectedItem.@enabled != "1") {
	tree_group.selectedItem = current_node_selected;
}

Di seguito il codice completo

<![CDATA[

	var current_node_selected:Object = null;
	private function treeClick(e:Event):void {
		if(tree_group.selectedItem.@enabled != "1") {
			tree_group.selectedItem = current_node_selected;
		} else {
			current_node_selected = tree_group.selectedItem;
			// my actions for enabled nodes
		}
	}
]]>
<mx:Tree id="tree_group" change="treeClick(event)" />

Written by Enrico Foschi

February 8, 2007 at 2:11 pm

How to include an XML into a DataGrid using custom columns – come includere un XML all’interno di un DataGrid utilizzando colonne personalizzate

without comments

Screenshot

[ENGLISH]

Today I am working about registered user views in DataGrid and I have to view all of them in a DataGrid. I can get them by an XML generated by a back-end script.

The code i have used is this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas implements="RMGConnect.Services.RMGIService" xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#009900" width="100%" height="100%">
	<mx:Script>
		<![CDATA[
			import RMGConnect.Core.*;
			[Bindable]
			private var user_data:XML = <preferences>
				<item id="1" userid="admin" />
				<item id="2" userid="collaborator" />
				<item id="3" userid="editor" />
				<item id="4" userid="vice-admin" />
				<item id="5" userid="alphatester" />
				<item id="6" userid="betatester" />
				<item id="7" userid="omegatester" />
				<item id="8" userid="dummyuser" />
			</preferences>

			public function startService():void {
				RMGCommon.showDebug(dg_users.columns.toString());
			}
		]]>
	</mx:Script>
	<mx:DataGrid dataProvider="{user_data.item}"  id="dg_users" width="100%" height="100%">
		<mx:columns>
			<mx:DataGridColumn headerText="id" dataField="@id" />
			<mx:DataGridColumn headerText="user-id" dataField="@userid" />
		</mx:columns>
	</mx:DataGrid>
</mx:Canvas>

Binding the XML foo-variables with the DataGrid, automatically i get an XMLListCollection of all “item” nodes. Using mx:columns and mx:DataGridColumn can set header text and source data of every column of my DataGrid.

[ITALIANO]

Oggi sto sviluppando un servizio che consenta di visualizzare una lista completa di tutti gli utenti registrati in un DataGrid. La lista la ottengo da un XML generato in automatico dai servizi back-end. Il codice che ho utilizzato è il seguente:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas implements="RMGConnect.Services.RMGIService" xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#009900" width="100%" height="100%">
	<mx:Script>
		<![CDATA[
			import RMGConnect.Core.*;
			[Bindable]
			private var user_data:XML = <preferences>
				<item id="1" userid="admin" />
				<item id="2" userid="collaborator" />
				<item id="3" userid="editor" />
				<item id="4" userid="vice-admin" />
				<item id="5" userid="alphatester" />
				<item id="6" userid="betatester" />
				<item id="7" userid="omegatester" />
				<item id="8" userid="dummyuser" />
			</preferences>

			public function startService():void {
				RMGCommon.showDebug(dg_users.columns.toString());
			}
		]]>
	</mx:Script>
	<mx:DataGrid dataProvider="{user_data.item}"  id="dg_users" width="100%" height="100%">
		<mx:columns>
			<mx:DataGridColumn headerText="id" dataField="@id" />
			<mx:DataGridColumn headerText="user-id" dataField="@userid" />
		</mx:columns>
	</mx:DataGrid>
</mx:Canvas>

Effettuando un binding tra la variabile XML (contenente dati fasulli) ed il DataGrid, automaticamente ottengo una XMLListCollection di tutti i nodi “item”, che posso gestire comodamente nelle colonne tramite i tag mx:columns e mx:DataGridColumn con gli attributi headerText (titolo della colonna) e dataField (dato da visualizzare).

Written by Enrico Foschi

February 2, 2007 at 10:45 am

getDefinitionByName & AS3 reflection

with 9 comments

[ENGLISH]

Today i solved an AS3 reflection problem: I wanted to create dynamically a class instance, using a string as class name.

So, why have I to make my life so hard?

Obviously, for giving more elegance to RMGConnecter, the RIA we are currently developing. It is intended to be a platform that will include many services. We still don’t know most of these services: we will develop them in the early future. But now, we still don’t know their names.

So, how to build RMGConnecter for creating instances of not-yet-known services (contained in a simple Canvas component)? How to import them?

With reflection all becomes very simply:
- we insert main components of every services in a single directory (for example: RMGConnectService[component name].mxml)
- we will import these component with the following code:

import RMGConnect.Services.*;

- we will use the getDefinitionByName method from package flash.utils for creating a reference to one of these classes. Considering a foo name, “RMGTest”, the code will be:

var myClass:Class = flash.utils.getDefinitionByName("RMGTest");
var myComponent:* = new myClass();
this.addChild(myComponent);

Unluckily, Flex 2 Artificial Intelligence will include in compiled files just the classes that are explicitly used in the code. So, if i will not declare any RMGTest variable, Flex Builder 2 will be sure that i will have not the need of that class and will not include it in swf files.
Executing the code, the debugger will trace a ReferenceError: Error #1065.
This feature was studied just for excluding not-used classes in compiled files (that will surely be more optimized and faster to execute) but it will also exclude from including all classes referenced dinamically through function getDefinitionByName.

Solution

We can solve the problem creating a variable for each type/classes that we want to instanziate with the following code:

var fooRMGTest:RMGTest = null;

Now, Flex Builder 2 will be sure that we will use RMGTest class and it will include it in compiled files withouth giving us any error. Unluckely, we loose our elegance :( .

[ITALIANO]

Oggi mi sono trovato ad affrontare un problema di reflection in ActionScript 3: volevo creare un’istanza di una classe dinamicamente, utilizzando una stringa contenente il nome della classe.

Ma perchè mi voglio complicare così tanto la vita?

Semplice, per una questione di eleganza. RMGConnecter, la RIA che stiamo sviluppando con tanto impegno, è una piattaforma studiata per essere implementata con una grande varietà di servizi.
Questi servizi verranno sviluppati nei prossimi mesi e ad oggi non abbiamo ancora le idee chiare su quali siano, quali funzionalità abbiano, come si possano comportare ma soprattutto non sappiamo come si possano CHIAMARE.

Come fare quindi a predisporre RMGConnecter per creare istanze di servizi che ancora non conosciamo (il cui componente contenitore è un semplice Canvas)? Come fare ad importarle?

Con la reflection tutto questo diventava assai semplice: si inseriscono i principali componenti di ogni servizio in una specifica directory (per esempio: RMGConnectServices[nome componente].mxml), si importano i componenti di tale directory con l’apposita sintassi:

import RMGConnect.Services.*;

e, grazie al metodo getDefinitionByName del package flash.utils, si crea un riferimento alla nostra classe (chiamata “RMGTest” in questo esempio):

var myClass:Class = flash.utils.getDefinitionByName("RMGTest");
var myComponent:* = new myClass();
this.addChild(myComponent);

Purtroppo l’intelligenza artificiale di Flex Builder 2 vincola l’inclusione nei file compilati soltanto alle librerie effettivamente usate nel codice: nell’eseguire il codice il debugger ci restituirà quindi “ReferenceError: Error #1065“.
Pertanto, se non dichiaro alcuna variabile esplicitamente di tipo RMGTest, Flex Builder 2 intuirà che io non avrò bisogno di tale classe ed escluderà in questo modo dal file compilato.
Tale funzionalità, studiata appositamente per non appesantire i file compilati con librerie mai utilizzate, esclude però dalla compilazione tutte quelle classi istanziate dinamicamente tramite la funzione getDefinitionByName.

La soluzione?

Creare una variabile per ogni tipo di servizio che vogliamo istanziare:

var fooRMGTest:RMGTest = null;

Ora Flex Builder 2 sarà sicuro del fatto che noi utilizziamo tale classe, la includerà nel file compilato e non restituirà alcun errore di istanziamento in fase di esecuzione. Purtroppo sarà necessario aggiungere una variabile per ogni tipo di servizio implementato.

Written by Enrico Foschi

January 30, 2007 at 2:36 pm