Friday 25 May 2012

What is sent to server?

How does in place editing work?

Normal flow is this. User clicks text on web page. Block of text becomes a form. User edits contents and presses submit button. New text is sent to webserver and saved. Form becomes normal text again.

Basic usage

While reading you might also want to check live demo. For basic examples we assume to have following html elements.
<div class="edit" id="div_1">Dolor</div>
<div class="edit_area" id="div_2">Lorem ipsum dolor sit amet, consectetuer 
adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore 
magna aliquam erat volutpat.</div>
There is only one mandatory parameter. URL where browser posts edited content.
 $(document).ready(function() {
     $('.edit').editable('http://www.example.com/save.php');
 });
Code above does several things: Elements with class edit become editable. Editing starts with single mouse click. Form input element is text. Width and height of input element matches the original element. If users clicks outside form changes are discarded. Same thing happens if users hits ESC. When user hits ENTER browser submits text to save.php at www.example.com.
Not bad for oneliner, huh? Lets add some options.
Elements with class edit_area will use textarea as input. They will also have spinning image when data is being submitted to server. Elements with class edit will have text Saving… instead of spinning image. As a bonus lets add tooltip to both. Tooltips are great for informing users what they should do.
 $(document).ready(function() {
     $('.edit').editable('http://www.example.com/save.php', {
         indicator : 'Saving...',
         tooltip   : 'Click to edit...'
     });
     $('.edit_area').editable('http://www.example.com/save.php', { 
         type      : 'textarea',
         cancel    : 'Cancel',
         submit    : 'OK',
         indicator : '<img src="img/indicator.gif">',
         tooltip   : 'Click to edit...'
     });
 });
These two examples cover most of needs you usually have. Since most of people like to tweak and hack, lets go forward…

What is sent to server?

When submitting change following data will be POST:ed to server:
 id=elements_id&value=user_edited_content
In some cases you might want to change default parameter names. If you want to data to be POST:ed as:
 elementid=elements_id&newvalue=user_edited_content
you need to add two parameters:
 $(document).ready(function() {
     $('.edit').editable('http://www.example.com/save.php', { 
         id   : 'elementid',
         name : 'newvalue'
     });
 });

Usage with Textile, Markdown, ReST, WiKi etc

If the content in edit_area class elements is for example WiKi, Textile or Markdown markup, you do not want to edit the html source. Instead you need the markup source. That can be fetched into input field by passing URL to loadurl parameter.
 $(document).ready(function() {
     $('.edit_area').editable('http://www.example.com/save.php', { 
         loadurl  : 'http://www.example.com/load.php',
         type    : 'textarea',
         submit  : 'OK'
     });
 });
In this example load.php should return the markup source not rendered html. However save.php should return rendered html. When saving the browser will display exactly what saving script returns. There is also another option. You can pass markup source in data parameter.

How to use selects?

You can use selects by giving type parameter value of select. Select is built from JSON encoded array. This array can be given using either data parameter or fetched from external URL given in loadurl parameter. Array keys are values for <option> tag. Array values are text shown in pulldown.
JSON encoded array looks like this:
{’E’:‘Letter E’,‘F’:‘Letter F’,‘G’:‘Letter G’, ‘selected’:’F’}
Note the last entry. It is special. With value of ‘selected’ in array you can tell Jeditable which option should be selected by default. Lets make two simple examples. First we pass values for pulldown in data parameter:
 $('.editable').editable('http://www.example.com/save.php', { 
     data   : " {'E':'Letter E','F':'Letter F','G':'Letter G', 'selected':'F'}",
     type   : 'select',
     submit : 'OK'
 });
What if you need to generate values for pulldown dynamically? Then you can fetch values from external URL. Lets assume we have following PHP script:
 <?php
 /* http://www.example.com/json.php */
 $array['E'] =  'Letter E'; 
 $array['F'] =  'Letter F'; 
 $array['G'] =  'Letter G'; 
 $array['selected'] =  'F';
 print json_encode($array);
 ?>
Then instead of data parameter we use loadurl:
 $('.editable').editable('http://www.example.com/save.php', { 
     loadurl : 'http://www.example.com/json.php',
     type   : 'select',
     submit : 'OK'
 });
But wait! Theres more. Some people are concerned about extra request made to server. You can also combine these two approaches. Let PHP output JSON encoded array directly into JavaScript code.
 <?php
 $array['E'] =  'Letter E'; 
 $array['F'] =  'Letter F'; 
 $array['G'] =  'Letter G'; 
 $array['selected'] =  'F';
 ?>
 $('.editable').editable('http://www.example.com/save.php', { 
     data   : '<?php print  json_encode($array); ?>',
     type   : 'select',
     submit : 'OK'
 });

How to style elements?

You can style input element with cssclass and style parameters. First one assumes to be name of a class defined in your CSS. Second one can be any valid style declaration as string. Check the following examples:
 $('.editable').editable('http://www.example.com/save.php', { 
     cssclass : 'someclass'
 });

 $('.editable').editable('http://www.example.com/save.php', { 
     loadurl : 'http://www.example.com/json.php',
     type    : 'select',
     submit  : 'OK',
     style   : 'display: inline'
 });
