Thoughts about improving load resiliency for CMS driven Websites

The following is an article I wrote based on a note I sent to the Mozilla Developer Network mailing list about an idea that crossed my mind to help scale a CMS driven website.

I’m convinced i am not the first one who came out with a similar idea, but I thought it would be useful to share anyway.

What’s common on a CMS driven Website?

What affects the page load is what happens in the backend before getting HTML back to the web browser. Sometimes its about converting the text stored in the database back into HTML, making some specific views, and the list can go on and on.

Problem is that we are spending a lot of CPU cycles to end up serving time and time again the same content, unique for each user when about 90% the generated content could be exactly the same for everybody.

What makes a content site page unique from what an anonymous visitor can get?
with web apps is that we make backend servers generate HTML as if it was unique when, in truth, most of it could be cached.

What if we could make a separation between what’s common, and use caching and serve it to everybody.

How HTTP cache works, roughly

Regardless of what software does it: Squid, Varnish, NGINX, Zeus, caching is done the same way.

In the end, the HTTP caching layer basically keeps in RAM generated HTTP Response body and keeps in memory based on the headers it had when it passed it through to the original request. Only GET Responses, without cookies, are cacheable. Other response body coming from a [PUT, DELETE, POST] request aren’t.

To come back on my previous example, what part is unique in the the current user compared to what the anonymous visitor gets on a documentation Website page.

What does a Website view serves us then? The content of the page, the “chrome” (what’s always there), Links to account settings, edit, or visualize details for the current page, account settings, the username, link to logout.

It means we are making unique content for things that could be cached and wasting cycles.

Even then, most of the content is cacheable because they would generally be with the same paths in the CMS.

How about we separate dynamic from static?

This makes me wonder if we could improve site resiliency by leveraging HTTP caching, strip off any cookies, and factor out what’s unique on a page so that we get the same output for any context.

As for the contextual parts of the site ‘chrome’, how about we expose a context-root which would take care of serving dynamically generated HTML to use as partials.

One way of doing it would be to make that context-root generate simple HTML strings that we can pass to a JavaScript manager that’ll convert it into DOM and inject it in the ‘chrome’.

Since we can make cookies to be isolated to specific context-roots, we can keep the statefulness of the session on MDN and have a clear separation of what’s dynamic and what’s not.

Upgrade to Python 2.7.9 on Ubuntu 14.04 LTS, and make your own .deb package for deployment

I had this post hanging in my drafts on how I attempted to install a valid Python 2.7.9 runtime environment on Ubuntu 14.04 and make my own .deb package for easy re-deployment.

IMPORTANT This procedure isn’t complete as I had to shift focus elsewhere. I might rework this article to adjust what’s missing.

While I understand that Ubuntu 14.04 will remain using Python 2.7.6 internally, applications we run can be configured to use another python environment. Its what virtualenv is all about after all, isn’t it.

This post attempts to install, and make an installable .deb package of Python 2.7.9 and is meant to be used by web applications without touching the system’s python runtime.

Why not replacing internal Python version?

The reason is simple. If you replace internal Python version, other softwares within the OS will have broken dependencies.

I realized this while I wanted to upgrade the version and breaking an hard dependency I have on Salt Stack. Since many components within a given Ubuntu version relies on Python, it could break anything else. This is why I stopped working on the idea of replacing internally, but instead to configure VirtualEnv to use another version instead.

If you see procedures that shows you to replace telling you to use update-alternatives to replace python, don’t do it! Go instead learn how to run your own Python version in VirtualEnv.

Procedure

  1. Install build dependencies

    Those were the ones I ran last before a successful build on Ubuntu 14.04 LTS, if you aren’t using the same distribution, you might get a different list.

      apt-get install -y gcc-multilib g++-multilib libffi-dev libffi6 libffi6-dbg python-crypto python-mox3 python-pil python-ply libssl-dev zlib1g-dev libbz2-dev libexpat1-dev libbluetooth-dev libgdbm-dev dpkg-dev quilt autotools-dev libreadline-dev libtinfo-dev libncursesw5-dev tk-dev blt-dev libssl-dev zlib1g-dev libbz2-dev libexpat1-dev libbluetooth-dev libsqlite3-dev libgpm2 mime-support netbase net-tools bzip2
    
  2. Get Python sources and compile

    wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz
    tar xfz Python-2.7.9.tgz
    cd Python-2.7.9/
    ./configure --prefix /usr/local/lib/python2.7.9 --enable-ipv6
    make
    make install
    
  3. Test if the version works

    /usr/local/lib/python2.7.9/bin/python -V
    Python 2.7.9
    
  4. Then prepare package through FPM

    apt-get install -y ruby-dev gcc
    gem install fpm
    ...
    

Its basically about creating a .deb based on your new runtime setup. You can do that by using fpm (“Fabulous Package Manager”), I am using this technique in a post I published recently about installing a PHP library.

Incomplete scratchpad

But that’s as far as my notes goes for now. Sorry about that.

Setuptools

