<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>unublog</title>
	<atom:link href="http://unusoft.it/blog/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://unusoft.it/blog</link>
	<description></description>
	<lastBuildDate>Sun, 12 May 2013 10:28:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Tab notifier for Firefox and SeaMonkey 1.2</title>
		<link>http://unusoft.it/blog/index.php/2012/tab-notifier-for-firefox-and-seamonkey-1-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tab-notifier-for-firefox-and-seamonkey-1-2</link>
		<comments>http://unusoft.it/blog/index.php/2012/tab-notifier-for-firefox-and-seamonkey-1-2/#comments</comments>
		<pubDate>Mon, 20 Feb 2012 18:20:13 +0000</pubDate>
		<dc:creator>aranor</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://unusoft.it/blog/?p=84</guid>
		<description><![CDATA[Tab notifier for Firefox 1.2.0 has been released and now it supports also SeaMonkey! Several features have been added since the first release, announced in this blog. The following localizations are available: Dutch (markh van BabelZilla.org) German (Archaeopteryx) Italian Simplified &#8230;<div class="read_more"><a href="http://unusoft.it/blog/index.php/2012/tab-notifier-for-firefox-and-seamonkey-1-2/">read more</a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="https://addons.mozilla.org/addon/tab-notifier/">Tab notifier for Firefox</a> 1.2.0 has been released and now it supports also SeaMonkey!</p>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/tab-notifier/versions/">Several features</a> have been added since the first release, announced in this blog.</p>
<p>The following <strong>localizations</strong> are available:</p>
<ul>
<li>Dutch (markh van BabelZilla.org)</li>
<li>German (Archaeopteryx)</li>
<li>Italian</li>
<li>Simplified Chinese (Wang.H.K)</li>
<li>Spanish</li>
<li>Swedish (Mikael Hiort af Ornäs)</li>
</ul>
<p>To <strong>contribute</strong> you can either donate on the <a href="https://addons.mozilla.org/en-US/firefox/addon/tab-notifier/">add-ons page</a> or translate it in you language with <a href="http://www.babelzilla.org/forum/index.php?showtopic=7101">BabelZilla</a></p>
<p>To report bugs or suggest improvements please post on the <a href="http://unusoft.it/blog/index.php/tab-notifier/tab-notifier-for-firefox-and-seamonkey/" title="Tab notifier for Firefox and SeaMonkey">support page</a></p>
]]></content:encoded>
			<wfw:commentRss>http://unusoft.it/blog/index.php/2012/tab-notifier-for-firefox-and-seamonkey-1-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A slideshow with Flex</title>
		<link>http://unusoft.it/blog/index.php/2012/slideshow/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=slideshow</link>
		<comments>http://unusoft.it/blog/index.php/2012/slideshow/#comments</comments>
		<pubDate>Wed, 04 Jan 2012 11:15:17 +0000</pubDate>
		<dc:creator>aranor</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://unusoft.it/blog/?p=62</guid>
		<description><![CDATA[Several months ago we needed a simple slideshow showing some pictures but emphasizing mainly some texts over them. I created a slideshow with the free and open source Flex SDK and TweenMax. You can see a demo here. How to &#8230;<div class="read_more"><a href="http://unusoft.it/blog/index.php/2012/slideshow/">read more</a></div>]]></description>
			<content:encoded><![CDATA[<p>Several months ago we needed a simple slideshow showing some pictures but emphasizing mainly some texts over them. I created a slideshow with the free and open source Flex SDK and <a href="http://www.greensock.com/">TweenMax</a>. <a href="http://unusoft.it/blog/wp-content/uploads/2012/01/slideshow.html">You can see a demo here</a>.</p>
<h3>How to use it</h3>
<p><a href="http://unusoft.it/blog/wp-content/uploads/2012/01/slideshow.zip">Download the slideshow</a> and modify the example <b>slideshow.xml</b>. The only other file that you need is <b>slideshow.swf</b>, but if you don&#8217;t want to use it on-line but to show images on a local drive use <b>slideshow-local.swf</b> instead. slideshow.xml is the default filename for the configuration file, but you can change it by means of the flashVar &#8220;<i>xml</i>&#8220;. The most important part of the xml are several <b>slide</b> elements contained in the root element. Each one of them can contain an optional <b>text</b> element and has to contain at least an <b>image</b> element (with its file attribute containing an url or a path depending on the version). The example explains the meaning of other tags and attributes:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;slides&gt;
&lt;!-- style is the css applied to the text (every text block is wrapped in a div) --&gt;
&lt;style&gt;
div{text-align:center;}
.key{font-style:italic;}
small {font-weight:normal;}
&lt;/style&gt;
&lt;parameters&gt;
&lt;!-- the first image of every slide shifts vertically and then shrinks toward the bottom of the screen until a size
defined by imagesFinalHeight (e.g. 0.5 means 50% of the height of screen) and with an alpha defined by imagesFinalAlpha
(from 0 invisible to 1 unchanged). If there are extra images in the same slide, these two parameters will define
height and alpha of these images as well --&gt;
&lt;imagesFinalAlpha&gt;0.75&lt;/imagesFinalAlpha&gt;
&lt;imagesFinalHeight&gt;0.75&lt;/imagesFinalHeight&gt;
&lt;!-- tune is the background music (optional) --&gt;
&lt;tune&gt;http://www.joshwoodward.com/mp3/ht/NoVox/JoshWoodward-HereTodayNoVox-06-LearnToFly.mp3&lt;/tune&gt;
&lt;!-- if firstSlideIsBlack is true you need an initial click to start the slideshow (used with a projector) --&gt;
&lt;firstSlideIsBlack&gt;false&lt;/firstSlideIsBlack&gt;
&lt;/parameters&gt;

&lt;slide&gt;
&lt;image file=&quot;http://3.bp.blogspot.com/_N_mOB63qPaE/SwmFueUiiJI/AAAAAAAAMm0/_7CS3KAsp_M/s400/Desktop-Wallpaper.jpg&quot; /&gt;
&lt;text&gt;
&lt;![CDATA[&lt;span class='key'&gt;Enter&lt;/span&gt;: fullscreen
click on on the left border or &lt;span class='key'&gt;Page Up&lt;/span&gt;: go to the previous slide
click or &lt;span class='key'&gt;Page Down&lt;/span&gt;: go to the next slide
]]&gt;&lt;/text&gt;
&lt;/slide&gt; 

&lt;slide&gt;
&lt;text&gt;If you put more than one image in the same slide the extra images will scroll from the right to the left&lt;/text&gt;
&lt;image file=&quot;http://1.bp.blogspot.com/_N_mOB63qPaE/SwmFtcpw54I/AAAAAAAAMmc/fmCo9rSEdI0/s400/Beautifull-Birds.jpg&quot; /&gt;
&lt;image file=&quot;http://4.bp.blogspot.com/_N_mOB63qPaE/SwmF7LSAa7I/AAAAAAAAMm8/WZArZHzJ1Ws/s400/Red-Bird-Wallpaper.Jpg&quot; /&gt;
&lt;!-- the optional attribute delay specifies the number of seconds before the image starts to scroll to replaces the previous one --&gt;
&lt;image delay=&quot;2.5&quot; file=&quot;http://4.bp.blogspot.com/_N_mOB63qPaE/SwmFt7Kxy0I/AAAAAAAAMmk/CW8cMKBduFY/s400/Birds-Wallpaper.jpg&quot; /&gt;
&lt;/slide&gt; 

&lt;slide&gt;
&lt;text&gt;
&lt;![CDATA[When you click on the last slide image,
text and sound fade out
&lt;small&gt;The images are taken from collectionbird.blogspot.com
The song is &quot;Lern to fly&quot;, by Josh Woodward (www.joshwoodward.com)&lt;/small&gt;
]]&gt;&lt;/text&gt;
&lt;image file=&quot;http://1.bp.blogspot.com/_N_mOB63qPaE/SwmFuGRR8nI/AAAAAAAAMms/WOenHtvajMw/s400/Bird-Wallpaper.jpg&quot; /&gt;
&lt;/slide&gt;
&lt;/slides&gt;
</pre>
<h3>How to build it</h3>
<p>Download the same <a href="http://unusoft.it/blog/wp-content/uploads/2012/01/slideshow.zip">zip file</a>, that contains the source code. It was coded hastily, still I think it&#8217;s a good example of what you can do with Flex SDK without framework (that&#8217;s with completely free and open source tools and with a target swf really small) and TweenLite or TweenMax. It embeds code of TwinMax that has its own <a href="http://www.greensock.com/licensing/">dual license</a>. To build the slideshow you can use Flash Builder (formerly named Flex Builder) or, if you can&#8217;t afford to buy it, download the <a href="http://opensource.adobe.com/wiki/display/flexsdk/Flex+SDK">Flex SDK</a> as I did.<br />
An ant script is not provided with the slideshow, but there are a batch file for windows (<b>build.bat</b>) and a shell script for Linux (<b>build.sh</b>) used to build it with Flex SDK 4. You may need to configure them depending on the installation directory of the SDK etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://unusoft.it/blog/index.php/2012/slideshow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Options for a chrome extension: tab notifier 1.1</title>
		<link>http://unusoft.it/blog/index.php/2011/options-for-a-chrome-extension/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=options-for-a-chrome-extension</link>
		<comments>http://unusoft.it/blog/index.php/2011/options-for-a-chrome-extension/#comments</comments>
		<pubDate>Wed, 21 Dec 2011 09:05:55 +0000</pubDate>
		<dc:creator>aranor</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://unusoft.it/blog/?p=49</guid>
		<description><![CDATA[The version 1.1.0 of tab notifier for chrome has been released. It now stores persistently the list of ignored sites and allows to manage it by means of a option page. Let&#8217;s see how it&#8217;s done. To store the options &#8230;<div class="read_more"><a href="http://unusoft.it/blog/index.php/2011/options-for-a-chrome-extension/">read more</a></div>]]></description>
			<content:encoded><![CDATA[<p>The version 1.1.0 of <a href="http://unusoft.it/blog/index.php/tab-notifier/" title="Tab notifier">tab notifier for chrome</a> has been released. It now stores persistently the list of ignored sites and allows to manage it by means of a option page. Let&#8217;s see how it&#8217;s done.<br />
To store the options now the extension uses the <a href="http://dev.w3.org/html5/webstorage/#the-localstorage-attribute">localStorage</a> attribute of the window object.<br />
This is the simplest part. As we saw in the <a href="../ontogeny-of-a-chrome-extension-the-tab-notifier/#other_improvements">previous post</a> everytime there is a click on the menu item &#8220;Ignore this site&#8221; we change the object <i>mutedDomains</i>. Now we also stringify it to store it in localStorage: </p>
<pre class="brush: jscript; auto-links: false; highlight: [14]; title: ; notranslate">
var menuItemId=chrome.contextMenus.create({type:&quot;checkbox&quot;,
	title:&quot;Ignore this site&quot;,
	checked:true,
	contexts:[&quot;all&quot;],
	documentUrlPatterns:[&quot;http://*/*&quot;, &quot;https://*/*&quot;],
	onclick:function(info,tab){
		var hostname = getHostname(tab.url);
		if (hostname) {
			if(info.checked) {
				mutedDomains[hostname]=true;
			} else {
				delete mutedDomains[hostname];
			}
			window.localStorage.ignoredSites = JSON.stringify(mutedDomains);
		}
	}
});
</pre>
<p>Please note that we don&#8217;t need to put the attributes of localStorage inside a namespace (hence ignoredSites is totally arbitrary) because they will be unique for every extension in the way they are unique for each subdomain when they are used in the scope of a web page.</p>
<p>To restore the object we use the following code: </p>
<pre class="brush: jscript; title: ; notranslate">
var updateOptions=function() {
	var s=window.localStorage.ignoredSites;
	if (s) try {
		mutedDomains=JSON.parse(s);
	} catch(e){console.log(e);};
};
updateOptions();
window[&quot;updateOptions&quot;]=updateOptions;
</pre>
<p>The function &#8220;updateOptions&#8221; is attached to the window object to be accessible to the option page as we&#8217;ll see pretty soon.<br />
Since now the list of ignored sites won&#8217;t be reset at the beginning of every session, it becomes more important to allow the users to manage that list. We can achieve that with an option page. Let&#8217;s add a row to the <b>manifest.json</b> file:</p>
<pre class="brush: jscript; auto-links: false; highlight: [14]; title: ; notranslate">
{
   &quot;background_page&quot;: &quot;background.html&quot;,
   &quot;content_scripts&quot;: [ {
      &quot;js&quot;: [ &quot;tabnot.js&quot; ],
      &quot;matches&quot;: [ &quot;http://*/*&quot;, &quot;https://*/*&quot; ]
   } ],
   &quot;description&quot;: &quot;Notifies when the title of a tab changes&quot;,
   &quot;icons&quot;: {
	&quot;16&quot;: &quot;icon16.png&quot;,
	&quot;48&quot;: &quot;icon.png&quot;
   },
   &quot;name&quot;: &quot;Tab notifier&quot;,
   &quot;permissions&quot;: [ &quot;tabs&quot;, &quot;notifications&quot;, &quot;contextMenus&quot; ],
   &quot;options_page&quot;: &quot;options.html&quot;,
   &quot;homepage_url&quot;: &quot;http://unusoft.it/blog/index.php/tab-notifier/&quot;,
   &quot;update_url&quot;: &quot;http://unusoft.it/extensions/updates.xml&quot;,
   &quot;version&quot;: &quot;1.1.0&quot;
}
</pre>
<p>Then we add two new files to the extensions: options.html and options.js. The first contains the interface of the configuration, here&#8217;s the core of it:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;select id=&quot;ignoredSitesSl&quot; multiple=&quot;multiple&quot; size=&quot;16&quot;&gt;
&lt;/select&gt;
&lt;div class=&quot;buttons&quot;&gt;
&lt;div class=&quot;left&quot;&gt;
	&lt;button id=&quot;removeBt&quot;&gt;Remove selected&lt;/button&gt;
	&lt;button id=&quot;selectAllBt&quot;&gt;Select all&lt;/button&gt;
&lt;/div&gt;
&lt;div class=&quot;right&quot;&gt;
	&lt;button id=&quot;saveBt&quot;&gt;Save&lt;/button&gt;
	&lt;button id=&quot;resetBt&quot;&gt;Reset&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;initOptionsPage();&lt;/script&gt;
</pre>
<p><i>ignoredSitesSl</i> will be programmatically filled when <i>initOptionsPage</i> (contained in <b>options.js</b>) is invoked. To see the full code follow the <a href="../ontogeny-of-a-chrome-extension-the-tab-notifier/#other_improvements">instructions in the previous post</a>.<br />
Beside the initialization of the interface <b>options.js</b> contains the javascript code bound to the click event of every button in the page:</p>
<pre class="brush: jscript; title: ; notranslate">
(function() {
    var ignoredSites,ignoredSitesSl,removeBt,selectAllBt,saveBt,ResetBt
    ,load=function() {
		var s=window.localStorage.ignoredSites;
		ignoredSites={};
		if (s) try {
			ignoredSites=JSON.parse(s);
		} catch(e){console.log(e);};

		for (i in ignoredSites) {
			var o = document.createElement(&quot;option&quot;);
			o.innerHTML=i;
			ignoredSitesSl.appendChild(o);
		}
		disButts(true);
    }
	,disButts=function(a) {
		resetBt.disabled = a;
        saveBt.disabled = a;
	}

    window.initOptionsPage = function() {
        removeBt = document.getElementById(&quot;removeBt&quot;);
		selectAllBt = document.getElementById(&quot;selectAllBt&quot;);
		saveBt = document.getElementById(&quot;saveBt&quot;);
		resetBt = document.getElementById(&quot;resetBt&quot;);
		ignoredSitesSl = document.getElementById(&quot;ignoredSitesSl&quot;);
		load();
        removeBt.addEventListener(&quot;click&quot;,function(){
		var d=false;
			for(var c=0;c&lt;ignoredSitesSl.options.length;c++) {
				var o=ignoredSitesSl.options1;
				if(o.selected) {
					delete ignoredSites[o.innerHTML];
					ignoredSitesSl.removeChild(o);
					c--;d=true;
				}
			}
			if (d)disButts(false);
		},false);
        selectAllBt.addEventListener(&quot;click&quot;,function(){
			var l=ignoredSitesSl.options.length;
			for(var c=0;c&lt;l;c++) {
				ignoredSitesSl.options1.selected=true;
			}
		},false);
        saveBt.addEventListener(&quot;click&quot;,function(){
			window.localStorage.ignoredSites = JSON.stringify(ignoredSites);
			chrome.extension.getBackgroundPage()[&quot;updateOptions&quot;]();
			disButts(true);
		},false);
        resetBt.addEventListener(&quot;click&quot;,function(){
			while (ignoredSitesSl.options.length&gt; 0) ignoredSitesSl.options.remove(0);
			load();
		},false);
    };
})();
</pre>
<p>As you can see from the rows 48 and 49, when the button &#8220;Save&#8221; is pressed two actions are performed: the list of ignored sites is stored and the updateOptions function in the background page is called. In this way the background page always uses the most recent version of the list.</p>
]]></content:encoded>
			<wfw:commentRss>http://unusoft.it/blog/index.php/2011/options-for-a-chrome-extension/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tab notifier for Firefox</title>
		<link>http://unusoft.it/blog/index.php/2011/tab-notifier-for-irefox/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tab-notifier-for-irefox</link>
		<comments>http://unusoft.it/blog/index.php/2011/tab-notifier-for-irefox/#comments</comments>
		<pubDate>Thu, 15 Dec 2011 16:21:41 +0000</pubDate>
		<dc:creator>aranor</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://unusoft.it/blog/?p=41</guid>
		<description><![CDATA[Tab notifier for Firefox has been released. This extension shows a desktop notification when the title of a tab changes while the tab is not focused. Here&#8217;s some features of this extension that are not yet available in the chrome &#8230;<div class="read_more"><a href="http://unusoft.it/blog/index.php/2011/tab-notifier-for-irefox/">read more</a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="https://addons.mozilla.org/addon/tab-notifier/">Tab notifier for Firefox</a> has been released.<br />
This extension shows a desktop notification when the title of a tab changes while the tab is not focused.<br />
Here&#8217;s some features of this extension that are not yet available in the <a href="http://unusoft.it/blog/index.php/tab-notifier/">chrome version</a>:</p>
<ul>
<li><del datetime="2011-12-21T09:29:19+00:00">You can manage the list of web sites to block.</del> Update (21/12/2011): added this feature to tab notifier for chrome as well
<li>You can block a web site just with one click when the first notification appears.
</ul>
<p>You can install it from the <a href="https://addons.mozilla.org/addon/tab-notifier/">Mozilla Add-ons</a> web site.</p>
]]></content:encoded>
			<wfw:commentRss>http://unusoft.it/blog/index.php/2011/tab-notifier-for-irefox/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ontogeny of a chrome extension: the tab notifier</title>
		<link>http://unusoft.it/blog/index.php/2011/ontogeny-of-a-chrome-extension-the-tab-notifier/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ontogeny-of-a-chrome-extension-the-tab-notifier</link>
		<comments>http://unusoft.it/blog/index.php/2011/ontogeny-of-a-chrome-extension-the-tab-notifier/#comments</comments>
		<pubDate>Fri, 04 Nov 2011 11:52:43 +0000</pubDate>
		<dc:creator>aranor</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://unusoft.it/blog/?p=31</guid>
		<description><![CDATA[The tab notifier is our solution for who uses messaging web clients but don&#8217;t want to renounce nice toasts popping up as alerts. Let&#8217;s see how it&#8217;s done, in order to be able to customize it or to learn something &#8230;<div class="read_more"><a href="http://unusoft.it/blog/index.php/2011/ontogeny-of-a-chrome-extension-the-tab-notifier/">read more</a></div>]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://unusoft.it/blog/index.php/tab-notifier/" title="Tab notifier">tab notifier</a> is our solution for who uses messaging web clients but don&#8217;t want to renounce <a href="http://unusoft.it/blog/index.php/2011/notifications/" title="Notifications for everyone">nice toasts popping up as alerts</a>. Let&#8217;s see how it&#8217;s done, in order to be able to customize it or to learn something that may be useful to make other extensions.<br />
To develop a chrome extension you need to know javascript and <a href="http://code.google.com/chrome/extensions/overview.html">few more things</a>.<br />
Let&#8217;s start from the begin.<br />
We need to create at least a <a href="http://code.google.com/chrome/extensions/manifest.html">manifest.json</a> file and a html file with the javascript code that will be run in background. A first simple technique that we can use to detect title changes is to compare every few seconds the title of every tab of every window with the previous value. We already know that we are going to do it in a better way, but getting the list of the tabs is definitely one thing that can turn out useful, so let&#8217;s start from here.</p>
<p>Here&#8217;s the file <b>manifest.json</b>:</p>
<pre class="brush: jscript; title: ; notranslate">
{
	&quot;background_page&quot;: &quot;background.html&quot;,
	&quot;description&quot;: &quot;Notifies when the title of a tab changes&quot;,
	&quot;name&quot;: &quot;Tab notifier&quot;,
	&quot;permissions&quot;: [ &quot;tabs&quot; ],
	&quot;version&quot;: &quot;0.1&quot;
}
</pre>
<p>Note that we need the <i>tabs</i> permission (as every time we need to use APIs from the chrome.windows or chrome.tabs namespace). This makes a warning show up when you install the extension from a compressed .crx file, but not when you install it form an unpacked directory (which it&#8217;s what we are going to do as long we are still developing it).</p>
<p>Here&#8217;s the file <b>background.html</b>:</p>
<pre class="brush: jscript; html-script: true; title: ; notranslate">
&lt;html&gt;&lt;head&gt;&lt;script&gt;

var pollInterval = 1000 * 20;  // 20 seconds
var globalTabs = {};

function populateTabs(winList) {
    var newTabs = {}; //scanned tabs
    for (x=0;x&lt;winList.length;x++) {
		var win=winList[x];
		win.tabs.forEach(function(tab) {
			if (tab.title) {
				var prevTab=globalTabs[tab.id];
				if (prevTab!==undefined &amp;&amp; prevTab.title!=tab.title &amp;&amp; prevTab.url==tab.url &amp;&amp; (!tab.selected || !win.focused)) {
					var popup = window.webkitNotifications.createNotification(tab.favIconUrl ? tab.favIconUrl : &quot;&quot;, &quot;&quot;, tab.title);
					popup.show();
				}
				newTabs[tab.id]={title:tab.title, url:tab.url};
			}
		});
    }
	globalTabs=newTabs;
}

function check()
{
	chrome.windows.getAll({'populate' : true}, populateTabs);
	window.setTimeout(check, pollInterval);
}

&lt;/script&gt;&lt;/head&gt;&lt;body onload=&quot;check()&quot;&gt;&lt;/body&gt;&lt;/html&gt;
</pre>
<p>The background page is loaded when the plug-in is started or reload, and it contain only the javascript code bound to the load event of the page. This code scans all the tabs every 20 seconds, please note from the row 13 that the pop up is showed only when a title is changed but the url is not (which means that the title has been changed by some javascrit code because the page is still the same) and only if the tab is not opened and the windows focused (that&#8217;s it only if the user is not seeing what it&#8217;s happening).<br />
To try the extension go to the page chrome://extensions/, active the &#8220;Developer mode&#8221; and click on &#8220;Load unpacked extension&#8230;&#8221;, going to the directory where our two files are.<br />
To test it more conveniently you may need a <a href="http://unusoft.it/blog/wp-content/uploads/2011/11/scrolling_title.html" target="scrolling_title">small html page like this</a>. It generates a scrolling title (which ideally is one of the things that we wouldn&#8217;t like to cause a notification but it&#8217;s perfect for our aim because it keeps on generating the event that we are trying to detect, anyway we&#8217;ll try to distinguish a scrolling title from an actual message notification, in some cases, later on, not showing it a second time after we close it, refer to <a href="#cyclic_messages">cyclic messages detection</a>). We can experiment some defects easy predictable. Definitely the more obvious is that we can have a delay after the tile change. This can be acceptable when we receive an email, but can be intolerable when we receive a instant message. We can play with the <i>pollInterval</i> variable, however, another defects is that a script has frequently to go through all the tabs even when nothing is happening, and decreasing pollInterval would make things worse.</p>
<h3>I believe in a better way (content scripts).</h3>
<p>Instead of polling every tab we can proceed the opposite way. We can use the DOMSubtreeModified events in every tab we want to monitor to detect at once every change of the title. This is possible because chrome allows us to <i>inject</i> javascript in the pages. Since this injected javascript can access only to <a href="http://code.google.com/chrome/extensions/extension.html">a small subset of the chrome APIs</a>, we need to send a message to the background page and let it do the rest. To inject javascript code we have to add the <i>content_scripts</i> permission and the new field <a href="http://code.google.com/chrome/extensions/content_scripts.html"><i>content_scripts</i></a> to the <b>manifest.json</b> file:</p>
<pre class="brush: jscript; auto-links: false; highlight: [2,3,4,5,6,7,11]; title: ; notranslate">
{
	&quot;content_scripts&quot;: [
		{
			&quot;matches&quot;: [&quot;http://*/*&quot;, &quot;https://*/*&quot;],
			&quot;js&quot;: [&quot;tabnot.js&quot;]
		}
	],
   &quot;background_page&quot;: &quot;background.html&quot;,
   &quot;description&quot;: &quot;Notifies when the title of a tab changes&quot;,
   &quot;name&quot;: &quot;Tab notifier&quot;,
   &quot;permissions&quot;: [ &quot;tabs&quot;, &quot;notifications&quot; ],
   &quot;version&quot;: &quot;0.2&quot;
}
</pre>
<p>our content_scripts field says that the javascript in <b>tabnot.js</b> will be injected in every page (but just if it&#8217;s the top frame) whose the url matches &#8220;http://*/*&#8221; or &#8220;https://*/*&#8221; (that&#8217;s for every page in a web site). This code will run inside an <i>isolated world</i>, so we don&#8217;t have to worry about clashes with any javascript in the monitored pages.</p>
<p>The content of <b>tabnot.js</b> file is:</p>
<pre class="brush: jscript; title: ; notranslate">
var titleEl = document.getElementsByTagName(&quot;title&quot;)[0];
var docEl = document.documentElement;

if (docEl &amp;&amp; docEl.addEventListener) {
	docEl.addEventListener(&quot;DOMSubtreeModified&quot;, function(evt) {
		var t = evt.target;
		if (t === titleEl || (t.parentNode &amp;&amp; t.parentNode === titleEl)) {
			titleModified();
		}
	}, false);
} 

function titleModified() {
	chrome.extension.sendRequest(&quot;&quot;);
}
</pre>
<p>We&#8217;ll make more complex the function titleModifier to fit the needs will occur. Now it&#8217;s pretty simple: it send a message to the background page (as we said the content scripts can&#8217;t use all of the chrome APIs but can, off course, communicate with other parts of the extension).<br />
This is the new <b>background.html</b>:</p>
<pre class="brush: jscript; html-script: true; title: ; notranslate">
&lt;html&gt;&lt;head&gt;&lt;script&gt;

function init() {
	chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
		var tab=sender.tab;
		chrome.windows.get(tab.windowId, function(win) {
			if (tab.selected &amp;&amp; win.focused) return;
			var popup = window.webkitNotifications.createNotification(tab.favIconUrl ? tab.favIconUrl : &quot;&quot;, &quot;&quot;, tab.title);
			popup.show();
		});

	});
}

&lt;/script&gt;&lt;/head&gt;&lt;body onload=&quot;init()&quot;&gt;&lt;/body&gt;&lt;/html&gt;
</pre>
<p>The _request_ parameter of the callback function passed as listener will be always an empty string according with the sendRequest inside tabnot.js. However we have all the information we need inside sender.tab.<br />
Please note that, unlike what we could do with the previous method, when after any change to the code we needed to reload only the extension, now we need to refresh also the monitored tab in order to reload the injected javascript.<br />
Testing it with <a href="http://unusoft.it/blog/wp-content/uploads/2011/11/scrolling_title.html" target="scrolling_title">this page</a> we&#8217;ll see that that shortly the screen will be filled with notifications. Probably it&#8217;s better if every tab can trigger just one notification each time, and that if the title changes again while a notification is still open the old notification will be replaced accordingly. In this way scrolling titles and cyclic messages will be readable the same way you can do it on the tab.<br />
The chrome API offer a simple way to achieve that, the property replaceId of the notification object. We set it before showing the popup and when we try to show it and a popup with the same value of replaceId is already open then the old one will be replaced. The API documentation says that the id of a tab is unique in a session, then we can use it as replaceId value.<br />
Another desirable feature is that capability to open the tab when you click on the popup showed by it. Then we&#8217;ll close the popup because its job is done.Here&#8217;s the third version of the background page:</p>
<pre class="brush: jscript; highlight: [9,10,11,12,13,14]; html-script: true; title: ; notranslate">
&lt;html&gt;&lt;head&gt;&lt;script&gt;

function init() {
	chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
		var tab=sender.tab;
		chrome.windows.get(tab.windowId, function(win) {
			if (tab.selected &amp;&amp; win.focused) return;
			var popup = window.webkitNotifications.createNotification(tab.favIconUrl ? tab.favIconUrl : &quot;&quot;, &quot;&quot;, tab.title);
			popup.onclick=function() {
				this.cancel();
				chrome.tabs.update(tab.id, {'selected' : true}, null);
				chrome.windows.update(tab.winowId, {'focused' : true}, null);
			}
			popup.replaceId=tab.id;
			popup.show();
		});

	});
}

&lt;/script&gt;&lt;/head&gt;&lt;body onload=&quot;init()&quot;&gt;&lt;/body&gt;&lt;/html&gt;
</pre>
<h3 id="cyclic_messages">Cyclic messages detection</h3>
<p>We have built something that detects promptly every change of title in the tabs but we&#8217;d like to show a notification only when it&#8217;s useful (and not annoying&#8230;).<br />
Let&#8217;s consider for instance a case that can be applied to several web sites. When an instant message arrives, Facebook changes the title alternatively from the original value (e.g. &#8220;Facebook&#8221;) to something like &#8220;Charlie Brown messaged you&#8221; and vice versa. The user may not be interested in the message, and she can just choose to close the notification, but, if we simply show the notification every time a title change (as we have done so far), the notification will keep on showing up. To avoid this we may use an algorithm as complex as we like, but we are going to restrict the scenario to the case of messages showed always in the same order and all different from each other, which should cover all of the relevant eventualities.<br />
We use an array containing the titles that could be part of a cyclic message.<br />
If the title changes twice within 15 seconds we push the titles in the array, but if the title changes slower we empty the array.<br />
As long as a change occurs fast enough we compare the new title with an old one (accordingly with an index increased every time there is a match and reset when there isn&#8217;t) and every time there isn&#8217;t a match we push it in the array. When the title matches the very last element of the array the boolean <b>cycle</b> is set to true. The comparison goes on with the following changes of the title and <b>cycle</b> will be reset the first time a new title doesn&#8217;t match an old one. If you close a popup during a sequence detection every new change to the title while <b>cycle</b> is true won&#8217;t trigger a new notification.<br />
The cyclic messages detection can be implemented in the content script or in the background page. Every choice has its own pro and con but they are not a big deal. In the current version (1.0) of the tab notifier the detection is implemented in the content script (tabnot.js) and the requests sent to the background page contains a string that indicates whether to show or to hide the notification, while the background page distinguishes the reason of the closing of a popup and when it&#8217;s due to a click of the user on the closing icon (that&#8217;s, if you look into the code, when popup.closingReason is undefined) it uses the API <a href="http://code.google.com/chrome/extensions/tabs.html#method-sendRequest">chrome.tabs.sendRequest</a> to communicate it to the content script.</p>
<h3 id="other_improvements">Other improvements</h3>
<p>To see the full code you can, after installing the extension, go to the directory where the files are stored by chrome, that should be ~/.config/google-chrome/Default/Extensions/ on linux, something like C:\Users\*UserName*\AppData\Local\Google\Chrome\User Data\Default\Extensions in a recent windows or C:\Documents and Settings\*UserName*\Local Settings\Application Data\Google\Chrome\User Data\Default\Extensions in an older version of windows.<br />
The code is a bit more complex compared with the one in this post. In fact, beside the <a href="#cyclic_messages">cyclic messages detection</a>, it implements some small extra ideas. For instance it reproduces the behaviour of a IM client also when it hides an open notification when the tab that triggered it is opened manually (this is done by means of the events <a href="http://code.google.com/chrome/extensions/tabs.html#event-onSelectionChanged">onSelectionChanged</a> and <a href="http://code.google.com/chrome/extensions/windows.html#event-onFocusChanged">onFocusChanged</a>).</p>
<p>What we think is really important is to leave the user free to decide what has to be notified and what must not. Which actually is another excuse to introduce another magic of the chrome extensions: the context menus.</p>
<p>Let&#8217;s change again the manifest: </p>
<pre class="brush: jscript; auto-links: false; highlight: [2,3,4,5,6,7,8,9,10,14]; title: ; notranslate">
{
	&quot;content_scripts&quot;: [
		{
			&quot;matches&quot;: [&quot;http://*/*&quot;, &quot;https://*/*&quot;],
			&quot;js&quot;: [&quot;tabnot.js&quot;]
		}
	],
	&quot;icons&quot;: {
		&quot;16&quot;: &quot;bell.png&quot;
	},
   &quot;background_page&quot;: &quot;background.html&quot;,
   &quot;description&quot;: &quot;Notifies when the title of a tab changes&quot;,
   &quot;name&quot;: &quot;Tab notifier&quot;,
   &quot;permissions&quot;: [ &quot;tabs&quot;, &quot;notifications&quot;, &quot;contextMenus&quot; ],
   &quot;update_url&quot;: &quot;http://unusoft.it/extensions/updates.xml&quot;,
   &quot;version&quot;: &quot;1.0.0&quot;
}
</pre>
<p>The highlighted changes show a new permission (<i>contextMenus</i>) that allows us to use the APIs in the <a href="http://code.google.com/chrome/extensions/contextMenus.html">chrome.contextMenus namespace</a>. The icon 16&#215;16 is showed next to a new &#8220;Tab notifier&#8221; item on the context menu by chrome. Just right-click on a web page too see it.<br />
In the background page we create a checkbox item in the context menu of chrome titled &#8220;Ignore this domain for the current session&#8221; with chrome.contextMenus.create during the initialization and we check or un-check it by means of chrome.contextMenus.update whenever the user selects a different tab. When the user clicks the menu item the extension updates a set of blocked hostnames. Here&#8217;s the creation of the item:</p>
<pre class="brush: jscript; title: ; notranslate">
var menuItemId=chrome.contextMenus.create({type:&quot;checkbox&quot;,
	title:&quot;Ignore this domain for the current session&quot;,
	checked:true,
	contexts:[&quot;all&quot;],
	documentUrlPatterns:[&quot;http://*/*&quot;, &quot;https://*/*&quot;],
	onclick:function(info,tab){
		var hostname = getHostname(tab.url);
		if (hostname) {
			if(info.checked) {
				mutedDomains[hostname]=true;
			} else {
				delete mutedDomains[hostname];
			}
		}
	}
});
</pre>
<p><i>getHostname</i> is a simple function that extracts the hostname by mean of a regular expression. <i>contexts</i> determines the types of elements of the page that will have the item in their context menu, <i>documentUrlPatterns</i> limits the documents that will have the item in their context menu on the basis of the url, in our case it&#8217;s equal to the <i>content_scripts.matches</i> field of the manifest, that limits the monitored pages. Here&#8217;s the function used to update the menu item: </p>
<pre class="brush: jscript; title: ; notranslate">
function updateMenu(url) {
	var hostname = getHostname(url);
	chrome.contextMenus.update(menuItemId,{checked:hostname.length&gt;0 &amp;&amp; (hostname in mutedDomains)});
}
</pre>
<h3>Ideas for the future</h3>
<p>Maybe you don&#8217;t like the matter that the list of ignored domains are not kept stored between two consecutive sessions. Indeed, doing that would be easy enough thanks to a new feature of Html5, <a href="http://dev.w3.org/html5/webstorage/#the-localstorage-attribute">localStorage</a>. But I wouldn&#8217;t do that until we enable the user to see and edit directly the list. We can do that adding an <a href="http://code.google.com/chrome/extensions/options.html">option page</a>, and with that we can do even more like managing regular expressions to ignore groups of url or subdomains (besides to ignore single urls). The list should be initially filled with a default set of web sites that already use desktop notifications.<br />
Html5 audio may helps to add another cool feature, that&#8217;s configurable audio notifications (that have to be disabled for a configurable list of web sites, initially filled with well-known sites that already play sounds when they have something to notify. </p>
<p>Update (21/12/2011): by the time you read this post some of the listed features will have been implemented.<br />
Please check the <a href="../../tab-notifier/#changelog" title="Tab notifier">changelog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://unusoft.it/blog/index.php/2011/ontogeny-of-a-chrome-extension-the-tab-notifier/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Notifications for everyone</title>
		<link>http://unusoft.it/blog/index.php/2011/notifications/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=notifications</link>
		<comments>http://unusoft.it/blog/index.php/2011/notifications/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 18:23:15 +0000</pubDate>
		<dc:creator>aranor</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://localhost/blog/?p=1</guid>
		<description><![CDATA[If you use one or more web-based emails or web thin clients for Instant Messaging such as Yahoo! Messenger, GMail chat or Facebook, it&#8217;s probably because for some reason you find them better than the equivalent desktop applications, or likely &#8230;<div class="read_more"><a href="http://unusoft.it/blog/index.php/2011/notifications/">read more</a></div>]]></description>
			<content:encoded><![CDATA[<p>If you use one or more web-based emails or web thin clients for Instant Messaging such as Yahoo! Messenger, GMail chat or Facebook, it&#8217;s probably because for some reason you find them better than the equivalent desktop applications, or likely you don&#8217;t want to install stuff at the office, or you can&#8217;t do it. A disadvantage of this solution is that you don&#8217;t have a visual notification when a new email or chat message arrives (at lest so far, and unless your browser is chrome and your web-mail is gmail (which uses the <a href="http://gmailblog.blogspot.com/2011/01/desktop-notifications-for-emails-and.html">desktop notifications</a>) or you can take advantage of some other combination of browser-plugin-webclient using HTML5 Notifications or similar, which is not my case).</p>
<p><a href="http://unusoft.it/blog/wp-content/uploads/2011/10/guification_greentoast.png"><img class="size-full wp-image-24 alignleft" title="pidgin + guification with the green toast theme" src="http://unusoft.it/blog/wp-content/uploads/2011/10/guification_greentoast.png" alt="" width="314" height="109" /></a>If you can install at least one desktop application, an excellent &#8220;all-in-one&#8221; solution is a multi-protocol IM program such as <a href="http://www.pidgin.im">pidgin</a> that notifies also new incoming emails for some kind of mailboxes. If you opt for pidgin you should install a plug-in that shows notifications in a &#8220;toaster popup&#8221;, for this porpuse  I used <a href="https://www.guifications.org/projects/gf2/wiki">guification 2</a> for long, but I don&#8217;t think it&#8217;s nice with the default theme. To install a theme, after downloading it, open the themes tab (Tools&gt;Plugins&gt;Guifications&gt;Configure Plugin&gt;Themes), drag the downloaded file and drop on it. This post shows a screenshot of guification with the <a href="http://gnome-look.org/content/show.php?action=content&amp;content=41614">Green Toast Theme</a>. On a recent linux distribution you may prefer to activate the pre-installed libnotify plug-in.<br />
Pidgin is not the only multiprotocol chat client out there, I&#8217;d like to mention at least <a href="http://live.gnome.org/Empathy">Empaty</a>.</p>
<p>An alternative for users without administrator privileges is to install a suitable extensions for your browser. I checked the <a href="https://chrome.google.com/webstore">chrome web store</a> and there were several of them. Some act as proper email clients, which means that you have to configure them the same way you would do it with your desktop email application, others use specific ways to check the mailbox such as the Yahoo! Mail API, I didn&#8217;t find an all-in-one solution (please post it if you find something with nice alerts for any of the major browsers).</p>
<h3>Let&#8217;s do it ourselves</h3>
<p><a href="http://unusoft.it/blog/wp-content/uploads/2011/10/yahoo_tab.png"><img class="size-full wp-image-25 alignleft" title="yahoo tab" src="http://unusoft.it/blog/wp-content/uploads/2011/10/yahoo_tab.png" alt="" width="163" height="63" /></a>The basic idea here is that to solve a simple problem you should need a simple solution. Most of the mentioned web clients change the title of the page to tell the user that something happened. If we can detect and correctly interpret these <em>alerts</em> we can take advantage of that, in this way we won&#8217;t need to poll the mailboxes duplicating the work of the web-based mails and we won&#8217;t need to configure anything. Basically we won&#8217;t need to reinvent te wheel, the web clients are there and usually they are good enough, we just need to add the things that they need: the desktop notifications.<br />
This is what the <a title="Tab notifier" href="http://unusoft.it/blog/index.php/tab-notifier/">Tab notifier for chrome</a> does. In the <a href="http://unusoft.it/blog/index.php/2011/ontogeny-of-a-chrome-extension-the-tab-notifier/" title="Ontogeny of a chrome extension: the tab notifier">next post</a> we&#8217;ll see how it is made, using it as an excuse to explore some of the capabilities in developing chrome extensions.</p>
]]></content:encoded>
			<wfw:commentRss>http://unusoft.it/blog/index.php/2011/notifications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