Both parameters can have special value of inherit. Setting class to inherit will make form to have same class as it parent. Setting style to inherit will make form to have same style attribute as it parent.
Following example will make word ipsum to be editable with pulldown menu. This pulldown inherits style from <span>. Thus it will be displayed inline.
 Lorem <span class="editable" style="display: inline">ipsum</span> dolor 
 sit amet.
 $('.editable').editable('http://www.example.com/save.php', { 
     loadurl : 'http://www.example.com/json.php',
     type    : 'select',
     submit  : 'OK',
     style   : 'inherit'
 });

Submitting to function instead of URL

Some people want to control absolutely everything. I want to keep you happy. You can get full control of Ajax request. Just submit to function instead of URL. Parameters passed are same as with callback.
 $('.editable').editable(function(value, settings) { 
     console.log(this);
     console.log(value);
     console.log(settings);
     return(value);
  }, { 
     type    : 'textarea',
     submit  : 'OK',
 });
Note that function must return string. Usually the edited content. This will be displayed on page after editing is done.

Parameter reference

(String) method: Method to use when submitting edited content. Default is POST. You most likely want to use POST or PUT. PUT method is compatible with Rails.
(Function) callback: Function is called after form has been submitted. Callback function receives two parameters. Value contains submitted form content. Settings contain all plugin settings. Inside function this refers to the original element.
 $('.editable').editable('http://www.example.com/save.php', { 
     type     : 'textarea',
     submit   : 'OK',
     callback : function(value, settings) {
         console.log(this);
         console.log(value);
         console.log(settings);
     }
 });
(String) name: Name of the submitted parameter which contains edited content. Default is value.
 $('.editable').editable('http://www.example.com/save.php', { 
     name     : 'new_value'
 });
(String) id: Name of the submitted parameter which contains content id. Default is id.
 $('.editable').editable('http://www.example.com/save.php', { 
     id     : 'element_id'
 });
(Mixed) submitdata: Extra parameters when submitting content. Can be either a hash or function returning a hash.
$(".editable").editable("http://www.example.com/save.php";, {
   submitdata : {foo: "bar"};
});
$(".editable").editable("http://www.example.com/save.php";, {
   submitdata : function(value, settings) {
       return {foo: "bar"};
   }
});
(String) type: Input type to use. Default input types are text, textarea or select. Additional input types are provided using custom input type API.
(Integer) rows: Number of rows if using textarea.
(Integer) cols: Number of columns if using textarea.
(Integer) height: Height of the input element in pixels. Default is auto. This means height is calculated automatically. Can also be set to none.
(Integer) width: Width of the input element in pixels. Default is auto. This means width is calculated automatically. Can also be set to none.
(Integer) loadurl: Normally content of the form will be same as content of the edited element. However using this parameter you can load form content from external URL.
$(".editable").editable("http://www.example.com/save.php";, {
    loadurl : "http://www.example.com/load.php"
});
Note that id of the edited element will be automatically added to query string. For example loadurl above would become something like:
http://www.example.com/load.php?id=element_id
(Integer) loadtype: Request type to use when using loadurl. Default is GET. You most likely want to use only GET or POST.
(Mixed) loaddata: Extra parameter to add to request when using loadurl. Can be either a hash or function returning a hash.
$(".editable").editable("http://www.example.com/save.php";, {
   loaddata : {foo: "bar"};
});
$(".editable").editable("http://www.example.com/save.php";, {
   loaddata : function(value, settings) {
       return {foo: "bar"};
   }
});
(Mixed) data: Form data passed as parameter. Can be either a string or function returning a string. Can be useful when you need to alter the text before editing.
$(".editable").editable("http://www.example.com/save.php";, {
   data : "Lorem ipsum";
});
$(".editable").editable("http://www.example.com/save.php";, {
    data: function(value, settings) {
      /* Convert <br> to newline. */
      var retval = value.replace(/<br[\s\/]?>/gi, '\n');
      return retval;
    }
});

Miscallenous options

Default action of when user clicks outside of editable area is to cancel edits. You can control this by setting onblur option. Possible values are:
  • onblur : cancel Clicking outside editable area cancels changes. Clicking submit button submits changes.
  • onblur : submit Clicking outside editable area submits changes.
  • onblur : ignore Click outside editable area is ignored. Pressing ESC cancels changes. Clicking submit button submits changes.
Event which starts editing the element can be controlled using option event. All jQuery events are available. Most usable ones are click and dblclick.

Demo

You can test how Jeditable works with live demo.

Jeditable – Edit In Place Plugin For jQuery

How does in place editing work?

Normal flow is this. User clicks text on web page. Block of text becomes a form. User edits contents and presses submit button. New text is sent to webserver and saved. Form becomes normal text again.

Basic usage

While reading you might also want to check live demo. For basic examples we assume to have following html elements.
<div class="edit" id="div_1">Dolor</div>
<div class="edit_area" id="div_2">
Lorem ipsum dolor sit amet, consectetuer 
adipiscing elit, sed diam nonummy nibh euismod 
tincidunt ut laoreet dolore 
magna aliquam erat volutpat.
</div>
There is only one mandatory parameter. URL where browser posts edited content.
 $(document).ready(function() {
     $('.edit').editable('http://www.example.com/save.php');
 });