As per recommended in Setuptools instructions, we can run easy_install through a wget, like so;

  wget https://bootstrap.pypa.io/ez_setup.py -O - | /usr/local/lib/python2.7.9/bin/python
  /usr/local/lib/python2.7.9/bin/easy_install pip
  /usr/local/lib/python2.7.9/bin/pip install virtualenv

Then, create symbolic links

  ln -s /usr/local/lib/python2.7.9/bin/easy_install /usr/bin/easy_install
  ln -s /usr/local/lib/python2.7.9/bin/pip /usr/bin/pip

You can try if it worked

  pip list
  pip (6.0.8)
  setuptools (14.3)
  virtualenv (12.0.7)

Resources

  • http://davebehnke.com/python-pyenv-ubuntu.html
  • https://github.com/yyuu/pyenv
  • https://www.python.org/downloads/release/python-279/
  • http://aboutsimon.com/2012/04/16/building-a-python-deb-in-a-bootstrapped-ubuntu-chroot-with-fpm/
  • http://serverfault.com/questions/669859/how-can-i-upgrade-python-to-2-7-9-on-ubuntu-14-4
  • http://askubuntu.com/questions/101591/how-do-i-install-python-2-7-2-on-ubuntu
  • https://wiki.debian.org/Debootstrap
  • http://www.stylesen.org/python_27_debian_squeeze_60

Astuce concernant le rafraîchissement du contenu des pages avec utilisation d’AJAX en exemple

Parmi les listes de courriels que je suis, Accesstech, une question a attiré mon attention et j’ai pensé partager ici la réponse que j’ai donnée avec un exemple en appui.

Concernant le rafraîchissement du contenu des pages avec utilisation d’AJAX, a-t-on trouvé une solution pour
qu’un lecteur d’écran le détecte et retourne l’information à l’utilisateur ?

Si non, quelles solutions alternatives avez-vous trouvées ( en dehors de recharger la page intégralement) ?

Ce que j’ai répondu

Je ne suis pas expert, mais je pense que ce qui arrive et modifie le DOM de façon asynchrone en regard de l’accessibilité, demande au minimum:

1. Faire une ecriture en creeant les elements DOM, puis les inserer

Avec jQuery, par exemple, il est possible de créer un élément DOM de cette façon. Mais attention, l’élément existe dans le document qu’au moment de son insertion via la commande element.append().

<script>
// dom ready...
var newNode = JQuery('<div id=patate>Allo</div>');
</script>

2. Assurer de donner le focus sur le nouvel element inséré

Une fois l’élément construit, il est possible d’ajouter des attributs et évidemment de l’introduire, comme suit:

<script>
// ...
newNode.appendTo('body');
newNode.trigger('focus');
// ...
</script>

Ici, l’élément est inséré à l’intérieur du body, puis un événement focus est appelé. Notez ici que lancer un événement de cette façon peut être fait pour a peu près n’importe quel type d’événement, on peut même créer nos propres événements

3. Bonus: Faire la muse a jour de façon Asynchrone avec jQuery 1.7+ avec le concept de ‘promise’:

Étant donné la nature d’AJAX; dans le sens que la resource demandée n’est pas nécessairement disponible à l’exact moment où la requête est faite. jQuery a instauré un concept qui permet de travailler avec l’objet demandé, et agir au moment de son arrivée: promise.

Dans ce sens, il est maintenant recommandé d’utiliser un callback et le déclarer a la fin de l’action ajax, comme suit:

<script>
var promiseCallback = function(data){   jQuery('#patate').replaceWith(jQuery(data)).trigger('focus');   };
// assumant que c'est du html reçu de /allo.html
var configObj ={dataType: 'html'};
jQuery.ajax('/allo.html', configObj).done( promiseCallback );
</script>

Finalement

Ce qui est souvent oublié c’est que $.ajax.done() est executé après avoir reçu ses donnees.

De cette facon, le refraichissement se fait quand elle est prete et le focus suivra.

Par-contre il y a des precautions a prendre: Assurez-vous que ce code est executé apres un action de l’utilisateur et non pas n’importe quand car l’evenement risque de deplacer le focus du lecteur d’ecran et perdre l’utilisateur.

Espérant que j’ai connecté quelques fils :)

Creating and using Javascript events while combining events on two separates behaviors

I discovered something that chocked me: Did you know that the ‘click’ event is only a string and you can create any event name you may want? Here is an experimentation example.

During web development, it often happens you want to attach events handler on something in your page. A common usage could be you want to flip a plus sign to a minus sign when you click on a button.

<a href="/some/url/324" class="flip-icon" data-target="#generated-324"><i class="icon-plus"></i></a>

Later in a script you may be compelled to do something similar to the following (assuming you are using jQuery):

$(document).ready(function(){
// Rest of the document in document.ready
// DO NOT USE AS-IS, SEE LAST EXAMPLE

    $('.flip-icon.).click(function(event){  
        event.preventDefault(); 
        var clicked = $(this);
        var flipElement = clicked.find('i');
        if (flipElement.hasClass('icon-plus')) {
            flipElement.removeClass('icon-plus').addClass('icon-minus');
        } else {
            flipElement.removeClass('icon-minus').addClass('icon-plus');
        }
    });
});

