Personal tools

May 07, 2010

... and finally: what if they want tab inside Plone portlets?

A little demo (and the idea behind) for collective.portlettabber product

They want tab!

The request is quite common in recent layout that you can see all around the Web. Ok, "portlet" is common, but you can also find many examples of portlets with tabs.

What is this? The data inside portlets is split in sections that you can easily switch with a little Javascript code. The benefit is to put more information inside a tiny space, maybe showing to users only the most interesting ones when he arrive at your page.

Technically speaking this task is so simple that a blog post is not needed... but we don't know what kind of contents we want put inside the portlet tab.

Also the customer want to have the choice of use all (maybe the most part) of Plone portlets available is his installation... We really can't rewrite/overrider all portlets to get this...

...and finally (like everytime) accessibility. Data inside portlets must the accessible and the requirement 15 of the Stanca Act force us to make this available also with Javascript disabled.

Solution

Let's starts from what we can't lose:

  • accessibility of the page without Javascript
  • all Plone portlet usable as "tab"

For those two reasons the simplest way is to keep Plone portlet engine like it is. Plone portlets are working normally without Javascript, so why don't simply show tabs in only when Javascript is there?

This lead us to a solution. "Simply" generate portlet with tab using Javascript.

One more time again jQuery is our hero. The product add to Plone portal_javascript tool a new jQuery plugin for this. Is not a perfect plugin right now (is a composition of jQuery and normal Javascript OOP) but reach the target.

Here an example:

jq(document).ready(function() {
    var generatedPortlet = jq.tabbedportlet();

    generatedPortlet.makeTab("#portal-column-two .portletNews");
    generatedPortlet.makeTab("#portal-column-two .portletCalendar");
    generatedPortlet.makeTab("#portal-column-two .portlet-static-static");
    jq("#portal-column-two .visualPadding").prepend(generatedPortlet.getPortlet());
});

When page is loaded a new Javascript object is created, and calling makeTab method you can "steal" other existing portlets all around the page (simply giving a jQuery selector, a DOM element or a jQuery object wrapping the portlet).

The method also has other features, look at the pypi page below for more.

Every call to makeTab will remove the portlet and move the DOM elements of the portlet inside a new ones (that, for now, is not inside the document yet).

When you have finished, just put the result of getPortlet method wherever you want.

The final effect is quite good... the demo will show you the page with disabled Javascript, then (long life to Web Developer's Firefox extension) it is enabled again and the page reloaded...

What next?

The product is not so simple to be used by Plone site members (this is not named collective.portlet.tabber... :-))

A developer or a skinner must provide the additional Javascript inside a product/theme and he must know something about jQuery selectors... but after this starting setup... nothing more!

Another thing Ithat is not perfect is the Javascript structure, not a fully jQuery plugin. You can't fully rely on chaining right now.

More info?

http://pypi.python.org/pypi/collective.portlettabber

 

May 04, 2010

New collective.funkload releases

I have recently released a new version of collective.funkload and collective.recipe.funkload. There is one major improvment - funkload recorder is now working properly with collective.funkload scripts.

Here @RedTurtle we are heavily using funkload for acceptance and benchmarking tests. We have started using it in 2008 just after Bristol Performance Sprint. We have found even more useful with buildout recipe. The only missing part was the recorder. It's built-in Funkload itself, but it was not enabled in the recipe. Well - now it is ;-)

/ If you want to know how to include funkload in buildout project - check my previous blog /

Starting a recorder is quite easy:

$ ./bin/funkload record -p 8080 MyTest


for full usage call:

$ ./bin/funkload record --help


This will start proxy on 8080 port and save all your browser requests to MyTest funkload scenario. Now open your browser, change proxy configuration to localhost:8080 and click-through test case. When you finish - stop the proxy with Ctrl-C. Funkload will generate a test_MyTest.py file and notify you where you can find it. It should be now collective.funkload compatible - you can lunch:

$ ./bin/funkload test /path/to/test_MyTest.py


To test it.

Another small improvement is a PloneFLTestCase. It extends default funkload test case, implementing two additional methods helping with Plone content creation. Right now instead of using this approach:

folder_portal_factory = self._browse(server_url + "/coreloadtests/Members/" + self.user_id +"/createObject?type_name=Folder",
                                             method='get', 
                                             follow_redirect=False,
                                             description = 'Get folder portal factory')

folder_edit_url = folder_portal_factory.headers.get('Location')        
folder_id = folder_edit_url.split('/')[-2]

folder_created = self.post(folder_edit_url, params=[
    ['id', folder_id],
    ['title', 'folder'],
    ['description', ''],
    ['description_text_format', 'text/plain'],
    ['subject_existing_keywords:default:list', ''],
    ['last_referer', 'http://localhost:8080/coreloadtests/Members/' + self.user_id + '/view'],
    ['form_submit', 'Save']],
    description="Post /coreloadtests/Members/user...280843853/atct_edit")

new_folder_id = folder_created.url.split('/')[-2]

 

you can just do:

new_folder_id = self.addContent(
        server_url, 
        portal_type='Folder', 
        params=[['id', 'id'],
                ['title', 'testing title'],
                ['description', 'testing description'],
                ['description_text_format', 'text/plain'],
                ['form.submitted', '1'],
                ['last_referer', ''],
                ['form_submit', 'Save']], 
        description='Create folder')

 

It doesn't do much, but for sure it helps you keep you test case readable.

May 03, 2010

No more "display:none" CSS rules!

Filed Under:

Plone give us the right way to hide elements from the HTML page! Just use it... but what about jQuery?