Code above does several things: Elements with class edit become editable. Editing starts with single mouse click. Form input element is text. Width and height of input element matches the original element. If users clicks outside form changes are discarded. Same thing happens if users hits ESC. When user hits ENTER browser submits text to save.php at www.example.com.
Not bad for oneliner, huh? Lets add some options.
Elements with class edit_area will use textarea as input. They will also have spinning image when data is being submitted to server. Elements with class edit will have text Saving… instead of spinning image. As a bonus lets add tooltip to both. Tooltips are great for informing users what they should do.
 $(document).ready(function() {
     $('.edit').editable('http://www.example.com/save.php', {
         indicator : 'Saving...',
         tooltip   : 'Click to edit...'
     });
     $('.edit_area').editable('http://www.example.com/save.php', { 
         type      : 'textarea',
         cancel    : 'Cancel',
         submit    : 'OK',
         indicator : '<img src="img/indicator.gif">',
         tooltip   : 'Click to edit...'
     });
 });
These two examples cover most of needs you usually have. Since most of people like to tweak and hack, lets go forward…

Ajax without Javascript in drupal

Ajax is nothing new. And especially since Drupal’s adoption of jQuery, ajax has certainly become much easier. Generally, ajax requests in Drupal involve
  • PHP code (usually in a module) to generate the necessary markup for the originating page.
  • Javascript code to handle the ajax response.
  • Some form of initialization code, usually in a Drupal behavior, to connect the markup to the behaviors.
  • PHP to generate the response, both for the ajax request and for the non-javascript page. (Oh, and it’s up to you to decide how to tell the difference!)

Let the Chaos begin

There’s nothing inherently wrong with the above method, but there’s definitely room for improvement. With the introduction of CTools (a.k.a Chaos tool suite), ajax development has become much simpler. From the CTools project page on Drupal.org,
“AJAX responder — tools to make it easier for the server to handle AJAX requests and tell the client what to do with them.”
CTools introduces the concept of an ajax command. A command is a javascript function within the Drupal.CTools.AJAX.commands namespace, which can be invoked as an ajax response. The server-side callback returns an object representation of a command, and this object contains everything necessary to run the command on the client-side. The easiest way to explain this is with an example.
We will be building an example module, which I will call “example”. This module will display a page with an ajax link that will reveal more content when clicked.
The first thing that is needed is a hook_menu() implementation to define two new paths. The first is the page that will hold the link, and the second defines the ajax callback. Take note of the %ctools_js in the second entry. This is how we will determine if the call is being made from an ajax call or not. More on that when we get to the callback code.
example.module, part 1
<?php
/** 
 * Implementation of hook_menu().
 */
function example_menu() {
 $items = array();
 $items['test'] = array(
 'title' => 'Ajax Test',
 'page callback' => 'example_test_main',
 'access arguments' => array('access content'),
 );
 $items['test/%ctools_js/go'] = array(
 'page callback' => 'example_test_ajax_callback',
 'page arguments' => array(1),
 'access arguments' => array('access content'),
 );
 return $items; 
}
?>
Now for the main page callback. The only output on this page is a link to the second path that we defined. The link has two things to take note of. First, the path of the link is test/nojs/go. The ‘nojs’ portion of the path will be replaced with ‘ajax’ when an ajax call is made. This distinction is how we detect if the callback is being called from an ajax request or not. The second thing to note is that we add a class of ‘ctools-use-ajax’ to the link. This tells the ajax-responder javascript that this link should be processed by the ajax responder. And finally, we must include the ajax-responder javascript.
example.module, part 2
<?php
function example_test_main() {
 $output = l('Load more content', 'test/nojs/go', array(
 'attributes' => array('id' => 'test-ajax-link', 'class' => 'ctools-use-ajax')));

 ctools_add_js('ajax-responder');
 return $output;
}
?>
Last but not least, the ajax callback. Notice how the function takes a boolean parameter for $js. CTools takes care of turning the strings (‘nojs’ or ‘ajax’) into a boolean, so we have a very clean way to determine how to respond. We will be returning the same content, in both conditions, to maintain accessibility for non-javascript enabled browsers (for progressive enhancement as well as SEO).
example.module, part 3
<?php
function example_test_ajax_callback($js = FALSE) {
 $output = t('<p>Lorem ipsum dolor sit amet...</p>');

 if ($js) {
 ctools_include('ajax');

 $commands = array();
 $commands[] = ctools_ajax_command_after('#test-ajax-link', $output);
 $commands[] = ctools_ajax_command_remove('#test-ajax-link');

 ctools_ajax_render($commands);
 // above command will exit().
 }
 else {
 return $output;
 }
}
?>
In the javascript branch of the conditional, we construct an array of command objects. Luckily for us, CTools offers a complementary php function for each javascript command, so creating the commands array is simple. The particular set of commands that we are using will add the output after the link, then remove the link. You can add as many commands as needed. The last thing to do, is to pass the commands array through ctools_ajax_render, which will output the commands array as JSON and exit. From that point on, the ajax-responder javascript on the first page takes over, and executes the commands in the order they are received.