But what happens if you want to add other events such as, for example, activating an accordion. You may end up with duplicating events and get some collisions.

Did you know that the ‘click’ event is only a string and you can create any event name you may want?

To describe what I am refering to, I have a add an other behavior that will also, in part, require the previous example.

Imagine we have an accordion managed already grabbing the element’s a[data-target] click event handler.

$(document).ready(function(){
// Rest of the document in document.ready
// DO NOT USE AS-IS, SEE LAST EXAMPLE

    $('a[data-target]').click(function(event){
        // do the accordion stuff
    });
});

But, what if for some reason, our page has to reload some sections and our event handler managing the a[data-target] click gets lost

Instead, of creating a click specific event handler (what if we want to change) and be potentially lost with the element to attach event onto.

You can use jQuery’s on method and attach an event to the <body>, a safe element that every document has.

Things to note about the on method:

  • First parameter is an event name, can be ANYTHING (yes, you read it), space separated
  • Second element is on what to listen, can be null
  • a Function object to handle the event

Also, there is nice thing about bubbling.

When an event happens, the event crawls the DOM up to the body (called ‘catch’) then gets back to the triggerer element (called ‘bubbling’) and firing in that order all event handlers.

Knowing all of this now, instead of attaching a single event type handler to a specific element, let’s take advantage of our new knowledge.

'use strict';
$(document).ready(function(){
// Rest of your document

    // Look at the 'flip-my-icon-event', we just made-up that one. See below.
    $('body').on('click flip-my-icon-event', '.flip-icon', function(){
/* Look here     *************************                                       */
        // Let's put it also in a self-executing anonymous, to isolate scope
        (function(triggered){

            // Same as earlier.
            var clicked = $(this);
            var flipElement = clicked.find('i');
            if (flipElement.hasClass('icon-plus')) {
                flipElement.removeClass('icon-plus').addClass('icon-minus');
            } else {
                flipElement.removeClass('icon-minus').addClass('icon-plus');
            }
            // End same as earlier

        })($(this)); // this fires the self-executing.
    });

    $('body').on('click', 'a[data-target]', function(event){
        event.preventDefault();

        // do the accordion stuff
        var collapsible = $($(this).attr('data-target'));
        if (typeof collapsible.attr('data-collapsible') === 'undefined')  {
            collapsible
                .collapse()
                .attr('data-collapsible', 'applied')
                .on('show', function(){
                    jQuery(this).parent().removeClass('is-hidden');
                })
                .on('hide', function(){
                    jQuery(this).parent().addClass('is-hidden');
                });
        // End do the accordion stuff

        jQuery(this).trigger('click').trigger('flip-my-icon-event');
/* Look here                         *******************************        */
        }
    });
});

The following works, because of the following trigger html pattern, as from the begining:

<a href="/some/url/324" class="flip-icon" data-target="#generated-324"><i class="icon-plus"></i></a>

And of the following:

  • We have an icon for .icon-plus and .icon-minus class names
  • The a[data-target] attribute has ALSO a .flip-icon class name
  • The a[data-target] triggers our made-up flip-my-icon-event event to an element that also matches (see the two ‘look here’ comments)

References

A list of quality indicators we could find on an application or web site

When we write a project specification document, we write functionnal and non-functionnal and other sections. As I want to communicate to my peers and sponsors the level of quality, I thought of creating this list of indicators.

 

Web application quality attributes

  • Frontend should adjust to the user browser (tablet, computer, phone) “Responsive” (already partially in place)
  • Frontend URIs should express what they represent for future/possible conversion to REST service endpoint
  • Frontend response time should be as quick as possible using optimization techniques such as assets minification and non-blocking javascript
  • Code “Domain” (language) should illustrate user intent
  • Frontend to use W3C valid markup following HTML5 recommendations in a “Progressive enhancement” manner;
  • Logging system should declare application state and intents and provide helpful feedback (e.g. “User jshmoe logged in from… Montreal Quebec.”)
  • Front-end error message should be using terms that speaks to the end user
  • Error message and notices should not break layout
  • All message and user read text should be without spelling mistakes or bad translation

 

Frontend as quick to load as possible

Among most recommendations and references about common user frustrations is the time a web page loads.

The idea is to basically push to the queue and forget returning a page back as soon as possible.

Other key aspects are graceful degradation of javascript, functional site even with javascript errors.

Most importantly. The portal frontend can be deployed in any number of instances, with only one address, and be completely transparent to the user.

 

Your opinion

What else should we also include in such a list? I agree that it is not complete as much as a W3C recommendation is. But I believe it is much good in a context of a project outline to explain details you are taking into account while evaluating.

 

Reference

Comment je valide et convertit des documents HTML trop chargés ou provenant de Microsoft Word en HTML valide et simplifié

Description

Cette procédure est faite optimiser la conversion document word en html, spécialement ceux qui sont généré avec beaucoup de «tagsoup» en en simplifier a sa plus simple expression html. Valide.

Sauter à la Procédure

Exemple

Avant
<h2 class="Standard" dir="ltr" lang="fr-FR" style="margin-top: 0; margin-bottom: 0; text-align: center;" xml:lang="fr-FR">
  <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">TERMS AND CONDITIONS OF 1</span> <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">‐</span> <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">YEAR OR 30</span> <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">‐</span> <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">DAY ACCESS AND USE</span>