It's not a news that accessibility is an important target of Plone... and Plone knows that CSS rules that use "display: none" are not readable by screen readers. However too often the display:none rules is used in themes, add-ons...

The problem is that this behavior is not so know outside the Plone core. Developers sometimes thinks that something that is hidden from the screen but present in HTML is accessible using a screen reader.
This is false.

How the screen reader works?

I'm not a real expert about it, but here what I learned.
When the page is loaded, the screen reader make a "screen-shot" of it and works on this. So elements that are hidden... for everyone!

So:

  • Use display:none if you really want something in HTML that no-one can read.
  • Do it like Plone does... apply the hiddenStructure class to your HTML element when you want something that can be accessible but not visible on you computer screen

What about Javascript/jQuery?

You like the jQuery .hide() and .show() features like me?

Well... keep in mind what you read some lines above... You use some .hide() call at load time? You use .hide() when clicking some links or buttons?

All this is not accessible...

Again, you need to think about using CSS given by Plone, so you must rely on the .addClass("hiddenStructure") and .removeClass("hiddenStructure") methods...

If you prefer give some new features to jQuery, you can also do something like this:

jQuery.fn.ploneHide = function() {
	return this.each(function() {
		jQuery(this).addClass("hiddenStructure");
	});
}

jQuery.fn.ploneShow = function() {
	return this.each(function() {
		var e = jQuery(this);
		if (e.is(":hidden")) e.show();
		e.removeClass("hiddenStructure");
	});
}

After this, you can rely on some new jQuery features!

jq(".documentByLine").ploneHide();

Apr 29, 2010

Ferrara WPD 2010 - un case study di evento riuscito

Filed Under:

Con la soddisfazione dei Clienti si possono fare molte cose, anche un evento di successo

Chi trova un amico....

Mesi fa, in un incontro strategico con esperti di marketing, abbiamo appreso con sorpresa che il "passaparola" tra Clienti soddisfatti e potenziali nuovi Clienti, che per noi è la norma, rappresenta il livello massimo del successo di mercato.

Col senno di poi, ci siamo resi conto di aver sempre saputo che un Cliente soddisfatto è anche un amico prezioso: PloneGov Italia è in fondo l'estensione a un livello più alto di questo principio di scambio di informazioni utili. Sentire qualcuno che dice "Ti consiglio Plone" per noi è quasi altrettanto importante che sentir dire "Ti consiglio RedTurtle" (per inciso, ad oggi metà degli Enti PloneGov Italia sono nostri Clienti).

La "Plonopoli" emiliana

Scendendo nel pratico: aver trovato la Città giusta (la nostra: a Ferrara Università, Camera di Commercio, Comune, Provincia, AUSL e AOU Sant'Anna tutti usano Plone), il Cliente giusto (AUSL Ferrara) e la persona giusta (Isabella Masina dell'Ufficio Comunicazione), ci ha consentito di mettere rapidamente in piedi un evento oggettivamente utile non solo per noi, ma soprattutto per gli stessi Enti che vi hanno preso parte.

L'occasione giusta

Consolidati luogo, Cliente e interlocutore, il World Plone Day ha fornito l'elemento mancante: l'occasione giusta. Isabella, ben coordinandosi con i responsabili di riferimento, capaci di cogliere il senso dell'iniziativa, e appoggiandosi a RedTurtle per individuare i relatori più interessanti, ha messo in gioco la capacità organizzativa del suo Ente, e (con una tempestiva adesione) la "fratellanza" PloneGov Italia, riuscendo a coinvolgere, oltre ai membri Ferraresi di PloneGov Italia, anche la Regione, AUSL Bologna ed anche Enti fuori regione come Ospedali Galliera Genova.

E' ovvio che questi stessi enti, compresi quelli già Clienti RedTurtle, non sono a disposizione di un'azienda e mai si sarebbero mossi per un evento "marcato" RedTurtle. Invece, le dinamiche di PloneGov e il modo con cui la AUSL si è messa in gioco, simile a quello già sperimentato da Camera di Commercio di Ferrara, hanno consentito a Enti differenti, uniti dall'appartenenza a PloneGov Italia, di investire il loro tempo in un'azione di autopromozione della tecnologia, lasciando spazio a nostri interventi tecnici a fronte di una piccola sponsorizzazione.

"A collective win-win"

Così abbiamo visto AUSL differenti parlare tra loro e con Comuni e Aziende Ospedaliere. Perchè la cosa ci faccia piacere, è chiaro, ed è legittima la speranza di aumentare il numero di nostri Clienti soddisfatti. La cosa interessante è che tutti assieme abbiamo abilitato un modello trasparente, lecito e non invadente per aiutare i nostri Clienti a condividere la loro soddisfazione, parlandosi tra loro di problemi e di soluzioni Plone. Forse siamo davvero al top del marketing....

Apr 28, 2010

Where is my FSS file?

Filed Under:

Sometimes you need to know where is your FSS file on disk. There is an easy way to get the full path

Following example returns full path to ATFile 'file' field on disk:

>>> field = self.context.getField('file')
>>> fss_info = field.storage.getFSSInfo('file',self.context)
>>> fss_info
<FSSFileInfo at test-file.pdf/>
>>> fss_strategy = field.storage.getStorageStrategy('file',self.context)
>>> fss_strategy
<iw.fss.strategy.DirectoryStorageStrategy instance at 0x21332c68>
>>> fss_props = field.storage.getStorageStrategyProperties('file',self.context,fss_info)
>>> path = fss_strategy.getValueFilePath(**fss_props)
>>> path
'/opt/buildout.plone/var/fss_storage_global/5b/5b09/5b09c322ae211207649e1803fe012cca_file'
Document Actions