Auto-completion

Auto-completion is an AJAX technique that provides suggestions as users type into a field. Pressing the down arrow highlights results and pressing Enter fills the field with the highlighted result.

By default, two types of fields can be auto-completed: usernames and pages. You can add new auto-completion schemes too. This requires familiarity with both PHP and Javascript.

Decide on a schema name

Your schema name should be alphanumeric and lowercase. This will be the value of $_GET['type'] in your server-side code, the CSS class you add to your input field, and the name of the entry in the Javascript autofill_schemas object.

Add the autofill hook

First, add support on the server side. Attach to the hook autofill_json_request and pass the variable $dataset (already initialized to an array) by reference to a helper function. The helper function should check $_GET['type'] to make sure it matches your schema name and return if it doesn't match. Then it should process the search term - $_GET['userinput'] - and append $dataset with an associative array containing, at a minimum, the key 0 which will be the value that goes into the field when the user presses enter, and highlighted, which should be an HTML string that contains the result with the user's search term highlighted.

Example

$plugins->attachHook('autofill_json_request', 'myplugin_autofill($dataset);');
 
function myplugin_autofill(&$dataset)
{
  if ( $_GET['type'] == 'cities' )
  {
    // Yes, I'm really using cities in India as my example dataset.
    $cities = array('Agra', 'Allahabad', 'Anand', 'Aruppukkottai', 'Asurbandh, Jharkhand',
    'Balasore', 'Banur', 'Barrackpur', 'Bhagalpur', 'Bhimavaram', 'Bihar Sharif', 'Bodh Gaya',
    'Barh', 'Chandannagar', 'Chengalpattu', 'Chitradurga', 'Bramhapuri Maharashtra', 'Dadra',
    'Darjeeling', 'Delhi', 'Dhule', 'Duhbai', 'Etah', 'Fatehpur Sikri', 'Ganjam', 'Gondiya',
    'Guntur', 'Gwalior', 'Howrah', 'Hathras', 'Imphal', 'Jalgaon', 'Jhabua', 'Khopoli',
    'Kanauj', 'Karaikudi', 'Khammam', 'Khilchipur', 'Kolar', 'Kota', 'Kulpahar', 'Kurukshetra',
    'Latur', 'Mahe', 'Mapusa', 'Moga', 'Mumbai/Bombay', 'Mokama', 'Nainital', 'Narsimhapur',
    'Nellore', 'Nurpur, Himachal Pradesh', 'Panipat', 'Patna', 'Pune', 'Rajsthan', 'Rajkot',
    'Ratangarh', 'Roorkee', 'Salem', 'Satna', 'Shevgaon', 'Siddipet', 'Shirala', 'Sonipat',
    'Sitapur', 'Thanjavur', 'Tindivanam', 'Tiruvarur', 'Udupi/Udipi', 'Vaikom',
    'Vasco da Gama, Goa', 'Vizianagaram');
 
    foreach ( $cities as $city )
    {
      if ( stristr($city, $_GET['userinput']) )
      {
        $dataset[] = array(
          0 => $city,
          // more on this later
          'highlighted' => highlight_term($_GET['userinput'], $city, '<b>', '</b>')
        );
      }
    }
  }
  // no need to return anything since $dataset is passed by reference
}

Add the Javascript schema

If you want to format your results at all, extend autofill_schemas. Add a new member named the same as your schema name you chose before (cities in our example above) as an object containing one member, init, a function that takes the arguments element, scheme, and params. From the init method, initialize auto-completion in jQuery using $(element).autocomplete().

The autocomplete() jQuery function takes two arguments, the URL prefix (which should almost always be set to "makeUrlNS('Special', 'Autofill', 'type=' + scheme) + '&userinput='" without quotes) and the options. In the options, set minChars to 3, tableHeader to something like <tr><th>Suggestions</th></tr>, and formatItem to a function that takes one argument, row. The row will be identical to the entry you added in $dataset on the server. Return a glob of HTML containing any formatting you want (but no table elements).

Other options supported by jQuery's autocomplete feature include width (of the results table, in pixels), noResultsHTML, and resultsClass (the CSS class of the div that wraps the whole thing).

The Javascript schema can be added using $template->add_header() at the hook compile_template. Make sure that safely initialize autofill_schemas as shown in the example below.

Example

$plugins->attachHook('compile_template', 'myplugin_af_add_js();');
 
function myplugin_af_add_js()
{
  global $template;
 
  $js = <<<EOF
    <script type="text/javascript">//<![CDATA[

      var autofill_schemas = window.autofill_schemas || {};
 
      autofill_schemas.cities = {
        init: function(element, fillclass, params)
        {
          $(element).autocomplete(makeUrlNS('Special', 'Autofill', 'type=' + fillclass)
                    + '&userinput=',
            {
              // minimum characters input before a search is fired off to the server
              minChars: 3,
              // function used to format an item. Should return a snippet of HTML.
              formatItem: function(row)
              {
                // this corresponds with the "highlighted" value in the dataset array above
                // notice we're just returning the contents of the table cell, not the cell itself
                return row.highlighted;
              },
              // This will be at the beginning of the table. Don't use a <td> element here.
              tableHeader: '<tr><th>Suggestions</th></tr>',
          });
        }
      }

      //]]>
    </script>
EOF;
  $template->add_header($js);
}

Using your new scheme

Auto-completion schemes can be invoked with simple HTML:

Input a city: <input type="text" class="autofill cities" />

This produces:

Input a city:

Categories: (Uncategorized)