Author: jablko
Date: Wed Sep  2 18:41:02 2009
New Revision: 3158

Log:
Add JavaScript behavior to progressively enhance inputs of class 
.form-autocomplete with YUI AutoComplete widget. Add class .form-autocomplete 
to inputs with potentially long lists of options. -- force

Added:
   trunk/web/js/autocomplete.js   (contents, props changed)
Modified:
   trunk/apps/qubit/modules/informationobject/config/view.yml
   trunk/apps/qubit/modules/informationobject/templates/editDcSuccess.php
   trunk/apps/qubit/modules/informationobject/templates/editIsadSuccess.php
   trunk/apps/qubit/modules/informationobject/templates/editModsSuccess.php
   trunk/apps/qubit/modules/informationobject/templates/editRadSuccess.php
   trunk/web/css/main.css

Modified: trunk/apps/qubit/modules/informationobject/config/view.yml
==============================================================================
--- trunk/apps/qubit/modules/informationobject/config/view.yml  Wed Sep  2 
18:10:16 2009        (r3157)
+++ trunk/apps/qubit/modules/informationobject/config/view.yml  Wed Sep  2 
18:41:02 2009        (r3158)
@@ -1,14 +1,14 @@
 editDcSuccess:
-  javascripts: [/sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
+  javascripts: [autocomplete, /sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
 
 editIsadSuccess:
-  javascripts: [/sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
+  javascripts: [autocomplete, /sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
 
 editRadSuccess:
-  javascripts: [/sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
+  javascripts: [autocomplete, /sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
 
 editModsSuccess:
-  javascripts: [/sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
+  javascripts: [autocomplete, /sfDrupalPlugin/vendor/drupal/misc/collapse, 
/sfDrupalPlugin/vendor/drupal/misc/textarea, multiDelete, multiInstanceInput, 
multiInstanceSelect, select]
 
 listSuccess:
   javascripts: [actions]

Modified: trunk/apps/qubit/modules/informationobject/templates/editDcSuccess.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/templates/editDcSuccess.php      
Wed Sep  2 18:10:16 2009        (r3157)
+++ trunk/apps/qubit/modules/informationobject/templates/editDcSuccess.php      
Wed Sep  2 18:41:02 2009        (r3158)
@@ -74,7 +74,7 @@
 
     <?php echo render_field($form->relation, $relation, array('name' => 
'value')) ?>
 
-    <?php echo $form->language->renderRow() ?>
+    <?php echo $form->language->renderRow(array('class' => 
'form-autocomplete')) ?>
 
      <?php include_partial('addAccessPointTermDialog') ?>
     <div class="form-item" id="subjectAccessPoints">

Modified: 
trunk/apps/qubit/modules/informationobject/templates/editIsadSuccess.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/templates/editIsadSuccess.php    
Wed Sep  2 18:10:16 2009        (r3157)
+++ trunk/apps/qubit/modules/informationobject/templates/editIsadSuccess.php    
Wed Sep  2 18:41:02 2009        (r3158)
@@ -108,9 +108,9 @@
   <fieldset class="collapsible collapsed" id="contextArea">
     <legend><?php echo __('context area') ?></legend>
 
-    <?php echo $form->creatorIds->label(__('Name of creator(s)'))->renderRow() 
?>
+    <?php echo $form->creatorIds->label(__('Name of 
creator(s)'))->renderRow(array('class' => 'form-autocomplete')) ?>
 
-    <?php echo $form->repositoryId->label(__('Repository'))->renderRow() ?>
+    <?php echo 
$form->repositoryId->label(__('Repository'))->renderRow(array('class' => 
'form-autocomplete')) ?>
 
     <?php echo render_field($form->archivalHistory, $informationObject, 
array('class' => 'resizable')) ?>
 
@@ -138,9 +138,9 @@
 
     <?php echo 
render_field($form->reproductionConditions->label(__('Conditions governing 
reproduction')), $informationObject, array('class' => 'resizable')) ?>
 
-    <?php echo $form->language->renderRow() ?>
+    <?php echo $form->language->renderRow(array('class' => 
'form-autocomplete')) ?>
 
-    <?php echo $form->script->renderRow() ?>
+    <?php echo $form->script->renderRow(array('class' => 'form-autocomplete')) 
?>
 
     <?php echo render_field($form->physicalCharacteristics->label(__('Physical 
characteristics and technical requirements')), $informationObject, 
array('class' => 'resizable')) ?>
 
@@ -348,9 +348,9 @@
 
     <?php echo render_field($form->revisionHistory->label(__('Dates of 
creation, revision and deletion')), $informationObject, array('class' => 
'resizable')) ?>
 
-    <?php echo $form->languageOfDescription->renderRow() ?>
+    <?php echo $form->languageOfDescription->renderRow(array('class' => 
'form-autocomplete')) ?>
 
-    <?php echo $form->scriptOfDescription->renderRow() ?>
+    <?php echo $form->scriptOfDescription->renderRow(array('class' => 
'form-autocomplete')) ?>
 
     <?php echo render_field($form->sources, $informationObject, array('class' 
=> 'resizable')) ?>
 

Modified: 
trunk/apps/qubit/modules/informationobject/templates/editModsSuccess.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/templates/editModsSuccess.php    
Wed Sep  2 18:10:16 2009        (r3157)
+++ trunk/apps/qubit/modules/informationobject/templates/editModsSuccess.php    
Wed Sep  2 18:41:02 2009        (r3158)
@@ -64,7 +64,7 @@
 
     <?php echo $form->typeIds->label(__('Type of resource'))->renderRow() ?>
 
-    <?php echo $form->language->renderRow() ?>
+    <?php echo $form->language->renderRow(array('class' => 
'form-autocomplete')) ?>
 
     <?php include_partial('addAccessPointTermDialog') ?>
     <div class="form-item" id="subjectAccessPoints">

Modified: 
trunk/apps/qubit/modules/informationobject/templates/editRadSuccess.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/templates/editRadSuccess.php     
Wed Sep  2 18:10:16 2009        (r3157)
+++ trunk/apps/qubit/modules/informationobject/templates/editRadSuccess.php     
Wed Sep  2 18:41:02 2009        (r3158)
@@ -76,7 +76,7 @@
       </tr>
     </table>
 
-    <?php echo $form->repositoryId->label(__('Repository'))->renderRow() ?>
+    <?php echo 
$form->repositoryId->label(__('Repository'))->renderRow(array('class' => 
'form-autocomplete')) ?>
 
     <?php echo $form->identifier->renderRow() ?>
 
@@ -235,9 +235,9 @@
 
     <?php echo render_field($form->arrangement, $informationObject, 
array('class' => 'resizable')) ?>
 
-    <?php echo $form->language->renderRow() ?>
+    <?php echo $form->language->renderRow(array('class' => 
'form-autocomplete')) ?>
 
-    <?php echo $form->script->renderRow() ?>
+    <?php echo $form->script->renderRow(array('class' => 'form-autocomplete')) 
?>
 
     <?php echo render_field($form->locationOfOriginals, $informationObject, 
array('class' => 'resizable')) ?>
 
@@ -349,9 +349,9 @@
 
     <?php echo render_field($form->revisionHistory->label(__('Dates of 
creation, revision and deletion')), $informationObject, array('class' => 
'resizable')) ?>
 
-    <?php echo $form->languageOfDescription->renderRow() ?>
+    <?php echo $form->languageOfDescription->renderRow(array('class' => 
'form-autocomplete')) ?>
 
-    <?php echo $form->scriptOfDescription->renderRow() ?>
+    <?php echo $form->scriptOfDescription->renderRow(array('class' => 
'form-autocomplete')) ?>
 
     <?php echo render_field($form->sources, $informationObject, array('class' 
=> 'resizable')) ?>
 

Modified: trunk/web/css/main.css
==============================================================================
--- trunk/web/css/main.css      Wed Sep  2 18:10:16 2009        (r3157)
+++ trunk/web/css/main.css      Wed Sep  2 18:41:02 2009        (r3158)
@@ -163,3 +163,11 @@
 {
   text-transform: lowercase;
 }
+
+/* Fix YUI autocomplete */
+
+.yui-skin-sam .yui-ac-input
+{
+  position: static;
+  width: 95%;
+}

Added: trunk/web/js/autocomplete.js
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/web/js/autocomplete.js        Wed Sep  2 18:41:02 2009        (r3158)
@@ -0,0 +1,218 @@
+// $Id$
+
+Drupal.behaviors.autocomplete = {
+  attach: function (context)
+    {
+      $('select.form-autocomplete', context).each(function ()
+        {
+          // Share <select> with nested scopes
+          var select = this;
+
+          // Make autocomplete <input>, copy @class from <select>, copy @id
+          // from <select> so <label for="..."> is correct
+          var input = $(<input class={$(this).attr('class')} 
id={$(this).attr('id')}/>.toXMLString()).insertAfter(this)[0]
+
+          if ($(this).attr('multiple'))
+          {
+            // If multiple <select>, make <ul> of selected <option>s
+            var ul = $(<ul/>.toXMLString()).insertAfter(this)[0];
+
+            $('option:selected', this).each(function ()
+              {
+                // Make <li> of hidden <input> with <option> value, and <span>
+                // with <option> HTML contents
+                $(<li><input name={$(select).attr('name')} type="hidden" 
value={$(this).val()}/><span>{XML($(this).html())}</span></li>.toXMLString())
+                  .click(function ()
+                    {
+                      // On click, remove <li>
+                      $(this).hide('fast', function ()
+                        {
+                          $(this).remove();
+                        });
+                    })
+                  .appendTo(ul);
+              });
+          }
+          else
+          {
+            // If single <select>, make one hidden <input> with <option> value,
+            var hidden = $(<input name={$(this).attr('name')} type="hidden" 
value={$(this).val()}/>.toXMLString()).insertAfter(this)[0];
+
+            // - and copy <option> value to autocomplete <input>
+            $(input).val($('option:selected', this).text());
+          }
+
+          var dataSource = new YAHOO.util.LocalDataSource();
+
+          $('option:enabled', this).each(function ()
+            {
+              if ($(this).val())
+              {
+                // For each item, select HTML contents and value of <option>
+                //
+                // Selecting HTML contents is important for <em>Untitled</em>
+                dataSource.liveData.push([$(this).html(), $(this).val()]);
+              }
+            });
+
+          // Can't figure out how to get access to the DOM event which
+          // triggered a custom YUI event, so bind a listener to the
+          // interesting DOM event before instantiating the YUI widget, to save
+          // the DOM event before triggering custom YUI events
+          //
+          // TODO File YUI issue for this
+          var event;
+          $(input).keydown(function ()
+            {
+              event = arguments[0];
+
+              // Tab key down
+              if (9 == event.keyCode)
+              {
+                autoComplete._onTextboxKeyDown(event, autoComplete);
+
+                // Call _onTextboxBlur() to trigger item select or unmatched
+                // item select custom YUI events
+                autoComplete._onTextboxBlur(event, autoComplete);
+              }
+            });
+
+          var autoComplete = new YAHOO.widget.AutoComplete(input, 
$(<div/>.toXMLString()).insertAfter(this)[0], dataSource);
+
+          // http://developer.yahoo.com/yui/autocomplete/#force
+          autoComplete.forceSelection = true;
+
+          // Show some items even if user types nothing,
+          // http://developer.yahoo.com/yui/autocomplete/#minquery
+          autoComplete.minQueryLength = 0;
+
+          // Give user chance to type something, one second may still be too
+          // little, http://developer.yahoo.com/yui/autocomplete/#delay
+          autoComplete.queryDelay = 1;
+
+          // Start throbbing when first query is sent, stop throbbing when the
+          // last query to be sent is complete
+          //
+          // TODO This binds too many listeners and doesn't actually detect the
+          // last query to be sent : (
+          var id = 0;
+          autoComplete.dataRequestEvent.subscribe(function ()
+            {
+              var thisId = ++id;
+
+              $(input).addClass('throbbing');
+
+              autoComplete.dataReturnEvent.subscribe(function ()
+                {
+                  if (id == thisId)
+                  {
+                    $(input).removeClass('throbbing');
+                  }
+                });
+            });
+
+          autoComplete.itemSelectEvent.subscribe(function (type, args)
+            {
+              if ($(select).attr('multiple'))
+              {
+                // Cancel default action of saved DOM event so as not to loose
+                // focus when selecting multiple items
+                if (event)
+                {
+                  event.preventDefault();
+                }
+
+                // If this item is already selected, highlight it, otherwise
+                // add it to list of selected items
+                if (!$('li:has(input[value=' + args[2][1] + '])', ul)
+                  .each(function ()
+                    {
+                      // Make background yellow for one second
+                      //
+                      // TODO Use CSS class
+                      var span = $('span', this).css('background', 
'yellow')[0];
+
+                      setTimeout(function ()
+                        {
+                          $(span).css('background', 'none');
+                        }, 1000);
+                    })
+                  .length)
+                {
+                  // Make <li> of hidden <input> with item value, and <span>
+                  // with item HTML
+                  //
+                  // Use XML() constructor to insert parsed HTML, works for
+                  // strings without an <element> and strings with one root
+                  // <element>, but not, I suspect, for strings with multiple
+                  // root <element>s or text outside the root <element>
+                  $(<li><input name={$(select).attr('name')} type="hidden" 
value={args[2][1]}/><span>{XML(args[2][0])}</span></li>.toXMLString())
+                    .click(function ()
+                      {
+                        // On click, remove <li>
+                        $(this).hide('fast', function ()
+                          {
+                            $(this).remove();
+                          });
+                      })
+                    .appendTo(ul);
+                }
+
+                // Select autocomplete <input> contents so typing will replace
+                // it
+                $(input).select();
+              }
+              else
+              {
+                // On single <select> item select, simply update the value of
+                // this input
+                $(hidden).val(args[2][1]);
+
+                // Update the value of the autocomplete <input> here with text
+                // of parsed HTML, instead of source
+                //
+                // Use XML() constructor as with multiple <select>, but use
+                // toString() to get text of parsed HTML
+                $(input).val(XML(args[2][0]));
+              }
+            });
+
+          if ($(select).attr('multiple'))
+          {
+            // If multiple <select>, clear autocomplete <input> on blur
+            //
+            // TODO Don't clear if event.preventDefault() was called?
+            autoComplete.textboxBlurEvent.subscribe(function ()
+              {
+                $(input).val('');
+              });
+          }
+
+          // Show autocomplete items, use named function so it can be bound to
+          // click and focus events, use private _nDelayID to cancel query on
+          // e.g. keypress before query delay
+          //
+          // TODO File YUI issue for this
+          function sendQuery()
+          {
+            if (-1 == autoComplete._nDelayID)
+            {
+              autoComplete._nDelayID = setTimeout(function ()
+                {
+                  autoComplete._sendQuery(autoComplete.getInputEl().value);
+                }, autoComplete.queryDelay * 1000);
+            }
+          }
+
+          // Use custom YUI event to avoid DOM focus events triggered by
+          // YUI widget interaction
+          autoComplete.textboxFocusEvent.subscribe(sendQuery);
+
+          // Listen for click to show autocomplete items after selecting
+          // existing item, but not changing focus
+          $(input).click(sendQuery);
+
+          // Finally remove <select> element
+          $(this).remove();
+        });
+    } };

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Qubit Toolkit Commits" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.ca/group/qubit-commits?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to