</h2>

<span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">OF THE SERVICE BY SUBSCRIBERS</span> <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">SECTION 1</span> <span lang="en-CA" style="font-weight: bold; font-size: 16.0px;" xml:lang="en-CA">PURPOSE OF THE SERVICE</span>
Après
<h2>TERMS AND CONDITIONS OF 1 ‐ YEAR OR 30 ‐ DAY ACCESS AND USE</h2>

<span>OF THE SERVICE BY SUBSCRIBERS SECTION 1 PURPOSE OF THE SERVICE</span> 

 

Inspiration et pistes

  1. Convertir de format document en ligne de commandeDe Word2000 vers HTML, voir UNOCONV http://dag.wieers.com/home-made/unoconv/#download

 

 

 

Procédure 

Version abstraite

  1. Utiliser Open Office (ou peu importe) pour exporter le document en HTML

* Purifier via HTMLTidy
* Nettoyer les attributs inutiles avec la classe htmLawed 

Use cases

Document texte seulement

  • Pas de formulaire, ni images, etc
  • Idéal pour un document légal, par exemple.

Étapes concrètes:

  1. A partir du fichier HTML généré exemple: Fichier appelé “1.1.2.en.html”

* Extraire le fichier htmLawed.zip
 
cd ~
mkdir htmlawed
mv htmLawed.zip htmlawed/
cd htmlawed
unzip htmLawed.zip

Passer au travers de la classe htmLawed

require('htmLawed.php');
$config = array('safe'=>1,'elements'=>'a,em,strong,p,ul,li,ol,h1,h2,h3,h4,h5,div,tr,td,table','deny_attribute'=>'* -title -href');
$out = htmLawed(file_get_contents('in.html'), $config);
echo $out;

Rouler le script. Déplacer le fichier a utiliser, puis exécuter le script pour en générer dans out.html

cp ~/1.1.2.en.tidy.html in.html
php cleanup.php &gt; out.html</pre>

Rouler Tidy. Normaliser le fichier “1.1.2.en.html”, Nettoyer les balises, minuscules, etc

tidy --drop-font-tags 1 --logical-emphasis 1 --clean 1 --merge-spans 1 --show-body-only 1 --output-xhtml 1 --word-2000 1 --indent "auto" --char-encoding "utf8" --indent-spaces "2" --wrap "90" 1.1.2.en.html &gt; 1.1.2.en.tidy.html

tada!

Précautions

Ordre d’exécution des tâches

Remarque:

J’ai essayé de passer Tidy avant htmLawed et j’ai réalisé que le nettoyage de htmLawed est assez drastique et que Tidy rend le code plus propre. Sans oublier que htmLawed peut générer des balises vides que Tidy va éliminer.

Références

  1. Options Tidy
  2. htmLawed Documentation a PHP Html purification Class
    1. original documentation
    2. Example settings

How I managed to make work Guzzle REST client library under Symfony 2.0.x as a bundle [Snipet]

Warning This is not a cut and paste solution. But some notes I want to share on how I did and what I’d like to cover and remember when I will continue working with that aspect on my current projects.

The problem i had was mostly that i had to see where to mix-and-match things between this wonderful library and Symfony2. I discovered after searching here that it’s not that complicated, you just need to get through the learning curve of reading the code AND the documentation.

I am posting here the hilight of what I have been struggling with and will re-read soon about how to use it and implement in into Symfony2.

Things I wished I understood faster

  • How to inject the configuration from symfony without hardcoding paths in my Managers/Controllers
  • Why do the XML configuration file has nodes like <client> in the main project file, but it’s not what triggers the Command. Answer: Use ServiceDescription::factory($xmlFileFullPath) from the Client class. Yes, it has <client> nodes… NO, they are not the same as in the client definition file xml (guzzleclients.xml).
  • How to extend a DynamicCommand from the ServiceDescription

The Gist

Improvement paths

Actually, now that I went through all this, A simple yaml annotation with a simple service definition with @MyBlogBundle/Resources/config/serviceDescription.clientName.xml could had done the job.

How to implement a CollectionType Form field with AJAX “add new” embedded form with re-usable markup using Symfony2 and Twitter Bootstrap

I wanted to create a re-usable piece of code that makes me able to “add new” input field and makes the relationship with the other entity.

I did only find some very specific (and not re-usable) examples, so I gave my try on this question. Hope you find it usefull.

Here is how I did it, in some generic manner.

In generic, I mean, Any collection that I add to the form just need to follow the Form template loop (in a macro, for example) and that’s all!

Using which convention

Form Type class

The form template

