#QTY# x
Index: branches/1.0.x/inc/js/cart_manager.js
===================================================================
diff -u -N
--- branches/1.0.x/inc/js/cart_manager.js (revision 0)
+++ branches/1.0.x/inc/js/cart_manager.js (revision 14798)
@@ -0,0 +1,597 @@
+function ShopCartManager( $settings ) {
+ this.updateUrl = '';
+ this.orderInfo = {};
+ this.constants = {};
+ this.currencyMask = '%s';
+ this.debugMode = false;
+
+ $.extend(this, $settings);
+
+ this.rowTimers = {};
+
+ var $me = this;
+
+ $(document).ready(
+ function () {
+ $me.init();
+ }
+ );
+}
+
+ShopCartManager.prototype.init = function () {
+ var $me = this;
+
+ this.process(this.orderInfo);
+
+ $('.delete-cart-link').click(
+ function ($e) {
+ var $order_item_id = $(this).parents('tr:first').attr('order_item_id');
+
+ $me.apply( [{name: 'delete_id', value: $order_item_id}] );
+
+ return false;
+ }
+ );
+
+ $('.product-qty:input', '#shopping-cart-form')
+ .blur(
+ function ($e) {
+ var $row_index = $(this).parents('tr[row_index]:first').attr('row_index');
+
+ if ( $me.debugMode ) {
+ console.log('blur on ', $row_index, ' row');
+ }
+
+ $me.clearRowTimers($row_index);
+
+ if ( $me.debugMode ) {
+ console.log('doing apply (from blur) on ', $row_index, ' row');
+ }
+
+ $me.apply();
+
+ return false;
+ }
+ )
+ .keyup(
+ function ($e) {
+ var $row_index = $(this).parents('tr[row_index]:first').attr('row_index');
+
+ if ( $me.debugMode ) {
+ console.log('keyup on ', $row_index, ' row');
+ }
+
+ $me.clearRowTimers($row_index);
+
+ $me.rowTimers[$row_index] = setTimeout(
+ function() {
+ if ( $me.debugMode ) {
+ console.log('doing apply (from keyup) on ', $row_index, ' row');
+ }
+
+ $me.apply();
+ }
+ , 2000
+ );
+ }
+ );
+
+
+ $('#remove-coupon').click(
+ function ($e) {
+ $me.apply( [{name: 'remove', value: 'coupon'}] );
+
+ return false;
+ }
+ );
+
+ $('#remove-gift-certificate').click(
+ function ($e) {
+ $me.apply( [{name: 'remove', value: 'gift_certificate'}] );
+
+ return false;
+ }
+ );
+
+ $('#update-cart, #apply-coupon, #apply-gift-certificate').click(
+ function ($e) {
+ $me.apply();
+
+ return false;
+ }
+ );
+}
+
+ShopCartManager.prototype.clearRowTimers = function ($row_index) {
+ if ( this.rowTimers[$row_index] !== undefined ) {
+ if ( this.debugMode ) {
+ console.log('cleartimers on ', $row_index, ' row -> found = delete');
+ }
+
+ clearTimeout(this.rowTimers[$row_index]);
+ delete this.rowTimers[$row_index];
+ }
+ else if ( this.debugMode ) {
+ console.log('cleartimers on ', $row_index, ' row -> not found = skip');
+ }
+}
+
+ShopCartManager.prototype.apply = function ($params) {
+ var $me = this;
+
+ $.post(
+ this.updateUrl,
+ this.getFormData($params),
+ function ($data) {
+ $data = eval('(' + $data + ')');
+
+ $me.process($data);
+ }
+ )
+}
+
+ShopCartManager.prototype.getFormData = function ($params) {
+ var $ret = $('#shopping-cart-form').serializeArray();
+
+ if ( $params !== undefined ) {
+ while( $params.length > 0 ) {
+ $ret.push( $params.shift() );
+ }
+ }
+
+ return $ret;
+}
+
+ShopCartManager.prototype.process = function ($data) {
+ // 1. row missing ajax response -> was deleted in db
+ // 2. row missing in HTML -> was added in db
+ var $me = this,
+ $old_rows = this.getOldRows(),
+ $new_rows = this.getNewRows($data),
+ $add_rows = $new_rows.diff($old_rows),
+ $delete_rows = $old_rows.diff($new_rows);
+
+ if ( this.debugMode ) {
+ console.log('proessing data: ', $data);
+ }
+
+ // add rows
+ $($add_rows).each(
+ function () {
+ $me.addRow( this, $data.items[this] );
+ }
+ );
+
+ // delete rows
+ $($delete_rows).each(
+ function () {
+ var $row = $me.getRowByIndex(this);
+
+// $row.next('tr.separator').remove();
+ $row.remove();
+ }
+ );
+
+ this.updateExistingRows($data);
+
+ this.showErrors($data);
+ this.showFooter($data);
+
+ if ( this.debugMode ) {
+ console.log('old: ', $old_rows, '; new: ', $new_rows, '; add: ', $add_rows, '; delete: ', $delete_rows);
+ }
+}
+
+ShopCartManager.prototype.addRow = function ($row_index, $row_data) {
+ if ( this.debugMode ) {
+ console.log('adding row: ', $row_data);
+ }
+
+ var $html = $('#product-row-mask').val(),
+ $value = '';
+
+ /*f: OrderItemId ; v: 101
+ f: ProductName ; v: Product With Stock Limit = 5; with backorder
+ f: BackOrderFlag ; v: 1
+ f: FlatPrice ; v: 2
+ f: Price ; v: 1.2308
+ f: Quantity ; v: 2
+ f: Virtual ; v: 0
+ f: cust_Availability ; v:*/
+
+ for (var $field in $row_data.fields) {
+ $value = $row_data.fields[$field];
+
+ if ( $field == 'Price' || $field == 'FlatPrice' ) {
+ $value = this.formatPrice($value);
+ }
+
+ $html = $html.replace(new RegExp('{field:' + $field + '}', 'g'), $value);
+
+ if ( this.debugMode ) {
+ console.log('f: ', $field, '; v: ', $value);
+ }
+ }
+
+ $html = $html.replace(/{ROW_INDEX}/g, $row_index);
+// $html = $html.replace(/{DISCOUNT}/g, $row_index);
+// $html = $html.replace(/{EXTENDED_PRICE}/g, $row_index);
+
+// var $separator = $( $('#product-row-separator-mask').val() );
+
+ $('.shop-cart-row:last').after($html);
+ /*$('.shop-cart-row:last').after($separator);
+ $separator.after($html);*/
+}
+
+ShopCartManager.prototype.updateExistingRows = function ($data) {
+ if ( $.isArray($data.items) ) {
+ // todo: hide empty shopping cart & show special message
+ $('#item-count').html(0);
+ return;
+ }
+
+ var $row_count = 0;
+
+ for (var $row_index in $data.items) {
+ var $fields = $data.items[$row_index].fields,
+ $discount = $fields['FlatPrice'] - $fields['Price'],
+ $product_row = this.getRowByIndex($row_index),
+ $discount_container = $('.product-discount', $product_row);
+
+ // update product title
+ var $product_with_link = $('.product-with-link', $product_row);
+
+ $('a:first', $product_with_link)
+ .attr('href', $data.items[$row_index].product_url)
+ .html($fields['ProductName']);
+ $product_with_link.toggle( $fields['Virtual'] == 0 );
+
+ $('.product-without-link', $product_row)
+ .toggle( $fields['Virtual'] == 1 )
+ .html($fields['ProductName']);
+
+ $('.free-shipping', $product_row).toggle( $data.items[$row_index].free_promo_shipping );
+ $('.back-order-mark', $product_row).toggle( $fields['BackOrderFlag'] > 0 );
+
+ $('.product-availability', $product_row)
+ .toggle( $fields['cust_Availability'] != '' )
+ .html('
' + $fields['cust_Availability']);
+
+ $('.product-qty.read-only', $product_row).toggle( $fields['Type'] != this.constants['PRODUCT_TYPE_TANGIBLE'] );
+ $('.product-qty:not(.read-only)', $product_row).toggle( $fields['Type'] == this.constants['PRODUCT_TYPE_TANGIBLE'] );
+
+
+ // update product specific discount
+ $('.item-price', $discount_container).html( this.formatPrice($fields['FlatPrice']) );
+ $('.item-discount', $discount_container).html( '- ' + this.formatPrice($discount) );
+ $discount_container.toggle( $discount > 0 );
+
+ // update product prices
+ $('.price-cell', $product_row).html( this.formatPrice($fields['Price']) );
+ $('.extended-price-cell', $product_row).html( this.formatPrice($fields['Quantity'] * $fields['Price']) );
+
+ $row_count++;
+ }
+
+ $('#item-count').html($row_count);
+}
+
+ShopCartManager.prototype.showErrors = function ($data) {
+ var $error_code = 0, $error_info = [],
+ $row_index = '', $field = '',
+ $tooltip_options = '',
+ $coupon_error_code = this.getErrorByType('OrderCheckoutErrorType::COUPON', $data),
+ $gift_certificate_error_code = this.getErrorByType('OrderCheckoutErrorType::GIFT_CERTIFICATE', $data),
+ $discount_error_code = this.getErrorByType('OrderCheckoutErrorType::DISCOUNT', $data);
+
+ if ( $.isArray($data.errors) ) {
+ // when no error, then it's array
+ return ;
+ }
+
+ if ( $coupon_error_code ) {
+ if ( $coupon_error_code == this.constants['OrderCheckoutError::COUPON_APPLIED'] ) {
+ var $input = $('.coupon-name', '#coupon-row');
+ }
+ else {
+ var $input = $('.coupon-code:input', '#coupon-row');
+ }
+
+ $tooltip_options = this.getCouponErrorOptions($coupon_error_code);
+
+ if ( $tooltip_options ) {
+ this.createTooltip($input, $tooltip_options);
+ }
+ }
+
+ if ( $gift_certificate_error_code ) {
+ if ( $gift_certificate_error_code == this.constants['OrderCheckoutError::GC_APPLIED'] ) {
+ var $input = $('.gift-certificate-discount', '#gift-certificate-row');
+ }
+ else {
+ var $input = $('.gift-certificate-code:input', '#gift-certificate-row');
+ }
+
+ $tooltip_options = this.getGiftCertificateErrorOptions($gift_certificate_error_code);
+
+ if ( $tooltip_options ) {
+ this.createTooltip($input, $tooltip_options);
+ }
+ }
+
+ if ( $discount_error_code ) {
+ $input = $('#sub-total');
+
+ $tooltip_options = this.getDiscountErrorOptions($discount_error_code);
+
+ if ( $tooltip_options ) {
+ this.createTooltip($input, $tooltip_options);
+ }
+ }
+
+ for (var $error_type in $data.errors) {
+ $tooltip_options = '';
+ $error_info = $error_type.split(':');
+ $error_code = parseInt( $data.errors[$error_type] );
+
+ if ( $error_info[0] == this.constants['OrderCheckoutErrorType::PRODUCT'] ) {
+ this.processProductError($error_info, $error_code, $data);
+ }
+
+ if ( this.debugMode ) {
+ console.log('error_type: ', $error_type, '; error_code: ', $error_code, '; row_index: ', $row_index, '; field: ', $field);
+ }
+ }
+}
+
+ShopCartManager.prototype.showFooter = function ($data) {
+ var $discount_total = $data.order['DiscountTotal'];
+
+ // update "Total Savings"
+ $('#discount-row').toggle( $discount_total > 0 );
+ $('.price1', '#discount-row').html( this.formatPrice($discount_total) );
+
+ // update Coupon Info
+ if ( $data.order['CouponId'] == 0 ) {
+ $('.coupon-code', '#coupon-row').val('');
+ }
+
+ $('.used', '#coupon-row').toggle( $data.order['CouponId'] > 0 );
+ $('.not-used', '#coupon-row').toggle( $data.order['CouponId'] == 0 );
+ $('.coupon-name', '#coupon-row').html( $data.order['CouponName'] );
+
+ // update Gift Certificate Info
+ if ( $data.order['GiftCertificateId'] == 0 ) {
+ $('.gift-certificate-code', '#gift-certificate-row').val('');
+ }
+
+ $('.used', '#gift-certificate-row').toggle( $data.order['GiftCertificateId'] > 0 );
+ $('.not-used', '#gift-certificate-row').toggle( $data.order['GiftCertificateId'] == 0 );
+ $('.gift-certificate-discount', '#gift-certificate-row').html( this.formatPrice($data.order['GiftCertificateDiscount']) );
+
+ // update "subtotal"
+ $('#sub-total').html( this.formatPrice($data.order['SubTotal']) );
+}
+
+ShopCartManager.prototype.processProductError = function ($error_info, $error_code, $data) {
+ var $error_type = $error_info.shift(),
+ $field = $error_info.pop(),
+ $row_index = $error_info.join(':');
+
+ if ( this.getRowByIndex($row_index).length == 0 ) {
+ // row was deleted
+ return ;
+ }
+
+ if ( $field == 'Quantity' ) {
+ var $input = $('.product-qty:input', this.getRowByIndex($row_index)),
+ $allow_qty_replace = [
+ this.constants['OrderCheckoutError::FIELD_UPDATE_SUCCESS'],
+ this.constants['OrderCheckoutError::QTY_CHANGED_TO_MINIMAL']
+ ];
+
+ if ( in_array($error_code, $allow_qty_replace) && $input.val() != $data.items[$row_index]['fields']['Quantity'] ) {
+ // qty changed during ord:OnRecalculateItems
+ $input.val( $data.items[$row_index]['fields']['Quantity'] );
+ }
+
+ $tooltip_options = this.getQtyErrorOptions($error_code);
+
+ if ( $tooltip_options ) {
+ this.createTooltip($input, $tooltip_options);
+ }
+ }
+}
+
+ShopCartManager.prototype.getErrorByType = function ($contant_name, $data) {
+ var $error_type = this.constants[$contant_name];
+
+ return $data.errors[$error_type] !== undefined ? $data.errors[$error_type] : false;
+}
+
+ShopCartManager.prototype.getRowByIndex = function ($row_index) {
+ return $("tr.shop-cart-row[row_index='" + $row_index + "']", '#shop-cart-table');
+}
+
+ShopCartManager.prototype.getOldRows = function () {
+ var $ret = [];
+
+ $('tr.shop-cart-row', '#shop-cart-table').each(
+ function () {
+ $ret.push( $(this).attr('row_index') );
+ }
+ );
+
+ return $ret;
+}
+
+ShopCartManager.prototype.getNewRows = function ($data) {
+ var $ret = [];
+
+ if ( $.isArray($data.items) ) {
+ return $data.items;
+ }
+
+ for (var $row_index in $data.items) {
+ $ret.push( $row_index );
+ }
+
+ return $ret;
+}
+
+ShopCartManager.prototype.formatPrice = function ($price) {
+ // TODO: format currency
+
+ var $price_parts = $price.toFixed(2).toString().split('.');
+
+ return this.currencyMask.replace('%s', $price_parts[0] + '.
' + $price_parts[1] + '');
+}
+
+ShopCartManager.prototype.getQtyErrorOptions = function ($error_code) {
+ var $ret = false;
+
+ switch ($error_code) {
+ case this.constants['OrderCheckoutError::FIELD_UPDATE_SUCCESS']:
+ $ret = this.getTooltipOptions('FIELD_UPDATE_SUCCESS', 'ui-tooltip-green');
+ break;
+
+ case this.constants['OrderCheckoutError::FIELD_UPDATE_ERROR']:
+ $ret = this.getTooltipOptions('FIELD_UPDATE_ERROR', 'ui-tooltip-red');
+ break;
+
+ case this.constants['OrderCheckoutError::QTY_UNAVAILABLE']:
+ $ret = this.getTooltipOptions('QTY_UNAVAILABLE', 'ui-tooltip-red');
+ break;
+
+ case this.constants['OrderCheckoutError::QTY_OUT_OF_STOCK']:
+ $ret = this.getTooltipOptions('QTY_OUT_OF_STOCK', 'ui-tooltip-red');
+ break;
+
+ case this.constants['OrderCheckoutError::QTY_CHANGED_TO_MINIMAL']:
+ $ret = this.getTooltipOptions('QTY_CHANGED_TO_MINIMAL', 'ui-tooltip-green');
+ break;
+ }
+
+ return $ret;
+}
+
+ShopCartManager.prototype.getCouponErrorOptions = function ($error_code) {
+ var $ret = false;
+
+ switch ($error_code) {
+ case this.constants['OrderCheckoutError::COUPON_APPLIED']: // for label
+ $ret = this.getTooltipOptions('COUPON_APPLIED', 'ui-tooltip-green');
+ break;
+
+ // all next error for input
+ case this.constants['OrderCheckoutError::COUPON_REMOVED']:
+ $ret = this.getTooltipOptions('COUPON_REMOVED', 'ui-tooltip-green');
+ break;
+
+ case this.constants['OrderCheckoutError::COUPON_REMOVED_AUTOMATICALLY']:
+ $ret = this.getTooltipOptions('COUPON_REMOVED_AUTOMATICALLY', 'ui-tooltip-green');
+ break;
+
+ case this.constants['OrderCheckoutError::COUPON_CODE_INVALID']:
+ $ret = this.getTooltipOptions('COUPON_CODE_INVALID', 'ui-tooltip-red');
+ break;
+
+ case this.constants['OrderCheckoutError::COUPON_CODE_EXPIRED']:
+ $ret = this.getTooltipOptions('COUPON_CODE_EXPIRED', 'ui-tooltip-red');
+ break;
+ }
+
+ return $ret;
+}
+
+ShopCartManager.prototype.getGiftCertificateErrorOptions = function ($error_code) {
+ var $ret = false;
+
+ switch ($error_code) {
+ case this.constants['OrderCheckoutError::GC_APPLIED']: // for label
+ $ret = this.getTooltipOptions('GC_APPLIED', 'ui-tooltip-green');
+ break;
+
+ // all next error for input
+ case this.constants['OrderCheckoutError::GC_REMOVED']:
+ $ret = this.getTooltipOptions('GC_REMOVED', 'ui-tooltip-green');
+ break;
+
+ case this.constants['OrderCheckoutError::GC_REMOVED_AUTOMATICALLY']:
+ $ret = this.getTooltipOptions('GC_REMOVED_AUTOMATICALLY', 'ui-tooltip-green');
+ break;
+
+ case this.constants['OrderCheckoutError::GC_CODE_INVALID']:
+ $ret = this.getTooltipOptions('GC_CODE_INVALID', 'ui-tooltip-red');
+ break;
+
+ case this.constants['OrderCheckoutError::GC_CODE_EXPIRED']:
+ $ret = this.getTooltipOptions('GC_CODE_EXPIRED', 'ui-tooltip-red');
+ break;
+ }
+
+ return $ret;
+}
+
+ShopCartManager.prototype.getDiscountErrorOptions = function ($error_code) {
+ var $ret = false;
+
+ switch ($error_code) {
+ case this.constants['OrderCheckoutError::DISCOUNT_APPLIED']:
+ $ret = this.getTooltipOptions('DISCOUNT_APPLIED', 'ui-tooltip-green');
+ break;
+
+ case this.constants['OrderCheckoutError::DISCOUNT_REMOVED']:
+ $ret = this.getTooltipOptions('DISCOUNT_REMOVED', 'ui-tooltip-green');
+ break;
+ }
+
+ return $ret;
+}
+
+ShopCartManager.prototype.createTooltip = function ($input, $tooltip_options) {
+ var $me = this,
+ $tooltip = $input.next('.formStatus'),
+ $is_error = $tooltip_options.classes == 'ui-tooltip-red',
+ $timer = $input.data('timer');
+
+ clearTimeout($timer);
+
+ if ( $tooltip.length == 1 ) {
+ $tooltip.hide().remove();
+ }
+
+ $tooltip = $('
');
+
+ $input
+ .after($tooltip)
+ .removeClass('statusSuccess statusError')
+ .addClass($is_error ? 'statusError' : 'statusSuccess');
+
+ $tooltip.fadeIn(
+ 'slow',
+ function () {
+ $timer = setTimeout( function() { $me.removeTooltip($input); }, 2000);
+ $input.data('timer', $timer);
+ }
+ );
+
+ $input.focus( function() { $me.removeTooltip($input); } );
+}
+
+ShopCartManager.prototype.removeTooltip = function ($input) {
+ var $tooltip = $input.next('.formStatus');
+ $input.removeClass('statusError').removeClass('statusSuccess');
+ $tooltip.fadeOut('slow', function() { $tooltip.remove(); });
+}
+
+ShopCartManager.prototype.getTooltipOptions = function ($text, $css_classes) {
+ return {
+ text: $text,
+ classes: $css_classes
+ };
+}