Skip to content. | Skip to navigation

Personal tools
Sections
You are here: Home Topics jQuery
Navigation
 

jQuery

Jul 13, 2010

Evil Javascript... use strip() or trim()?

by keul — last modified Jul 13, 2010 05:22 PM

I hate doing the same error all the time! One time again: how to obtain a cross browser method for Javascript to remove leading and trailing whitespaces inside strings?

Every time I make the same stupid error! So, let's make quickly, a guide for obtaining this behavior.

The trim() function works only on Firefox and maybe other browsers, but not on IE.

In my experience the stript() function instead works better, both on Firefox and IE.

So what is the problem? That every time I forget to use this last one, and I use again trim instead of stript...

There is a solution for my lazy brain? Well... I use very often (AKA "always") jQuery for our projects, so... please Luca... from now just use jQuery.trim().

I feel better! No more error from now...

...

... until next time.

Jun 29, 2010

TextAreaBound: trying my first jQuery plugin

by keul — last modified Jun 29, 2010 12:22 PM

HTML has some nice attributes to control the size and bound of input fields. However those features aren't working for textarea. Our customer asked us for those features: max number of lines in a textarea, max numbers of character in the textarea AND in a line... Let's try to develop a jQuery plugin for obtaining this!

The APIs we want

We must reach this:

$(...).maxLinesLengthBound(n)
$(...).maxLinesCountBound(n)
$(...).maxTextLength(n)

Obviously, we like jQuery chaining so also this must work:

$("#textareaid").maxLinesLengthBound(20).maxLinesCountBound(15)

All of the 3 new jQuery feature take all the textarea element from the expression given and apply new bounds.

  • The maxLinesLengthBound method will put a limit on the number of lines in a textarea
  • The maxLinesCountBound method will put a limit in the number of characters of each line
  • The maxTextLength method is the most simple: put a limit to the number of total character in textareas

Bad news one: Javascript events

