diff --git a/l10n_client.css b/l10n_client.css
index ed7b2e7..470cec6 100644
--- a/l10n_client.css
+++ b/l10n_client.css
@@ -10,7 +10,7 @@ how it wants to round. */
   line-height:1em;
   color:#000; background:#fff;
   position:fixed;
-  width:100%; height: 2em;
+  width:100%;
   bottom:0px; left:0px;
   overflow:hidden;}
 
@@ -195,3 +195,14 @@ how it wants to round. */
   background-color: #F00;
   color: #fff;
 }
+#l10n-client .collapsed {
+  height: 2em;
+  overflow: hidden;
+}
+#l10n-client .expanded {
+  height: 22em;
+}
+
+#l10n-client .toggle-expanded {
+  border-bottom: 22em solid #fff;
+}
diff --git a/l10n_client.js b/l10n_client.js
index def53e7..8904c99 100644
--- a/l10n_client.js
+++ b/l10n_client.js
@@ -1,217 +1,222 @@
 
-(function ($) {
+(function ($, Drupal, undefined) {
 
 // Store all l10n_client related data + methods in its own object
-$.extend(Drupal, {
-  l10nClient: new (function() {
-    // Set "selected" string to unselected, i.e. -1
-    this.selected = -1;
-    // Keybindings
-    this.keys = {'toggle':'ctrl+shift+s', 'clear': 'esc'}; // Keybindings
-    // Keybinding functions
-    this.key = function(pressed) {
-      switch(pressed) {
-        case 'toggle':
-          // Grab user-hilighted text & send it into the search filter
-          userSelection = window.getSelection ? window.getSelection() : document.getSelection ? document.getSelection() : document.selection.createRange().text;
-          userSelection = String(userSelection);
-          if(userSelection.length > 0) {
-            Drupal.l10nClient.filter(userSelection);
-            Drupal.l10nClient.toggle(1);
-            $('#l10n-client .string-search').focus();
-          } else {
-            if($('#l10n-client').is('.hidden')) {
-              Drupal.l10nClient.toggle(1);
-              if(!$.browser.safari) {
-                $('#l10n-client .string-search').focus();
-              }
-            } else {
-              Drupal.l10nClient.toggle(0);
+Drupal.l10nClient = {
+  // Set "selected" string to unselected, i.e. -1
+  selected: -1,
+  // Keybindings
+  keys: {'toggle':'ctrl+shift+s', 'clear': 'esc'}, // Keybindings
+  // Keybinding functions
+  key: function(pressed) {
+    var $l10nClient = Drupal.l10nClient.$l10nClient;
+    switch(pressed) {
+      case 'toggle':
+        // Grab user-hilighted text & send it into the search filter
+        var userSelection = window.getSelection ? window.getSelection() : document.getSelection ? document.getSelection() : document.selection.createRange().text;
+        userSelection = String(userSelection);
+        if(userSelection.length > 0) {
+          this.filter(userSelection);
+          this.toggle(1);
+          $l10nClient.find('.string-search').focus();
+        } else {
+          if($l10nClient.is('.collapsed')) {
+            this.toggle(1);
+            if(!$.browser.safari) {
+              $l10nClient.find('.string-search').focus();
             }
+          } else {
+            this.toggle(0);
           }
-        break;
-        case 'clear':
-          this.filter(false);
-        break;
-      }
-    }
-    // Toggle the l10nclient
-    this.toggle = function(state) {
-      switch(state) {
-        case 1:
-          $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label').show();
-          $('#l10n-client').height('22em').removeClass('hidden');
-          $('#l10n-client .labels .toggle').text('X');
-          if(!$.browser.msie) {
-            $('body').css('border-bottom', '22em solid #fff');
-          }
-          $.cookie('Drupal_l10n_client', '1', {expires: 7, path: '/'});
-        break;
-        case 0:
-          $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label').hide();
-          $('#l10n-client').height('2em').addClass('hidden');
-          $('#l10n-client .labels .toggle').text(Drupal.t('Translate Text'));
-          if(!$.browser.msie) {
-            $('body').css('border-bottom', '0px');
-          }
-          $.cookie('Drupal_l10n_client', '0', {expires: 7, path: '/'});
-        break;
-      }
-    }
-    // Get a string from the DOM tree
-    this.getString = function(index, type) {
-      return $('#l10n-client-data div:eq('+index+') .'+type).text();
-    }
-    // Set a string in the DOM tree
-    this.setString = function(index, data) {
-      $('#l10n-client-data div:eq('+index+') .target').text(data);
+        }
+      break;
+      case 'clear':
+        this.filter(false);
+      break;
     }
-    // Filter the the string list by a search string
-    this.filter = function(search) {
-      if(search == false || search == '') {
-        $('#l10n-client #l10n-client-search-filter-clear').focus();
-        $('#l10n-client-string-select li').show();
-        $('#l10n-client .string-search').val('');
-        $('#l10n-client .string-search').focus();
-      } else {
-        if(search.length > 0) {
-          $('#l10n-client-string-select li').hide();
-          $('#l10n-client-string-select li:contains('+search+')').show();
-          $('#l10n-client .string-search').val(search);
+  },
+  // Toggle the l10nclient
+  toggle: function(state) {
+    var $l10nClient = Drupal.l10nClient.$l10nClient;
+    var $clientWrapper = $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label');
+    switch(state) {
+      case '1':
+      case true:
+        $clientWrapper.show();
+        $l10nClient.removeClass('collapsed').addClass('expanded').find('.labels .toggle').text('X');
+        if(!$.browser.msie) {
+          $('body').addClass('toggle-expanded');
         }
-      }
+        $.cookie('Drupal_l10n_client', '1', {expires: 7, path: '/'});
+      break;
+      case '0':
+      case false:
+        $clientWrapper.hide();
+        $l10nClient.removeClass('expanded').addClass('collapsed').find('.labels .toggle').text(Drupal.t('Translate Text'));
+        if(!$.browser.msie) {
+          $('body').removeClass('.toggle-expanded');
+        }
+        $.cookie('Drupal_l10n_client', '0', {expires: 7, path: '/'});
+      break;
     }
-  })
-});
-
-// Attaches the localization editor behavior to all required fields.
-Drupal.behaviors.l10nClient = {}
-Drupal.behaviors.l10nClient.attach = function (context) {
-  // Killswitch - attach only once.
-  if ($('#l10n-client').is('.l10n-client-processed')) {
-    return;
-  }
-
-  // First time - init & attach all handlers.
-  $('#l10n-client').addClass('l10n-client-processed');
-
-  switch($.cookie('Drupal_l10n_client')) {
-    case '1':
-      Drupal.l10nClient.toggle(1);
-    break;
-    default:
-      Drupal.l10nClient.toggle(0);
-    break;
-  }
-
-  // If the selection changes, copy string values to the source and target fields.
-  // Add class to indicate selected string in list widget.
-  $('#l10n-client-string-select li').click(function() {
-    $('#l10n-client-string-select li').removeClass('active');
-    $(this).addClass('active');
-    var index = $('#l10n-client-string-select li').index(this);
-
-    $('#l10n-client-string-editor .source-text').text(Drupal.l10nClient.getString(index, 'source'));
-    $('#l10n-client-form .translation-target').val(Drupal.l10nClient.getString(index, 'target'));
-    $('#l10n-client-form .source-textgroup').val(Drupal.l10nClient.getString(index, 'textgroup'));
-    $('#l10n-client-form .source-context').val(Drupal.l10nClient.getString(index, 'context'));
-    $('#l10n-client-string-editor .context').text(Drupal.l10nClient.getString(index, 'context'));
-
-    Drupal.l10nClient.selected = index;
-    $('#l10n-client-form .form-submit').removeAttr("disabled");
-  });
-
-  // When l10n_client window is clicked, toggle based on current state.
-  $('#l10n-client .labels .toggle').click(function() {
-    if($('#l10n-client').is('.hidden')) {
-      Drupal.l10nClient.toggle(1);
+  },
+  // Get a string from the DOM tree
+  getString: function(index, type) {
+    return $('#l10n-client-data div:eq('+index+') .'+type).text();
+  },
+  // Set a string in the DOM tree
+  setString: function(index, data) {
+    $('#l10n-client-data div:eq('+index+') .target').text(data);
+  },
+  // Filter the the string list by a search string
+  filter: function(search) {
+    var $l10nClient = Drupal.l10nClient.$l10nClient;
+    var $stringSearch = $l10nClient.find('.string-search');
+    var $stringSelect = $('#l10n-client-string-select').find('li');
+    if(search === false || search === '') {
+      $('#l10n-client-search-filter-clear').focus();
+      $stringSelect.show();
+      $stringSearch.val('').focus();
     } else {
-      Drupal.l10nClient.toggle(0);
+      if(search.length > 0) {
+        $stringSelect.not(':contains('+search+')').hide();
+        $stringSearch.val(search);
+      }
     }
-  });
-
-  // Copy source text to translation field on button click.
-  $('#l10n-client-form .edit-copy').click(function() {
-    $('#l10n-client-form .translation-target').val($('#l10n-client-string-editor .source-text').text());
-    return false;
-  });
-
-  // Clear translation field on button click.
-  $('#l10n-client-form .edit-clear').click(function() {
-    $('#l10n-client-form .translation-target').val('');
-    return false;
-  });
-
-  // Register keybindings using jQuery hotkeys
-  if($.hotkeys) {
-    $.hotkeys.add(Drupal.l10nClient.keys['toggle'], function(){Drupal.l10nClient.key('toggle')});
-    $.hotkeys.add(Drupal.l10nClient.keys['clear'], {target:'#l10n-client .string-search', type:'keyup'}, function(){Drupal.l10nClient.key('clear')});
   }
+};
 
-  // Custom listener for l10n_client livesearch
-  $('#l10n-client .string-search').keyup(function(key) {
-    Drupal.l10nClient.filter($('#l10n-client .string-search').val());
-  });
-
-  // Clear search
-  $('#l10n-client #l10n-client-search-filter-clear').click(function() {
-    Drupal.l10nClient.filter(false);
-    return false;
-  });
-
-  // Send AJAX POST data on form submit.
-  $('#l10n-client-form').submit(function() {
-    $('#l10n-client-form .form-submit').attr("disabled", "true");
-    $.ajax({
-      type: "POST",
-      url: $('#l10n-client-form').attr('action'),
-      // Send source and target strings.
-      data: {
-        source: $('#l10n-client-string-editor .source-text').text(),
-        target: $('#l10n-client-form .translation-target').val(),
-        textgroup: $('#l10n-client-form .source-textgroup').val(),
-        context: $('#l10n-client-string-editor .context').text(),
-        'form_token': $('#l10n-client-form input[name=form_token]').val()
-      },
-      success: function (data) {
-        // Store string in local js
-        Drupal.l10nClient.setString(Drupal.l10nClient.selected, $('#l10n-client-form .translation-target').val());
-
-        // Figure out the display of the new translation in the selection list.
-        var newTranslation = $('#l10n-client-form .translation-target').val();
-        var newTranslationDisplay = newTranslation;
-        var newTranslationStripped = newTranslation.replace(/<\/?[^<>]+>/gi, '')
-                                                   .replace(/&quot;/g, '"')
-                                                   .replace(/&lt;/g, "<")
-                                                   .replace(/&gt;/g, ">")
-                                                   .replace(/&amp;/g, "&");
-        if (newTranslationStripped.length == 0) {
-          // Only contains HTML tags (edge case). Keep the whole string.
-          // HTML tags will show up in the selector, but that is normal in this case.
-          newTranslationDisplay = newTranslation;
-        }
-        else if (newTranslationStripped.length > 81) {
-          // Long translation, strip length to display only first part.
-          // We strip at 78 chars and add thre dots, if the total length is
-          // above 81.
-          newTranslationDisplay = newTranslationStripped.substr(0, 78) + '...';
-        }
+// Attaches the localization editor behavior to all required fields.
+Drupal.behaviors.l10nClient = {
+  attach: function (context) {
+    $('#l10n-client').once('l10n-client', function () {
+      var $l10nClient = $(this);
+      var $l10nClientForm = $('#l10n-client-form');
+      var $stringEditor = $('#l10n-client-string-editor');
+      var $stringEditorSoruceText = $stringEditor.find('.source-text');
+      var $stringSelect = $('#l10n-client-string-select');
+      Drupal.l10nClient.$l10nClient = $l10nClient;
+      Drupal.l10nClient.toggle($.cookie('Drupal_l10n_client'));
+
+      // If the selection changes, copy string values to the source and target fields.
+      // Add class to indicate selected string in list widget.
+      $stringSelect.find('li').click(function() {
+        var $this = $(this);
+        var $lis = $stringSelect.find('li');
+        var index = $lis.index(this);
+
+        $lis.removeClass('active');
+        $this.addClass('active');
+
+        $stringEditorSoruceText.text(Drupal.l10nClient.getString(index, 'source'));
+        $l10nClientForm.find('.translation-target').val(Drupal.l10nClient.getString(index, 'target'));
+        $l10nClientForm.find('.source-textgroup').val(Drupal.l10nClient.getString(index, 'textgroup'));
+        $l10nClientForm.find('.source-context').val(Drupal.l10nClient.getString(index, 'context'));
+        $stringEditor.find('.context').text(Drupal.l10nClient.getString(index, 'context'));
+
+        Drupal.l10nClient.selected = index;
+        $l10nClientForm.find('.form-submit').removeAttr("disabled");
+      });
+
+      // When l10n_client window is clicked, toggle based on current state.
+      $l10nClient.find('.labels .toggle').click(function() {
+        Drupal.l10nClient.toggle($l10nClient.is('.collapsed'));
+      });
+
+      // Copy source text to translation field on button click.
+      $l10nClientForm.find('.edit-copy').click(function() {
+        $l10nClientForm.find('.translation-target').val($stringEditorSoruceText.text());
+        return false;
+      });
+
+      // Clear translation field on button click.
+      $l10nClientForm.find('.edit-clear').click(function() {
+        $l10nClientForm.find('.translation-target').val('');
+        return false;
+      });
+
+      // Register keybindings using jQuery hotkeys
+      if($.hotkeys) {
+        $.hotkeys.add(Drupal.l10nClient.keys.toggle, function(){
+          Drupal.l10nClient.key('toggle');
+        });
+        $.hotkeys.add(Drupal.l10nClient.keys.clear, {target:'#l10n-client .string-search', type:'keyup'}, function(){
+          Drupal.l10nClient.key('clear');
+        });
+      }
 
-        // Mark string as translated.
-        $('#l10n-client-string-select li').eq(Drupal.l10nClient.selected).removeClass('untranslated').removeClass('active').addClass('translated').text(newTranslationDisplay);
+      // Custom listener for l10n_client livesearch
+      $l10nClient.find('.string-search').keyup(function(key) {
+        Drupal.l10nClient.filter($l10nClient.find('.string-search').val());
+      });
+
+      // Clear search
+      $l10nClient.find('#l10n-client-search-filter-clear').click(function() {
+        Drupal.l10nClient.filter(false);
+        return false;
+      });
+
+      // Send AJAX POST data on form submit.
+      $l10nClientForm.submit(function() {
+        var $this = $(this);
+
+        // Prevent submit empty strings.
+        $this.find('.form-submit').attr("disabled", true);
+
+        $.ajax({
+          type: "POST",
+          url: $this.attr('action'),
+          // Send source and target strings.
+          data: {
+            source: $stringEditorSoruceText.text(),
+            target: $this.find('.translation-target').val(),
+            textgroup: $this.find('.source-textgroup').val(),
+            context: $stringEditor.find('.context').text(),
+            'form_token': $this.find('input[name=form_token]').val()
+          },
+          success: function (data) {
+            var $translationTarget = $l10nClientForm.find('.translation-target');
+            var newTranslation = $translationTarget.val();
+            // Store string in local js
+            Drupal.l10nClient.setString(Drupal.l10nClient.selected, newTranslation);
+
+            // Figure out the display of the new translation in the selection list.
+            var newTranslationStripped = newTranslation.replace(/<\/?[^<>]+>/gi, '')
+              .replace(/&quot;/g, '"')
+              .replace(/&lt;/g, "<")
+              .replace(/&gt;/g, ">")
+              .replace(/&amp;/g, "&");
+
+            // Only contains HTML tags (edge case). Keep the whole string.
+            // HTML tags will show up in the selector, but that is normal in this case.
+            newTranslationDisplay = newTranslation;
+            if (newTranslationStripped.length > 81) {
+              // Long translation, strip length to display only first part.
+              // We strip at 78 chars and add thre dots, if the total length is
+              // above 81.
+              newTranslationDisplay = newTranslationStripped.substr(0, 78) + '...';
+            }
 
-        // Empty input fields.
-        $('#l10n-client-string-editor .source-text').html(data);
-        $('#l10n-client-form .translation-target').val('');
+            // Mark string as translated.
+            $stringSelect.find('li')
+              .eq(Drupal.l10nClient.selected)
+              .removeClass('untranslated active')
+              .addClass('translated')
+              .text(newTranslationDisplay);
 
-      },
-      error: function (xmlhttp) {
-        alert(Drupal.t('An HTTP error @status occured.', { '@status': xmlhttp.status }));
-      }
-    });
-    return false;
-  });
+            // Empty input fields.
+            $stringEditorSoruceText.html(data);
+            $translationTarget.val('');
 
+          },
+          error: function (xmlhttp) {
+            alert(Drupal.t('An HTTP error @status occured.', { '@status': xmlhttp.status }));
+          }
+        });
+        return false;
+      });
+    });
+  }
 };
 
-})(jQuery);
+})(jQuery, Drupal);
