--- uc_aac copy.module
+++ (clipboard)
@@ -107,7 +107,7 @@
 
     /**
      * Initialize select attributes so that prices update on change, radio
-     * buttons update on click.
+     * buttons and checkboxes update on click.
      */
     function initialize_fields_'. $nid .'() {
       $("#node-'. $nid .' select").each(function () {
@@ -118,7 +118,7 @@
           });
         }
       });
-      $("#node-'. $nid .' :radio").each(function () {
+      $("#node-'. $nid .' :radio, #node-'. $nid .' :checkbox").each(function () {
         var element = this;
         if (element.name && element.name.match("attributes")) {
           // Needed because off odd click() behavior in IE with Jquery Update
@@ -151,6 +151,12 @@
           aac_form.elements[aac_form.elements.length] = element;
         }
       });
+			 $("#node-'. $nid .' :checkbox").each(function () {
+			   var element = this;
+			   if (element.name && element.name.match("attributes")) {
+			   aac_form.elements[aac_form.elements.length] = element;
+			   }
+			 });
       var this_update = new Date();
       aac_'. $nid .'_update = this_update.getTime();
       $(aac_form).ajaxSubmit( {
@@ -210,6 +216,29 @@
                     initialize_fields_'. $nid .'();
                   }
                 }
+								if (json_results.attributes[i].type == "checkbox") {
+								  var checkbox_index = 0;
+								  $("#node-'. $nid .' :checkbox").parent().each(function (j) {
+								    if (this.firstChild.name.substr(0, json_results.attributes[i].name.length) == json_results.attributes[i].name) {
+								      checkbox_option = json_results.attributes[i].options[checkbox_index];
+								      if (checkbox_option.adjustment.length > 0) {
+								        checkbox_option.label += ",";
+								      }
+								      checkbox_index ++;
+								      if ($.browser.msie) {
+								        var checkbox_input = this.innerHTML.slice(0, this.innerHTML.indexOf(">") + 1);
+								        this.innerHTML = checkbox_input + " " + checkbox_option.label + " " + checkbox_option.adjustment;
+								      }
+								      else {
+								        this.childNodes[this.childNodes.length-1].textContent = " " + checkbox_option.label + " " + checkbox_option.adjustment;
+								      }
+								    }
+							    });
+								  if ($.browser.msie) {
+								    // Re-apply all of the onClick events that get lost when using innerHTML
+								    initialize_fields_'. $nid .'();
+								  }
+								}
               }
             }
             var currentsellHTML= $("#node-'. $nid .' .uc-price-sell").html();
@@ -244,10 +273,17 @@
   $base_price = db_result(db_query('SELECT sell_price FROM {uc_products} WHERE nid=%d AND vid=(SELECT vid FROM {node} WHERE nid=%d)', $nid, $nid));
   $updated_price = $base_price;
   $attributes = $field_values['attributes'];
-  $types = array(0 => "text", 1 => "select", 2 => "radio");
+  $types = array(0 => "text", 1 => "select", 2 => "radio", 3 => 'checkbox');
   if ($attributes) {
-    foreach ($attributes as $attribute) {
-      $aid = db_result(db_query('SELECT aid FROM {uc_attribute_options} WHERE oid = %d', $attribute));
+    foreach ($attributes as $aid => $selected_options) {
+		  if(!$selected_options || (is_array($selected_options && empty($selected_options)))) {
+		    continue;
+		  }
+
+		  if(!is_array($selected_options)) {
+		    $selected_options = array($selected_options);
+		  }
+		
       $display = db_result(db_query('SELECT display FROM {uc_product_attributes} WHERE aid = %d AND nid = %d', $aid, $nid));
       $options = db_query('SELECT DISTINCT upo.oid, uao.name, upo.cost, upo.price FROM {uc_attribute_options} AS uao LEFT JOIN {uc_product_options} AS upo ON uao.oid = upo.oid WHERE uao.aid = %d AND upo.nid = %d ORDER BY upo.ordering, uao.ordering, uao.name', $aid, $nid);
       $names = array();
@@ -255,20 +291,35 @@
       while ($option = db_fetch_object($options)) {
         $names[$option->oid] = $option->name;
         $prices[$option->oid] = $option->price;
-        if ($option->oid == $attribute) {
+        if (in_array($option->oid, $selected_options)) {
+				  // note: $used_price only makes sense for the attributes where option selection is exclusive
           $used_price[$aid] = $option->price;
           $updated_price += $option->price;
+					if ($types[$display] == 'checkbox') {
+					  // special case for selected checkbox options - display effect on price when removed
+					  $prices[$option->oid] = -$option->price;
+					}
         }
       }
       $attribute_options = array();
-      foreach ($prices as $oid => $attribute_price) {
-        $adjusted_price = $attribute_price - $used_price[$aid];
+      foreach ($prices as $oid => $option_price) {
+			  $adjusted_price = ($types[$display] != 'checkbox' ? $option_price - $used_price[$aid] : $option_price);
         $price_text = '';
         if ($adjusted_price != 0) {
-          if ($adjusted_price > 0) {
-            $price_text .= "+";
+          if ($types[$display] != 'checkbox') {
+					  if ($adjusted_price > 0) {
+					    $price_text .= "+";
+					  }
+					  $price_text .= uc_currency_format($adjusted_price);
+					}
+					else {
+					  if ($adjusted_price > 0) {
+					    $price_text .= "+" . uc_currency_format($adjusted_price);
+					  }
+					  else {
+					    $price_text .= "(" . uc_currency_format($adjusted_price) . ")";
+					  }
           }
-          $price_text .= uc_currency_format($adjusted_price);
         }
         $attribute_options[] = array('key' => $oid, 'label' => $names[$oid], 'adjustment' => $price_text);
       }