Tada!

And that’s it. No javascript, just commands. CTools provides many commands for most of the basic javascript actions, from which you can build compound actions to do almost anything. Obviously, this set of commands cannot possibly cover every possible option, but I’ll leave that for another day. Until then, here is the list of ajax commands provided by CTools.
  • replace (ctools_ajax_command_replace)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • data: The data to use with the jquery replace() function.
  • prepend (ctools_ajax_command_prepend)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • data: The data to use with the jquery prepend() function.
  • append (ctools_ajax_command_append)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • data: The data to use with the jquery append() function.
  • after (ctools_ajax_command_after)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • data: The data to use with the jquery after() function.
  • before (ctools_ajax_command_before)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • data: The data to use with the jquery before() function.
  • remove (ctools_ajax_command_remove) * selector: The CSS selector. This can be any selector jquery uses in $().
  • changed (ctools_ajax_command_change)
    • selector: The CSS selector. This selector will have ‘changed’ added as a clas.
    • star: If set, will add a star to this selector. It must be within the ‘selector’ above.
  • alert (ctools_ajax_command_alert)
    • title: The title of the alert.
    • data: The data in the alert.
  • css (ctools_ajax_command_css)
    • selector: The CSS selector to add CSS to.
    • argument: An array of ‘key’: ‘value’ CSS selectors to set.
  • attr (ctools_ajax_command_attr)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • name: The name or key of the data attached to this selector.
    • value: The value of the data.
  • settings (ctools_ajax_command_settings) * argument: An array of settings to add to Drupal.settings via $.extend
  • data (ctools_ajax_command_data)
    • selector: The CSS selector. This can be any selector jquery uses in $().
    • name: The name or key of the data attached to this selector.
    • value: The value of the data. Not just limited to strings can be any format.
  • redirect (ctools_ajax_command_redirect) * url: The url to be redirected to. This can be an absolute URL or a Drupal path.
  • reload (ctools_ajax_command_reload)
    • submit (ctools_ajax_command_submit)
    • selector: The CSS selector to identify the form for submission. This can be any selector jquery uses in $().

Ajax modal windows, the easy way

We will be building a very simple module with two pages. The first simply holds the link to the modal window, the second is the page that will be displayed in the modal. Lets start with some basic code to set up our test module. This is almost identical to the ajax module we built last week. The biggest difference here, is that the class on the link has been changed to ‘ctools-use-modal’ and we are adding the javascript using ctools_modal_add_js().
example.module, part 1
<?php
/**
 * Implementation of hook_menu().
 */
function example_menu() { 
 $items = array();
 $items['test'] = array(
 'title' => 'Ajax Test',
 'page callback' => 'example_test_main',
 'access arguments' => array('access content'),
 );
 $items['test/%ctools_js/go'] = array(
 'page callback' => 'example_test_modal_callback',
 'page arguments' => array(1),
 'access arguments' => array('access content'),
 );
 return $items;
}

/**
 * The main page that holds the link to the modal.
 */
function example_test_main() {
 // Load the modal library and add the modal javascript.
 ctools_include('modal');
 ctools_modal_add_js();

 $output = l('Load modal content', 'test/nojs/go', array(
 'attributes' => array('class' => 'ctools-use-modal')));

 return $output;
}
?>
All that is left is to define the modal callback. Since we are using the %ctools_js wildcard, this same callback will be responsible for the content in both modal and non-modal states. Remember that the %ctools_js wildcard will be translated to a boolean value in which TRUE signals that we are in a javascript context.
example.module, part 2
<?php
function example_test_modal_callback($js = FALSE) {
 $output = t('<p>Lorem ipsum dolor sit amet...</p>');
 $title = t('Modal example');
 if ($js) {
 ctools_include('ajax');
 ctools_include('modal');
 ctools_modal_render($title, $output);
 // above command will exit().
 }
 else {
 drupal_set_title($title);
 return $output;
 }
}
?>
The code above is about as simple as it gets with modal windows. It simply outputs some text and a title in a modal window. The modal library provides a nice utility function for this, ctools_modal_render(). The function builds the necessary ajax command object and passes it to the browser using ctools_ajax_render().
But now for something not so trivial. Arguably the best use case for modal windows is for displaying forms. This is where the modal library really excels. In this example, we will show the user login form in a modal. Your first impulse might be to just send the output of drupal_get_form() to the modal. While this would display the form in the modal, it would not handle all of the submission and validation properly. Normally Drupal form submissions end in a redirect, which would break our ajax callbacks. Luckily, CTools has an answer for this situation. In the ajax context, we use ctools_modal_form_wrapper() to build the form. The one tricky part here, is that we must evaluate the return value of this function. This function returns an array, that may or may not be populated with ajax commands. If the form submission was not completed for any reason, such as validation errors, then the array will have the commands needed to re-display the form, with errors, in the modal window. If the array is empty, then we can assume that the form was submitted properly. In this case, we add one or more ajax commands to the array to let the user know that the form submitted successfully. In the case of our login form, we do that by redirecting the user to their account page.
One thing I forgot to mention, is that ctools_modal_form_wrapper() expects you to pass in a form_state array. drupal_get_form() allows you to pass in additional arguments after the form id, but the ctools form functions expect all arguments to be passed through the form_state array. In the case of modal forms, the form_state must contain at least an ‘ajax’ and a ‘title’ element.
example.module, part 3
<?php
function example_test_modal_callback($js = FALSE) {
 if ($js) {
 ctools_include('ajax');
 ctools_include('modal');
 $form_state = array(
 'ajax' => TRUE,
 'title' => t('Login'),
 );
 $output = ctools_modal_form_wrapper('user_login', $form_state);
 if (empty($output)) {
 $output[] = ctools_modal_command_loading();
 $output[] = ctools_ajax_command_redirect('user');
 }
 ctools_ajax_render($output);
 }
 else {
 return drupal_get_form('user_login');
 }
}
?>
Hopefully, I’ve explained enough so that you can understand what is going on in the above function.

