diff --git a/Makefile b/Makefile
index 2bc6e55d6d5771e3a76ec8543fcf3db8a6fa3101..62feb1f7b098ee4c1edeb436a88ada0257d51772 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 BASE=ordernumber
 PLUGINTYPE=vmshopper
-VERSION=1.90
+VERSION=2.0
 
-PLUGINFILES=$(BASE).php $(BASE).script.php $(BASE).xml index.html
+PLUGINFILES=$(BASE).php $(BASE).script.php $(BASE).xml index.html $(BASE)/
 
 SYSTRANSLATIONS=$(call wildcard,language/*/*.plg_$(PLUGINTYPE)_$(BASE).*sys.ini)
 NONSYSTRANSLATIONS=${SYSTRANSLATIONS:%.sys.ini=%.ini}
diff --git a/fields/vmordernumbercounters.php b/fields/vmordernumbercounters.php
index 48972225c58ae6f941f3d4128208fd3d922a9d93..2c1dbf1c5ce58349fe25644e98d38e059626d808 100644
--- a/fields/vmordernumbercounters.php
+++ b/fields/vmordernumbercounters.php
@@ -66,20 +66,20 @@ class JFormFieldVmOrdernumberCounters extends JFormField {
         $pluginpath = '/plugins/vmshopper/ordernumber/ordernumber/';
         $doc = JFactory::getDocument()->addStyleSheet(JURI::root(true) . $pluginpath . 'assets/css/ordernumber.css');
         $doc->addScript(JURI::root(true).$pluginpath . 'assets/js/ordernumber.js');
+        vmJsApi::jQuery();
         
         // Look up the current counters
         $db = JFactory::getDBO();
         $db->setQuery('SELECT `number_format`, `count` FROM `#__virtuemart_shopper_plg_ordernumber` WHERE `number_type`='.$db->quote($this->countertype) . ' ORDER BY `number_format`;' );
         $counters = $db->loadObjectList();
         // Joomla 2.x uses <li> for the params and float:left on the controls, so we need to add that too
-        $version = new JVersion();
         $float = "";
         if (version_compare(JVERSION, '3.0', 'lt')) {
             $float = "float: left; ";
         }
         
         $html=array();
-        $html[] = "<table class=\"vmordernumber-countertable table-striped \" display: inline-table; $float\">";
+        $html[] = "<img src='".JURI::root(true).$pluginpath . "assets/images/loading.gif' class='vm-ordernumber-loading' style=\"display: none; position: absolute; top: 2px; left: 0px; z-index: 9999;\"/><table class=\"vmordernumber-countertable table-striped \" style=\"display: inline-table; $float\">";
         $html[] = "  <tr>";
         $html[] = "    <th class='counter_format'>".JText::_('PLG_ORDERNUMBER_COUNTERLIST_HEADER_COUNTER')."</th>";
         $html[] = "    <th class='counter_value'>".JText::_('PLG_ORDERNUMBER_COUNTERLIST_HEADER_VALUE'). "</th>";
@@ -94,11 +94,11 @@ class JFormFieldVmOrdernumberCounters extends JFormField {
             $html[] = "  <tr class='counter_row counter_type_$this->countertype'>";
             $html[] = "    <td class='counter_format'>" . (string)$displayfmt . "</td>";
             $html[] = "    <td class='counter_value'>" . (string)$c->count . "</td>";
-            $html[] = "    <td class='counter_buttons'><img src='" .JURI::root(true).$pluginpath . "assets/images/icon-16-edit.png' class='vmordernumber-counter-editbtn vmordernumber-btn' onClick='ajaxEditCounter(this, $this->countertype, ".json_encode($c->number_format).", $c->count)' /><img src='" . JURI::root(true).$pluginpath . "assets/images/icon-16-delete.png' class='vmordernumber-counter-deletebtn vmordernumber-btn' onClick='ajaxDeleteCounter(this, $this->countertype, ".json_encode($c->number_format).", $c->count)' /></td>";
+            $html[] = "    <td class='counter_buttons'><div class='ordernumber-ajax-loading'><img src='" .JURI::root(true).$pluginpath . "assets/images/icon-16-edit.png' class='vmordernumber-counter-editbtn vmordernumber-btn' onClick='ajaxEditCounter(this, $this->countertype, ".json_encode($c->number_format).", $c->count)' /></div><div class='ordernumber-ajax-loading'><img src='" . JURI::root(true).$pluginpath . "assets/images/icon-16-delete.png' class='vmordernumber-counter-deletebtn vmordernumber-btn' onClick='ajaxDeleteCounter(this, $this->countertype, ".json_encode($c->number_format).", $c->count)' /></div></td>";
             $html[] = "  </tr>";
         }
         $html[] = "  <tr class='addcounter_row'>";
-        $html[] = "    <td colspan=3 class='counter_add'><div class='vmordernumber-counter-addbtn vmordernumber-btn' onClick='ajaxAddCounter(this, $this->countertype)'><img src='" . JURI::root(true).$pluginpath . "assets/images/icon-16-new.png' class='vmordernumber-counter-addbtn' />" . JText::_('PLG_ORDERNUMBER_COUNTERLIST_ADD') . "</div></td>";
+        $html[] = "    <td colspan=3 class='counter_add'><div class='vmordernumber-counter-addbtn vmordernumber-btn' onClick='ajaxAddCounter(this, $this->countertype)'><div class='ordernumber-ajax-loading'><img src='" . JURI::root(true).$pluginpath . "assets/images/icon-16-new.png' class='vmordernumber-counter-addbtn' /></div>" . JText::_('PLG_ORDERNUMBER_COUNTERLIST_ADD') . "</div></td>";
         $html[] = "  </tr>";
         $html[] = "</table>";
         return implode("\n", $html);
diff --git a/language/en-GB/en-GB.plg_vmshopper_ordernumber.ini b/language/en-GB/en-GB.plg_vmshopper_ordernumber.ini
index 37a3f73f2ed3162673f3c136b3de142ac13db753..b4218138eb9b4d81d3fc896bbcb312493d0c0f89 100644
--- a/language/en-GB/en-GB.plg_vmshopper_ordernumber.ini
+++ b/language/en-GB/en-GB.plg_vmshopper_ordernumber.ini
@@ -51,3 +51,7 @@ PLG_ORDERNUMBER_COUNTERLIST_HEADER_COUNTER="Counter format/name"
 PLG_ORDERNUMBER_COUNTERLIST_HEADER_VALUE="Counter value"
 PLG_ORDERNUMBER_COUNTERLIST_ADD="Add new counter"
 PLG_ORDERNUMBER_COUNTERLIST_EXISTS="Counter '%s' already exists."
+
+PLG_ORDERNUMBER_FIELDSET_ORDERNUMBER="Order Numbers"
+PLG_ORDERNUMBER_FIELDSET_INVOICENUMBER="Invoice Numbers"
+PLG_ORDERNUMBER_FIELDSET_CUSTOMERNUMBER="Customer Numbers"
diff --git a/language/en-GB/en-GB.plg_vmshopper_ordernumber.sys.ini b/language/en-GB/en-GB.plg_vmshopper_ordernumber.sys.ini
index 37a3f73f2ed3162673f3c136b3de142ac13db753..b4218138eb9b4d81d3fc896bbcb312493d0c0f89 100644
--- a/language/en-GB/en-GB.plg_vmshopper_ordernumber.sys.ini
+++ b/language/en-GB/en-GB.plg_vmshopper_ordernumber.sys.ini
@@ -51,3 +51,7 @@ PLG_ORDERNUMBER_COUNTERLIST_HEADER_COUNTER="Counter format/name"
 PLG_ORDERNUMBER_COUNTERLIST_HEADER_VALUE="Counter value"
 PLG_ORDERNUMBER_COUNTERLIST_ADD="Add new counter"
 PLG_ORDERNUMBER_COUNTERLIST_EXISTS="Counter '%s' already exists."
+
+PLG_ORDERNUMBER_FIELDSET_ORDERNUMBER="Order Numbers"
+PLG_ORDERNUMBER_FIELDSET_INVOICENUMBER="Invoice Numbers"
+PLG_ORDERNUMBER_FIELDSET_CUSTOMERNUMBER="Customer Numbers"
diff --git a/ordernumber.php b/ordernumber.php
index d4226928851d0e0c52a0d37987609c3c23f4943a..9270fc64ee498ac67fb178f6f99a882d0418610d 100644
--- a/ordernumber.php
+++ b/ordernumber.php
@@ -274,26 +274,26 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
         $authorized = ($user->authorise('core.admin','com_virtuemart') or
                        $user->authorise('core.manage','com_virtuemart') or 
                        $user->authorise('vm.orders','com_virtuemart'));
-        $output = array();
-        $output['authorized'] = $authorized;
+        $json = array();
+        $json['authorized'] = $authorized;
         if (!$authorized) return FALSE;
 
         $action = vRequest::getCmd('action');
         $counter= vRequest::getString('counter');
         $nrtype = vRequest::getInt('nrtype');
-        $output['action'] = $action;
-        $output['success'] = 0; // default: unsuccessfull
+        $json['action'] = $action;
+        $json['success'] = 0; // default: unsuccessfull
         switch ($action) {
             case "deleteCounter":
-                $output['success'] = $this->_deleteCounter($nrtype, $counter);
+                $json['success'] = $this->_deleteCounter($nrtype, $counter);
                 break;
             case "addCounter":
                 $value = vRequest::getInt('value',0);
                 if ($this->_counterExists($nrtype, $counter)) {
-                    $output['error'] = JText::sprintf('PLG_ORDERNUMBER_COUNTERLIST_EXISTS', $counter);
-                    $output['success'] = false;
+                    $json['error'] = JText::sprintf('PLG_ORDERNUMBER_COUNTERLIST_EXISTS', $counter);
+                    $json['success'] = false;
                 } else {
-                    $output['success'] = $this->_addCounter($nrtype, $counter, $value);
+                    $json['success'] = $this->_addCounter($nrtype, $counter, $value);
                     // Return the table row for the new counter in the JSON:
                     $pluginpath = '/plugins/vmshopper/ordernumber/ordernumber/';
                     $displayfmt = ($counter=="") ? JText::_('PLG_ORDERNUMBER_COUNTERLIST_GLOBAL') : $counter;
@@ -303,12 +303,12 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
                     $html[] = "  <td class='counter_value'>" . (string)$value . "</td>";
                     $html[] = "  <td class='counter_buttons'><img src='" .JURI::root(true).$pluginpath . "assets/images/icon-16-edit.png' class='vmordernumber-counter-editbtn vmordernumber-btn' onClick='ajaxEditCounter(this, $nrtype, ".json_encode($counter).", $value)' /><img src='" . JURI::root(true).$pluginpath . "assets/images/icon-16-delete.png' class='vmordernumber-counter-deletebtn vmordernumber-btn' onClick='ajaxDeleteCounter(this, $nrtype, ".json_encode($counter).", $value)' /></td>";
                     $html[] = "</tr>";
-                    $output['newrow'] = implode("\n", $html);
+                    $json['newrow'] = implode("\n", $html);
                 }
                 break;
             case "setCounter":
                 $value = vRequest::getInt('value');
-                $output['success'] = $this->_setCounter($nrtype, $counter, $value);
+                $json['success'] = $this->_setCounter($nrtype, $counter, $value);
                 break;
         }
         
@@ -319,8 +319,16 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
         $previoustype = $document->getType();
         $document->setType('html');
         $msgrenderer = $document->loadRenderer('message');
-        $output['messages'] = $msgrenderer->render('Message');
+        $json['messages'] = $msgrenderer->render('Message');
         $document->setType($previoustype);
+
+        // WORKAROUND for broken (i.e. duplicate) content-disposition headers in Joomla 2.x:
+        // We request everything in raw and here send the headers for JSON and return
+        // the raw output in json format
+        $document =JFactory::getDocument();
+        $document->setMimeEncoding('application/json');
+        JResponse::setHeader('Content-Disposition','attachment;filename="ordernumber.json"');
+        $output = json_encode($json);
     }
     
     
diff --git a/ordernumber.xml b/ordernumber.xml
index e702bd7df099c675b568c4e07c16b42900ad05dd..7caf4baf26de7671714253beac81c71d01d331ef 100644
--- a/ordernumber.xml
+++ b/ordernumber.xml
@@ -20,6 +20,7 @@
         <filename>index.html</filename>
         <folder>language</folder>
         <folder>fields</folder>
+        <folder>ordernumber</folder>
     </files>
     <scriptfile>ordernumber.script.php</scriptfile>
     <languages folder="language">
@@ -31,7 +32,7 @@
     <!-- Joomla 2.5 & 3.0 config -->
     <config>
         <fields name="params" addfieldpath="/plugins/vmshopper/ordernumber/fields">
-            <fieldset name="basic">
+            <fieldset name="ordernumbers" label="PLG_ORDERNUMBER_FIELDSET_ORDERNUMBER">
                 <field name="order_options" type="spacer" label="PLG_ORDERNUMBER_ORDERNR" />
                 <field name="customize_order_number" type="radio" default="0" class="btn-group btn-group-yesno" label="PLG_ORDERNUMBER_ORDERNR_CUSTOMIZE" description="PLG_ORDERNUMBER_ORDERNR_CUSTOMIZE_DESC">
                     <option value="1">JYES</option>
@@ -45,14 +46,15 @@
                 </field>
                 <field name="order_number_allcounters" type="VmOrdernumberCounters" label="PLG_ORDERNUMBER_ORDERNR_ALLCOUNTERS" countertype="0" />
 
-
                 <field name="password_options" type="spacer" label="PLG_ORDERNUMBER_PASSWD" />
                 <field name="customize_order_password" type="radio" default="0" class="btn-group btn-group-yesno" label="PLG_ORDERNUMBER_PASSWD_CUSTOMIZE" description="PLG_ORDERNUMBER_PASSWD_CUSTOMIZE_DESC">
                     <option value="1">JYES</option>
                     <option value="0">JNO</option>
                 </field>
                 <field name="order_password_format" type="text" default="p_[randomHex5]" label="PLG_ORDERNUMBER_PASSWD_FMT" description="PLG_ORDERNUMBER_PASSWD_FMT_DESC"/>
+            </fieldset>
 
+            <fieldset name="invoicenumbers" label="PLG_ORDERNUMBER_FIELDSET_INVOICENUMBER">
                 <field name="invoice_options" type="spacer" label="PLG_ORDERNUMBER_INVOICENR" />
                 <field name="customize_invoice_number" type="radio" default="0" class="btn-group btn-group-yesno" label="PLG_ORDERNUMBER_INVOICENR_CUSTOMIZE" description="PLG_ORDERNUMBER_INVOICENR_CUSTOMIZE_DESC">
                     <option value="1">JYES</option>
@@ -65,7 +67,9 @@
                     <option value="0">PLG_ORDERNUMBER_COUNTER_PERFORMAT</option>
                 </field>
                 <field name="invoice_number_allcounters" type="VmOrdernumberCounters" label="PLG_ORDERNUMBER_ORDERNR_ALLCOUNTERS" countertype="1" />
+            </fieldset>
 
+            <fieldset name="customernumbers" label="PLG_ORDERNUMBER_FIELDSET_CUSTOMERNUMBER">
                 <field name="customer_options" type="spacer" label="PLG_ORDERNUMBER_CUSTOMERNR" />
                 <field name="customize_customer_number" type="radio" default="0" class="btn-group btn-group-yesno" label="PLG_ORDERNUMBER_CUSTOMERNR_CUSTOMIZE" description="PLG_ORDERNUMBER_CUSTOMERNR_CUSTOMIZE_DESC">
                     <option value="1">JYES</option>
diff --git a/ordernumber/assets/css/ordernumber.css b/ordernumber/assets/css/ordernumber.css
index ca337903ddd492f9cf67d6c1d718dec03581f207..140beb3364c25fa7693cd146513729e762f2cc65 100644
--- a/ordernumber/assets/css/ordernumber.css
+++ b/ordernumber/assets/css/ordernumber.css
@@ -15,4 +15,19 @@ table.vmordernumber-countertable.table-striped tbody > tr:nth-child(odd) > th {
 
 col.counter_type, th.counter_type, td.counter_type {
     display:none;
-}
\ No newline at end of file
+}
+
+fieldset table.vmordernumber-countertable img {
+    padding: 0;
+    margin: 0;    
+}
+div.ordernumber-ajax-loading, div.vmordernumber-counter-addbtn {
+    display: inline;
+}
+div.ordernumber-ajax-loading, div.ordernumber-ajax-loading img.vmordernumber-btn {
+    position: relative;
+    top: 0; left: 0;
+}
+div.ordernumber-ajax-loading img {
+    z-index:0;
+}
diff --git a/ordernumber/assets/images/loading.gif b/ordernumber/assets/images/loading.gif
new file mode 100644
index 0000000000000000000000000000000000000000..94da6d80e05ef96d9d7551013d59c22551c0ae1a
Binary files /dev/null and b/ordernumber/assets/images/loading.gif differ
diff --git a/ordernumber/assets/images/loading.png b/ordernumber/assets/images/loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac0aa90cbc6fde315828934a2494ec1324b8af56
Binary files /dev/null and b/ordernumber/assets/images/loading.png differ
diff --git a/ordernumber/assets/js/ordernumber.js b/ordernumber/assets/js/ordernumber.js
index bee01cade3b3f334cfe8d14e967706237303e569..7ef87b76349f7fa09c0723c0d8f7c8d07fa4798c 100644
--- a/ordernumber/assets/js/ordernumber.js
+++ b/ordernumber/assets/js/ordernumber.js
@@ -1,11 +1,15 @@
 var updateMessages = function(messages, area) {
-    jQuery( "#system-message-container #system-message div."+area+"-message").remove();
+    jQuery( "#system-message-container #system-message ."+area+"-message").remove();
     // Extract the messages from the returned string, add the ordernumber-message class (so the next ajax call
     // can remove them again) and then move the messages to the original message container.
     // Things are complicated by the fact that no #system-message element exists if no messages were printed so far
-    var newmessages = jQuery( messages ).find("div.alert").addClass(area+"-message");
+    var newmessages = jQuery( messages ).find("div.alert, .message").addClass(area+"-message");
     if (!jQuery( "#system-message-container #system-message").length && newmessages.length) {
-        jQuery( "#system-message-container" ).append( "<div id='system-message'></div>" );
+        if (jQuery(newmessages).first().prop("tagName")=="dt") { // Joomla 2.x:
+            jQuery( "#system-message-container" ).append( "<dl id='system-message'></div>" );
+        } else {
+            jQuery( "#system-message-container" ).append( "<div id='system-message'></div>" );
+        }
     }
     newmessages.appendTo( "#system-message-container #system-message");
 }
@@ -38,11 +42,12 @@ var ajaxEditCounter = function (btn, nrtype, ctr, value) {
             msgprefix = "You entered an invalid value for the counter.\n\n";
     }
     if (value != null) {
+        var loading = jQuery("img.vm-ordernumber-loading").first().clone().insertAfter(btn).show();
         jQuery.ajax({
             type: "POST",
             cache: false,
             dataType: "text", // Read text, but interpret as JSON later in the done method (prevents a warning!)
-            url: "index.php?option=com_virtuemart&view=plugin&type=vmshopper&name=ordernumber&action=setCounter&format=json",
+            url: "index.php?option=com_virtuemart&view=plugin&type=vmshopper&name=ordernumber&action=setCounter&format=raw",
             data: { nrtype: counter.type, counter: counter.counter, value: value },
             success: function( data ) {
                 var json = data ? jQuery.parseJSON(data) : null;
@@ -53,7 +58,8 @@ var ajaxEditCounter = function (btn, nrtype, ctr, value) {
                     alert ("Failed modifying counter "+counter.counter);
                 }
             },
-            error: function() { alert ("ERROR: Failed modifying counter "+counter.counter); }
+            error: function() { alert ("ERROR: Failed modifying counter "+counter.counter); },
+            complete: function() { jQuery(loading).remove(); },
         });
     }
 }
@@ -64,11 +70,12 @@ var ajaxDeleteCounter = function (btn, nrtype, ctr, value) {
     counter.value=value;
     var proceed = confirm ("Really delete counter '"+counter.counter+"' with value '"+counter.value+"'?");
     if (proceed == true) {
+        var loading = jQuery("img.vm-ordernumber-loading").first().clone().insertAfter(btn).show();
         jQuery.ajax({
             type: "POST",
             cache: false,
             dataType: "text", // Read text, but interpret as JSON later in the done method (prevents a warning!)
-            url: "index.php?option=com_virtuemart&view=plugin&type=vmshopper&name=ordernumber&action=deleteCounter&format=json",
+            url: "index.php?option=com_virtuemart&view=plugin&type=vmshopper&name=ordernumber&action=deleteCounter&format=raw",
             data: { nrtype: counter.type, counter: counter.counter },
             success: function( data ) {
                 var json = data ? jQuery.parseJSON(data) : null;
@@ -79,7 +86,8 @@ var ajaxDeleteCounter = function (btn, nrtype, ctr, value) {
                     alert ("Failed modifying counter "+counter.counter);
                 }
             },
-            error: function() { alert ("ERROR: Failed modifying counter "+counter.counter); }
+            error: function() { alert ("ERROR: Failed modifying counter "+counter.counter); },
+            complete: function() { jQuery(loading).remove(); },
         });
     }
 }
@@ -87,11 +95,12 @@ var ajaxAddCounter = function (btn, nrtype) {
     var row = jQuery(btn).parents("tr.addcounter_row");
     var countername = prompt ("Please enter the format/name of the new counter:");
     if (countername != null) {
+        var loading = jQuery("img.vm-ordernumber-loading").first().clone().insertAfter(jQuery(btn).find("img.vmordernumber-counter-addbtn")).show();
         jQuery.ajax({
             type: "POST",
             cache: false,
             dataType: "text", // Read text, but interpret as JSON later in the done method (prevents a warning!)
-            url: "index.php?option=com_virtuemart&view=plugin&type=vmshopper&name=ordernumber&action=addCounter&format=json",
+            url: "index.php?option=com_virtuemart&view=plugin&type=vmshopper&name=ordernumber&action=addCounter&format=raw",
             data: { nrtype: nrtype, counter: countername },
             success: function( data ) {
                 var json = data ? jQuery.parseJSON(data) : null;
@@ -102,7 +111,8 @@ var ajaxAddCounter = function (btn, nrtype) {
                     }
                 }
             },
-            error: function() { alert ("ERROR: Failed adding counter "+countername); }
+            error: function() { alert ("ERROR: Failed adding counter "+countername); },
+            complete: function() { jQuery(loading).remove(); },
         });
     }
 }