Trick here is that I would have had used the original {{ form_widget(form }} but I needed to add some specific to the view form and I could not make it shorter.

And I tried to edit only the targeted field and found out it was a bit complex

My notes on Snipt.net

I created a Snipt to use on my Sublime Text 2 editor installation. In case you want to use it:

References

I wrote a complete answer, hoping to add some value on StackOverflow, here is some other paths I read about it.

    Résumé de mes essais avec composer sous Symfony 2.0.x et un manifeste composer.json pour vos propres tests

    Ce soir j’ai pris le temps d’essayer de configurer une distribution Symfony 2.0.x sous Composer. Je ne suis pas certain encore si j’ai totalement réussi. J’aimerai votre avis sur ma proposition de fichier composer.json.

    Statut mis à jour

    Je suis retourné avec le fichier deps à cause que je n’ai pas réussi a avoir toutes mes dépendances fonctionnelles dans un délai raisonnable (trois soirs). J’essaierai à nouveau plus tard.

    Résultat

    En ce moment je n’arrive pas a faire fonctionner JmsDiExtraBundle ni la nouvelle version de MopaBootstrapBundle notamment pour le mopa/bootstrap-sandbox-bundle. Je mettrai ce billet a jour lorsque j’aurai terminé mes essais.

    Résultat escompté

    Avoir un manifeste complet pour Symfony 2.0.x que je pourrai utiliser avec mes bundles préférés:

    • jms/security-extra-bundle
    • jms/di-extra-bundle
    • jms/serializer-bundle
    • gedmo/doctrine-extensions
    • stof/doctrine-extensions-bundle
    • knplabs/knp-components
    • mopa/bootstrap-bundle
    • knplabs/knp-paginator-bundle
    • polishsymfonycommunity/blog-bundle

    Composer.json file

    {
        "description": "This bundle is meant to run latest 2.0.x Symfony-standard distribution, based on Composer.",
        "keywords": ["symfony2"],
        "type": "symfony-bundle",
        "license": "MIT",
        "authors": [{
            "name" : "Renoir Boulanger",
            "email" : "[email protected]"
        }],
         "autoload": {
            "psr-0": { "": "src/" }
        },
        "require": {
            "php": ">=5.3",
            "symfony/symfony": "2.0.*",
     
            "twig/twig": "1.6.*",
            "doctrine/orm": "2.1.7",
            "doctrine/common": "2.1.4",
            "doctrine/dbal":   "2.1.7",
            "swiftmailer/swiftmailer": ">=4.1.7",
            "monolog/monolog": "1.0.*",
     
            "symfony/assetic-bundle": ">=1.0.1",
            "sensio/distribution-bundle": "2.0.*",
            "sensio/framework-extra-bundle": ">=2.0",
            "sensio/generator-bundle": "2.0.*",
     
            "jms/metadata": ">=1.1.0",
            "jms/security-extra-bundle": "1.0.x",
            "jms/di-extra-bundle": ">=1.0.0",
            "jms/serializer-bundle": "master",
     
            "gedmo/doctrine-extensions": "v2.2.2",
            "stof/doctrine-extensions-bundle": "1.0.2",
            "liip/imagine-bundle": "master",
     
            "knplabs/knp-components": "1.1.*",
            "mopa/bootstrap-bundle": "2.0.*",
     
            "knplabs/knp-paginator-bundle": "dev-master",
            "knplabs/knp-menu-bundle": "dev-master",
            "mopa/bootstrap-sandbox-bundle": "2.0.x-dev",
            "liip/theme-bundle": "dev-master"
        },
        "config": {
            "bin-dir": "bin"
        },
        "extra": {
            "symfony-app-dir": "app",
            "symfony-web-dir": "web"
        }
    }

    Confirm form before submitting using Twitter Bootstrap in a Modal window [Snippet]

    Idea

    Have you ever wanted to create a way to confirm input before actually submitting the form. Automatically.

    My snippet’s goal is exactly for that purpose. The idea is that it reads the form inputs and labels, and generates a modal window (like a lightbox) and asks confirmation. This project is a contribution I do to Twitter Bootstrap and jQuery-bootstrap-scripting (“dialog2”) to add on any form using Twitter Bootstrap form markup convention the capability to create a confirmation modal window.

    The concept is that some forms needs to have some confirmation and requires more than “are you sure”, but also what you are submitting.

    How it works

    When the pages load, it executes in this order the following:

    • Whether there is a form[data-behavior=confirm], and modify the form default submit button to replace it with a link (idea being that if there is no javascript enabled, you can still submit!)
    • on a Click action on the newly created a.confirm-toggle, it fires up some html manipulation and creates a modal window using jQuery Bootstrap Scriptin’s Dialog2 plugin

    Word of advice

    I have to warn you though. The solution is not yet complete. It works well with input[type=text] and some select. But I need to add more field types as time goes. That’s why I created this Fiddle to give room for improvement. Feel free to collaborate. When the solution will be strong enough, i’ll contribute it to both projects in their respective syntax (dialog2 doesnt initialize the same way as Bootstrap’s modal()

    Known limitations

    • Works only with select and input[type=text], and breaks bad with radio and checkbox
    • Works only with ONE form in the page, for now.
    • ¨

    The code

    You can play with this Fiddle in the meantime i make it ready-er

    The javascript

     
        /**
         * Use form's content into a confirmation modal
         *
         * Using: http://nikku.github.com/jquery-bootstrap-scripting/
         * Requires: Twitter Bootstrap, dialog2
         *
         * @author: Renoir Boulanger
         */
        if ($('form[data-behavior=confirm]').length >= 1) {
     
            console.log('run.js: document ready : Applying confirmation, ' + $('form[data-behavior=confirm]').length + ' times');
     
            $('form[data-behavior=confirm] select').click(function() {
                var dataValue = $(this).find(':selected').text();
                $(this).attr('data-value', dataValue);
     
                // Debug console
                console.log('Adding data-value at: ' + dataValue);
            });
     
            $('form[data-behavior=confirm] .confirm-toggle').replaceWith('<input id="confirm-submit" type="submit" class="is-hidden"/>' + '<a href="#" class="confirm-toggle btn btn-primary">Continue</a>');
     
            /**
             *  Since we know javascript is executed so far, lets handle it with the confirmation.
             *
             *  That way, no javascript-enabled browsing user will be able to use the form. #progressiveEnhancement
             *
             *  Do the work.
             */
            $('form[data-behavior=confirm] .confirm-toggle').click(function(event) {
                event.preventDefault();
     
                // Get form content
                var form = $('form[data-behavior=confirm]').clone().attr('id', 'cloned'); //.appendTo('body');
                var i = 0;
                form.find(':input:not([type=hidden])').each(function() {
                    var field = $(this);
     
     
                    if (field.is('select')) {
                        fieldValue = $(this).attr('data-value');
                        if (fieldValue === undefined) {
                            fieldValue = field.find(':selected').html();
     
                            // Debug console
                            console.log('fieldValue was undefined, setting to : ' + fieldValue);
                        }
     
                        // Debug console
                        console.log('fieldValue is : ' + fieldValue);
                    } else {
                        fieldValue = field.val();
                    }
     
                    // Remove undefined field (they are useless)
                    if (fieldValue === '') {
                        field.parent().parent().addClass('empty-field-resolved');
                    }
     
                    // Debug console
                    console.log('Field ' + i + ' :' + fieldValue + ' for #' + field.attr('id'));
     
                    // Wrap fieldValue in a tag, Tested in IE7!!
                    field.after($('<span class="value">' + fieldValue + '</span>'));
     
                    // Remove the field itself, we only want to see the resulting
                    field.remove();
     
                    i++;
                });
     
                // Work stuff out for modal window, copying content, and building modal into the DOM
                var decorate = $("<div id=\"modal-placeholder\"><div class=\"modal-builder\"></div></div>");
                var buildup = decorate.find(".modal-builder").html(form);
     
                buildup.appendTo('body');
     
                // Debug console
                console.log('Appending #modal-placeholder in body, ready to call dialog2()');
     
                // Remove not needed anymore stuff
                $('.modal-builder .help-block, .modal-builder .input-append, .modal-builder .form-actions').remove();
     
                $('.modal-builder').dialog2({
                    title: "Are you sure?",
                    id: "confirm-modal",
                    modalClass: "modal-wide fade in",
                    closeOnOverlayClick: false,
                    closeOnEscape: false,
                    initialLoadText: "Loading in progress...",
                    buttons: {
                        Confirm: {
                            primary: true,
                            click: function() {
                                // Debug
                                console.log('Inside dialog2() clicked Confirm');
     
                                $('#confirm-submit').click();
                            }
                        },
                        "Forgot something": {
                            click: function() {
                                // Debug
                                console.log('Inside dialog2() clicked cancel');
     
                                $(this).dialog2("close");
                                $('.modal').remove();
                                return false;
                            }
                        }
                    }
                });
                // Do my own cleanup. Remove potentially bogus nodes
                $('#modal-placeholder, .modal-header .close, .control-group.empty-field-resolved').remove();
            });
        }

    The CSS

    Minimally…

    .modal-wide {
      overflow:visible;
      width: 650px;
    }
     
    .modal-builder .control-label {
          padding:0 !important;
          font-weight:bold;
    }
     
     /* In case you use a span.required-star
      * with title="required field", I don't want to
      * have them in modal
      **/
    .modal-builder  .required-star {
        display:none;
    }
     
    .modal-builder .hide-in-confirm {
      display:none !important;
    }

    Tell me in the comments if you want the LESS block I created

    The Form

    Always using Twitter Bootstrap markup, A form minimally needs

    What is really required here is

    • Form tag has data-behavior="confirm" attribute
    • Form submit button has at least the class name confirm-toggle

    Just use any combination of Twitter Bootstrap Form patterns

    <form class="form-horizontal" method="post">
    <fieldset>
    <div class="control-group hidden-in-confirm">
    <!-- This block will be hidden -->
                <label class="control-label" for="input01">Text input</label>
    <div class="controls">
    <input id="input01" class="input-xlarge" type="text" />
     
    In addition to freeform text, any HTML5 text-based input appears like so.</div>
    </div>
    <!-- ... the form ... -->
    <div class="form-actions">
                <button class="btn">Cancel</button>
    <input class="btn btn-primary confirm-toggle" type="submit" value="Continue" /></div></fieldset>
    </form>

    Possible enhancements paths

    My solution fit for what I needed. A two parameters to add confirm in a modal using the project’s markup. Sadly I read after doing it that there is some plugins I could have considered such as the Form plugin

    .

    End word

    I am going to prepare this post and propose a pull request to the jQuery Bootstrap Scripting AND Bootstrap project in a day or two.

    Ressources

    • http://nikku.github.com/jquery-bootstrap-scripting/#
    • http://twitter.github.com/bootstrap/base-css.html#forms

    L’appel aux conférenciers pour ConFoo 2011 est lancé!

    Passe ConFoo 2010
    Photo prise sur Flickr par Pyxis technologies

    Depuis cet été j’ai commencé à m’impliquer dans l’organisation de la conférence «ConFoo Web Techno Conference». Je crois que j’en ai parlé dans ce billet. Il s’agit d’un événement annuel pensé pour les programmeurs, les passionnés du web et des logiciels libres.

    La semaine passée, nous avons publié officiellement l’appel aux conférenciers. C’est la première annonce grand public du début de la programmation 2011. Jusqu’au 26 Novembre 2010, nous acceptons les propositions de présentations.

    La procédure est simple, il faut proposer sa présentation par le formulaire “appel aux conférenciers” sur le site officiel.

    La date et le lieux de la conférence sont maintenant officielles et se déroulera à l’Hôtel
    Hilton Bonaventure de Montreal du 9 au 11 Mars 2011. Durant cette semaine il y aura aussi des journées de formation privés.

    Ma participation

    Pour moi ce sera ma première année dans l’équipe d’organisation de cet événement d’envergure. Je pense que ça tombe dans le sens de m’y impliquer car lorsque j’ai démissionné de l’animation des scouts j’ai décidé de pousser dans des loisirs qui sont plus près de ma carrière mais qui demanderont d’autres talents que ceux de faire de l’Intégration ou de la programmation.

    Bug trouvé et corrigé sur un thème WordPress rtTheme

    Depuis que nous avons fondé EVOCATIO Solutions technologiques nous avons pris une position d’experts dans le domaine des acrobaties techniques. C’est ce qu’on faisait dans nos journées de tout les jours avant.

    Ce que j’avait pas pensé c’est que je trouverait de la demande pour des tâches pointues et qu’on devait  «faire marcher». L’une d’elles a été fait, justement, pour un ami que je respecte beaucoup: Geoffroi Garon.

    Avec sa permission je publie ici comment j’ai réglé un petit bug Javascript. Rien d’extraordinaire mais quand même bête lorsqu’on s’attend a ce que de quoi fonctionne qu’on a acheté et qu’il ne fonctionne pas. Finalement, tout juste avant de publier ce billet, j’ai réalisé que, l’auteur (@ftolgacan) a réparé le code. Comme quoi j’ai pris trop de temps avant de le publier.

    Il s’agit d’un thème adapté qui a été acheté sur ThemeForest pour un site fait en WordPress. Étant donné que le thème fourni n’a pas vraiment d’endroit ou proposer les correctifs j’ai décidé de publier sur mon blogue.

    Je contribue en français mais ferai une courte explication de ma correction en anglais sur l’item précis sur le site officiel.

    Pour voir le démo du thème, allez dans la section “Preview” puis dans la section “products” du site qui est illustré.

    Continue reading “Bug trouvé et corrigé sur un thème WordPress rtTheme”

    Comment remplacer les caract√®res bizzares dans WordPress lorsqu’on a mal fait la conversion

    Accrocheur mon titre n’est-ce pas? Je trouve ça tellement pas drôle lorsque ça m’arrive ce genre de situation avec les caractères accentués. Le problème n’arrive pas tout le temps qu’avec WordPress.

    Voici, enfin, une suite a mon billet Pourquoi tout ces caractères bizzares. Je devais travailler sur un problème de conversion de caractères pour un client dus a une conversion non réussie et/ou terminée entre latin1 et utf-8 puis je me suis remis a penser a ce problème. Pourquoi ne pas le régler, et documenter!

    Voilà pourquoi ce billet ;)

    La situation

    Mon cas était bien simple. J’avait mal fait ma sauvegarde lors d’un transfert et j’avait tout mes commentaires, billets, et autres données qui avait des accents “transform√©s comme √áa” (transformés comme ça).

    Ce genre de problème arrive pour toutes sortes de raisons. Mais le symptôme est le même. Si vous avez des
    Je partage avec vous mon bout de code a «copier-coller» dans phpmyadmin pour votre blogue WordPress si vous avez ces problèmes (oubliez-pas de faire des sauvegardes là(!)).

    Plusieurs tutoriels existent pour régler la situation mais mon cas était assez unique. J’ai conservé le problème puis j’ai publié plusieurs billets (qui sortent bien) et laissé ceux “ab√Æm√©s” là. Il n’était plus question d’extraire, convertir et ré-importer.

    Pourquoi?!

    C’est une réponse assez complexe. L’article UTF-8 sur TikiWiki.org l’explique en détail.

    In short, UTF-8 is a character encoding that uses 1 to 3 bytes for each character.
    It is one of the existing character encodings of the UCS (Universal Character Set), that contains nearly a hundred thousand abstract characters (including ASCII characters).

    UTF-8 greatly simplifies the task of internationalization by replacing multiple alternative encodings (such as ISO8859-15 Latin-9, which encodes those English, French, German, Spanish and Portuguese characters not available in ASCII).

    En simple, le UTF-8 est un format d’encodage qui utilise 1 a 3 bytes pour chaque caractère. C’est un format d’encodage qui comprend près de plusieurs centaines de milliers de caractères (Incluant ceux du ASCII).

    UTF-8 est fait pour contenir tout les caractères existants pour simplifier l’internationalisation.

    C’est un standard qui est pas nécessairement jeune mais qui n’était pas non plus supporté partout.

    MySQL a commencé a le supporter qu’a partir de la version 4.1.

    Ce qui arrive c’est qu’avec le temps, les gens prennent de plus en plus soin de rendre accessible pour toutes les langues leur applications. Ainsi un russe pourrait écrire en cyrillic et un Japonais en Kanji dans la même base de donnée. Le coup est difficile! Surtout que les versions de MySQL et PHP et Java offrent maintenant le choix par défaut en UTF-8… lorsqu’on fait pas attention: on se fait coincer!

    Continue reading “Comment remplacer les caract√®res bizzares dans WordPress lorsqu’on a mal fait la conversion”

    Plugin MODx pour générer automatiquement les balises ABBR et autres pour chaque page

    Il s’agit d’un plugin que j’ai fait, en PHP 4 il y a deux ans pour MODx 0.9.6.3, pour un site web et je pense qu’il vaut la peine que je partage le code avec la communauté.

    Le plugin sert a entourer des mots définis dans un fichier CSV (séparé par des virgules) dans le contenu qui est retourné par le CMS.

     

    LA SITUATION

    Lorsque je travaillait sur ce site web, mon employeur et mon collègue nous étions donné comme objectif de paufiner l’Ergonomie et l’Accessibilité du contenu. Ce qui est dommage c’est qu’il n’a jamais été évalué par AccessibilitéWeb. J’ai pourtant reçu la formation pour évaluer les sites… mais je préfère, personnellement, programmer des applications.

     

    Continue reading “Plugin MODx pour générer automatiquement les balises ABBR et autres pour chaque page”

    Réalisation d’une application d’échange de cadeau avec RED L’agence le «club échangiste» [2009]

    Il s’agit d’une réalisation que j’ai effectuée en deux semaines pour RED L’agence. L’idée vient de François Sauvé lors d’une rencontre pour un autre projet. Il m’a dit: «J’ai une idée de fou. Je ne sais pas si on pourrait faire ça rapidement mais…».

    C’est le genre de situation que j’aime!  Une question, la possibilité de me laisser aller, et hop!

    RED voulait faire offrir un cadeau à chacun de ses clients privilégiés d’une façon hors de l’ordinaire. Les participants étaient invités a visionner leur cadeau par une petite carte de noël reçue par la poste (devant, dos) avec une adresse web et un code.

    Le concept graphique était, selon moi, bien rendu. Un club échangiste avec les lumières tamisés, rien d’offensant mais tellement bien choisi pour le jeu.

    Le site web devait permettre aux participants de voir leur cadeau et de pouvoir «Participer au club échangiste» en volant le cadeau d’un autre participant. Chaque participant qui se faisait voler son cadeau reçevait un courriel qui lui annonçait qu’il s’était fait voler et qu’il pouvait aller le récupérer.

    Continue reading “Réalisation d’une application d’échange de cadeau avec RED L’agence le «club échangiste» [2009]”

    Manipulation des liens extérieurs et les popup pour améliorer l’Accessibilité

    En rédigeant Accessibilité et les liens externes j’ai réalisé qu’il y aurait trop de matière pour être lue dans un simple billet. Alors j’ai décidé d’aller plus en profondeur et de le documenter.

    Cet article explique une méthode simple pour transformer tout les liens d’une page qui vont à l’extérieur du site courrant en ajoutant un icône approprié et la note disant qu’une fenêtre s’ouvrira

    Continue reading “Manipulation des liens extérieurs et les popup pour améliorer l’Accessibilité”

    Accessibilité et les liens externes

    Il existe plusieurs normes en accessibilité du web qui demande des choses qu’on ne prend pas nécessairement le temps de faire.

    Soit que c’est pas manque de temps, trop de choses à penser, ou on n’y pense simplement pas.

    Dans cet article j’exprime mon opinion sur l’importance (du point de vue utilisabilité) des icones de liens extérieurs. Plus tard je montrerai une méthode pour automatiser [EDIT 2009-08-23] J’ai documenté comment faire dans Manipulation des liens extérieurs et les popup pour améliorer l’Accessibilité.

    Continue reading “Accessibilité et les liens externes”

    Detection de langue

    Lorsqu’on travaille sur un site qui doit avoir plusieurs langues… il m’arrive souvent de devoir détecter la langue du visiteur. Ce bout de code permet de détecter la langue selon les données fournies dans HTTP_ACCEPT_LANGUAGE et HTTP_USER_AGENT. Il faut comprendre que ce n’est pas une solution absolue, mais un bout de code qui peut s’avérer utile!
    Continue reading “Detection de langue”