Dialog API

So here is where I will diverge a little bit. While using the CTools modals, I kept wishing that I could use the jQuery UI Dialog widget as the front-end for my modals. So I took the time to build it. Dialog API aims to be functionally equivalent to the modal library, except that it uses jQuery UI. The ajax commands that it exposes are all nearly identical to their modal equivalents, except that the display command allows you to pass an array of options to the Dialog widget. This allows you to control things like height and width from the ajax callback.

AJAX on a link with no form.

<?php
$link = array(
'#type' => 'link',
'#title' => t('something'),
'#href' => 'some/path',
'#ajax' => array(
'callback' => 'some_callback_function',
'wrapper' => 'ajax-response-goes-here',
'method' => 'replace',
'effect' => 'fade',
),
// Using the onload below is entirely optional; It's just included as
// a reminder of an easy way to add extra simple jQuery tricks.
'#attributes' => array(
'onload' => "jQuery('something-to-hide').hide();",
),
);
$output = "<div id='ajax-response-goes-here'></div>Some HTML and stuff" . drupal_render($link);
?>
trigger an AJAX callback using the enter key when focusing on an element, add keypress = TRUE to the #ajax array, e.g.:
<?php
$form['element'] = array(
'#type' => 'textfield',
'#title' => 'Title',
'#ajax' => array(
'callback' => '...',
'keypress' => TRUE,
),
);
?>

Nice select list creation using chosen jquery plugin

Chosen is a JavaScript plugin that makes long, unwieldy select boxes much more user-friendly. It is currently available in both jQuery and Prototype flavors.

http://harvesthq.github.com/chosen/
Default Text Support
Chosen automatically sets the default field text (“Choose a country…”) by reading the select element’s data-placeholder value. If no data-placeholder value is present, it will default to “Select Some Option” or “Select Some Options” depending on whether the select is single or multiple. You can change these elements in the plugin js file as you see fit.
<select data-placeholder="Choose a country..." style="width:350px;" multiple">Note: on single selects, the first element is assumed to be selected by the browser. To take advantage of the default text support, you will need to include a blank option as the first element of your select list.

No Results Text Support

Setting the “No results” search text is as easy as passing an option when you create Chosen:
$(".chzn-select").chosen({no_results_text: "No results matched"}); // jQuery version
New Chosen($("chzn_select_field"),{no_results_text: "No results matched"}); // Prototype version

Allow Deselect on Single Selects

Change / Update Events

  • Form Field Change

    When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a “change” event* on the original form field. That let’s you do something like this:
    $("#form_field").chosen().change( … );
    Note: Prototype doesn’t offer support for triggering standard browser events. Event.simulate is required to trigger the change event when using the Prototype version.
  • Updating Chosen Dynamically

    If you need to update the options in your select field and want Chosen to pick up the changes, you’ll need to trigger the “liszt:updated” event on the field. Chosen will re-build itself based on the updated content.
    • jQuery Version: $("#form_field").trigger("liszt:updated");
    • Prototype Version: Event.fire($("form_field"), "liszt:updated");

Why use Chosen?

  • User Friendly

    Instead of forcing your users to scroll through a giant list of items, they can just start typing the name of the item they were looking for. Non-matching entries are removed from view and choices can be selected using enter or mouse click.
  • Progressive Enhancement

    Because chosen replaces normal html select fields, you don’t need to do anything special to make it work for browsers without JavaScript. You don’t need to do anything special on the back end to handle the data either — the form field still gets submitted as normal.
  • Painless Setup

    Add Chosen’s files to your app and trigger the plugin (see Setup below). Chosen automatically respects optgroups, selected state, the multiple attribute and browser tab order. You don’t need to do anything else except customize the style as you see fit.

Setup

Using Chosen is easy as can be.
  1. Download the plugin and copy the related files to your app.
  2. Activate the plugin:
    • jQuery Version:
      Call the chosen plugin: $(".chzn-select").chosen();
    • Prototype Version:
      Create a new instance of Chosen: new Chosen(some_form_element);
  3. Disco.