When adding character in Javascript we can rely on 3 events:

  • keydown event is called when a key is pressed (before it's released)
  • keyup event is called when a key came up after keydown.
  • keypress event is called when a key is... pressed! So it goes down and then up. More important, if you keep pressed a button, starting the characters-repeat, this even is called multiple times.

As you can see, the keypress is the best choice... but using this event has a great limitation.

When you rely on keydown event, the "actual" value of the field is the old one. When you bind an handler to the keyup or keypress events the value you can read is the new one. You have no way to know what was the old value of the field.

Don't think to use other events like change event. This type of event has the same problems and also is called only when the control loose focus.

Solution to bad news one

Yes, we can only read the new value of the field, but we can also use the event object and take from it the value of the pressed key, so we can know what new character will be added to the textarea

Bad news two: knowing where the cursor is (on Internet Explorer)

Unluckily in a textarea you not always append characters... you can also add new characters inside the text. The pressed key is still a very important resource, but we must also know in which position we are inside the textarea.

The task seems simple on all browsers, with only a single exception: you can read the selectionStart attribute of the textarea DOM element.

We really need this only for one of the 3 APIs we need above: the maxLinesLengthBound method. Other 2 APIs don't need to know where the cursor is...

The vary bad news is this: Internet Explorer do not support selectionStart!

Solution to bad news two (AKA: bad news three)

You can surf the Web looking for an alternative, and you will find a lot of blog post, articles and script for giving an alternative.

What is clear is that you must use some funny IE specific APIs like getBookmark and createRange... and you will fail.

I found no way to really have the same simple features. On Internet Explorer 7 I have a lot of problems when I go to the second line. Those APIs seems buggy and the browser don't see that you go on a new line.

Tired of this, I leave the problem to someone more expert than me with IE Javascript.

Wanna help me?

The jQuery plugin

You can find the plugin on the jQuery plugin official page, and also other info and the SVN repository in my Google Code space.

 

May 07, 2010

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

by keul — last modified May 07, 2010 11:25 AM

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 03, 2010

No more "display:none" CSS rules!

by keul — last modified May 03, 2010 02:25 PM

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 11, 2010

Change navigation behaviour with jQuery: collective.navigationtoggle

by keul — last modified Apr 11, 2010 09:05 PM

A requirement from one of our customer lead us to develop a very tiny Plone add-ons... After all jQuery make all the dirty work!

Navigation collapsedOne of the navigation portlet in the main site of our customer is done like the one you see on the left.

The element with arrow icon is unique and very important, but is not the element itself that links to an important document. The real useful information for end users are elements inside the section with this special icon (the subelements).

If facts the different icon itself is not enough so the customer asked us to develop an expand/collapse feature to make possible to users to not be forced to visit the not-important-section, then choose one of the subelements. For user experience the first click is only a waste of time (it's matter of usability) as the general element you see in the navigation is only a way to keep together and categorize the real infos.

Question: how many not-important-section you have in your Plone sites? Folder that only show folder_listing view or useless welcome pages?

Navigation expandedHowever: what we developed in the first version of this site was a very simple (and not configurable) expand/collapse feature, you'll see on the right.

This was a Plone 2.1 site and what you see wasn't a real Plone navigation portlet. Important subelements were all loaded with the page and a simple Javascript script make them visible/invisible.

As we recently migrated this site to Plone 3, the question was: can we reproduce the same effect keeping the Plone real navigation... and this time make the feature more reusable?

Some of you can say at this point that there are already other dynamic Javascript/AJAX navigation system for Plone (for example, I well remember collective.portlet.explore) but the problem here is different... we don't want to make all navigation(s) entries expansible/collapsible but only one (or few).
Another important fact: this is the site of an italian public company, so it must follow the Stanca Act accessibility requirements (so very restrictive in matter of client side scripts technology) and a complete Javascript UI is not a good choice.

The role of jQuery

Instead of developing some new funny navigation system, our work was focused on making the most possible client side (whit an eye on graceful degradation like the Law say).

We used jQuery to obtain a cross-browser, configurable and simple plugin for Plone that make possible to chose on which navigation elements apply the expand/collapse feature. All this client side!

Welcome to collective.navigationtoggle.

The only server side component is a simple view that query the Plone catalog to show all element inside a given folder, and return all information needed by jQuery to generate navigation sub-elements on the fly (quite simple, isn't it?).

The view return only a JSON data structure, so the HTML is generated client side. How? The code create new navigation elements cloning existing ones from the navigation itself (using parents of the trigger element), then filling them using response data.

Is this way is possible that even a non-standard Plone navigation could works normally with this product (not so sure of this... to be honest some assumption are done, like the main element structure of the navigation that must be composed of UL and LI elements).

Cache

Two different problem there: prevent browser from caching server response for a too long time, but also prevent that if a user begin to click 10.000 times onto the navigation element this will send to the server one non cached request for every click.

The first problem is quite simple playing a little bit with HTTP header sent by the server, and adding timestamps with the client side request.

For the second problem we rely on jQuery.data() fantastic method, caching the generated HTML and preventing that expand/collapse actions will ask the server for the same data.

Configuration

Right now we have a real well-know problem to solve, so the product is targeted on developers. To configure it you must provide a tiny Javascript with line(s) of code like this:

jq.collective_navigationtoggle.toggle_elements.push("/foo1/foo2");

This is a simple Javascript array stored in the jQuery plugin namespace. Data provided must be the final part of the href attribute of links inside navigations portlet. This link will no more move the user to the target page but will be gifted with the expand/collapse feature.
All the magic left is done by the power of jQuery.

Plone 4 and jQuery 1.4

The product works on Plone 4 also... no problems with jQuery 1.4 (delivered with the next version of our favorite CMS, while Plone 3.3 still rely on jQuery 1.3), in facts dropping jQuery 1.3 support can reduce the Javascript code size and complexity (jQuery 1.4 has new fantastic features... take a look!).

However a real and pretty integration like with the Plone 3 theme right now is not available in Plone 4 also. Maybe in future I can work on this (Plone 4 Sunburst is not using anymore the IMG tag, instead it generate icon usin CSS classes). If you are interested and wanna help, you are welcome!

Mar 22, 2010

Conditional Javascript choices relying on server side configurations

by keul — last modified Mar 22, 2010 10:12 PM

Have you ever felt the need of make a Javascript choice, executing some client side actions, basic this choice on some server side configuration? Here an interesting way I recently taked, thanks to the powerful jQuery plugins structure.

Describing the problem

I'm near to release a new version of collective.flowplayer_toolbar (so it's only on collective SVN right now).

The first version of the product (see the old blog post about it) give a new Javascript controlsbar to Flowplayer, disabling the native Flash ones.

In a production environment we received some comments about this choice because when disabling the Flash controls you are not able anymore to use fullscreen mode... bad!
The only solution is to keep both control systems because is not possible (due to security issue) to control fullscreen from Javascript.

Have both controls give us the best freedom (features and accessibility)... but to be honest I find it really ugly!

Flowplayer instance with controlsbar

So, the best way is to give some configuration for switch from:

  • using only the Javascript controls
  • using Javascript and Flash controls

The collective.flowplayer choice

The same kind of problem has been overcome by collective.flowplayer.
Some of the configuration you can manage in the flowplayer_properties leave to changes in the client-side Javascript behaviour.

I'm not sure that this is the only motivation, but this problem is solved there providing the Javascript code not using a static file (so not giving a Javascript text source) but using a zope 3 view.
This view (collective.flowplayer.js) return a text/javascript content type:

    def __call__(self, request=None, response=None):
        """ Returns global configuration of the Flowplayer taken from portal_properties """
        self.update()
        self.request.response.setHeader("Content-type", "text/javascript")
        ...

The problem with this approach is that you must work with Javascript code written inside Python string... not really comfortable.

Of course, the problem is only for the developer. Client side the Web browser will not feel any difference.

Experimental approach

As far as Flowplayer works well with jQuery (and jQuery Tools, that is a requirement of collective.flowplayer using plone.app.jquerytools) I'm trying a second approach to the problem. This because:

  • I don't like to write Javascript inside strings
  • I really like the power of jQuery plugins support, and this has become more clear to me after having read recently a book on this.

Following the server side collective.flowplayer approach I added a new property to the portal_properties tool (it's only a single property, so I added it to the same flowplayer_properties sheet).

This boolean property (toolbar_flash_controlsbar) must only controls this single line of Javascript code:

this.getPlugin("controls").hide();

I need a way to execute this only when the flag is True.

The solution is simple: execute this line of code only when a Javascript variable is evaluated true/false:

if (!show_flash_controlsbar)
	this.getPlugin("controls").hide();

Now we only need a way to controls from the server this client variable, but first it's better to provide a default initialization.

As far as this control is executed inside a Flowplayer event, we can add the initialization before or after this piece of code, directly in the flow of page execution (so the order matters not):

var show_flash_controlsbar = false;

So the default is also the default of the toolbar_flash_controlsbar property (False) and we will not see that Flash controls.

Now we really need a way to react to a True value server-side.

The way used here is to include another (minimal) Javascript piece of code, this time after the ones above (so, if included, it must be after the initialization of the show_flash_controlsbar).

show_flash_controlsbar = true;

To keep controls on the inclusion of this we need to put this into a separate Javascript file and include it conditionally after the ones above.

The Generic Setup inclusion take this form:

 <javascript cacheable="True"
             compression="safe"
             cookable="True"
             enabled="True"
             id="++resource++flowplayer_toolbar_js/flash_controlsbar.js"
             insert-after="++resource++flowplayer_toolbar_js/flowplayer.accessible-controls.js"
             expression="portal/portal_properties/flowplayer_properties/toolbar_flash_controlsbar|nothing"
             inline="False"/>

In the expression TAL we check and evaluate the server side property (and for security we also put a |nothing, to prevent all sort of errors if, for example, the property has been deleted).

The portal_javascript tool take care of providing this Javascript script or not, even when the it's merged with other and cached.

Don't you talked of jQuery somewhere above?

The only problem with this approach is the namespace pollution. We must be sure that the name of this variable is not used/taken from other Javascript code somewhere in Plone.

jQuery and its plugins technology help in this, and also help to keep things more clear and ordered.

With the syntax below we can make this definition available only inside the jQuery environment, preventing that non-jQuery Javascript code change/use this variable.

jQuery.show_flash_controlsbar = false;

Note the use of jQuery name, not $ or jq: this is how plugin development guidelines recommend to define and use jQuery object when developing plugins.

In our code we can continue testing the condition in this way:

if (!jq.show_flash_controlsbar)
	this.getPlugin("controls").hide();

This is better than before, but we can make it more robust.

This approach can fails only if another jQuery plugin define and use the same name for an internal variable of function (ok, this is paranoyc); if this become true we can get errors or unexpected results.

The best jQuery way is to define an internal namespace, making this problem more and more difficult to arise.

So finally we define the variable in this way:

jQuery.flowplayer_toolbar = {
	/**
	 * Some other script can put this to true to enable also the native controlsbar plugin
	 * This is the only way to get features like the fullscreen.
	 */
	show_flash_controlsbar: false
};

And we test it like this:

if (!jq.flowplayer_toolbar.show_flash_controlsbar)
	this.getPlugin("controls").hide();

The last benefit of using an internal jQuery namespace is to keep similar variables or function together. May be that some other variables (or global functions?) can be needed in future version of this product, so we can add them inside the same namespace.

Going back: is this approach better or not?

Aswer: I don't know. This works well with browser cache but as you can see it needs some more work than providing a dynamic Javascript source from the server using a view.

The most annoying things is the registration of an additional entry inside the portal_javascript tool only for put an additional line of Javascript code... this is not a problem for one script, but can you imagine this repeated for all collective.flowplayer configuration (or for other products too)?
The numbers of entries will explode!

Mar 11, 2010

Careful with that ajax, Eugene

by Alessandro Pisa — last modified Mar 11, 2010 04:40 PM

Ajax calls are an invaluable and powerful tool to deploy pleasant user interfaces, but some attention must be paid to avoid bad surprises.

In these days it happened to me to work on a couple of custom Plone edit forms using ajax calls to simplify user data entry.

At a first glance, the user experience was great, but under the hood the whole machinery was hiding potential problems, the reason being that in both cases the ajax calls used in the form were relative to the document path, even when if the document was in the factory!

This means that every time the ajax call was invoked, additional security checks were performed and in the case of the documents inside the factory other this lead to an unwanted creation of temporary documents!

The security checks and the portal factory abuse increased the response time and could potentially raise conflict errors.

During the development phase the problem is hardly noticeable, but on a production server it will probably make the form unusable, especially if you complex security checks are needed.

The solution was simply to call the views with another context (in those cases the container). 

Lesson learned: be careful to the context of your ajax call

Dec 14, 2009

collective.flowplayer_toolbar: adding accessibility in an unobtrusive way

by keul — last modified Dec 14, 2009 09:43 AM

The way I used to make Flowplayer use inside Plone a little more accessible, this time without branching the collective.flowplayer product!

First of all: some terms

After finishing this article I understand that people not familiar with this argument and software can be confused, so:

  • Flowplayer (in capitalized form) is a Flash player for audio/video files, indipendent from the Plone technology.
  • collective.flowplayer is a Plone products that use Flowplayer and give this player well integrated in Plone CMS
  • collective.flowplayer 1.x is an old release family, that use Flowplayer 2.x
  • collective.flowplayer 3.x is the last release family, that use Flowplayer 3

Introduction to main characters

Flowplayer is one of the most promising Flash audio/video player available right now, and we can use it in a simple way inside Plone site thanks the collective.flowplayer, a well know product that replaced the use of p4a.video in recent Plone experiences.

Flowplayer is good, and open source, but not the most accessible available player. Our work with collective.flowplayer accessibility begin when the available release was the 1.0.x version.

As noted above, Flowplayer version used in this old release was the old 2.x, so many of the most recent and cool features were missing; on the other hand, the current 3.x family is heavily integrated with jQuery Javascript framework.
Not less important, the Flowplayer team is the one who released the jQuery Tools, the javascript addon for jQuery recently integrated in Plone 4 thanks to plone.app.jquery.

Fixing collective.flowplayer 1.x

The main accessibility problem of Flowplayer is its flash controlbar. Practical tests show that is not easy to handle video controls using the keyboard.

Our customer, the same that ask for accessible videos in Plone and also like Flowplayer very much, provide us a static HTML example of Flowplayer that use Javascript controlbar, simply usable with keyboard. The problem was that this example supports Flowplayer 3.2, the current version of the Flash player, but not the version used in the Plone addon.
Also the example provide a patched version of the controlbar plugin for Flowplayer. This custom version add some missing HTML attributes and WAI-ARIA support.

After looking on the web we found that even if Flowplayer 2 was backward compared to the new branch, it provides some limited APIs, usable through Javascript.

Our target was to replicate all the feature seen in the Flowplayer 3 demo in the Flowplayer 2 environment... of course this was not so easy! However after some work we find a way to provide those features:

  • a play/pause button
  • a stop button (not required, but was simple to do)
  • a timer display

The collective.flowplayer branchThe only feature "impossible" to obtain (directly) was the progressbar... to be honest, some additional Javascript could also realize this (we have the duration of the video, we have the current execution time, we know how to perform arithmetic division... why not draw ourself? :-) but was enough.

What we really don't like was this: we found no (simple) way to write a Plone addon that work with collective.flowplayer 1.0, adding to it our new features.

We don't waste more time: we made a branch of the original collective.flowplayer 1.x, providing our new feature.

Thank you! Thank you! We have collective.flowplayer 3.x!

After a few weeks collective.flowplayer 3.x was released (I think that the developers team skipped the 2.x version for aligning the Plone product's version to the Flowplayer one).
So we came back to the original example give to us (the customer project was happy finished using our branch) just for test the new feature available and to understand is in future a new, better approach is possible.

The API's of the latest Flowplayer versions are more complete and powerful, heavily filled with the jQuery power.

This time we were able to develop something that could live and enhance the original collective.flowplayer, releasing only a new product: collective.flowplayer_toolbar.

The final result really better than the old approach; without embarrassment I can say that we did a few line of codes! The most part of the work of our new controlbar came from Flowplayer features and one more time from the great jQuery library.

You want see the "core" of this product?

/**
 * Javascript code for adding accessible toolbar to flowplayer players in the page 
 */

jq(document).ready(function(event) {
	$f("*").each(function() {
		this.onLoad(function(event) {
			this.getPlugin("controls").hide();
			var p = jq(this.getParent());
			var p_width = p.width();
			var time_width = (p_width<400?99:129);
			var hulu_id = "hulu-"+ (jq(".hulu").length+1);
			p.after('<div id="'+hulu_id+'" style="width:'+p_width+'px" class="hulu">\n'
				+'<a class="play" href="javascript:;" role="button">Play</a>\n'
				+'<div class="track" style="width:'+(p_width-46-46-time_width)+'px">\n'
				+'    <div class="buffer"></div>\n'
				+'    <div class="progress"></div>\n'
				+'    <div class="playhead"></div>\n'
				+'</div>\n'
				+'<div class="time" style="width:'+time_width+'px"></div>\n'
				+'<a class="mute" href="javascript:;" role="button">Mute</a>\n'
				+'</div>\n');
			this.controls(hulu_id);
			// Now I'll fix all other positions of the new toolbar
			jq("#"+hulu_id+" a.mute").css('left', p_width-46);
			jq("#"+hulu_id+" div.time").css('left', p_width-46-time_width);
		});
	});
});

The rest of the egg simply use a limited version of the original CSS of the demo page in Flowplayer site, the patched controlbar plugin (but you can use the original one without problems)... nothing more!

The jQuery presence make real the injection our new feature on existings Flowplayer instance in the page (for example, this is also working properly for our redturtle.video product). No need to patch/branch collective.flowplayer, also no need to override some views or resource of it.

Conclusion

This work can be also a proof-of-concept for future Flowplayer integration with additional features. The player supports many additional plugins (Yuri point my attention to the Caption Flash plugin...).

Oct 04, 2009

Hidden Javascript Jewels inside Plone!

by keul — last modified Oct 04, 2009 03:09 PM

The basic Plone installation rely on some little javascript sources that can be very useful.

Right now Plone is filled with a lot of jQuery javascript script for obtain UI effects. Every time you need an effect that Plone has, you must before ask to you: I'm sure that I only need to write down some good HTML, and nothing more?

Please not that even if this page try to integrate the same examples reported, you can't really see them working due to CSS issue. Use Firebug "Inspect element" feature to see how the javascript is changing the DOM.

Expand/collapse like "history" does

The javascript jem responsible of this is collapsiblesections.js.

It's javascript docstring says:

/* - collapsiblesections.js - */
/*
 * This is the code for the collapsibles. It uses the following markup:
 *
 * <dl class="collapsible">
 *   <dt class="collapsibleHeader">
 *     A Title
 *   </dt>
 *   <dd class="collapsibleContent">
 *     <!-- Here can be any content you want -->
 *   </dd>
 * </dl>
 *
 * When the collapsible is toggled, then the dl will get an additional class
 * which switches between 'collapsedBlockCollapsible' and
 * 'expandedBlockCollapsible'. You can use this to style it accordingly, for
 * example:
 *
 * .expandedBlockCollapsible .collapsibleContent {
 *   display: block;
 * }
 *
 * .collapsedBlockCollapsible .collapsibleContent {
 *   display: none;
 * }
 *
 * If you add the 'collapsedOnLoad' class to the dl, then it will get
 * collapsed on page load, this is done, so the content is accessible even when
 * javascript is disabled.
 *
 * If you add the 'inline' class to the dl, then it will toggle between
 * 'collapsedInlineCollapsible' and 'expandedInlineCollapsible' instead of
 * 'collapsedBlockCollapsible' and 'expandedBlockCollapsible'.
 *
 */


This piece fo code can be great for obtain the same sexy expand/collapse feature that you see all around Plone UI.

For example, I can use here this code:

<dl class="collapsible collapsedOnLoad">
    <dt class="collapsibleHeader">
      See the RedTurtle Hidden logo
    </dt>
    <dd class="collapsibleContent">
      <img alt="The RedTurtle Logo" src="http://www.redturtle.net/logo.jpg" />
    </dd>
 </dl>


And what is the results?

See the RedTurtle Hidden logo
The RedTurtle Logo

Dropdown menus

Wow! Can you believe that the dropdown menus you see in the working area of Plone (like "View", "Add portal content", ...) are only a piece of simple HTML and a magic javascipt does all the work?
The script this time is dropdown.js.

It says:

/* - dropdown.js - */
/*
 * This is the code for the dropdown menus. It uses the following markup:
 *
 * <dl class="actionMenu" id="uniqueIdForThisMenu">
 *   <dt class="actionMenuHeader">
 *     <!-- The following a-tag needs to be clicked to dropdown the menu -->
 *     <a href="some_destination">A Title</a>
 *   </dt>
 *   <dd class="actionMenuContent">
 *     <!-- Here can be any content you want -->
 *   </dd>
 * </dl>
 *
 * When the menu is toggled, then the dl with the class actionMenu will get an
 * additional class which switches between 'activated' and 'deactivated'.
 * You can use this to style it accordingly, for example:
 *
 * .actionMenu.activated {
 *   display: block;
 * }
 *
 * .actionMenu.deactivated {
 *   display: none;
 * }
 *
 * When you click somewhere else than the menu, then all open menus will be
 * deactivated. When you move your mouse over the a-tag of another menu, then
 * that one will be activated and all others deactivated. When you click on a
 * link inside the actionMenuContent element, then the menu will be closed and
 * the link followed.
 *
 */


So you only need to design an HTML dl structure like this:

 <dl class="actionMenu" id="myDummyMenuId">
   <dt class="actionMenuHeader">
     <a href="some_destination">Open the magic dropdown</a>
   </dt>
   <dd class="actionMenuContent">  
       <img alt="The RedTurtle Logo" src="http://www.redturtle.net/logo.jpg" />
   </dd>
 </dl>


Here follow the example usage

Open the magic dropdown
The RedTurtle Logo

Conclusion

There is a lot of Magic behind Plone, but thanks to jQuery and a smart infrastructure you can use this Magic for your needs!