Drupal 7 theme table creation with pagination & sorting

$header = array(array(‘data’=>t(‘Module’),’field’=>’module’,'sort’=>’asc’), t(‘Delta’), t(‘Theme’));
$sql_query = db_select(‘block’, ‘s’);
$sql_query->fields(‘s’, array(‘module’, ‘delta’, ‘theme’));
$sql_query = $sql_query->extend(‘TableSort’)->extend(‘PagerDefault’)->limit(5);
$result = $sql_query->orderByHeader($header)->execute();
foreach($result as $res){
$rows[] = array($res->module,$res->delta,$res->theme);
}
$output = theme(‘table’, array(‘header’ => $header, ‘rows’ => $rows, ‘attributes’ => array(‘id’ => ‘my-module-table’)));
$output .= theme(‘pager’);
print $output;
?>

Making the Flag Module’s Confirmation form use AJAX

Extending the Standard Confirmation Form

Out of the box, the confirmation form provided by the Flag module does nothing more than display a form containing a submit button to confirm the action and a link to cancel it. We can just use hook_form_alter() to add a few of additional fields to this a basic implementation of which is shown below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * Implements hook_form_alter()
 */
function example_form_alter(&$form, &$form_state, $form_id){
  if($form_id == 'flag_confirm'){
    $form['reason'] = array(
      '#type' => 'select',
      '#title' => t('Reason for reporting this comment'),
      '#options' => array(
        'offensive' => t('Comment\'s offensive or unlawful'),
        'spam' => t('Advertising / Spam'),
        'other' => t('Another reason'),
      ),
    );
    $form['other'] = array(
      '#type' => 'textfield',
      '#title' => t('Reason'),
    );
    $form['comment_id'] = array(
      '#type' => 'value',
      '#value' => arg(4),
    );
    //Add our own submit handler to process this data.
    $form['#submit'][] = 'example_confirm_form_submit';
  }
}
There’s nothing scary involved here. You’ll notice we’ve added a hidden field to store the ID of the comment we are interested in – this just gives use easy access to it should we need to load the entity again in the submit handler. On this subject we’ve included our own submit handler to process this data. We need to do this as the Flag module will only care about the form elements that it has generated so in order to process these new fields we just add another function to the form’s $form['#submit'] array. The function this points to will just take the standard arguments we pass to a submit handler so as a basic example we need to include a function like:
/**
 * Additional submit handler for the comment confirmation form
 */
function example_confirm_form_submit($form, &$form_state){
  $params = $form_state['values'];
  //Do something with these submitted values
  //For example send them in an email to a moderator using php drupal_mail()
}
That’s all we need to do with the confirmation form at this stage and if we didn’t want to load it in a modal window then this would be enough to allow users to report comments and include additional information as part of that process. Working with modals makes things a bit more interesting.

AJAX and the Chaos Tool Suite

The reason why this is slightly more complicated than it first sounds is because we want the rendered form but we don’t want to push it through the entire Drupal theme engine as this would mean we’d end up rendering another whole page within the popup when in fact all we want is the markup for the form. Loading forms in modal windows isn’t actually that complicated in itself as the Chaos Tool Suite module provides some nice functionality to do the heavy lifting for us. What makes this particular example more complex is the fact that the form we want to render isn’t being generated by our module and neither are any references to it so we need to extend the Flag module in a way that means our custom module can just slot in to add this modal functionality.
To get our module working with Chaos Tools we need to follow a similar technique to that described in our Make a link use ajax in Drupal 7 (it’s easy) article. We begin by defining an implementation of hook_menu() as shown below:
/**
 * Implements hook_menu()
 */
function example_menu(){
  $items['comments/%ctools_js/confirm/%flag/%'] = array(
    'title' => 'Contact',
    'page callback' => 'example_test_modal',
    'page arguments' => array(1, 3, 4),
    'access arguments' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}
You’ll notice that there are a few placeholders in the path for our callback. We use these to tie into both the Chaos Tools and Flag modules and to pass through the ID of the comment being reported. The first wildcard is $ctools_js – this will trigger a function called ctools_js_load() to run within Chaos Tools to check whether or not the link is capable of running the JavaScript required to fire the AJAX request. If it is then this placeholder becomes ajax; if not it’s set to nojs in exactly the same way as is shown in the Make a link use ajax in Drupal 7 (it’s easy) article. However, in that example we explicitly define two callbacks whereas here the %ctools_js wildcard allows one callback to suffice as the Chaos Tools module will change the argument dynamically.
The next wildcard is %flag and this is what makes our menu callback work with the Flag module. When rendering the form the Flag module needs to reference an object that represents the flag that is being used as the trigger. This object is passed through to the form as an argument which means that it needs to be loaded as a variable before we can call the form. By including this placeholder we run the Flag module’s implementation of flag_load() , which takes the string entered in the path and returns the relevant flag object.
The final wildcard is just a simple reference to the ID of the comment we’re interacting with; again this will be needed to allow the Flag module to do its magic, as we’ll see shortly.
Next we need to implement the page callback function we reference in hook_menu() as this will be what actually generates the response to any requests that hit a path matching our definition. We need to make sure it accepts three arguments corresponding to the wildcards discussed above; these parameters will have been set by each modules’ _load() functions by the time we invoke the callback function.
function example_test_modal($js, $flag, $cid){
  //If JavaScript isn't enabled the just go to the standard confirmation form
  if (!$js) {
    drupal_goto('flag/confirm/flag/abuse/' . $cid, array('query' => array('destination', $_GET['destination'])));
  }
  //Include the relevant code from CTools
  ctools_include('modal');
  ctools_include('ajax');
  ctools_add_js('ajax-responder');
  //Build up the $form_state array
  //This is passed through to the form generated by the Flag module
  $form_state = array(
    'title' => t('Report Comment'),
    'ajax' => TRUE,
    'build_info' => array(
      'args' => array(
        0 => 'flag',
        1 => $flag,
        3 => $cid,
      ),
    ),
  );
  //Wrap the Flag module's form in a wrapper provided by CTools
  $output = ctools_modal_form_wrapper('flag_confirm', $form_state);
  if (!empty($form_state['executed'])) {
    $output = array();
    //This makes sure we go to the right place once we close the modal window
    if (isset($_GET['destination'])) {
      $output[] = ctools_ajax_command_redirect($_GET['destination']);
    }
    else {
      $output[] = ctools_ajax_command_reload();
    }
  }
  //Return the JSON string ready to be rendered back to the DOM
  print ajax_render($output);
  exit;
}
There’s quite a lot going on in this function. First of all we check to see if we can use AJAX and render a modal version of the form. If not then we just redirect to the standard form which will be displayed on its own page. If JavaScript is enabled we then need to make sure we add all the code we need from Chaos Tools – this is just done by some simple helper functions provided by the module. The next thing we need to do is build up the $form_state array – this is an important stage as we also need to include the arguments in under a build_info key in order to get them over to the Flag module. This differs from how we’d usually do things if we weren’t trying to render a modal form as it would be possible to just call drupal_get_form() and pass the arguments through as normal. Because we are using the Chaos Tools wrapper around the form we can’t do this so we need to add them into the $form_state array. We also set the title of the modal window and the ajax key to TRUE .
We then use the Chaos Tools wrapper to add the form to the $output variable and apply a bit of logic to make sure we still honour the destination argument in the query string if it’s present. If it’s not then we just reload the current page when the modal window is closed. Finally we just print the JSON string and exit the function to stop it running through the theme engine and having markup added that will break the AJAX response.

Tying Everything Together

Now we have a function that will provide a valid AJAX response if requested, we need to start tying this into the links already being rendered by the Flag module. Chaos Tools is clever enough to realise that any link that has a class of ctools-use-modal needs to be loaded in a modal window if possible. So we need to add this class to the ‘Flag’ link on the comment to begin with. Next the link provided by the Flag module still points at the MENU_CALLBACK defined in that module so we need to rewrite this to point at our new page callback function defined in our implementation of hook_menu(). We could do all this using hook_comment_view_alter(); however, I opted to use jQuery to add the classes as this means that in real terms if JavaScript isn’t enabled then the class won’t be added and the link will never get pointed at our function so it will just work as normal
function ($) {
Drupal.behaviors.initModalFormsConfirm = {
  attach: function (context, settings) {
    $(".flag-link-confirm", context).once('init-modal-forms-contact', function () {
      this.href = this.href.replace(/flag\/confirm\/flag\/abuse/,'comments/nojs/confirm/abuse');
    }).addClass('ctools-use-modal ctools-modal-modal-popup-confirm');
  }
};
})(jQuery);
The jQuery code above just looks for any link that has a class of flag-link-confirm and then rewrites its href attribute based on a regular expression matching the entire string up to the point where the flag placeholder and comment ID are appended. We then add the ctools-use-modal class; you’ll notice we also add another class of ctools-modal-modal-popup-confirm – this is to allow us to control how the modal window is rendered and we’ll look at this next. To add this code to the comment we just use hook_comment_view() to call drupal_add_js(). It is important to notice that we set the weight to -20 – this ensures that this code runs before the Chaos Tools JavaScript. If you didn’t do this then the ctools-use-modal class won’t have been set in time for the Chaos Tools JavaScript to recognise it when it runs.
/**
 * Implements hook_node_view_alter().
 */
function example_comment_view_alter($comment, $view_mode, $langcode) {
  drupal_add_js(drupal_get_path('module', 'example') . '/js/example.js', array('weight' => -20));
}
At the moment we’re not quite there – clicking the link still won’t load the modal window even though the class has been added as required. This is because when we’re viewing a comment no code has been added in from the Chaos Tools module so this class has no context. In our page callback function above we’ve had to add this code in but this only runs after the link has been clicked, so we need a way to ensure that the code is also included before. In order to get around this we use an implementation of hook_init() to invoke a function that will add all the required JavaScript to the current page. We also wrap it in some logic to stop the code from being added to any of the Drupal installation pages.**
 * Implements hook_init().
 */
function example_init() {
  if (!drupal_installation_attempted()) {
    example_configure();
  }
}
The code this calls will just add any JavaScript files that Chaos Tools needs in order to respond to the ctools-use-modal class and load the modal window. We also define some settings that will be added as JavaScript to help us theme the form; the code these reference is based on the Modal Forms module. This module provides some nice functionality to get some of the common core forms rendering in modal windows – for example using a ‘login’ link to load a modal version of the core user_login form. We’re not actually using the module here but are borrowing the code it uses to render the modal window.
function example_configure(){
  static $configured = FALSE;
  if ($configured) {
    return;
  }
  //Include the relevant CTools code
  ctools_include('ajax');
  ctools_include('modal');
  ctools_modal_add_js();
  $throbber = theme('image', array('path' => ctools_image_path('loading_animation.gif', 'modal_forms'), 'alt' => t('Loading...'), 'title' => t('Loading')));
  $js_settings = array(
    'modal-popup-confirm' => array(
      'modalSize' => array(
        'type' => 'fixed',
        'width' => 500,
        'height' => 200,
      ),
      'modalOptions' => array(
        'opacity' => 0.85,
        'background' => '#000',
      ),
      'animation' => 'fadeIn',
      'modalTheme' => 'ModalFormsPopup',
      'throbber' => $throbber,
      'closeText' => t('Close'),
    ),
  );
  drupal_add_js($js_settings, 'setting');
  //Add in some custom CSS and our jQuery template
  ctools_add_css('example_popup', 'example');
  ctools_add_js('example', 'example');
  $configured = TRUE;
}
You can see that the $js_settings just take the form of an array with the key corresponding to the second class we added above. It also specifies that we should render the form using a ‘theme’ called ModalFormsPopup. This option just references a JavaScript file containing some code to override the standard Chaos Tools theming of the modal window – it’s purely aesthetic. The Drupal.theme.prototype namespace was added in Drupal 6 to allow provide a method of cleanly overriding another module’s JavaScript generated HTML code.
/**
* Provide the HTML to create the modal dialog.
*/
Drupal.theme.prototype.ModalFormsPopup = function () {
  var html = ''
  html += '<div id="ctools-modal">';
  html += '  <div>';
  html += '    <div>';
  html += '      <div>';
  html += '        <h3 id="modal-title"></h3>';
  html += '        <span>' + Drupal.CTools.Modal.currentSettings.closeText + '</span>';
  html += '      </div>';
  html += '      <div><div id="modal-content"></div></div>';
  html += '    </div>';
  html += '  </div>';
  html += '</div>';
  return html;
}
That’s pretty much all there is to it. We’ve essentially just written a lot of glue to get the Flag module’s confirmation form working with the Chaos Tools modal popup functionality. More importantly, we’ve not hacked either module and all the AJAX degrades gracefully. I’ve used the implementation of example_configure() to also add some CSS just to polish the final result a bit. I’ve also included a custom throbber that I generated using an online Tool just to make it tie nicely into my site’s look and feel.

Change Drupal Theme Based On URL Path

$THEME_URLS = array(
 array('/admin','garland'), # Drupal already support admin theme anywho
 array('/users','fancy_user_theme'),
 array('/forum','forums_theme'),
 );
foreach ( $THEME_URLS as $info)
 if ( strpos($_SERVER['REQUEST_URI'],$info[0])===0)
  $conf['theme_default'] = $info[1];

CSS Attribute Selectors

Style HTML Elements With Specific Attributes

It is possible to style HTML elements that have specific attributes, not just class and id.
Note: IE7 and IE8 support attribute selectors only if a !DOCTYPE is specified. Attribute selection is NOT supported in IE6 and lower.

Attribute Selector

The example below styles all elements with a title attribute:

Example

[title]
{
color:blue;
}


Attribute and Value Selector

The example below styles all elements with title=”W3Schools”:

Example

[title=W3Schools]
{
border:5px solid green;
}


Attribute and Value Selector – Multiple Values

The example below styles all elements with a title attribute that contains a specified value. This works even if the attribute has space separated values:

Example

[title~=hello] { color:blue; }

The example below styles all elements with a lang attribute that contains a specified value. This works even if the attribute has hyphen ( – ) separated values:

Example

[lang|=en] { color:blue; }
eg lang=’en’, lang=’en-2′,lang=’en-1′


Styling Forms

The attribute selectors are particularly useful for styling forms without class or ID:

Example

input[type="text"]
{
width:150px;
display:block;
margin-bottom:10px;
background-color:yellow;
}
input[type="button"]
{
width:120px;
margin-left:35px;
display:block;
}

Force Drupal to attach Drupal behavior to new ajaxed content

Drupal.behaviors.my_ajax = function (context) {
    $('#content-group-inner a').live('click', function (e) {

        $('#content-group-inner a').addClass('my_ajax-processed');
        var url = $(this).attr('href');
        $('#content-region-inner').empty().html('<img src="ajax-loader.gif" style="margin-left:50%;"/>');        
        $('#content-region-inner').load(url,'ajax=1',function() {
                        Drupal.attachBehaviors('#content-region-inner');
                        });
        return false;
        });
   };

just change   $('selector').onvent(function (){}); 
=> $('selector').live('onvent', function (e){});