Rhapsody Posted September 25, 2012 Share Posted September 25, 2012 (edited) Working on 1.4.9.0! (without Ajax Cart) It is working for 1.4.9.0 without the Ajax cart. I have created two product.tpl files that work. One is for the old stock Prestashop theme. The other is for the new Prestashop 1.5 compatible theme available for download at this link: http://addons.presta...emplate-15.html The product.tpl files move the text boxes up from the bottom and eliminate the "Save" button when used with the CartController override. The override/controller/CartController.php file I used was the one that Ben23 created in post #95 above. Rename the files attached in the zip file to product.tpl and use the one applicable for the stock theme you use. They are named for the "old" and "new" Prestashop themes. Remember to open the blockcart module in the BO and use configure to turn off the ajax cart. All that is needed now is for someone to help debug the ajax-cart.js file so the Ajax cart can be enabled again. For Ajax debug, the old theme uses the blockcart module. If you install the new Prestashop theme there is a module called blockcart2. product.tpl.zip Edited September 25, 2012 by Rhapsody (see edit history) Link to comment Share on other sites More sharing options...
rjgout Posted October 8, 2012 Share Posted October 8, 2012 It this option also available for prestashop 1.5? Link to comment Share on other sites More sharing options...
adameriksson Posted October 12, 2012 Share Posted October 12, 2012 Working on 1.4.9.0! (without Ajax Cart) It is working for 1.4.9.0 without the Ajax cart. I have created two product.tpl files that work. One is for the old stock Prestashop theme. The other is for the new Prestashop 1.5 compatible theme available for download at this link: http://addons.presta...emplate-15.html The product.tpl files move the text boxes up from the bottom and eliminate the "Save" button when used with the CartController override. The override/controller/CartController.php file I used was the one that Ben23 created in post #95 above. Rename the files attached in the zip file to product.tpl and use the one applicable for the stock theme you use. They are named for the "old" and "new" Prestashop themes. Remember to open the blockcart module in the BO and use configure to turn off the ajax cart. All that is needed now is for someone to help debug the ajax-cart.js file so the Ajax cart can be enabled again. For Ajax debug, the old theme uses the blockcart module. If you install the new Prestashop theme there is a module called blockcart2. I copied your code from "<!-- Customizable products --> {if $product->customizable}" to "</form> {* Rhapsody moved custo..." I also use Ben23's cartcontroller. But my store keeps saying that I need to save the customization. It doesnt add to cart... why? Link to comment Share on other sites More sharing options...
Rhapsody Posted October 12, 2012 Share Posted October 12, 2012 I copied your code from "<!-- Customizable products --> {if $product->customizable}" to "</form> {* Rhapsody moved custo..." I also use Ben23's cartcontroller. But my store keeps saying that I need to save the customization. It doesnt add to cart... why? 1. What version of ps are you using? 2. What Theme are you using? 3. What directory did you copy Ben23's CartController.php file to? 4. Did you turn off the Ajax cart in the blockcart module? 5. Did you set in the BO performance section Force Compile to Yes and Cache to No in order to recompile your modified template? Link to comment Share on other sites More sharing options...
adameriksson Posted October 12, 2012 Share Posted October 12, 2012 (edited) 1. What version of ps are you using? 2. What Theme are you using? 3. What directory did you copy Ben23's CartController.php file to? 4. Did you turn off the Ajax cart in the blockcart module? 5. Did you set in the BO performance section Force Compile to Yes and Cache to No in order to recompile your modified template? 1. 1.4.9 2. A Theme from template monster. 3. /override/controllers 4. Yes I did 5. Yes, I see the update. And the save button is gone, but it dont work.. The weird thing is that the popup that says "please fill in required fields and save customization" is gone. I'm now being transfered to cart.php, and there I get a warning saying I must fill the mandatory fields and press save beforde adding to cart. I then press back and fill in the two textfields, press save, then i can add to cart. --EDIT-- Now I dont have the textfields mandatory. But I still need to press save to add the texts to the product. Do I need to modify ajax-cart.js ? as mentioned in this thread before Edited October 12, 2012 by adameriksson (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted October 12, 2012 Share Posted October 12, 2012 (edited) ..... The weird thing is that the popup that says "please fill in required fields and save customization" is gone. I'm now being transfered to cart.php, and there I get a warning saying I must fill the mandatory fields and press save before adding to cart. I then press back and fill in the two textfields, press save, then i can add to cart. The problem may be the theme from Template Monster. Is it based on the old or new PS theme? Try the stock PS theme with the mod and see if it works. If so, the problem is with your theme. If not, more troubleshooting to do. I think it is related to your theme, because when you press back you mention seeing the save button. I believe the save button should be gone completely with the modified tpl file Edit: Post your modified product.tpl file and I will try it on one of my installations. Edited October 12, 2012 by Rhapsody (see edit history) Link to comment Share on other sites More sharing options...
adameriksson Posted October 12, 2012 Share Posted October 12, 2012 (edited) The problem may be the theme from Template Monster. Is it based on the old or new PS theme? Try the stock PS theme with the mod and see if it works. If so, the problem is with your theme. If not, more troubleshooting to do. I think it is related to your theme, because when you press back you mention seeing the save button. I believe the save button should be gone completely with the modified tpl file Edit: Post your modified product.tpl file and I will try it on one of my installations. Sorry, of course I dont see the save button. It was with my own code, sorry. I have your product.tpl code now (only the "Customizable products" part). I paste the whole product.tpl code here {include file="$tpl_dir./errors.tpl"} {if $errors|@count == 0} <script type="text/javascript"> // <![CDATA[ // PrestaShop internal settings var currencySign = '{$currencySign|html_entity_decode:2:"UTF-8"}'; var currencyRate = '{$currencyRate|floatval}'; var currencyFormat = '{$currencyFormat|intval}'; var currencyBlank = '{$currencyBlank|intval}'; var taxRate = {$tax_rate|floatval}; var jqZoomEnabled = {if $jqZoomEnabled}true{else}false{/if}; //JS Hook var oosHookJsCodeFunctions = new Array(); // Parameters var id_product = '{$product->id|intval}'; var productHasAttributes = {if isset($groups)}true{else}false{/if}; var quantitiesDisplayAllowed = {if $display_qties == 1}true{else}false{/if}; var quantityAvailable = {if $display_qties == 1 && $product->quantity}{$product->quantity}{else}0{/if}; var allowBuyWhenOutOfStock = {if $allow_oosp == 1}true{else}false{/if}; var availableNowValue = '{$product->available_now|escape:'quotes':'UTF-8'}'; var availableLaterValue = '{$product->available_later|escape:'quotes':'UTF-8'}'; var productPriceTaxExcluded = {$product->getPriceWithoutReduct(true)|default:'null'} - {$product->ecotax}; var reduction_percent = {if $product->specificPrice AND $product->specificPrice.reduction AND $product->specificPrice.reduction_type == 'percentage'}{$product->specificPrice.reduction*100}{else}0{/if}; var reduction_price = {if $product->specificPrice AND $product->specificPrice.reduction AND $product->specificPrice.reduction_type == 'amount'}{$product->specificPrice.reduction}{else}0{/if}; var specific_price = {if $product->specificPrice AND $product->specificPrice.price}{$product->specificPrice.price}{else}0{/if}; var specific_currency = {if $product->specificPrice AND $product->specificPrice.id_currency}true{else}false{/if}; var group_reduction = '{$group_reduction}'; var default_eco_tax = {$product->ecotax}; var ecotaxTax_rate = {$ecotaxTax_rate}; var currentDate = '{$smarty.now|date_format:'%Y-%m-%d %H:%M:%S'}'; var maxQuantityToAllowDisplayOfLastQuantityMessage = {$last_qties}; var noTaxForThisProduct = {if $no_tax == 1}true{else}false{/if}; var displayPrice = {$priceDisplay}; var productReference = '{$product->reference|escape:'htmlall':'UTF-8'}'; var productAvailableForOrder = {if (isset($restricted_country_mode) AND $restricted_country_mode) OR $PS_CATALOG_MODE}'0'{else}'{$product->available_for_order}'{/if}; var productShowPrice = '{if !$PS_CATALOG_MODE}{$product->show_price}{else}0{/if}'; var productUnitPriceRatio = '{$product->unit_price_ratio}'; var idDefaultImage = {if isset($cover.id_image_only)}{$cover.id_image_only}{else}0{/if}; {* var ipa_default = {if isset($ipa_default)}{$ipa_default}{/if}; *} // Customizable field var img_ps_dir = '{$img_ps_dir}'; var customizationFields = new Array(); {assign var='imgIndex' value=0} {assign var='textFieldIndex' value=0} {foreach from=$customizationFields item='field' name='customizationFields'} {assign var="key" value="pictures_`$product->id`_`$field.id_customization_field`"} customizationFields[{$smarty.foreach.customizationFields.index|intval}] = new Array(); customizationFields[{$smarty.foreach.customizationFields.index|intval}][0] = '{if $field.type|intval == 0}img{$imgIndex++}{else}textField{$textFieldIndex++}{/if}'; customizationFields[{$smarty.foreach.customizationFields.index|intval}][1] = {if $field.type|intval == 0 && isset($pictures.$key) && $pictures.$key}2{else}{$field.required|intval}{/if}; {/foreach} // Images var img_prod_dir = '{$img_prod_dir}'; var combinationImages = new Array(); {if isset($combinationImages)} {foreach from=$combinationImages item='combination' key='combinationId' name='f_combinationImages'} combinationImages[{$combinationId}] = new Array(); {foreach from=$combination item='image' name='f_combinationImage'} combinationImages[{$combinationId}][{$smarty.foreach.f_combinationImage.index}] = {$image.id_image|intval}; {/foreach} {/foreach} {/if} combinationImages[0] = new Array(); {if isset($images)} {foreach from=$images item='image' name='f_defaultImages'} combinationImages[0][{$smarty.foreach.f_defaultImages.index}] = {$image.id_image}; {/foreach} {/if} // Translations var doesntExist = '{l s='The product does not exist in this model. Please choose another.' js=1}'; var doesntExistNoMore = '{l s='This product is no longer in stock' js=1}'; var doesntExistNoMoreBut = '{l s='with those attributes but is available with others' js=1}'; var uploading_in_progress = '{l s='Uploading in progress, please wait...' js=1}'; var fieldRequired = '{l s='Please fill in all required fields, then save the customization.' js=1}'; {if isset($groups)} // Combinations {foreach from=$combinations key=idCombination item=combination} addCombination({$idCombination|intval}, new Array({$combination.list}), {$combination.quantity}, {$combination.price}, {$combination.ecotax}, {$combination.id_image}, '{$combination.reference|addslashes}', {$combination.unit_impact}, {$combination.minimal_quantity}); {/foreach} // Colors {if $colors|@count > 0} {if $product->id_color_default}var id_color_default = {$product->id_color_default|intval};{/if} {/if} {/if} //]]> </script> {include file="$tpl_dir./breadcrumb.tpl"} {if isset($confirmation) && $confirmation} <p class="confirmation"> {$confirmation} </p> {/if} <div id="primary_block" class="clearfix"> {if isset($adminActionDisplay) && $adminActionDisplay} <div id="admin-action"> <p>{l s='This product is not visible to your customers.'} <input type="hidden" id="admin-action-product-id" value="{$product->id}" /> <input type="submit" value="{l s='Publish'}" class="exclusive" onclick="submitPublishProduct('{$base_dir}{$smarty.get.ad}', 0)"/> <input type="submit" value="{l s='Back'}" class="exclusive" onclick="submitPublishProduct('{$base_dir}{$smarty.get.ad}', 1)"/> </p> <div class="clear" ></div> <p id="admin-action-result"></p> </p> </div> {/if} {* left column *} <div id="pb-right-column"> {* product img *} <div id="image-block" class="bordercolor"> {if $have_image} <img src="{$link->getImageLink($product->link_rewrite, $cover.id_image, 'large')}" {if $jqZoomEnabled}class="jqzoom" alt="{$link->getImageLink($product->link_rewrite, $cover.id_image, 'thickbox')}"{else} title="{$product->name|escape:'htmlall':'UTF-8'}" alt="{$product->name|escape:'htmlall':'UTF-8'}" {/if} id="bigpic" width="{$largeSize.width}" height="{$largeSize.height}" /> {else} <img src="{$img_prod_dir}{$lang_iso}-default-large.jpg" id="bigpic" alt="" title="{$cover.legend|escape:'htmlall':'UTF-8'}" width="{$largeSize.width}" height="{$largeSize.height}" /> {/if} </div> {if isset($images) && count($images) > 0} {* thumbnails *} <div id="views_block" {if isset($images) && count($images) < 2}class="hidden"{/if}> {if isset($images) && count($images) > 3}<a id="view_scroll_left" class="hidden" title="{l s='Other views'}" href="javascript:{ldelim}{rdelim}">{l s='Previous'}</a>{/if} <div id="thumbs_list"> <ul id="thumbs_list_frame"> {if isset($images)} {foreach from=$images item=image name=thumbnails} {assign var=imageIds value="`$product->id`-`$image.id_image`"} <li id="thumbnail_{$image.id_image}" class="{if $smarty.foreach.thumbnails.last}thumb_last{/if}"> <a href="{$link->getImageLink($product->link_rewrite, $imageIds, 'thickbox')}" rel="other-views" class="thickbox bordercolor {if (isset($image.cover) AND $image.cover == 1) OR (!isset($image.cover) AND $smarty.foreach.thumbnails.first)}shown{/if}" title="{$image.legend|htmlspecialchars}"> <img id="thumb_{$image.id_image}" src="{$link->getImageLink($product->link_rewrite, $imageIds, 'medium')}" alt="{$image.legend|htmlspecialchars}" height="{$mediumSize.height}" width="{$mediumSize.width}" /> </a> </li> {/foreach} {/if} </ul> </div> {if isset($images) && count($images) > 3}<a id="view_scroll_right" title="{l s='Other views'}" href="javascript:{ldelim}{rdelim}">{l s='Next'}</a>{/if} </div> {/if} {if isset($images) && count($images) > 1}<span id="wrapResetImages" style="display:none;"><div><a id="resetImages" href="{$link->getProductLink($product)}" onclick="$('span#wrapResetImages').hide('slow');return (false);">{l s='Display all pictures'}</a></div></span>{/if} {* usefull links *} <ul id="usefull_link_block" class="bordercolor"> {if $HOOK_EXTRA_LEFT}{$HOOK_EXTRA_LEFT}{/if} <li class="print"><a href="javascript:print();">{l s='Print'}</a></li> {if $have_image && !$jqZoomEnabled} <li class="view-size"><span id="view_full_size" class="span_link">{l s='View full size'}</span></li> {/if} </ul> {* social icons *} <div class="share bordercolor"><!-- AddThis Button BEGIN --> <div class="addthis_toolbox addthis_default_style "> <a class="addthis_button_facebook_like" fb:like:layout="button_count"></a> <a class="addthis_button_tweet"></a> <a class="addthis_button_google_plusone" g:plusone:size="medium"></a> <a class="addthis_counter addthis_pill_style"></a> </div> <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4f419f410efe76d3"></script> </div> </div> {* right column *} <div id="pb-left-column"> <h1>{$product->name|escape:'htmlall':'UTF-8'}</h1> {if ($product->show_price AND !isset($restricted_country_mode)) OR isset($groups) OR $product->reference OR (isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS)} <form id="buy_block" class="bordercolor" {if $PS_CATALOG_MODE AND !isset($groups) AND $product->quantity > 0}class="hidden"{/if} action="{$link->getPageLink('cart.php')}" method="post"> {* hidden datas *} <p class="hidden"> <input type="hidden" name="token" value="{$static_token}" /> <input type="hidden" name="id_product" value="{$product->id|intval}" id="product_page_product_id" /> <input type="hidden" name="add" value="1" /> <input type="hidden" name="id_product_attribute" id="idCombination" value="" /> </p> {if $product->show_price AND !isset($restricted_country_mode) AND !$PS_CATALOG_MODE} <div class="price bordercolor"> {if !$priceDisplay || $priceDisplay == 2}{assign var='productPrice' value=$product->getPrice(true, $smarty.const.NULL, 2)}{assign var='productPriceWithoutRedution' value=$product->getPriceWithoutReduct(false, $smarty.const.NULL)}{elseif $priceDisplay == 1}{assign var='productPrice' value=$product->getPrice(false, $smarty.const.NULL, 2)}{assign var='productPriceWithoutRedution' value=$product->getPriceWithoutReduct(true, $smarty.const.NULL)}{/if} {* price *} <span class="our_price_display"> {if $priceDisplay >= 0 && $priceDisplay <= 2} <span id="our_price_display" class="price">{convertPrice price=$productPrice}</span> {if $tax_enabled && ((isset($display_tax_label) && $display_tax_label == 1) OR !isset($display_tax_label))} <span class="our_price_display_tax">{if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if}</span> {/if} {/if} </span> {* tax excl *} {if $priceDisplay == 2} <span id="pretaxe_price"><span id="pretaxe_price_display">{convertPrice price=$product->getPrice(false, $smarty.const.NULL, 2)}</span> {l s='tax excl.'}</span> {/if} {* add to cart btn *} <p id="add_to_cart" {if (!$allow_oosp && $product->quantity <= 0) OR !$product->available_for_order OR (isset($restricted_country_mode) AND $restricted_country_mode) OR $PS_CATALOG_MODE} style="display:none;"{/if}> <a class="exclusive" href="javascript:document.getElementById('add2cartbtn').click();">{l s='Add to cart'}</a> <input id="add2cartbtn" type="submit" name="Submit" value="{l s='Add to cart'}" /> </p> {* quantity wanted *} <p id="quantity_wanted_p"{if (!$allow_oosp && $product->quantity == 0) OR $virtual OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> <input type="text" name="qty" id="quantity_wanted" class="text" value="{if isset($quantityBackup)}{$quantityBackup|intval}{else}{if $product->minimal_quantity > 1}{$product->minimal_quantity}{else}1{/if}{/if}" size="2" maxlength="3" {if $product->minimal_quantity > 1}onkeyup="checkMinimalQuantity({$product->minimal_quantity});"{/if} /> <label>{l s='Quantity :'}</label> </p> </div> {* minimal quantity wanted *} <p id="minimal_quantity_wanted_p" class="bordercolor"{if $product->minimal_quantity <= 1 OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display:none;"{/if}>{l s='You must add '}<b id="minimal_quantity_label">{$product->minimal_quantity}</b>{l s=' as a minimum quantity to buy this product.'}</p> {if $product->minimal_quantity > 1}<script type="text/javascript">checkMinimalQuantity();</script>{/if} {/if} <div class="other_options bordercolor"> {if $product->show_price AND !isset($restricted_country_mode) AND !$PS_CATALOG_MODE} <div id="other_prices"> {if $product->specificPrice AND $product->specificPrice.reduction} {* old price *} <p id="old_price"> {if $priceDisplay >= 0 && $priceDisplay <= 2} {if $productPriceWithoutRedution > $productPrice} <span id="old_price_display">{convertPrice price=$productPriceWithoutRedution}</span> {if $tax_enabled}{if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if}{/if} {/if} {/if} </p> {/if} {* reduction percent *} {if $product->specificPrice AND $product->specificPrice.reduction_type == 'percentage'} <p id="reduction_percent">{l s='(price reduced by'} <span id="reduction_percent_display">{$product->specificPrice.reduction*100}</span> %{l s=')'}</p> {/if} {* pack price *} {if $packItems|@count} <p class="pack_price">{l s='instead of'} <span style="text-decoration: line-through;">{convertPrice price=$product->getNoPackPrice()}</span></p> {/if} {* price ecotax *} {if $product->ecotax != 0} <p class="price-ecotax">{l s='include'} <span id="ecotax_price_display">{if $priceDisplay == 2}{$ecotax_tax_exc|convertAndFormatPrice}{else}{$ecotax_tax_inc|convertAndFormatPrice}{/if}</span> {l s='for green tax'} {if $product->specificPrice AND $product->specificPrice.reduction}<br />{l s='(not impacted by the discount)'}{/if} </p> {/if} {* unit price *} {if !empty($product->unity) && $product->unit_price_ratio > 0.000000} {math equation="pprice / punit_price" pprice=$productPrice punit_price=$product->unit_price_ratio assign=unit_price} <p class="unit-price"><span id="unit_price_display" class="price">{convertPrice price=$unit_price}</span> {l s='per'} {$product->unity|escape:'htmlall':'UTF-8'}</p> {/if} {* online only *} {if $product->online_only}<p class="online_only">{l s='Online only'}!</p>{/if} {* number of item in stock *} {if ($display_qties == 1 && !$PS_CATALOG_MODE && $product->available_for_order)} <p id="pQuantityAvailable" {if $product->quantity <= 0} style="display:none;"{/if} > <span id="quantityAvailable">{$product->quantity|intval}</span> <span {if $product->quantity > 1} style="display:none;"{/if} id="quantityAvailableTxt">{l s='item in stock'}</span> <span {if $product->quantity == 1} style="display:none;"{/if} id="quantityAvailableTxtMultiple">{l s='items in stock'}</span> </p> {/if} {* last quantities *} <p id="last_quantities"{if ($product->quantity > $last_qties OR $product->quantity <= 0) OR $allow_oosp OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display:none;"{/if} >{l s='Warning: Last items in stock!'}</p> {* product reference *} <p id="product_reference" {if isset($groups) OR !$product->reference}style="display:none;"{/if}><label for="product_reference">{l s='Reference :'} </label><span class="editable">{$product->reference|escape:'htmlall':'UTF-8'}</span></p> {* availability *} <p id="availability_statut"{if ($product->quantity <= 0 && !$product->available_later && $allow_oosp) OR ($product->quantity > 0 && !$product->available_now) OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display:none;"{/if}> <span id="availability_label">{l s='Availability:'}</span> <span id="availability_value"{if $product->quantity <= 0} class="warning_inline"{/if}> {if $product->quantity <= 0}{if $allow_oosp}{$product->available_later}{else}{l s='This product is no longer in stock'}{/if}{else}{$product->available_now}{/if} </span> </p> </div> {*close if for show price*} {/if} <div id="attributes"> {* ON SALE *} {if $product->on_sale}<span class="on_sale">{l s='On sale!'}</span>{elseif $product->specificPrice AND $product->specificPrice.reduction AND $productPriceWithoutRedution > $productPrice}<span class="discount">{l s='Reduced price!'}</span>{/if} <div class="clearblock"></div> {* attributes *} {if isset($groups)} {foreach from=$groups key=id_attribute_group item=group} {if $group.attributes|@count} <p> {assign var="groupName" value="group_$id_attribute_group"} <select name="{$groupName}" id="group_{$id_attribute_group|intval}" onchange="javascript:findCombination();{if $colors|@count > 0}$('#wrapResetImages').show('slow');{/if};"> {foreach from=$group.attributes key=id_attribute item=group_attribute} <option value="{$id_attribute|intval}"{if (isset($smarty.get.$groupName) && $smarty.get.$groupName|intval == $id_attribute) || $group.default == $id_attribute} selected="selected"{/if} title="{$group_attribute|escape:'htmlall':'UTF-8'}">{$group_attribute|escape:'htmlall':'UTF-8'}</option> {/foreach} </select> <label for="group_{$id_attribute_group|intval}">{$group.name|escape:'htmlall':'UTF-8'}:</label> </p> {/if} {/foreach} {/if} </div> <div class="clearblock"></div> </div> {* short descriptions *} {if $product->description_short} <div id="short_description_block" class="bordercolor" style="display:none;"> {if $product->description_short} <div id="short_description_content" class="rte align_justify">{$product->description_short}</div> {/if} {if $product->description} <p class="buttons_bottom_block"><a href="javascript:{ldelim}{rdelim}" class="button">{l s='More details'}</a></p> {/if} </div> {/if} {* pack content *} {if $packItems|@count > 0} <div class="pack_content bordercolor bgcolor"> <h3>{l s='Pack content'}</h3> <ul> {foreach from=$packItems item=packItem} <li> {$packItem.pack_quantity} x <a href="{$link->getProductLink($packItem.id_product, $packItem.link_rewrite, $packItem.category)}">{$packItem.name|escape:'htmlall':'UTF-8'}</a> <p>{$packItem.description_short|truncate:100:'...'}</p> </li> {/foreach} </ul> </div> {/if} {* Out of stock hook *} {if !$allow_oosp} <p id="oosHook"{if $product->quantity > 0} style="display: none;"{/if}>{$HOOK_PRODUCT_OOS}</p> {/if} {* colors *} {if isset($colors) && $colors} <div id="color_picker" class="bgcolor bordercolor"> <h3>{l s='Pick a color:' js=1}</h3> <ul id="color_to_pick_list"> {foreach from=$colors key='id_attribute' item='color'} <li><a id="color_{$id_attribute|intval}" class="color_pick" style="background:{$color.value};" onclick="updateColorSelect({$id_attribute|intval});$('#wrapResetImages').show('slow');" title="{$color.name}">{if file_exists($col_img_dir|cat:$id_attribute|cat:'.jpg')}<img src="{$img_col_dir}{$id_attribute}.jpg" alt="{$color.name}" width="20" height="20" />{/if}</a></li> {/foreach} </ul> </div> {/if} {if isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS}{$HOOK_PRODUCT_ACTIONS}{/if} <div class="clearblock"></div> </form> {/if} <!-- Rhapsody moved customizable fields in this section --> <!-- Customizable products --> {if $product->customizable} <ul class="idTabs"> <li><a style="cursor: pointer">{l s='Product customization'}</a></li> </ul> <div class="customization_block"> {* Rhapsody comment out this section <form method="post" action="{$customizationFormTarget}" enctype="multipart/form-data" id="customizationForm"> <p> <img src="{$img_dir}icon/infos.gif" alt="Informations" /> {l s='After saving your customized product, remember to add it to your cart.'} {if $product->uploadable_files}<br />{l s='Allowed file formats are: GIF, JPG, PNG'}{/if} </p> Rhapsody Commented out *} {if $product->uploadable_files|intval} <h2>{l s='Pictures'}</h2> <ul id="uploadable_files"> {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 0} <li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='pictures_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if isset($pictures.$key)}<div class="customizationUploadBrowse"> <img src="{$pic_dir}{$pictures.$key}_small" alt="" /> <a href="{$link->getProductDeletePictureLink($product, $field.id_customization_field)}" title="{l s='Delete'}" > <img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" class="customization_delete_icon" width="11" height="13" /> </a> </div>{/if} <div class="customizationUploadBrowse"><input type="file" name="file{$field.id_customization_field}" id="img{$customizationField}" class="customization_block_input {if isset($pictures.$key)}filled{/if}" />{if $field.required}<sup>*</sup>{/if} <div class="customizationUploadBrowseDescription">{if !empty($field.name)}{$field.name}{else}{l s='Please select an image file from your hard drive'}{/if}</div></div> </li> {counter} {/if} {/foreach} </ul> {/if} <div class="clear"></div> {if $product->text_fields|intval} <h2>{l s='Texts'}</h2> <ul id="text_fields"> {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}<textarea type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input" />{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> </li> {counter} {/if} {/foreach} </ul> {/if} <p style="clear: left;" id="customizedDatas"> <input type="hidden" name="ipa_customization" id="ipa_customization" value="{$ipa_customization}" /> <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> <p class="clear required"><sup>*</sup> {l s='required fields'}</p> {* Rhapsody hid save button in next line <input type="button" class="button" value="{l s='Save'}" onclick="javascript:saveCustomization()" /> * * * * end of comment *} <span id="ajax-loader" style="display:none"><img src="{$img_ps_dir}loader.gif" alt="loader" /></span> </p> </form> </div> {/if} {* Rhapsody moved customization block above *} </form> {* Rhapsody moved customization block above - need to capture the /form also *} {if $HOOK_EXTRA_RIGHT}{$HOOK_EXTRA_RIGHT}{/if} </div> </div> {* quantity discount *} {if $quantity_discounts} <div id="quantityDiscount" class="bgcolor bordercolor"> <h3>{l s='Quantity discount'}</h3> <table> <tr> {foreach from=$quantity_discounts item='quantity_discount' name='quantity_discounts'} <th class="bordercolor">{$quantity_discount.quantity|intval} {if $quantity_discount.quantity|intval > 1} {l s='quantities'} {else} {l s='quantity'} {/if} </th> {/foreach} </tr> <tr> {foreach from=$quantity_discounts item='quantity_discount' name='quantity_discounts'} <td> {if $quantity_discount.price != 0 OR $quantity_discount.reduction_type == 'amount'} -{convertPrice price=$quantity_discount.real_value|floatval} {else} -{$quantity_discount.real_value|floatval}% {/if} </td> {/foreach} </tr> </table> </div> {/if} {* description and features *} {if $product->description || $features || $accessories || $HOOK_PRODUCT_TAB || $attachments} <div id="more_info_block" class="clear"> <ul id="more_info_tabs" class="idTabs idTabsShort"> {if $product->description}<li><a id="more_info_tab_more_info" href="#idTab1">{l s='More info'}</a></li>{/if} {if $features}<li><a id="more_info_tab_data_sheet" href="#idTab2">{l s='Data sheet'}</a></li>{/if} {if $attachments}<li><a id="more_info_tab_attachments" href="#idTab9">{l s='Download'}</a></li>{/if} {if isset($accessories) AND $accessories}<li><a href="#idTab4">{l s='Accessories'}</a></li>{/if} {$HOOK_PRODUCT_TAB} </ul> <div id="more_info_sheets" class="bgcolor bordercolor"> {if $product->description} {* full description *} <div id="idTab1"><div>{$product->description}</div></div> {/if} {if $features} {* product's features *} <ul id="idTab2" class="bullet"> {foreach from=$features item=feature} <li><span>{$feature.name|escape:'htmlall':'UTF-8'}</span> {$feature.value|escape:'htmlall':'UTF-8'}</li> {/foreach} </ul> {/if} {if $attachments} {* product's attachments *} <ul id="idTab9" class="bullet"> {foreach from=$attachments item=attachment} <li><a href="{$link->getPageLink('attachment.php', true)}?id_attachment={$attachment.id_attachment}">{$attachment.name|escape:'htmlall':'UTF-8'}</a><br />{$attachment.description|escape:'htmlall':'UTF-8'}</li> {/foreach} </ul> {/if} {if isset($accessories) AND $accessories} {* accessories *} <ul id="idTab4"> {foreach from=$accessories item=accessory name=accessories_list} {assign var='accessoryLink' value=$link->getProductLink($accessory.id_product, $accessory.link_rewrite, $accessory.category)} <li class="bordercolor ajax_block_product {if $smarty.foreach.accessories_list.first}first_item{elseif $smarty.foreach.accessories_list.last}last_item{else}item{/if} product_accessories_description"> <div class="accessories_desc"> <a class="accessory_image product_img_link bordercolor" href="{$accessoryLink|escape:'htmlall':'UTF-8'}" title="{$accessory.legend|escape:'htmlall':'UTF-8'}"><img src="{$link->getImageLink($accessory.link_rewrite, $accessory.id_image, 'medium')}" alt="{$accessory.legend|escape:'htmlall':'UTF-8'}" /></a> <h5><a class="product_link" href="{$accessoryLink|escape:'htmlall':'UTF-8'}">{$accessory.name|truncate:22:'...':true|escape:'htmlall':'UTF-8'}</a></h5> <a class="product_descr" href="{$accessoryLink|escape:'htmlall':'UTF-8'}" title="{l s='More'}">{$accessory.description_short|strip_tags|truncate:70:'...'}</a> </div> <div class="accessories_price bordercolor"> {if $accessory.show_price AND !isset($restricted_country_mode) AND !$PS_CATALOG_MODE}<span class="price">{if $priceDisplay != 1}{displayWtPrice p=$accessory.price}{else}{displayWtPrice p=$accessory.price_tax_exc}{/if}</span>{/if} {if ($accessory.allow_oosp || $accessory.quantity > 0) AND $accessory.available_for_order AND !isset($restricted_country_mode) AND !$PS_CATALOG_MODE} <a class="exclusive button ajax_add_to_cart_button" href="{$link->getPageLink('cart.php')}?qty=1&id_product={$accessory.id_product|intval}&token={$static_token}&add" rel="ajax_id_product_{$accessory.id_product|intval}" title="{l s='Add to cart'}">{l s='Add to cart'}</a> {else} <span class="exclusive">{l s='Add to cart'}</span> {/if} </div> </li> {/foreach} </ul> {/if} {$HOOK_PRODUCT_TAB_CONTENT} </div> </div> {/if} {$HOOK_PRODUCT_FOOTER} {* pack items list *} {if $packItems|@count > 0} <div id="pack_product_list"> <h2>{l s='Pack content'}</h2> {include file="$tpl_dir./product-list-pack.tpl" products=$packItems} </div> {/if} {/if} The template Is built for 1.4.8, but I use it with 1.4.9. Everything else is working so... Edited October 12, 2012 by adameriksson (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted October 12, 2012 Share Posted October 12, 2012 I have confirmed the problem is with your product.tpl file when I try it with a stock ps theme on one of my 1.4.9.0 test installations. With your file I get the message. There is 1 error : Please fill in all required fields, then save the customization. Try using the product.tpl file I modified from the old template in your theme and see if it works, then go from there for any other mods. A good tool to use to compare the files and make the changes is called WinMerge. Link to comment Share on other sites More sharing options...
adameriksson Posted October 12, 2012 Share Posted October 12, 2012 I have confirmed the problem is with your product.tpl file when I try it with a stock ps theme on one of my 1.4.9.0 test installations. With your file I get the message. There is 1 error : Please fill in all required fields, then save the customization. Try using the product.tpl file I modified from the old template in your theme and see if it works, then go from there for any other mods. A good tool to use to compare the files and make the changes is called WinMerge. Okey, Thanks for your help! The sad thing is when i Use your code, everyting looks weird, I dont even see a add to cart button.. Well, I think I'm stuck with the save button then, If I'm not able to modify your tpl file to have it look like my themes tpl Link to comment Share on other sites More sharing options...
Rhapsody Posted October 12, 2012 Share Posted October 12, 2012 No problem. Seriously - create another theme folder and make changes to the stock PS theme which should be as easy as copying the product.tpl file that I posted. Once that works, use WinMerge to compare those files with your theme and that should help you find where / why there are differences. Link to comment Share on other sites More sharing options...
adameriksson Posted October 12, 2012 Share Posted October 12, 2012 No problem. Seriously - create another theme folder and make changes to the stock PS theme which should be as easy as copying the product.tpl file that I posted. Once that works, use WinMerge to compare those files with your theme and that should help you find where / why there are differences. That's a good idea. I just duplicated standard theme, overvrited the product.tpl file with yours. I have the modified controller file. But it doesnt work anyway, the text isn't in the cart. Maybe it is something with my templatemonster modules... Link to comment Share on other sites More sharing options...
Rhapsody Posted October 12, 2012 Share Posted October 12, 2012 does Template Monster modify the blockcart module? Link to comment Share on other sites More sharing options...
adameriksson Posted October 12, 2012 Share Posted October 12, 2012 (edited) does Template Monster modify the blockcart module? Yeah The do, they have a modified ajax-cart.js. But I dont use their file yet. I don't know what it does. Do you think it would work better if I use it? I see now that I also have "blockcart-json.tpl" and "blockcart.tpl" in my themes/modules folder. So templatemonster have modified the cart module... I did a comparison, looks like they only have customized it for design purpose, they have not changed core functions Edited October 12, 2012 by adameriksson (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted October 13, 2012 Share Posted October 13, 2012 Yeah The do, they have a modified ajax-cart.js. But I dont use their file yet. I don't know what it does. Do you think it would work better if I use it? I see now that I also have "blockcart-json.tpl" and "blockcart.tpl" in my themes/modules folder. So templatemonster have modified the cart module... I did a comparison, looks like they only have customized it for design purpose, they have not changed core functions I moved some code around in your monster template file and got it to work, but am not sure if it formats correctly since I don't have your entire theme. Try the attached file and unzip it to product.tpl product.zip Link to comment Share on other sites More sharing options...
adameriksson Posted October 13, 2012 Share Posted October 13, 2012 I moved some code around in your monster template file and got it to work, but am not sure if it formats correctly since I don't have your entire theme. Try the attached file and unzip it to product.tpl IT WORKS!!!!!! Thank you so much, you are the best! May I ask you what U think was the problem in the code? Was it the position of some code, or did you modify something else? Thank so much, I'm so glad! Link to comment Share on other sites More sharing options...
Rhapsody Posted October 13, 2012 Share Posted October 13, 2012 It was the position of code. You can use WinMerge and compare what you posted with what I changed. Link to comment Share on other sites More sharing options...
franmille Posted November 22, 2012 Share Posted November 22, 2012 (edited) Hi everybody, Thanks for this solution, works perfectly. I would like it to work well with file fields, you can help me? Regards edit: I use the Prestashop version 1.4.9, with the Prestashop_new theme. And I've gotten it to work with ajax cart, deleting the code between "//for every 'add' buttons..." and "//for 'delete' buttons in the cart block.." in the ajax-cart.js theme's file. Edited November 22, 2012 by franmille (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted November 22, 2012 Share Posted November 22, 2012 @franmille - would you please post your ajax-cart.js file so I can try it? Link to comment Share on other sites More sharing options...
cagrie Posted November 25, 2012 Share Posted November 25, 2012 this is one of the issues that makes me wanna move to opencart. what were the developers thinking by making a separate save button when it is totally unecessary? Link to comment Share on other sites More sharing options...
cagrie Posted November 25, 2012 Share Posted November 25, 2012 (edited) when I do all the said, the customization is saved but the attributes aren't. when the line <input type="hidden" name="submitCustomizedDatas" value="1" /> is in the product.tpl, the customization is saved but the attributes arent. if it is not, the attributes are saved but the customizations arent. I'm on ps 1.4.8.2 pulling my hair here... Edited November 25, 2012 by cagrie (see edit history) Link to comment Share on other sites More sharing options...
franmille Posted November 26, 2012 Share Posted November 26, 2012 (edited) @Rhapsody here is my ajax-cart.js, I can´t upload it... Edited November 26, 2012 by franmille (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted November 28, 2012 Share Posted November 28, 2012 @franmille - thanks for the link. I am unable to get the Ajax cart to work with my mods. Link to comment Share on other sites More sharing options...
shamun Posted January 1, 2013 Share Posted January 1, 2013 Anybody got a working controller and tpl for 1.5? I tried the one provided for 1.4.9 and no go. Link to comment Share on other sites More sharing options...
shamun Posted January 2, 2013 Share Posted January 2, 2013 Figured out a way to do it granted it's not the correct way and I'm on too short of a deadline to make it clean. Also, only for text fields. I didn't need image upload so I didnt even try with that. See attached. Tested on 1.5.2. Put the file in /overrides/controllers/front/ Requires .tpl modifcation that is fairly straightforward: Remove the save button and put the following code in the form which submits to the cart: {if $product->text_fields|intval} {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input" />{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> {counter} {/if} {/foreach} {/if} <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> Of course all you really need are the inputs. The code is stolen from the other customization area on the page and minified a little. Nothing changed. Be sure to remove the customization form as well. CartController.php 1 Link to comment Share on other sites More sharing options...
naeems Posted January 4, 2013 Share Posted January 4, 2013 Figured out a way to do it granted it's not the correct way and I'm on too short of a deadline to make it clean. Also, only for text fields. I didn't need image upload so I didnt even try with that. See attached. Tested on 1.5.2. Put the file in /overrides/controllers/front/ Requires .tpl modifcation that is fairly straightforward: Remove the save button and put the following code in the form which submits to the cart: {if $product->text_fields|intval} {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input" />{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> {counter} {/if} {/foreach} {/if} <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> Of course all you really need are the inputs. The code is stolen from the other customization area on the page and minified a little. Nothing changed. Be sure to remove the customization form as well. I tried on my PS 1.5.2 but no luck. Can you help me out, did you change some else as well or just change the CartController.php file. I mean did you make changes ajax-cart.js too. Regards, Naeem Link to comment Share on other sites More sharing options...
shamun Posted January 4, 2013 Share Posted January 4, 2013 Forgot to mention, I didn't do it for ajax cart. Only non-ajax. Link to comment Share on other sites More sharing options...
Lufox Posted January 8, 2013 Share Posted January 8, 2013 This worked great on 1.5.3.1 How do I make it compatible with ajax cart? Figured out a way to do it granted it's not the correct way and I'm on too short of a deadline to make it clean. Also, only for text fields. I didn't need image upload so I didnt even try with that. See attached. Tested on 1.5.2. Put the file in /overrides/controllers/front/ Requires .tpl modifcation that is fairly straightforward: Remove the save button and put the following code in the form which submits to the cart: {if $product->text_fields|intval} {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input" />{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> {counter} {/if} {/foreach} {/if} <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> Of course all you really need are the inputs. The code is stolen from the other customization area on the page and minified a little. Nothing changed. Be sure to remove the customization form as well. Link to comment Share on other sites More sharing options...
monxu Posted February 6, 2013 Share Posted February 6, 2013 I'm using 1.4.9 with module Visible customization (http://catalogo-onlinersi.net/en/add-ons-prestashop-modules/341-visible-customization.html), i removed the button save butt not work. without this module is work fine, but i need this module because i change some options. Link to comment Share on other sites More sharing options...
Daxidov Posted February 11, 2013 Share Posted February 11, 2013 Hi, Im using prestashop 1.3.0.10 with wallcraft template and Im looking for something like this but I want to have "reqiured" option avaliable and picture upload. Is it avaliable? It would be perfect if it would be on ajax. Thanks.. Link to comment Share on other sites More sharing options...
cagrie Posted February 27, 2013 Share Posted February 27, 2013 Has anyone got this working on 1.4.x just curious... Link to comment Share on other sites More sharing options...
Rhapsody Posted February 27, 2013 Share Posted February 27, 2013 Has anyone got this working on 1.4.x just curious... Yes - see this post. It is now working on 3 shops I upgraded to 1.4.10.0 Link to comment Share on other sites More sharing options...
dOnkSkie Posted March 9, 2013 Share Posted March 9, 2013 (edited) Hi Everyone, Sorry, had to edit my post. I think I have it working using shamun's CartController.php in Prestashop 1.5.2 with the default theme. I moved the entire <!-- Customizable products --> content to where the add to cart button is. Removed the Save button and added onclick="javascript:saveCustomization()" to the add to cart input button. It works and just need some CSS adjustments. But, I'm not quite sure if it won't affect other modules or features. Anyway, I achieved my goal in removing the save button and make sure the input data will display after clicking the add to cart button. Thank you all! To Rhapsody and shamun, very useful post Edited March 9, 2013 by dOnkSkie (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted March 12, 2013 Share Posted March 12, 2013 Working 1.5.3.1 Mod to remove save button! (without Ajax Cart) The Zip file attached includes what is needed to modify the basic "default" theme on Prestashop 1.5.3.1 to eliminate the save button so you can add to cart directly. Thanks to shamun who got this to work on version 1.5.2 in post #124 above, the CartController.php override file has been updated with 1.5.3.1 code. 1. Put the CartController.php file in the override/controllers/front directory 2. Put the product.tpl file in your default theme directory (or the theme directory you created from the default theme). 3. In the BO under modules, set the Cart block configuration to deactivate the Ajax cart 4. In the BO on the Advnaced Parameters menu, select performance, Turn off the smarty cache and compile templates, then try it in the front office. It should work. Then reenable the smarty cache and turn compile off in the BO. If anyone is able to accomplish the following that is NOT incorporated in this mod, please post in this thread: 1. update to include uploading of files & images 2. Get the Ajax cart working with this mod 1.5.3.1 Mod to eliminate svae button.zip 3 Link to comment Share on other sites More sharing options...
FranciscoVillen Posted March 18, 2013 Share Posted March 18, 2013 Hello Rhapsody, thanks for your time. It seems to be working but I have a problem: With the new files (product.tpl and CartController.php in the override), the button to remove products in the cart redirect to the homepage and the product isn't removed from the cart. I'm using prestashop 1.5 and the theme "Free Template PS001" from http://www.uhupage.com/ where could it be the problem? any idea about solving this? Thanks. Link to comment Share on other sites More sharing options...
FranciscoVillen Posted April 2, 2013 Share Posted April 2, 2013 It seems the problem occurs when Ajax is deactivated but I need it to this solution to remove the save button. Link to comment Share on other sites More sharing options...
FranciscoVillen Posted April 9, 2013 Share Posted April 9, 2013 (edited) Finally, I have decided to change to the default theme of Prestashop 1.5 Using a 1.4 theme in prestashop 1.5 is a bad idea. The problem seems to me solved. Edited April 9, 2013 by FranciscoVillen (see edit history) Link to comment Share on other sites More sharing options...
defuzed Posted April 15, 2013 Share Posted April 15, 2013 hey, many thanks to all the contributors, was really stuck on this one ... i managed to extend rhapsodys working 1.5 mod to also work with files, was actually pretty simple. Just add the following in overrides/controllers/front/CartCOntroller.php $this->pictureUpload($product); below $this->textRecord($product); and add the slightly modified pictureUpload function from the productscontroller protected function pictureUpload($product) { if (!$field_ids = $product->getCustomizationFieldIds()) return false; $authorized_file_fields = array(); foreach ($field_ids as $field_id) if ($field_id['type'] == Product::CUSTOMIZE_FILE) $authorized_file_fields[(int)$field_id['id_customization_field']] = 'file'.(int)$field_id['id_customization_field']; $indexes = array_flip($authorized_file_fields); foreach ($_FILES as $field_name => $file) if (in_array($field_name, $authorized_file_fields) && isset($file['tmp_name']) && !empty($file['tmp_name'])) { $file_name = md5(uniqid(rand(), true)); if ($error = ImageManager::validateUpload($file, (int)Configuration::get('PS_PRODUCT_PICTURE_MAX_SIZE'))) $this->errors[] = $error; $product_picture_width = (int)Configuration::get('PS_PRODUCT_PICTURE_WIDTH'); $product_picture_height = (int)Configuration::get('PS_PRODUCT_PICTURE_HEIGHT'); $tmp_name = tempnam(_PS_TMP_IMG_DIR_, 'PS'); if ($error || (!$tmp_name || !move_uploaded_file($file['tmp_name'], $tmp_name))) return false; /* Original file */ if (!ImageManager::resize($tmp_name, _PS_UPLOAD_DIR_.$file_name)) $this->errors[] = Tools::displayError('An error occurred during the image upload process.'); /* A smaller one */ elseif (!ImageManager::resize($tmp_name, _PS_UPLOAD_DIR_.$file_name.'_small', $product_picture_width, $product_picture_height)) $this->errors[] = Tools::displayError('An error occurred during the image upload process.'); elseif (!chmod(_PS_UPLOAD_DIR_.$file_name, 0777) || !chmod(_PS_UPLOAD_DIR_.$file_name.'_small', 0777)) $this->errors[] = Tools::displayError('An error occurred during the image upload process.'); else $this->context->cart->addPictureToProduct($product->id, $indexes[$field_name], Product::CUSTOMIZE_FILE, $file_name); unlink($tmp_name); } return true; } then all you have to do id add enctype="multipart/form-data" to the add-to-cart form in product.tpl Pretty easy to figure out, still hope it helps someone maybe. Am still trying to get this to work with the ajax-cart, no luck so far. Link to comment Share on other sites More sharing options...
Rhapsody Posted April 16, 2013 Share Posted April 16, 2013 (edited) defused - thanks for the update. Can you post some more specifics on where in the product.tpl file you added; enctype="multipart/form-data" Edited December 3, 2013 by Rhapsody (see edit history) Link to comment Share on other sites More sharing options...
defuzed Posted April 16, 2013 Share Posted April 16, 2013 oh, right i should've been more specific. The enctype snippet needs to be in the "buy-block" form so: <form id="buy_block" {if $PS_CATALOG_MODE AND !isset($groups) AND $product->quantity > 0}class="hidden"{/if} action="{$link->getPageLink('cart')}" method="post" enctype="multipart/form-data"> let me know if this works Link to comment Share on other sites More sharing options...
Rhapsody Posted April 17, 2013 Share Posted April 17, 2013 defuzed - - thanks! that works great. 1 Link to comment Share on other sites More sharing options...
huduyudesign Posted June 9, 2013 Share Posted June 9, 2013 Using Rhapsody's method for 1.5.3.1 can anyone help me move some things around? I'd like to move attributes, customizations & add to cart to resemble this http://adogstore.com/index.php?id_product=49&controller=product&id_lang=1 but when I try it stops saving the entered customization. Link to comment Share on other sites More sharing options...
defuzed Posted June 10, 2013 Share Posted June 10, 2013 @huduydesign : I guess you figured it out? When i enter customizations, they are being saved to the cart. Or do you want to move the customizations out of the tab region? To achieve that you need to keep the form itself intact and move it around as a whole. You can switch around the individual parts to your liking but you need to keep all inputs and the submit (add to cart in this case) in the form. Link to comment Share on other sites More sharing options...
huduyudesign Posted June 10, 2013 Share Posted June 10, 2013 Defuzed I did finally get it to work but not using Rhapsody's method but one in post #132. Rhapsody's method I could not find right combinations to make it work so resorted to using the "save" function in the add to cart function, ajax off & the one cart file from Rhapsody's download is in there, not sure it's doing anything. This is same set up I used earlier but stopped it stopped working, possibly because I had ajax on or something went wacko when moving to VPS hosting. Hoping it continues to work. Link to comment Share on other sites More sharing options...
projects Posted July 1, 2013 Share Posted July 1, 2013 Has anyone been able to get this working with ajax? Link to comment Share on other sites More sharing options...
aaronjpitts Posted July 11, 2013 Share Posted July 11, 2013 Could anyone please update Rhapsody's code so that the respective files are updated for the latest version of prestashop? Thanks Link to comment Share on other sites More sharing options...
defuzed Posted July 12, 2013 Share Posted July 12, 2013 aaronjpitts, have you tried using rhapsody's code in 1.5.4.1? I'm using my modified version (with file-upload) and i didn't have to change anything when upgrading to 1.5.4.1 ( i don't think that update changed anything in the relevant files). Link to comment Share on other sites More sharing options...
Nishith Nesdiya Posted July 17, 2013 Share Posted July 17, 2013 yes friends try this... add : function(idProduct, idCombination,addedFromProductPage, callerElement, quantity, whishlist){ if (addedFromProductPage) { $('#add_to_cart input').attr('disabled', true).removeClass('exclusive').addClass('exclusive_disabled'); $('.filled').removeClass('filled'); } else $(callerElement).attr('disabled', true); if ($('#cart_block_list').hasClass('collapsed')) this.expand(); var formData = $('#customizationForm').serialize(); $.ajax({ url: $('#customizationForm').attr('action'), type: 'POST', data: formData, async: false, success: function (data) { $.ajax({ type: 'POST', url: baseUri, async: true, cache: false, dataType : "json", data: 'controller=cart&add=1&ajax=true&qty=' + ((quantity && quantity != null) ? quantity : '1') + '&id_product=' + idProduct + '&token=' + static_token + ( (parseInt(idCombination) && idCombination != null) ? '&ipa=' + parseInt(idCombination): ''), success: function(jsonData,textStatus,jqXHR) { // add appliance to whishlist module if (whishlist && !jsonData.errors) WishlistAddProductCart(whishlist[0], idProduct, idCombination, whishlist[1]); // add the picture to the cart var $element = $(callerElement).parent().parent().find('a.product_image img,a.product_img_link img'); if (!$element.length) $element = $('#bigpic'); var $picture = $element.clone(); var pictureOffsetOriginal = $element.offset(); if ($picture.size()) $picture.css({'position': 'absolute', 'top': pictureOffsetOriginal.top, 'left': pictureOffsetOriginal.left}); var pictureOffset = $picture.offset(); if ($('#cart_block').offset().top && $('#cart_block').offset().left) var cartBlockOffset = $('#cart_block').offset(); else var cartBlockOffset = $('#shopping_cart').offset(); // Check if the block cart is activated for the animation if (cartBlockOffset != undefined && $picture.size()) { $picture.appendTo('body'); $picture.css({ 'position': 'absolute', 'top': $picture.css('top'), 'left': $picture.css('left'), 'z-index': 4242 }) .animate({ 'width': $element.attr('width')*0.66, 'height': $element.attr('height')*0.66, 'opacity': 0.2, 'top': cartBlockOffset.top + 30, 'left': cartBlockOffset.left + 15 }, 1000) .fadeOut(100, function() { ajaxCart.updateCartInformation(jsonData, addedFromProductPage); }); } else ajaxCart.updateCartInformation(jsonData, addedFromProductPage); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert("Impossible to add the product to the cart.\n\ntextStatus: '" + textStatus + "'\nerrorThrown: '" + errorThrown + "'\nresponseText:\n" + XMLHttpRequest.responseText); //reactive the button when adding has finished if (addedFromProductPage) $('#add_to_cart input').removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); else $(callerElement).removeAttr('disabled'); } }); } }); it is work for me.. 5 Link to comment Share on other sites More sharing options...
Rhapsody Posted July 17, 2013 Share Posted July 17, 2013 yes friends try this... ....... What file is this code from? Link to comment Share on other sites More sharing options...
Nishith Nesdiya Posted July 17, 2013 Share Posted July 17, 2013 sorry ... modules/blockcart/ajax-cart.js file find the this add : function(idProduct, idCombination,addedFromProductPage, callerElement, quantity, whishlist) Link to comment Share on other sites More sharing options...
iztok Posted July 23, 2013 Share Posted July 23, 2013 sorry ... modules/blockcart/ajax-cart.js file find the this add : function(idProduct, idCombination,addedFromProductPage, callerElement, quantity, whishlist) Works perfectly, thanks for sharing saved me tons of banging my head ) for clarity, before the remove : function(idProduct, idCombination, customizationId, idAddressDelivery) starts theres a }, missing, but thats pretty obvious Link to comment Share on other sites More sharing options...
mrkgmr Posted August 6, 2013 Share Posted August 6, 2013 For my don´t work with ajax. It don´t do anything :S any idea? :S Link to comment Share on other sites More sharing options...
aaronjpitts Posted September 1, 2013 Share Posted September 1, 2013 Could anyone please update Rhapsody's code so that the respective files are updated for the latest version of prestashop? As the CartController.php file is updated in the latest update. Thanks Link to comment Share on other sites More sharing options...
Kungpin Posted September 28, 2013 Share Posted September 28, 2013 If anyone has an solution for PS1.5.3.1 to remove the save button and make it work with ajax cart. (only have to work with textfields.) Im willing to pay for it. PM me. Link to comment Share on other sites More sharing options...
aaronjpitts Posted October 6, 2013 Share Posted October 6, 2013 Could anyone confirm if they have this modification working with the latest prestashop version (doesn't have to work with ajax cart). I had been using rhapsody's mod before but now with a clean install of prestashop 1.5.5.0 when clicking the add to cart button (with the customisation field inputted) I get an error on the cart page: Please fill in all of the required fields, and then save your customizations.So it's obviously not saving the fields anymore. Can anyone please help with this? Many thanks Link to comment Share on other sites More sharing options...
SkyHiRider Posted December 2, 2013 Share Posted December 2, 2013 I can't get it working on 1.4.4 - used both files from post #101 but when I add text and then click add to cart it does not save the text (as cannot see it in thecart below the product). AJAX cart is disabled. Is there something else I need to enable? Link to comment Share on other sites More sharing options...
ZenVisuals Posted March 31, 2014 Share Posted March 31, 2014 (edited) Hey guys, I managed to get it working with P.S 1.5.4.1 and AJAX on. If i'm not wrong, in the original version, the user has to save the customised data first then the adding to the cart will work is because when adding to the cart, the script checks whether there is customised data saved in the MySQL database first ( check for id_customization and its data). In the product page, the customised datas are sent to the ProductController's textRecord() and pictureUpload() function to process and to update the database, this is sent using the form id called customizationForm. The add to cart button originally interacts with the CartController and not the ProductController and is separated from the customizationForm's form. Even when you add textRecord() function in the CartController, the values in the customised fields are not recorded as the $_POST values for both CartController and ProductController are different. Basically the solution is like this, I first submit the customised field values with the help of AJAX and then call another AJAX query to add the product to the cart when the customised field values have been updated in the database already. For the text validation, I used jQuery to check for empty textfields instead. The code is here, just edit the file modules\blockcart\ajax-cart.js and the method add : function around line 177 with this, remember to backup your original copy in case. // add a product in the cart via ajax add : function(idProduct, idCombination, addedFromProductPage, callerElement, quantity, whishlist){ var addBtn_val = $('#add_to_cart input').val(); if (addedFromProductPage) { //button change, disable and do status text $('#add_to_cart input').attr('disabled', true).removeClass('exclusive').addClass('exclusive_disabled').val("Processing..."); $('.filled').removeClass('filled'); //not depending on php backend to do validation but jquery $("form#customizationForm .required :input").each(function() { if ($.trim($(this).val()).length == 0) { $(this).css("border", "red 1px solid"); $form_verify = false; $('#add_to_cart input').val(addBtn_val).removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); } else { $(this).removeAttr("style"); $(this).css("height", "30px"); $form_verify = true; } }); if($form_verify) { var cform = $("form#customizationForm"); var cform_data = cform.serialize(); var cform_action = cform.attr("action"); var cform_method = cform.attr("method"); var cform_enctype = cform.attr("enctype"); //use ajax send the customizationForm data, will still be successful even though there is error on PHP side. $.ajax({ type: cform_method, headers: { "cache-control": "no-cache" }, url: cform_action, cache: false, data: cform_data, success: function(response) { //when customizationForm is successfully submitted, proceed to adding product to cart emptyCustomizations(); // adding product now $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&add=1&ajax=true&qty=' + ((quantity && quantity != null) ? quantity : '1') + '&id_product=' + idProduct + '&token=' + static_token + ( (parseInt(idCombination) && idCombination != null) ? '&ipa=' + parseInt(idCombination): ''), success: function(jsonData,textStatus,jqXHR) { // add appliance to whishlist module if (whishlist && !jsonData.errors) WishlistAddProductCart(whishlist[0], idProduct, idCombination, whishlist[1]); // add the picture to the cart var $element = $(callerElement).parent().parent().find('a.product_image img,a.product_img_link img'); if (!$element.length) $element = $('#bigpic'); var $picture = $element.clone(); var pictureOffsetOriginal = $element.offset(); if ($picture.size()) $picture.css({'position': 'absolute', 'top': pictureOffsetOriginal.top, 'left': pictureOffsetOriginal.left}); var pictureOffset = $picture.offset(); if ($('#cart_block')[0] && $('#cart_block').offset().top && $('#cart_block').offset().left) var cartBlockOffset = $('#cart_block').offset(); else var cartBlockOffset = $('#shopping_cart').offset(); // Check if the block cart is activated for the animation if (cartBlockOffset != undefined && $picture.size()) { $picture.appendTo('body'); $picture.css({ 'position': 'absolute', 'top': $picture.css('top'), 'left': $picture.css('left'), 'z-index': 4242 }) .animate({ 'width': $element.attr('width')*0.66, 'height': $element.attr('height')*0.66, 'opacity': 0.2, 'top': cartBlockOffset.top + 30, 'left': cartBlockOffset.left + 705 }, 1000) .fadeOut(100, function() { ajaxCart.updateCartInformation(jsonData, addedFromProductPage); }); } else ajaxCart.updateCartInformation(jsonData, addedFromProductPage); $('#add_to_cart input').val("Successfully Added!").css("background-color","#74bd00").delay(2000).queue(function(){ $(this).val(addBtn_val).css("background-color","black"); }); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert("Impossible to add the product to the cart.\n\ntextStatus: '" + textStatus + "'\nerrorThrown: '" + errorThrown + "'\nresponseText:\n" + XMLHttpRequest.responseText); //reactive the button when adding has finished if (addedFromProductPage) $('#add_to_cart input').removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); else $(callerElement).removeAttr('disabled'); } }); }, error: function(response) { alert("error: " + response.error); } }); } else { alert("Please fill in the required fields"); } } else { $(callerElement).attr('disabled', true); } if ($('#cart_block_list').hasClass('collapsed')) this.expand(); }, Here is my ajax-cart.js file for reference. Cheers ajax-cart.zip Edited March 31, 2014 by ZenVisuals (see edit history) Link to comment Share on other sites More sharing options...
Rhapsody Posted March 31, 2014 Share Posted March 31, 2014 Hey guys, I managed to get it working with P.S 1.5.4.1 and AJAX on. .......... Here is my ajax-cart.js file for reference. Cheers ZenVisuals, Thanks for that! I tried it on my test shop using 1.5.6.2 and it works with the default theme. I have made enough changes on my custom theme that I believe take out all the ajax calls, so it doesn't work there.I plan on going back to the custom theme and restoring that code. Have you checked operation with the mobile theme? I found there were some things on the default mobile theme that didn't work, so I significantly customized it to meet my needs. Nice work! Link to comment Share on other sites More sharing options...
ZenVisuals Posted March 31, 2014 Share Posted March 31, 2014 (edited) Hey guys, @Rhapsody: Thanks for the feedback! Yeah I didn't bother about the non ajax operation so it didn't work. Good point about the mobile operation, I totally neglected it! I'm glad you updated your codes on the custom theme and got it working I was looking at the non ajax operation and figuring out how the CartController works. Anyway, these are my findings: Since the forms for the customised fields and the other inputs such as the quantity and combination are different and they are posted to ProductController and CartController respectively. To have them submit as one, I combined the inputs into one single form and post it to the CartController only. The CartController then retrieves the $_POST values of all the inputs in the product page including the customised fields. I then override the processChangeProductInCart() method and proceeded with updating the database with the customised fields first then the other inputs. I took codes from the textRecord() in ProductController and changed it to fit the process. It should work without AJAX. However, I didn't update my ajax-cart.js for this so if AJAX is on, I don't think it will work. Perhaps the original ajax-cart.js might work. Another thing is only text-fields and areas will work, the image upload will not work as I never included codes from pictureUpload(). This code should be placed in override/modules/front/CartController.php class CartController extends CartControllerCore { /** * This process add or update a product in the cart */ protected function processChangeProductInCart() { $mode = (Tools::getIsset('update') && $this->id_product) ? 'update' : 'add'; if ($this->qty == 0) $this->errors[] = Tools::displayError('Null quantity.'); else if (!$this->id_product) $this->errors[] = Tools::displayError('Product not found'); $product = new Product($this->id_product, true, $this->context->language->id); if (!$product->id || !$product->active) { $this->errors[] = Tools::displayError('This product is no longer available.', false); return; } // Check product quantity availability if ($this->id_product_attribute) { if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $this->qty)) $this->errors[] = Tools::displayError('There isn\'t enough product in stock.'); } else if ($product->hasAttributes()) { $minimumQuantity = ($product->out_of_stock == 2) ? !Configuration::get('PS_ORDER_OUT_OF_STOCK') : !$product->out_of_stock; $this->id_product_attribute = Product::getDefaultAttribute($product->id, $minimumQuantity); // @todo do something better than a redirect admin !! if (!$this->id_product_attribute) Tools::redirectAdmin($this->context->link->getProductLink($product)); else if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $this->qty)) $this->errors[] = Tools::displayError('There isn\'t enough product in stock.'); } else if (!$product->checkQty($this->qty)) $this->errors[] = Tools::displayError('There isn\'t enough product in stock.'); // If no errors, process product addition if (!$this->errors && $mode == 'add') { // Add cart if no cart found if (!$this->context->cart->id) { if (Context::getContext()->cookie->id_guest) { $guest = new Guest(Context::getContext()->cookie->id_guest); $this->context->cart->mobile_theme = $guest->mobile_theme; } $this->context->cart->add(); if ($this->context->cart->id) $this->context->cookie->id_cart = (int)$this->context->cart->id; } // Process customizable fields first //get product's customized text fields and input them to $field_ids if (!$field_ids = $product->getCustomizationFieldIds()) return false; $authorized_text_fields = array(); $required_fields = $product->getRequiredCustomizableFields(); $required_fieldsArray = array(); //get required field ids foreach ($required_fields as $requiredfield_id) if ($requiredfield_id['type'] == Product::CUSTOMIZE_TEXTFIELD) $required_fieldsArray[(int)$requiredfield_id['id_customization_field']] = 'textField'.(int)$requiredfield_id['id_customization_field']; //$authorized_text_fields[int] = textField[int of id_customization_field]; foreach ($field_ids as $field_id) if ($field_id['type'] == Product::CUSTOMIZE_TEXTFIELD) $authorized_text_fields[(int)$field_id['id_customization_field']] = 'textField'.(int)$field_id['id_customization_field']; //values 1,2,3,4,5,6,7 put into array[textField1,2,3,4,5,6,7] $indexes = array_flip($authorized_text_fields); foreach ($_POST as $field_name => $value) { //filter required fields if (in_array($field_name, $required_fieldsArray) && empty($value)) { // stop and make sure user enters required fields //p(Customization::getLabel($indexes[$field_name],1)) - gets the label of the id_customization_field with id_lang = 1, 1 is English i assume $this->errors[] = Tools::displayError('Please fill this field:' . Customization::getLabel($indexes[$field_name],1)); } else { if (!Validate::isMessage($value)) $this->errors[] = Tools::displayError('Invalid message'); } } // if all required fields are filled, then proceed to add custom fields to database if (!$this->errors) { foreach ($_POST as $field_name => $value) { if (in_array($field_name, $authorized_text_fields)) { $this->context->cart->addTextFieldToProduct($product->id, $indexes[$field_name], Product::CUSTOMIZE_TEXTFIELD, $value); } } } if (!$this->errors) { $cart_rules = $this->context->cart->getCartRules(); $update_quantity = $this->context->cart->updateQty($this->qty, $this->id_product, $this->id_product_attribute, $this->customization_id, Tools::getValue('op', 'up'), $this->id_address_delivery); if ($update_quantity < 0) { // If product has attribute, minimal quantity is set with minimal quantity of attribute $minimal_quantity = ($this->id_product_attribute) ? Attribute::getAttributeMinimalQty($this->id_product_attribute) : $product->minimal_quantity; $this->errors[] = sprintf(Tools::displayError('You must add %d minimum quantity', false), $minimal_quantity); } elseif (!$update_quantity) $this->errors[] = Tools::displayError('You already have the maximum quantity available for this product.', false); elseif ((int)Tools::getValue('allow_refresh')) { // If the cart rules has changed, we need to refresh the whole cart $cart_rules2 = $this->context->cart->getCartRules(); if (count($cart_rules2) != count($cart_rules)) $this->ajax_refresh = true; else { $rule_list = array(); foreach ($cart_rules2 as $rule) $rule_list[] = $rule['id_cart_rule']; foreach ($cart_rules as $rule) if (!in_array($rule['id_cart_rule'], $rule_list)) { $this->ajax_refresh = true; break; } } } } } $removed = CartRule::autoRemoveFromCart(); CartRule::autoAddToCart(); if (count($removed) && (int)Tools::getValue('allow_refresh')) $this->ajax_refresh = true; } } I combined both forms in product.tpl <!-- Customizable products combined with standard inputs--> {if ($product->show_price AND !isset($restricted_country_mode)) OR isset($groups) OR $product->reference OR (isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS)} <!-- add to cart form--> <form id="buy_block" {if $PS_CATALOG_MODE AND !isset($groups) AND $product->quantity > 0}class="hidden"{/if} action="{$link->getPageLink('cart')}" method="post" enctype="multipart/form-data"> <!-- hidden datas --> <p class="hidden"> <input type="hidden" name="token" value="{$static_token}" /> <input type="hidden" name="id_product" value="{$product->id|intval}" id="product_page_product_id" /> <input type="hidden" name="add" value="1" /> <input type="hidden" name="id_product_attribute" id="idCombination" value="" /> </p> <div class="product_attributes"> {if isset($groups)} <!-- attributes --> <div id="attributes"> <div class="clear"></div> {foreach from=$groups key=id_attribute_group item=group} {if $group.attributes|@count} <fieldset class="attribute_fieldset"> <label class="attribute_label" for="group_{$id_attribute_group|intval}">{$group.name|escape:'htmlall':'UTF-8'} : </label> {assign var="groupName" value="group_$id_attribute_group"} <div class="attribute_list"> {if ($group.group_type == 'select')} <select name="{$groupName}" id="group_{$id_attribute_group|intval}" class="attribute_select" onchange="findCombination();getProductAttribute();"> {foreach from=$group.attributes key=id_attribute item=group_attribute} <option value="{$id_attribute|intval}"{if (isset($smarty.get.$groupName) && $smarty.get.$groupName|intval == $id_attribute) || $group.default == $id_attribute} selected="selected"{/if} title="{$group_attribute|escape:'htmlall':'UTF-8'}">{$group_attribute|escape:'htmlall':'UTF-8'}</option> {/foreach} </select> {elseif ($group.group_type == 'color')} <ul id="color_to_pick_list" class="clearfix"> {assign var="default_colorpicker" value=""} {foreach from=$group.attributes key=id_attribute item=group_attribute} <li{if $group.default == $id_attribute} class="selected"{/if}> <a id="color_{$id_attribute|intval}" class="color_pick{if ($group.default == $id_attribute)} selected{/if}" style="background: {$colors.$id_attribute.value};" title="{$colors.$id_attribute.name}" onclick="colorPickerClick(this);getProductAttribute();"> {if file_exists($col_img_dir|cat:$id_attribute|cat:'.jpg')} <img src="{$img_col_dir}{$id_attribute}.jpg" alt="{$colors.$id_attribute.name}" width="20" height="20" /><br /> {/if} </a> </li> {if ($group.default == $id_attribute)} {$default_colorpicker = $id_attribute} {/if} {/foreach} </ul> <input type="hidden" class="color_pick_hidden" name="{$groupName}" value="{$default_colorpicker}" /> {elseif ($group.group_type == 'radio')} <ul> {foreach from=$group.attributes key=id_attribute item=group_attribute} <li> <input type="radio" class="attribute_radio" name="{$groupName}" value="{$id_attribute}" {if ($group.default == $id_attribute)} checked="checked"{/if} onclick="findCombination();getProductAttribute();" /> <span>{$group_attribute|escape:'htmlall':'UTF-8'}</span> </li> {/foreach} </ul> {/if} </div> </fieldset> {/if} {/foreach} </div> {/if} <p id="product_reference" {if isset($groups) OR !$product->reference}style="display: none;"{/if}> <label for="product_reference">{l s='Reference:'} </label> <span class="editable">{$product->reference|escape:'htmlall':'UTF-8'}</span> </p> <!-- quantity wanted --> {if $product->id == 6}{else} <p id="quantity_wanted_p"{if (!$allow_oosp && $product->quantity <= 0) OR $virtual OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> <label>{l s='Quantity:'}</label> <input type="text" name="qty" id="quantity_wanted" class="text" value="{if isset($quantityBackup)}{$quantityBackup|intval}{else}{if $product->minimal_quantity > 1}{$product->minimal_quantity}{else}1{/if}{/if}" size="2" maxlength="3" {if $product->minimal_quantity > 1}onkeyup="checkMinimalQuantity({$product->minimal_quantity});"{/if} /> </p> {/if} <!-- minimal quantity wanted --> <p id="minimal_quantity_wanted_p"{if $product->minimal_quantity <= 1 OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> {l s='This product is not sold individually. You must select at least'} <b id="minimal_quantity_label">{$product->minimal_quantity}</b> {l s='quantity for this product.'} </p> {if $product->minimal_quantity > 1} <script type="text/javascript"> checkMinimalQuantity(); </script> {/if} <!-- availability --> <p id="availability_statut"{if ($product->quantity <= 0 && !$product->available_later && $allow_oosp) OR ($product->quantity > 0 && !$product->available_now) OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> <span id="availability_label">{l s='Availability:'}</span> <span id="availability_value"{if $product->quantity <= 0} class="warning_inline"{/if}>{if $product->quantity <= 0}{if $allow_oosp}{$product->available_later}{else}{l s='This product is no longer in stock'}{/if}{else}{$product->available_now}{/if}</span> </p> <p id="availability_date"{if ($product->quantity > 0) OR !$product->available_for_order OR $PS_CATALOG_MODE OR !isset($product->available_date) OR $product->available_date < $smarty.now|date_format:'%Y-%m-%d'} style="display: none;"{/if}> <span id="availability_date_label">{l s='Availability date:'}</span> <span id="availability_date_value">{dateFormat date=$product->available_date full=false}</span> </p> <!-- number of item in stock --> {if ($display_qties == 1 && !$PS_CATALOG_MODE && $product->available_for_order)} <p id="pQuantityAvailable"{if $product->quantity <= 0} style="display: none;"{/if}> <span id="quantityAvailable">{$product->quantity|intval}</span> <span {if $product->quantity > 1} style="display: none;"{/if} id="quantityAvailableTxt">{l s='Item in stock'}</span> <span {if $product->quantity == 1} style="display: none;"{/if} id="quantityAvailableTxtMultiple">{l s='Items in stock'}</span> </p> {/if} <!-- Out of stock hook --> <div id="oosHook"{if $product->quantity > 0} style="display: none;"{/if}> {$HOOK_PRODUCT_OOS} </div> <p class="warning_inline" id="last_quantities"{if ($product->quantity > $last_qties OR $product->quantity <= 0) OR $allow_oosp OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none"{/if} >{l s='Warning: Last items in stock!'}</p> </div> <div class="content_prices clearfix"> <!-- prices --> {if $product->show_price AND !isset($restricted_country_mode) AND !$PS_CATALOG_MODE} {if $product->online_only} <p class="online_only">{l s='Online only'}</p> {/if} <div class="price"> <p class="our_price_display"> {if $priceDisplay >= 0 && $priceDisplay <= 2} <span id="our_price_display">{convertPrice price=$productPrice}</span> <!--{if $tax_enabled && ((isset($display_tax_label) && $display_tax_label == 1) OR !isset($display_tax_label))} {if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if} {/if}--> {/if} </p> {if $product->on_sale} <img src="{$img_dir}onsale_{$lang_iso}.gif" alt="{l s='On sale'}" class="on_sale_img"/> <span class="on_sale">{l s='On sale!'}</span> {elseif $product->specificPrice AND $product->specificPrice.reduction AND $productPriceWithoutReduction > $productPrice} <span class="discount">{l s='Reduced price!'}</span> {/if} {if $priceDisplay == 2} <br /> <span id="pretaxe_price"><span id="pretaxe_price_display">{convertPrice price=$product->getPrice(false, $smarty.const.NULL)}</span> {l s='tax excl.'}</span> {/if} </div> <p id="reduction_percent" {if !$product->specificPrice OR $product->specificPrice.reduction_type != 'percentage'} style="display:none;"{/if}><span id="reduction_percent_display">{if $product->specificPrice AND $product->specificPrice.reduction_type == 'percentage'}-{$product->specificPrice.reduction*100}%{/if}</span></p> <p id="reduction_amount" {if !$product->specificPrice OR $product->specificPrice.reduction_type != 'amount' || $product->specificPrice.reduction|intval ==0} style="display:none"{/if}> <span id="reduction_amount_display"> {if $product->specificPrice AND $product->specificPrice.reduction_type == 'amount' AND $product->specificPrice.reduction|intval !=0} -{convertPrice price=$productPriceWithoutReduction-$productPrice|floatval} {/if} </span> </p> {if $product->specificPrice AND $product->specificPrice.reduction && $product->specificPrice.reduction > 0} <p id="old_price"><span class="bold"> {if $priceDisplay >= 0 && $priceDisplay <= 2} {if $productPriceWithoutReduction > $productPrice} <span id="old_price_display">{convertPrice price=$productPriceWithoutReduction}</span> <!-- {if $tax_enabled && $display_tax_label == 1} {if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if} {/if} --> {/if} {/if} </span> </p> {/if} {if $packItems|@count && $productPrice < $product->getNoPackPrice()} <p class="pack_price">{l s='Instead of'} <span style="text-decoration: line-through;">{convertPrice price=$product->getNoPackPrice()}</span></p> <br class="clear" /> {/if} {if $product->ecotax != 0} <p class="price-ecotax">{l s='Include'} <span id="ecotax_price_display">{if $priceDisplay == 2}{$ecotax_tax_exc|convertAndFormatPrice}{else}{$ecotax_tax_inc|convertAndFormatPrice}{/if}</span> {l s='For green tax'} {if $product->specificPrice AND $product->specificPrice.reduction} <br />{l s='(not impacted by the discount)'} {/if} </p> {/if} {if !empty($product->unity) && $product->unit_price_ratio > 0.000000} {math equation="pprice / punit_price" pprice=$productPrice punit_price=$product->unit_price_ratio assign=unit_price} <p class="unit-price"><span id="unit_price_display">{convertPrice price=$unit_price}</span> {l s='per'} {$product->unity|escape:'htmlall':'UTF-8'}</p> {/if} {*close if for show price*} {/if} {if isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS}{$HOOK_PRODUCT_ACTIONS}{/if} <div class="clear"></div> </div> {/if} {if isset($HOOK_EXTRA_RIGHT) && $HOOK_EXTRA_RIGHT}{$HOOK_EXTRA_RIGHT}{/if} {if isset($product) && $product->customizable} <div id="idTab10" class="bullet customization_block"> <p class="infoCustomizable"> {l s='After saving your customized product, remember to add it to your cart.'} {if $product->uploadable_files}<br />{l s='Allowed file formats are: GIF, JPG, PNG'}{/if} </p> {if $product->uploadable_files|intval} <div class="customizableProductsFile"> <!--<h3>{l s='Pictures'}</h3>--> <ul id="uploadable_files" class="clearfix"> {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 0} <li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='pictures_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if isset($pictures.$key)} <div class="customizationUploadBrowse"> <img src="{$pic_dir}{$pictures.$key}_small" alt="" /> <a href="{$link->getProductDeletePictureLink($product, $field.id_customization_field)}" title="{l s='Delete'}" > <img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" class="customization_delete_icon" width="11" height="13" /> </a> </div> {/if} <div class="customizationUploadBrowse"> <label class="customizationUploadBrowseDescription">{if !empty($field.name)}{$field.name}{else}{l s='Please select an image file from your computer'}{/if}{if $field.required}<sup>*</sup>{/if}</label> <input type="file" name="file{$field.id_customization_field}" id="img{$customizationField}" class="customization_block_input {if isset($pictures.$key)}filled{/if}" /> </div> </li> {counter} {/if} {/foreach} </ul> </div> {/if} {if $product->text_fields|intval} <div class="customizableProductsText"> <!--<h3>{l s='Text'}</h3>--> <ul id="text_fields"> {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <li class="customizationUploadLine{if $field.required} required{/if}"> <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea style="height: 30px;" type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input">{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> </li> {counter} {/if} {/foreach} </ul> </div> {/if} <p id="customizedDatas"> <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> {if (!$allow_oosp && $product->quantity <= 0) OR !$product->available_for_order OR (isset($restricted_country_mode) AND $restricted_country_mode) OR $PS_CATALOG_MODE} <span class="exclusive"> <span></span> {l s=''} </span> {else} <p id="add_to_cart" class="buttons_bottom_block"> <span></span> <input type="submit" name="Submit" value="{l s='Add to cart'}" class="add_to_cart_ft" /> </p> {/if} <span id="ajax-loader" style="display:none"><img src="{$img_ps_dir}loader.gif" alt="loader" /></span> </p> </form> <p class="clear required"><sup>*</sup> {l s='required fields'}</p> </div> {/if} Attached are the files for product.tpl and CartController.php for references There might be some layout problems with the product.tpl because I just copied and paste the containers for the forms. Do adjust accordinly to fit your theme. NOTE: This will not work with the ajax-cart.js that i came up with, it is only for non-ajax cart. Cheers CartController.zip product_combinedform.zip Edited March 31, 2014 by ZenVisuals (see edit history) 1 Link to comment Share on other sites More sharing options...
Alberto Fernández Posted April 11, 2014 Share Posted April 11, 2014 Hey guys, @Rhapsody: Thanks for the feedback! Yeah I didn't bother about the non ajax operation so it didn't work. Good point about the mobile operation, I totally neglected it! I'm glad you updated your codes on the custom theme and got it working I was looking at the non ajax operation and figuring out how the CartController works. Anyway, these are my findings: Since the forms for the customised fields and the other inputs such as the quantity and combination are different and they are posted to ProductController and CartController respectively. To have them submit as one, I combined the inputs into one single form and post it to the CartController only. The CartController then retrieves the $_POST values of all the inputs in the product page including the customised fields. I then override the processChangeProductInCart() method and proceeded with updating the database with the customised fields first then the other inputs. I took codes from the textRecord() in ProductController and changed it to fit the process. It should work without AJAX. However, I didn't update my ajax-cart.js for this so if AJAX is on, I don't think it will work. Perhaps the original ajax-cart.js might work. Another thing is only text-fields and areas will work, the image upload will not work as I never included codes from pictureUpload(). This code should be placed in override/modules/front/CartController.php class CartController extends CartControllerCore { /** * This process add or update a product in the cart */ protected function processChangeProductInCart() { $mode = (Tools::getIsset('update') && $this->id_product) ? 'update' : 'add'; if ($this->qty == 0) $this->errors[] = Tools::displayError('Null quantity.'); else if (!$this->id_product) $this->errors[] = Tools::displayError('Product not found'); $product = new Product($this->id_product, true, $this->context->language->id); if (!$product->id || !$product->active) { $this->errors[] = Tools::displayError('This product is no longer available.', false); return; } // Check product quantity availability if ($this->id_product_attribute) { if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $this->qty)) $this->errors[] = Tools::displayError('There isn\'t enough product in stock.'); } else if ($product->hasAttributes()) { $minimumQuantity = ($product->out_of_stock == 2) ? !Configuration::get('PS_ORDER_OUT_OF_STOCK') : !$product->out_of_stock; $this->id_product_attribute = Product::getDefaultAttribute($product->id, $minimumQuantity); // @todo do something better than a redirect admin !! if (!$this->id_product_attribute) Tools::redirectAdmin($this->context->link->getProductLink($product)); else if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $this->qty)) $this->errors[] = Tools::displayError('There isn\'t enough product in stock.'); } else if (!$product->checkQty($this->qty)) $this->errors[] = Tools::displayError('There isn\'t enough product in stock.'); // If no errors, process product addition if (!$this->errors && $mode == 'add') { // Add cart if no cart found if (!$this->context->cart->id) { if (Context::getContext()->cookie->id_guest) { $guest = new Guest(Context::getContext()->cookie->id_guest); $this->context->cart->mobile_theme = $guest->mobile_theme; } $this->context->cart->add(); if ($this->context->cart->id) $this->context->cookie->id_cart = (int)$this->context->cart->id; } // Process customizable fields first //get product's customized text fields and input them to $field_ids if (!$field_ids = $product->getCustomizationFieldIds()) return false; $authorized_text_fields = array(); $required_fields = $product->getRequiredCustomizableFields(); $required_fieldsArray = array(); //get required field ids foreach ($required_fields as $requiredfield_id) if ($requiredfield_id['type'] == Product::CUSTOMIZE_TEXTFIELD) $required_fieldsArray[(int)$requiredfield_id['id_customization_field']] = 'textField'.(int)$requiredfield_id['id_customization_field']; //$authorized_text_fields[int] = textField[int of id_customization_field]; foreach ($field_ids as $field_id) if ($field_id['type'] == Product::CUSTOMIZE_TEXTFIELD) $authorized_text_fields[(int)$field_id['id_customization_field']] = 'textField'.(int)$field_id['id_customization_field']; //values 1,2,3,4,5,6,7 put into array[textField1,2,3,4,5,6,7] $indexes = array_flip($authorized_text_fields); foreach ($_POST as $field_name => $value) { //filter required fields if (in_array($field_name, $required_fieldsArray) && empty($value)) { // stop and make sure user enters required fields //p(Customization::getLabel($indexes[$field_name],1)) - gets the label of the id_customization_field with id_lang = 1, 1 is English i assume $this->errors[] = Tools::displayError('Please fill this field:' . Customization::getLabel($indexes[$field_name],1)); } else { if (!Validate::isMessage($value)) $this->errors[] = Tools::displayError('Invalid message'); } } // if all required fields are filled, then proceed to add custom fields to database if (!$this->errors) { foreach ($_POST as $field_name => $value) { if (in_array($field_name, $authorized_text_fields)) { $this->context->cart->addTextFieldToProduct($product->id, $indexes[$field_name], Product::CUSTOMIZE_TEXTFIELD, $value); } } } if (!$this->errors) { $cart_rules = $this->context->cart->getCartRules(); $update_quantity = $this->context->cart->updateQty($this->qty, $this->id_product, $this->id_product_attribute, $this->customization_id, Tools::getValue('op', 'up'), $this->id_address_delivery); if ($update_quantity < 0) { // If product has attribute, minimal quantity is set with minimal quantity of attribute $minimal_quantity = ($this->id_product_attribute) ? Attribute::getAttributeMinimalQty($this->id_product_attribute) : $product->minimal_quantity; $this->errors[] = sprintf(Tools::displayError('You must add %d minimum quantity', false), $minimal_quantity); } elseif (!$update_quantity) $this->errors[] = Tools::displayError('You already have the maximum quantity available for this product.', false); elseif ((int)Tools::getValue('allow_refresh')) { // If the cart rules has changed, we need to refresh the whole cart $cart_rules2 = $this->context->cart->getCartRules(); if (count($cart_rules2) != count($cart_rules)) $this->ajax_refresh = true; else { $rule_list = array(); foreach ($cart_rules2 as $rule) $rule_list[] = $rule['id_cart_rule']; foreach ($cart_rules as $rule) if (!in_array($rule['id_cart_rule'], $rule_list)) { $this->ajax_refresh = true; break; } } } } } $removed = CartRule::autoRemoveFromCart(); CartRule::autoAddToCart(); if (count($removed) && (int)Tools::getValue('allow_refresh')) $this->ajax_refresh = true; } } I combined both forms in product.tpl <!-- Customizable products combined with standard inputs--> {if ($product->show_price AND !isset($restricted_country_mode)) OR isset($groups) OR $product->reference OR (isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS)} <!-- add to cart form--> <form id="buy_block" {if $PS_CATALOG_MODE AND !isset($groups) AND $product->quantity > 0}class="hidden"{/if} action="{$link->getPageLink('cart')}" method="post" enctype="multipart/form-data"> <!-- hidden datas --> <p class="hidden"> <input type="hidden" name="token" value="{$static_token}" /> <input type="hidden" name="id_product" value="{$product->id|intval}" id="product_page_product_id" /> <input type="hidden" name="add" value="1" /> <input type="hidden" name="id_product_attribute" id="idCombination" value="" /> </p> <div class="product_attributes"> {if isset($groups)} <!-- attributes --> <div id="attributes"> <div class="clear"></div> {foreach from=$groups key=id_attribute_group item=group} {if $group.attributes|@count} <fieldset class="attribute_fieldset"> <label class="attribute_label" for="group_{$id_attribute_group|intval}">{$group.name|escape:'htmlall':'UTF-8'} : </label> {assign var="groupName" value="group_$id_attribute_group"} <div class="attribute_list"> {if ($group.group_type == 'select')} <select name="{$groupName}" id="group_{$id_attribute_group|intval}" class="attribute_select" onchange="findCombination();getProductAttribute();"> {foreach from=$group.attributes key=id_attribute item=group_attribute} <option value="{$id_attribute|intval}"{if (isset($smarty.get.$groupName) && $smarty.get.$groupName|intval == $id_attribute) || $group.default == $id_attribute} selected="selected"{/if} title="{$group_attribute|escape:'htmlall':'UTF-8'}">{$group_attribute|escape:'htmlall':'UTF-8'}</option> {/foreach} </select> {elseif ($group.group_type == 'color')} <ul id="color_to_pick_list" class="clearfix"> {assign var="default_colorpicker" value=""} {foreach from=$group.attributes key=id_attribute item=group_attribute} <li{if $group.default == $id_attribute} class="selected"{/if}> <a id="color_{$id_attribute|intval}" class="color_pick{if ($group.default == $id_attribute)} selected{/if}" style="background: {$colors.$id_attribute.value};" title="{$colors.$id_attribute.name}" onclick="colorPickerClick(this);getProductAttribute();"> {if file_exists($col_img_dir|cat:$id_attribute|cat:'.jpg')} <img src="{$img_col_dir}{$id_attribute}.jpg" alt="{$colors.$id_attribute.name}" width="20" height="20" /><br /> {/if} </a> </li> {if ($group.default == $id_attribute)} {$default_colorpicker = $id_attribute} {/if} {/foreach} </ul> <input type="hidden" class="color_pick_hidden" name="{$groupName}" value="{$default_colorpicker}" /> {elseif ($group.group_type == 'radio')} <ul> {foreach from=$group.attributes key=id_attribute item=group_attribute} <li> <input type="radio" class="attribute_radio" name="{$groupName}" value="{$id_attribute}" {if ($group.default == $id_attribute)} checked="checked"{/if} onclick="findCombination();getProductAttribute();" /> <span>{$group_attribute|escape:'htmlall':'UTF-8'}</span> </li> {/foreach} </ul> {/if} </div> </fieldset> {/if} {/foreach} </div> {/if} <p id="product_reference" {if isset($groups) OR !$product->reference}style="display: none;"{/if}> <label for="product_reference">{l s='Reference:'} </label> <span class="editable">{$product->reference|escape:'htmlall':'UTF-8'}</span> </p> <!-- quantity wanted --> {if $product->id == 6}{else} <p id="quantity_wanted_p"{if (!$allow_oosp && $product->quantity <= 0) OR $virtual OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> <label>{l s='Quantity:'}</label> <input type="text" name="qty" id="quantity_wanted" class="text" value="{if isset($quantityBackup)}{$quantityBackup|intval}{else}{if $product->minimal_quantity > 1}{$product->minimal_quantity}{else}1{/if}{/if}" size="2" maxlength="3" {if $product->minimal_quantity > 1}onkeyup="checkMinimalQuantity({$product->minimal_quantity});"{/if} /> </p> {/if} <!-- minimal quantity wanted --> <p id="minimal_quantity_wanted_p"{if $product->minimal_quantity <= 1 OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> {l s='This product is not sold individually. You must select at least'} <b id="minimal_quantity_label">{$product->minimal_quantity}</b> {l s='quantity for this product.'} </p> {if $product->minimal_quantity > 1} <script type="text/javascript"> checkMinimalQuantity(); </script> {/if} <!-- availability --> <p id="availability_statut"{if ($product->quantity <= 0 && !$product->available_later && $allow_oosp) OR ($product->quantity > 0 && !$product->available_now) OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none;"{/if}> <span id="availability_label">{l s='Availability:'}</span> <span id="availability_value"{if $product->quantity <= 0} class="warning_inline"{/if}>{if $product->quantity <= 0}{if $allow_oosp}{$product->available_later}{else}{l s='This product is no longer in stock'}{/if}{else}{$product->available_now}{/if}</span> </p> <p id="availability_date"{if ($product->quantity > 0) OR !$product->available_for_order OR $PS_CATALOG_MODE OR !isset($product->available_date) OR $product->available_date < $smarty.now|date_format:'%Y-%m-%d'} style="display: none;"{/if}> <span id="availability_date_label">{l s='Availability date:'}</span> <span id="availability_date_value">{dateFormat date=$product->available_date full=false}</span> </p> <!-- number of item in stock --> {if ($display_qties == 1 && !$PS_CATALOG_MODE && $product->available_for_order)} <p id="pQuantityAvailable"{if $product->quantity <= 0} style="display: none;"{/if}> <span id="quantityAvailable">{$product->quantity|intval}</span> <span {if $product->quantity > 1} style="display: none;"{/if} id="quantityAvailableTxt">{l s='Item in stock'}</span> <span {if $product->quantity == 1} style="display: none;"{/if} id="quantityAvailableTxtMultiple">{l s='Items in stock'}</span> </p> {/if} <!-- Out of stock hook --> <div id="oosHook"{if $product->quantity > 0} style="display: none;"{/if}> {$HOOK_PRODUCT_OOS} </div> <p class="warning_inline" id="last_quantities"{if ($product->quantity > $last_qties OR $product->quantity <= 0) OR $allow_oosp OR !$product->available_for_order OR $PS_CATALOG_MODE} style="display: none"{/if} >{l s='Warning: Last items in stock!'}</p> </div> <div class="content_prices clearfix"> <!-- prices --> {if $product->show_price AND !isset($restricted_country_mode) AND !$PS_CATALOG_MODE} {if $product->online_only} <p class="online_only">{l s='Online only'}</p> {/if} <div class="price"> <p class="our_price_display"> {if $priceDisplay >= 0 && $priceDisplay <= 2} <span id="our_price_display">{convertPrice price=$productPrice}</span> <!--{if $tax_enabled && ((isset($display_tax_label) && $display_tax_label == 1) OR !isset($display_tax_label))} {if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if} {/if}--> {/if} </p> {if $product->on_sale} <img src="{$img_dir}onsale_{$lang_iso}.gif" alt="{l s='On sale'}" class="on_sale_img"/> <span class="on_sale">{l s='On sale!'}</span> {elseif $product->specificPrice AND $product->specificPrice.reduction AND $productPriceWithoutReduction > $productPrice} <span class="discount">{l s='Reduced price!'}</span> {/if} {if $priceDisplay == 2} <br /> <span id="pretaxe_price"><span id="pretaxe_price_display">{convertPrice price=$product->getPrice(false, $smarty.const.NULL)}</span> {l s='tax excl.'}</span> {/if} </div> <p id="reduction_percent" {if !$product->specificPrice OR $product->specificPrice.reduction_type != 'percentage'} style="display:none;"{/if}><span id="reduction_percent_display">{if $product->specificPrice AND $product->specificPrice.reduction_type == 'percentage'}-{$product->specificPrice.reduction*100}%{/if}</span></p> <p id="reduction_amount" {if !$product->specificPrice OR $product->specificPrice.reduction_type != 'amount' || $product->specificPrice.reduction|intval ==0} style="display:none"{/if}> <span id="reduction_amount_display"> {if $product->specificPrice AND $product->specificPrice.reduction_type == 'amount' AND $product->specificPrice.reduction|intval !=0} -{convertPrice price=$productPriceWithoutReduction-$productPrice|floatval} {/if} </span> </p> {if $product->specificPrice AND $product->specificPrice.reduction && $product->specificPrice.reduction > 0} <p id="old_price"><span class="bold"> {if $priceDisplay >= 0 && $priceDisplay <= 2} {if $productPriceWithoutReduction > $productPrice} <span id="old_price_display">{convertPrice price=$productPriceWithoutReduction}</span> <!-- {if $tax_enabled && $display_tax_label == 1} {if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if} {/if} --> {/if} {/if} </span> </p> {/if} {if $packItems|@count && $productPrice < $product->getNoPackPrice()} <p class="pack_price">{l s='Instead of'} <span style="text-decoration: line-through;">{convertPrice price=$product->getNoPackPrice()}</span></p> <br class="clear" /> {/if} {if $product->ecotax != 0} <p class="price-ecotax">{l s='Include'} <span id="ecotax_price_display">{if $priceDisplay == 2}{$ecotax_tax_exc|convertAndFormatPrice}{else}{$ecotax_tax_inc|convertAndFormatPrice}{/if}</span> {l s='For green tax'} {if $product->specificPrice AND $product->specificPrice.reduction} <br />{l s='(not impacted by the discount)'} {/if} </p> {/if} {if !empty($product->unity) && $product->unit_price_ratio > 0.000000} {math equation="pprice / punit_price" pprice=$productPrice punit_price=$product->unit_price_ratio assign=unit_price} <p class="unit-price"><span id="unit_price_display">{convertPrice price=$unit_price}</span> {l s='per'} {$product->unity|escape:'htmlall':'UTF-8'}</p> {/if} {*close if for show price*} {/if} {if isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS}{$HOOK_PRODUCT_ACTIONS}{/if} <div class="clear"></div> </div> {/if} {if isset($HOOK_EXTRA_RIGHT) && $HOOK_EXTRA_RIGHT}{$HOOK_EXTRA_RIGHT}{/if} {if isset($product) && $product->customizable} <div id="idTab10" class="bullet customization_block"> <p class="infoCustomizable"> {l s='After saving your customized product, remember to add it to your cart.'} {if $product->uploadable_files}<br />{l s='Allowed file formats are: GIF, JPG, PNG'}{/if} </p> {if $product->uploadable_files|intval} <div class="customizableProductsFile"> <!--<h3>{l s='Pictures'}</h3>--> <ul id="uploadable_files" class="clearfix"> {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 0} <li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='pictures_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if isset($pictures.$key)} <div class="customizationUploadBrowse"> <img src="{$pic_dir}{$pictures.$key}_small" alt="" /> <a href="{$link->getProductDeletePictureLink($product, $field.id_customization_field)}" title="{l s='Delete'}" > <img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" class="customization_delete_icon" width="11" height="13" /> </a> </div> {/if} <div class="customizationUploadBrowse"> <label class="customizationUploadBrowseDescription">{if !empty($field.name)}{$field.name}{else}{l s='Please select an image file from your computer'}{/if}{if $field.required}<sup>*</sup>{/if}</label> <input type="file" name="file{$field.id_customization_field}" id="img{$customizationField}" class="customization_block_input {if isset($pictures.$key)}filled{/if}" /> </div> </li> {counter} {/if} {/foreach} </ul> </div> {/if} {if $product->text_fields|intval} <div class="customizableProductsText"> <!--<h3>{l s='Text'}</h3>--> <ul id="text_fields"> {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <li class="customizationUploadLine{if $field.required} required{/if}"> <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea style="height: 30px;" type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input">{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> </li> {counter} {/if} {/foreach} </ul> </div> {/if} <p id="customizedDatas"> <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> {if (!$allow_oosp && $product->quantity <= 0) OR !$product->available_for_order OR (isset($restricted_country_mode) AND $restricted_country_mode) OR $PS_CATALOG_MODE} <span class="exclusive"> <span></span> {l s=''} </span> {else} <p id="add_to_cart" class="buttons_bottom_block"> <span></span> <input type="submit" name="Submit" value="{l s='Add to cart'}" class="add_to_cart_ft" /> </p> {/if} <span id="ajax-loader" style="display:none"><img src="{$img_ps_dir}loader.gif" alt="loader" /></span> </p> </form> <p class="clear required"><sup>*</sup> {l s='required fields'}</p> </div> {/if} Attached are the files for product.tpl and CartController.php for references There might be some layout problems with the product.tpl because I just copied and paste the containers for the forms. Do adjust accordinly to fit your theme. NOTE: This will not work with the ajax-cart.js that i came up with, it is only for non-ajax cart. Cheers Nice! Wich versions are supported for this mod? Anyway, hope someone try to mod it for ajax-cart soon! Link to comment Share on other sites More sharing options...
Maxmito Posted April 30, 2014 Share Posted April 30, 2014 Hi all, I'm running 1.5.6.2, i tried all the solution posted here but no success (Ajax mode). Did somone manage to make it work wit 1.5.6.2 too? Thanks Link to comment Share on other sites More sharing options...
Presta_Kev Posted May 3, 2014 Share Posted May 3, 2014 I would also like to add that I downloaded and tried the files above provided by ZenVisuals and it did not work. It added the product to the cart but ignored the customisation field. Just for reference, I tried this on version 1.5.6.1 with Ajax turned off. Link to comment Share on other sites More sharing options...
Junaid Khawaja Posted May 15, 2014 Share Posted May 15, 2014 I am using the Prestashop 1.5.4.1 with default theme and non-ajax cart. The problem is, I've made several customizations to the product page, even though I've added a module to move the product customization elements before the add to cart button. Furthermore, I've added some ajax call to show customization in realtime on the image. The question is: how to do that thing now? Is there any step by step way to do that as I can't figure out with that long discussion. My shop is: http://www.mattgeo.com/ Link to comment Share on other sites More sharing options...
starsg38 Posted May 28, 2014 Share Posted May 28, 2014 Figured out a way to do it granted it's not the correct way and I'm on too short of a deadline to make it clean. Also, only for text fields. I didn't need image upload so I didnt even try with that. See attached. Tested on 1.5.2. Put the file in /overrides/controllers/front/ Requires .tpl modifcation that is fairly straightforward: Remove the save button and put the following code in the form which submits to the cart: {if $product->text_fields|intval} {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input" />{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> {counter} {/if} {/foreach} {/if} <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> Of course all you really need are the inputs. The code is stolen from the other customization area on the page and minified a little. Nothing changed. Be sure to remove the customization form as well. Yes this worked perfectly for me in 1.6! Thanks so much I have been looking for a solution to this problem for so long! I do have an image upload but I just left that in it's original form and labeled the save button as Upload instead of save. Link to comment Share on other sites More sharing options...
Presta_Kev Posted May 31, 2014 Share Posted May 31, 2014 Yes this worked perfectly for me in 1.6! Thanks so much I have been looking for a solution to this problem for so long! I do have an image upload but I just left that in it's original form and labeled the save button as Upload instead of save. I'm still having trouble getting this to work. It seems to add it to the cart but none of the customisation seems to appear. Could you give me any advice as to what I'm doing wrong? I copied the attached file into cart/controllers/front/ I also copied the small code snippet onto the page (under the cart submission) which creates the text input box. But when I click submit, it adds the product to the cart as if there is no customisation option. Is there any advice for what I'm doing wrong? Also, probably worth mentioning that I am trying this on version 1.6.0.6. P.S - Is it also necessary to place the code snippet in a specific part of the .TPL file? Could I place it in a different place in the template? Link to comment Share on other sites More sharing options...
guidor Posted June 16, 2014 Share Posted June 16, 2014 (edited) I'm working with the default theme on prestashop 1.6 When customers fill in the custum fields and forget to push the save button and directly push add to cart we lose the information the customer filled in. PS should auto save the custum fields for them when pressing add to cart! this I thought should be easy but, for me, its not. I hoped to edit the product.tpl and find a "click-on code" that I could copy and paste to the add to cart button. But unfortunatly thats not a slolution. Annybody hav a simple solution for me? I would realy apriciate it! Anybody please Edited June 28, 2014 by guidor (see edit history) Link to comment Share on other sites More sharing options...
guidor Posted June 29, 2014 Share Posted June 29, 2014 I'm working with the default theme on prestashop 1.6 When customers fill in the custum fields and forget to push the save button and directly push add to cart we lose the information the customer filled in. PS should auto save the custum fields for them when pressing add to cart! this I thought should be easy but, for me, its not. I hoped to edit the product.tpl and find a "click-on code" that I could copy and paste to the add to cart button. But unfortunatly thats not a slolution. Annybody hav a simple solution for me? I would realy apriciate it! Anybody please anybody please Link to comment Share on other sites More sharing options...
serperui Posted July 1, 2014 Share Posted July 1, 2014 (edited) same problem. And I don't know how starsg38 in the last post Yes this worked perfectly for me in 1.6! Thanks so much I have been looking for a solution to this problem for so long! I do have an image upload but I just left that in it's original form and labeled the save button as Upload instead of save. not wok! Edited July 1, 2014 by serperui (see edit history) Link to comment Share on other sites More sharing options...
thuxu007 Posted July 23, 2014 Share Posted July 23, 2014 (edited) Figured out a way to do it granted it's not the correct way and I'm on too short of a deadline to make it clean. Also, only for text fields. I didn't need image upload so I didnt even try with that. See attached. Tested on 1.5.2. Put the file in /overrides/controllers/front/ Requires .tpl modifcation that is fairly straightforward: Remove the save button and put the following code in the form which submits to the cart: {if $product->text_fields|intval} {counter start=0 assign='customizationField'} {foreach from=$customizationFields item='field' name='customizationFields'} {if $field.type == 1} <label for ="textField{$customizationField}">{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field} {if !empty($field.name)}{$field.name}{/if}{if $field.required}<sup>*</sup>{/if}</label> <textarea type="text" name="textField{$field.id_customization_field}" id="textField{$customizationField}" rows="1" cols="40" class="customization_block_input" />{if isset($textFields.$key)}{$textFields.$key|stripslashes}{/if}</textarea> {counter} {/if} {/foreach} {/if} <input type="hidden" name="quantityBackup" id="quantityBackup" value="" /> <input type="hidden" name="submitCustomizedDatas" value="1" /> Of course all you really need are the inputs. The code is stolen from the other customization area on the page and minified a little. Nothing changed. Be sure to remove the customization form as well. Good morning, Thanks for sharing with us. I'm using the latest version of prestashop 1.6 and have disabled the ajax. Something is not working for me, when I give "add to cart" tells me "Please fill in all required fields, then save the customization." Does CartController.php file in 1.6 also goes in the / override/controllers/front ? Now I'm testing a 1.5.6.2 and still and work but 1.6 not work please i need you Thank you Edited July 23, 2014 by thuxu007 (see edit history) Link to comment Share on other sites More sharing options...
ryanb4614 Posted July 23, 2014 Share Posted July 23, 2014 Can someone supply the files or instruction for a fix with 1.6.x? I have tried multiple ways as listed here but nothing seems to be working for me. The customizations are not appearing in the cart. Link to comment Share on other sites More sharing options...
bubbleman Posted August 19, 2014 Share Posted August 19, 2014 Hi, someone find a solution to use in 1.6, save customizations and add cart at the same time? Or maybe, when click on Add Product, click hiden over Save button. Thanks. Link to comment Share on other sites More sharing options...
defuzed Posted August 19, 2014 Share Posted August 19, 2014 (edited) I haven't followed this thread in a while so I'm not sure about the findings beyond page 7. But the solutions posted page 7 by Rhapsody ( http://www.prestashop.com/forums/topic/76874-how-to-remove-save-button-for-customized-fields/?p=1140428 ) [for text fields] and my addition for file uploads ( http://www.prestashop.com/forums/topic/76874-how-to-remove-save-button-for-customized-fields/?p=1185115 ) work perfectly on 1.6 ! You will need to disable ajax-cart though since those solutions do not work with ajax cart. I think some modifications for getting it to work with ajax cart have been posted after page 7, just read carefully. Edited August 19, 2014 by defuzed (see edit history) Link to comment Share on other sites More sharing options...
bubbleman Posted August 19, 2014 Share Posted August 19, 2014 Hi defuzed, I have uses the modifications on page 7, but no lucky. Its only for text, but something is not working fine. Frustating.... Link to comment Share on other sites More sharing options...
Martin C Posted September 11, 2014 Share Posted September 11, 2014 Because of all the code snippets, ajax cart or non ajax this topic is totally unreadable Can somebody post the solution for Prestashop 1.6 with ajax cart enabled? Thank in advance! Link to comment Share on other sites More sharing options...
subaru4wd Posted September 18, 2014 Share Posted September 18, 2014 Because of all the code snippets, ajax cart or non ajax this topic is totally unreadable Can somebody post the solution for Prestashop 1.6 with ajax cart enabled? Thank in advance! I agree... I have no clue where to start since this thread is so old and 9 pages long. Can anyone give a clear guide for 1.6 to accomplish this mod?? I seriously need this. Link to comment Share on other sites More sharing options...
Alberto Fernández Posted September 18, 2014 Share Posted September 18, 2014 I agree... I have no clue where to start since this thread is so old and 9 pages long. Can anyone give a clear guide for 1.6 to accomplish this mod?? I seriously need this. If you really need to hide the save button, there is a module for that, works with ajax, for any ps version, has more functions and cost 49,90 €. The module is Advanced customizations and works very well: http://addons.prestashop.com/es/aplicaciones-front-office-prestashop-modulos/6638-advanced-customizations.html You can see it working in my site: http://cincelaser.com/cristaleria/85-copa-gin-tonic-990-ml-en-cajita-regalo.html Link to comment Share on other sites More sharing options...
subaru4wd Posted September 18, 2014 Share Posted September 18, 2014 If you really need to hide the save button, there is a module for that, works with ajax, for any ps version, has more functions and cost 49,90 €. The module is Advanced customizations and works very well: http://addons.prestashop.com/es/aplicaciones-front-office-prestashop-modulos/6638-advanced-customizations.html You can see it working in my site: http://cincelaser.com/cristaleria/85-copa-gin-tonic-990-ml-en-cajita-regalo.html Thank you. That looks to be exactly what I am looking for. Is this your module?? I need to be absolutely sure it will work with my custom paid theme if i am going to spend $70 USD on it. Thanks again. Link to comment Share on other sites More sharing options...
Alberto Fernández Posted September 18, 2014 Share Posted September 18, 2014 Thank you. That looks to be exactly what I am looking for. Is this your module?? I need to be absolutely sure it will work with my custom paid theme if i am going to spend $70 USD on it. Thanks again. it's not my module, I'm a ps user like you that was looking for this a long time too. In case it doesn't work for you you can request a refund. Just only take into account that some paid templates doesn't follow Prestashop's standards, so maybe the developer have to adapt it for you. That was happenned to me. In my case, the users can't delete customized products from block cart but is a template problem that happened before installing the module. Working to solve it. Link to comment Share on other sites More sharing options...
ccjumana Posted October 7, 2014 Share Posted October 7, 2014 hi Am I supposed just to download the zip with the cart.php and the ajax-cart.js and upload it to the server? Sorry if my question sound silly, but I'm not a programmer and I'm trying to solve this by my own. I've uploaded the two files to the server and nothing happens. It seems like it's not overwriting the files. I've already changes the permissions of those 2 files to 777 My shop is running the 1.3.1 version. Thanks in advance Link to comment Share on other sites More sharing options...
cagrie Posted December 22, 2014 Share Posted December 22, 2014 tried everything but cant get it working on 1.6.0.8 modified theme .... Link to comment Share on other sites More sharing options...
dOnkSkie Posted December 24, 2014 Share Posted December 24, 2014 Works great! tried it using ps 1.6.09 Link to comment Share on other sites More sharing options...
web-port.pl Posted January 27, 2015 Share Posted January 27, 2015 (edited) This is solution for AJAX CART Prestashop 1.6.0.9 but which standard module of CART and required field - REMEMBER only change this file \themes\default-bootstrap\js\modules\blockcart\ajax-cart.js /** 2007-2014 PrestaShop** NOTICE OF LICENSE** This source file is subject to the Academic Free License (AFL 3.0)* that is bundled with this package in the file LICENSE.txt.* It is also available through the world-wide-web at this URL:* http://opensource.org/licenses/afl-3.0.php* If you did not receive a copy of the license and are unable to* obtain it through the world-wide-web, please send an email* to [email protected] so we can send you a copy immediately.** DISCLAIMER** Do not edit or add to this file if you wish to upgrade PrestaShop to newer* versions in the future. If you wish to customize PrestaShop for your* needs please refer to http://www.prestashop.com for more information.** @author PrestaShop SA <[email protected]>* @copyright 2007-2014 PrestaShop SA* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)* International Registered Trademark & Property of PrestaShop SA*/$(document).ready(function(){ ajaxCart.overrideButtonsInThePage(); $(document).on('click', '.block_cart_collapse', function(e){ e.preventDefault(); ajaxCart.collapse(); }); $(document).on('click', '.block_cart_expand', function(e){ e.preventDefault(); ajaxCart.expand(); }); var cart_qty = 0; var current_timestamp = parseInt(new Date().getTime() / 1000); if (typeof $('.ajax_cart_quantity').html() == 'undefined' || (typeof generated_date != 'undefined' && generated_date != null && (parseInt(generated_date) + 30) < current_timestamp)) ajaxCart.refresh(); else cart_qty = parseInt($('.ajax_cart_quantity').html()); /* roll over cart */ var cart_block = new HoverWatcher('#header .cart_block'); var shopping_cart = new HoverWatcher('#header .shopping_cart'); if ('ontouchstart' in document.documentElement) { $('.shopping_cart > a:first').on('click', function(e){ e.preventDefault(); }); } $(document).on('touchstart', '#header .shopping_cart a:first', function(){ if ($(this).next('.cart_block:visible').length) $("#header .cart_block").stop(true, true).slideUp(450); else $("#header .cart_block").stop(true, true).slideDown(450); e.preventDefault(); e.stopPropagation(); }); $("#header .shopping_cart a:first").hover( function(){ if (ajaxCart.nb_total_products > 0 || cart_qty > 0) $("#header .cart_block").stop(true, true).slideDown(450); }, function(){ setTimeout(function(){ if (!shopping_cart.isHoveringOver() && !cart_block.isHoveringOver()) $("#header .cart_block").stop(true, true).slideUp(450); }, 200); } ); $("#header .cart_block").hover( function(){ }, function(){ setTimeout(function(){ if (!shopping_cart.isHoveringOver()) $("#header .cart_block").stop(true, true).slideUp(450); }, 200); } ); $(document).on('click', '.delete_voucher', function(e){ e.preventDefault(); $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, async: true, cache: false, url:$(this).attr('href') + '?rand=' + new Date().getTime() }); $(this).parent().parent().remove(); if ($('body').attr('id') == 'order' || $('body').attr('id') == 'order-opc') { if (typeof(updateAddressSelection) != 'undefined') updateAddressSelection(); else location.reload(); } }); $(document).on('click', '#cart_navigation input', function(e){ $(this).prop('disabled', 'disabled').addClass('disabled'); $(this).closest("form").get(0).submit(); }); $(document).on('click', '#layer_cart .cross, #layer_cart .continue, .layer_cart_overlay', function(e){ e.preventDefault(); $('.layer_cart_overlay').hide(); $('#layer_cart').fadeOut('fast'); }); $('#columns #layer_cart, #columns .layer_cart_overlay').detach().prependTo('#columns');});//JS Object : update the cart by ajax actionsvar ajaxCart = { nb_total_products: 0, //override every button in the page in relation to the cart overrideButtonsInThePage : function(){ //for every 'add' buttons... $(document).on('click', '.ajax_add_to_cart_button', function(e){ e.preventDefault(); var idProduct = $(this).data('id-product'); if ($(this).prop('disabled') != 'disabled') ajaxCart.add(idProduct, null, false, this); }); //for product page 'add' button... $(document).on('click', '#add_to_cart button', function(e){ e.preventDefault(); ajaxCart.add($('#product_page_product_id').val(), $('#idCombination').val(), true, null, $('#quantity_wanted').val(), null); }); //for 'delete' buttons in the cart block... $(document).on('click', '.cart_block_list .ajax_cart_block_remove_link', function(e){ e.preventDefault(); // Customized product management var customizationId = 0; var productId = 0; var productAttributeId = 0; var customizableProductDiv = $($(this).parent().parent()).find("div[data-id^=deleteCustomizableProduct_]"); var idAddressDelivery = false; if (customizableProductDiv && $(customizableProductDiv).length) { var ids = customizableProductDiv.data('id').split('_'); if (typeof(ids[1]) != 'undefined') { customizationId = parseInt(ids[1]); productId = parseInt(ids[2]); if (typeof(ids[3]) != 'undefined') productAttributeId = parseInt(ids[3]); if (typeof(ids[4]) != 'undefined') idAddressDelivery = parseInt(ids[4]); } } // Common product management if (!customizationId) { //retrieve idProduct and idCombination from the displayed product in the block cart var firstCut = $(this).parent().parent().data('id').replace('cart_block_product_', ''); firstCut = firstCut.replace('deleteCustomizableProduct_', ''); ids = firstCut.split('_'); productId = parseInt(ids[0]); if (typeof(ids[1]) != 'undefined') productAttributeId = parseInt(ids[1]); if (typeof(ids[2]) != 'undefined') idAddressDelivery = parseInt(ids[2]); } // Removing product from the cart ajaxCart.remove(productId, productAttributeId, customizationId, idAddressDelivery); }); }, // try to expand the cart expand : function(){ if ($('.cart_block_list').hasClass('collapsed')) { $('.cart_block_list.collapsed').slideDown({ duration: 450, complete: function(){ $(this).addClass('expanded').removeClass('collapsed'); } }); // save the expand statut in the user cookie $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseDir + 'modules/blockcart/blockcart-set-collapse.php' + '?rand=' + new Date().getTime(), async: true, cache: false, data: 'ajax_blockcart_display=expand', complete: function(){ $('.block_cart_expand').fadeOut('fast', function(){ $('.block_cart_collapse').fadeIn('fast'); }); } }); } }, // try to collapse the cart collapse : function(){ if ($('.cart_block_list').hasClass('expanded')) { $('.cart_block_list.expanded').slideUp('slow', function(){ $(this).addClass('collapsed').removeClass('expanded'); }); // save the expand statut in the user cookie $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseDir + 'modules/blockcart/blockcart-set-collapse.php' + '?rand=' + new Date().getTime(), async: true, cache: false, data: 'ajax_blockcart_display=collapse' + '&rand=' + new Date().getTime(), complete: function(){ $('.block_cart_collapse').fadeOut('fast', function(){ $('.block_cart_expand').fadeIn('fast'); }); } }); } }, // Fix display when using back and previous browsers buttons refresh : function(){ $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&ajax=true&token=' + static_token, success: function(jsonData) { ajaxCart.updateCart(jsonData); } }); }, // Update the cart information updateCartInformation : function (jsonData, addedFromProductPage){ ajaxCart.updateCart(jsonData); //reactive the button when adding has finished if (addedFromProductPage) { $('#add_to_cart button').removeProp('disabled').removeClass('disabled'); if (!jsonData.hasError || jsonData.hasError == false) $('#add_to_cart button').addClass('added'); else $('#add_to_cart button').removeClass('added'); } else $('.ajax_add_to_cart_button').removeProp('disabled'); }, // close fancybox updateFancyBox : function (){}, // add a product in the cart via ajax /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ add : function(idProduct, idCombination, addedFromProductPage, callerElement, quantity, whishlist){ var addBtn_val = $('#add_to_cart button').val(); if (addedFromProductPage) { //button change, disable and do status text $('#add_to_cart button').prop('disabled', 'disabled').addClass('disabled'); //$('#add_to_cart button').attr('disabled', true).removeClass('exclusive').addClass('exclusive_disabled').val("Processing..."); $('.filled').removeClass('filled'); //not depending on php backend to do validation but jquery $("form#customizationForm .required :input").each(function() { if ($.trim($(this).val()).length == 0) { $(this).css("border", "red 1px solid"); $form_verify = false; $('#add_to_cart button').val(addBtn_val).removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); } else { $(this).removeAttr("style"); $(this).css("height", "30px"); $form_verify = true; } }); if($form_verify) { var cform = $("form#customizationForm"); var cform_data = cform.serialize(); var cform_action = cform.attr("action"); var cform_method = cform.attr("method"); var cform_enctype = cform.attr("enctype"); //use ajax send the customizationForm data, will still be successful even though there is error on PHP side. $.ajax({ type: cform_method, headers: { "cache-control": "no-cache" }, url: cform_action, cache: false, data: cform_data, success: function(response) { //when customizationForm is successfully submitted, proceed to adding product to cart emptyCustomizations(); // adding product now $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&add=1&ajax=true&qty=' + ((quantity && quantity != null) ? quantity : '1') + '&id_product=' + idProduct + '&token=' + static_token + ( (parseInt(idCombination) && idCombination != null) ? '&ipa=' + parseInt(idCombination): ''), success: function(jsonData,textStatus,jqXHR) { // add appliance to whishlist module if (whishlist && !jsonData.errors) WishlistAddProductCart(whishlist[0], idProduct, idCombination, whishlist[1]); //== Pokazywanie okna po dodaniu do koszyka oraz wyczyszczenie listy z wgranymi fotkami /*----------------------------------------------------------------------------------------------------------------------*/ if (!jsonData.hasError) { /*-----------------------------------------------------------------------------------------------------*/ $('#add_to_cart').css('display','none !important'); $('#add_to_cart button').removeProp('disabled').removeClass('disabled'); $('#previews div').html(''); $('.parameters_info').removeClass('show_parameters_info'); /*-----------------------------------------------------------------------------------------------------*/ if (contentOnly) { window.parent.ajaxCart.updateCartInformation(jsonData, addedFromProductPage); } else { ajaxCart.updateCartInformation(jsonData, addedFromProductPage); } if (jsonData.crossSelling) $('.crossseling').html(jsonData.crossSelling); if (idCombination) $(jsonData.products).each(function(){ if (this.id != undefined && this.id == parseInt(idProduct) && this.idCombination == parseInt(idCombination)) if (contentOnly) window.parent.ajaxCart.updateLayer(this); else ajaxCart.updateLayer(this); }); else $(jsonData.products).each(function(){ if (this.id != undefined && this.id == parseInt(idProduct)) if (contentOnly) window.parent.ajaxCart.updateLayer(this); else ajaxCart.updateLayer(this); }); if (contentOnly) parent.$.fancybox.close(); } else { if (contentOnly) { window.parent.ajaxCart.updateCart(jsonData); } else { ajaxCart.updateCart(jsonData); } if (addedFromProductPage) { $('#add_to_cart button').removeProp('disabled').removeClass('disabled'); } else { $(callerElement).removeProp('disabled'); } } /*----------------------------------------------------------------------------------------------------------------------*/ // add the picture to the cart var $element = $(callerElement).parent().parent().find('a.product_image img,a.product_img_link img'); if (!$element.length) $element = $('#bigpic'); var $picture = $element.clone(); var pictureOffsetOriginal = $element.offset(); if ($picture.size()) $picture.css({'position': 'absolute', 'top': pictureOffsetOriginal.top, 'left': pictureOffsetOriginal.left}); var pictureOffset = $picture.offset(); if ($('#cart_block')[0] && $('#cart_block').offset().top && $('#cart_block').offset().left) var cartBlockOffset = $('#cart_block').offset(); else var cartBlockOffset = $('#shopping_cart').offset(); // Check if the block cart is activated for the animation if (cartBlockOffset != undefined && $picture.size()) { $picture.appendTo('body'); $picture.css({ 'position': 'absolute', 'top': $picture.css('top'), 'left': $picture.css('left'), 'z-index': 4242 }) .animate({ 'width': $element.attr('width')*0.66, 'height': $element.attr('height')*0.66, 'opacity': 0.2, 'top': cartBlockOffset.top + 30, 'left': cartBlockOffset.left + 705 }, 1000) .fadeOut(100, function() { ajaxCart.updateCartInformation(jsonData, addedFromProductPage); }); } else ajaxCart.updateCartInformation(jsonData, addedFromProductPage); $('#add_to_cart button').val("Successfully Added!").css("background-color","#74bd00").delay(2000).queue(function(){ $(this).val(addBtn_val).css("background-color","black"); }); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert("Impossible to add the product to the cart.\n\ntextStatus: '" + textStatus + "'\nerrorThrown: '" + errorThrown + "'\nresponseText:\n" + XMLHttpRequest.responseText); //reactive the button when adding has finished if (addedFromProductPage) $('#add_to_cart button').removeProp('disabled').removeClass('disabled'); else $(callerElement).removeProp('disabled'); } }); }, error: function(response) { alert("error: " + response.error); } }); } else { alert("Please fill in the required fields"); } } else { $(callerElement).attr('disabled', true); } if ($('#cart_block_list').hasClass('collapsed')) this.expand(); }, /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ //remove a product from the cart via ajax remove : function(idProduct, idCombination, customizationId, idAddressDelivery){ //send the ajax request to the server $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&delete=1&id_product=' + idProduct + '&ipa=' + ((idCombination != null && parseInt(idCombination)) ? idCombination : '') + ((customizationId && customizationId != null) ? '&id_customization=' + customizationId : '') + '&id_address_delivery=' + idAddressDelivery + '&token=' + static_token + '&ajax=true', success: function(jsonData) { ajaxCart.updateCart(jsonData); if ($('body').attr('id') == 'order' || $('body').attr('id') == 'order-opc') deleteProductFromSummary(idProduct+'_'+idCombination+'_'+customizationId+'_'+idAddressDelivery); }, error: function() { var error = 'ERROR: unable to delete the product'; if (!!$.prototype.fancybox) { $.fancybox.open([ { type: 'inline', autoScale: true, minHeight: 30, content: error } ], { padding: 0 }); } else alert(error); } }); }, //hide the products displayed in the page but no more in the json data hideOldProducts : function(jsonData){ //delete an eventually removed product of the displayed cart (only if cart is not empty!) if ($('.cart_block_list:first dl.products').length > 0) { var removedProductId = null; var removedProductData = null; var removedProductDomId = null; //look for a product to delete... $('.cart_block_list:first dl.products dt').each(function(){ //retrieve idProduct and idCombination from the displayed product in the block cart var domIdProduct = $(this).data('id'); var firstCut = domIdProduct.replace('cart_block_product_', ''); var ids = firstCut.split('_'); //try to know if the current product is still in the new list var stayInTheCart = false; for (aProduct in jsonData.products) { //we've called the variable aProduct because IE6 bug if this variable is called product //if product has attributes if (jsonData.products[aProduct]['id'] == ids[0] && (!ids[1] || jsonData.products[aProduct]['idCombination'] == ids[1])) { stayInTheCart = true; // update the product customization display (when the product is still in the cart) ajaxCart.hideOldProductCustomizations(jsonData.products[aProduct], domIdProduct); } } //remove product if it's no more in the cart if (!stayInTheCart) { removedProductId = $(this).data('id'); if (removedProductId != null) { var firstCut = removedProductId.replace('cart_block_product_', ''); var ids = firstCut.split('_'); $('dt[data-id=' + removedProductId + ']').addClass('strike').fadeTo('slow', 0, function(){ $(this).slideUp('slow', function(){ $(this).remove(); // If the cart is now empty, show the 'no product in the cart' message and close detail if($('.cart_block:first dl.products dt').length == 0) { $("#header .cart_block").stop(true, true).slideUp(200); $('.cart_block_no_products:hidden').slideDown(450); $('.cart_block dl.products').remove(); } }); }); $('dd[data-id="cart_block_combination_of_' + ids[0] + (ids[1] ? '_'+ids[1] : '') + (ids[2] ? '_'+ids[2] : '') + '"]').fadeTo('fast', 0, function(){ $(this).slideUp('fast', function(){ $(this).remove(); }); }); } } }); } }, hideOldProductCustomizations : function (product, domIdProduct){ var customizationList = $('ul[data-id=customization_' + product['id] + '_' + product['idCombination'] + '"]'); if(customizationList.length > 0) { $(customizationList).find("li").each(function(){ $(this).find("div").each(function(){ var customizationDiv = $(this).data('id'); var tmp = customizationDiv.replace('deleteCustomizableProduct_', ''); var ids = tmp.split('_'); if ((parseInt(product.idCombination) == parseInt(ids[2])) && !ajaxCart.doesCustomizationStillExist(product, ids[0])) $('div[data-id=' + customizationDiv + ']').parent().addClass('strike').fadeTo('slow', 0, function(){ $(this).slideUp('slow'); $(this).remove(); }); }); }); } var removeLinks = $('.deleteCustomizableProduct[data-id=' + domIdProduct + ']').find('.ajax_cart_block_remove_link'); if (!product.hasCustomizedDatas && !removeLinks.length) $('div[data-id=' + domIdProduct + ']' + ' span.remove_link').html('<a class="ajax_cart_block_remove_link" rel="nofollow" href="' + baseUri + '?controller=cart&delete=1&id_product=' + product['id'] + '&ipa=' + product['idCombination'] + '&token=' + static_token + '"> </a>'); if (product.is_gift) $('div[data-id=' + domIdProduct + ']' + ' span.remove_link').html(''); }, doesCustomizationStillExist : function (product, customizationId){ var exists = false; $(product.customizedDatas).each(function(){ if (this.customizationId == customizationId) { exists = true; // This return does not mean that we found nothing but simply break the loop return false; } }); return (exists); }, //refresh display of vouchers (needed for vouchers in % of the total) refreshVouchers : function (jsonData){ if (typeof(jsonData.discounts) == 'undefined' || jsonData.discounts.length == 0) $('.vouchers').hide(); else { $('.vouchers tbody').html(''); for (i=0;i<jsonData.discounts.length;i++) { if (parseFloat(jsonData.discounts.price_float) > 0) { var delete_link = ''; if (jsonData.discounts.code.length) delete_link = '<a class="delete_voucher" href="'+jsonData.discounts.link+'" title="'+delete_txt+'"><i class="icon-remove-sign"></i></a>'; $('.vouchers tbody').append($( '<tr class="bloc_cart_voucher" data-id="bloc_cart_voucher_'+jsonData.discounts.id+'">' +' <td class="quantity">1x</td>' +' <td class="name" title="'+jsonData.discounts.description+'">'+jsonData.discounts.name+'</td>' +' <td class="price">-'+jsonData.discounts.price+'</td>' +' <td class="delete">' + delete_link + '</td>' +'</tr>' )); } } $('.vouchers').show(); } }, // Update product quantity updateProductQuantity : function (product, quantity){ $('dt[data-id=cart_block_product_' + product.id + '_' + (product.idCombination ? product.idCombination : '0')+ '_' + (product.idAddressDelivery ? product.idAddressDelivery : '0') + '] .quantity').fadeTo('fast', 0, function(){ $(this).text(quantity); $(this).fadeTo('fast', 1, function(){ $(this).fadeTo('fast', 0, function(){ $(this).fadeTo('fast', 1, function(){ $(this).fadeTo('fast', 0, function(){ $(this).fadeTo('fast', 1); }); }); }); }); }); }, //display the products witch are in json data but not already displayed displayNewProducts : function(jsonData){ //add every new products or update displaying of every updated products $(jsonData.products).each(function(){ //fix ie6 bug (one more item 'undefined' in IE6) if (this.id != undefined) { //create a container for listing the products and hide the 'no product in the cart' message (only if the cart was empty) if ($('.cart_block:first dl.products').length == 0) { $('.cart_block_no_products').before('<dl class="products"></dl>'); $('.cart_block_no_products').hide(); } //if product is not in the displayed cart, add a new product's line var domIdProduct = this.id + '_' + (this.idCombination ? this.idCombination : '0') + '_' + (this.idAddressDelivery ? this.idAddressDelivery : '0'); var domIdProductAttribute = this.id + '_' + (this.idCombination ? this.idCombination : '0'); if ($('dt[data-id=cart_block_product_' + domIdProduct + ']').length == 0) { var productId = parseInt(this.id); var productAttributeId = (this.hasAttributes ? parseInt(this.attributes) : 0); var content = '<dt class="unvisible" data-id="cart_block_product_' + domIdProduct + '">'; var name = $.trim($('<span />').html(this.name).text()); name = (name.length > 12 ? name.substring(0, 10) + '...' : name); content += '<a class="cart-images" href="' + this.link + '" title="' + name + '"><img src="' + this.image_cart + '" alt="' + this.name +'"></a>'; content += '<div class="cart-info"><div class="product-name">' + '<span class="quantity-formated"><span class="quantity">' + this.quantity + '</span> x </span><a href="' + this.link + '" title="' + this.name + '" class="cart_block_product_name">' + name + '</a></div>'; if (this.hasAttributes) content += '<div class="product-atributes"><a href="' + this.link + '" title="' + this.name + '">' + this.attributes + '</a></div>'; if (typeof(freeProductTranslation) != 'undefined') content += '<span class="price">' + (parseFloat(this.price_float) > 0 ? this.priceByLine : freeProductTranslation) + '</span></div>'; if (typeof(this.is_gift) == 'undefined' || this.is_gift == 0) content += '<span class="remove_link"><a rel="nofollow" class="ajax_cart_block_remove_link" href="' + baseUri + '?controller=cart&delete=1&id_product=' + productId + '&token=' + static_token + (this.hasAttributes ? '&ipa=' + parseInt(this.idCombination) : '') + '"> </a></span>'; else content += '<span class="remove_link"></span>'; content += '</dt>'; if (this.hasAttributes) content += '<dd data-id="cart_block_combination_of_' + domIdProduct + '" class="unvisible">'; if (this.hasCustomizedDatas) content += ajaxCart.displayNewCustomizedDatas(this); if (this.hasAttributes) content += '</dd>'; $('.cart_block dl.products').append(content); } //else update the product's line else { var jsonProduct = this; if($.trim($('dt[data-id=cart_block_product_' + domIdProduct + '] .quantity').html()) != jsonProduct.quantity || $.trim($('dt[data-id=cart_block_product_' + domIdProduct + '] .price').html()) != jsonProduct.priceByLine) { // Usual product if (!this.is_gift) $('dt[data-id=cart_block_product_' + domIdProduct + '] .price').text(jsonProduct.priceByLine); else $('dt[data-id=cart_block_product_' + domIdProduct + '] .price').html(freeProductTranslation); ajaxCart.updateProductQuantity(jsonProduct, jsonProduct.quantity); // Customized product if (jsonProduct.hasCustomizedDatas) { customizationFormatedDatas = ajaxCart.displayNewCustomizedDatas(jsonProduct); if (!$('ul[data-id=customization_' + domIdProductAttribute + ']').length) { if (jsonProduct.hasAttributes) $('dd[data-id=cart_block_combination_of_' + domIdProduct + ']').append(customizationFormatedDatas); else $('.cart_block dl.products').append(customizationFormatedDatas); } else { $('ul[data-id=customization_' + domIdProductAttribute + ']').html(''); $('ul[data-id=customization_' + domIdProductAttribute + ']').append(customizationFormatedDatas); } } } } $('.cart_block dl.products .unvisible').slideDown(450).removeClass('unvisible'); var removeLinks = $('dt[data-id=cart_block_product_' + domIdProduct + ']').find('a.ajax_cart_block_remove_link'); if (this.hasCustomizedDatas && removeLinks.length) $(removeLinks).each(function(){ $(this).remove(); }); } }); }, displayNewCustomizedDatas : function(product){ var content = ''; var productId = parseInt(product.id); var productAttributeId = typeof(product.idCombination) == 'undefined' ? 0 : parseInt(product.idCombination); var hasAlreadyCustomizations = $('ul[data-id=customization_' + productId + '_' + productAttributeId + ']').length; if (!hasAlreadyCustomizations) { if (!product.hasAttributes) content += '<dd data-id="cart_block_combination_of_' + productId + '" class="unvisible">'; if ($('ul[data-id=customization_' + productId + '_' + productAttributeId + ']').val() == undefined) content += '<ul class="cart_block_customizations" data-id="customization_' + productId + '_' + productAttributeId + '">'; } $(product.customizedDatas).each(function(){ var done = 0; customizationId = parseInt(this.customizationId); productAttributeId = typeof(product.idCombination) == 'undefined' ? 0 : parseInt(product.idCombination); content += '<li name="customization"><div class="deleteCustomizableProduct" data-id="deleteCustomizableProduct_' + customizationId + '_' + productId + '_' + (productAttributeId ? productAttributeId : '0') + '"><a rel="nofollow" class="ajax_cart_block_remove_link" href="' + baseUri + '?controller=cart&delete=1&id_product=' + productId + '&ipa=' + productAttributeId + '&id_customization=' + customizationId + '&token=' + static_token + '"></a></div>'; // Give to the customized product the first textfield value as name $(this.datas).each(function(){ if (this['type'] == CUSTOMIZE_TEXTFIELD) { $(this.datas).each(function(){ if (this['index'] == 0) { content += ' ' + this.truncatedValue.replace(/<br \/>/g, ' '); done = 1; return false; } }) } }); // If the customized product did not have any textfield, it will have the customizationId as name if (!done) content += customizationIdMessage + customizationId; if (!hasAlreadyCustomizations) content += '</li>'; // Field cleaning if (customizationId) { $('#uploadable_files li div.customizationUploadBrowse img').remove(); $('#text_fields input').attr('value', ''); } }); if (!hasAlreadyCustomizations) { content += '</ul>'; if (!product.hasAttributes) content += '</dd>'; } return (content); }, updateLayer : function(product){ $('#layer_cart_product_title').text(product.name); $('#layer_cart_product_attributes').text(''); if (product.hasAttributes && product.hasAttributes == true) $('#layer_cart_product_attributes').html(product.attributes); $('#layer_cart_product_price').text(product.price); $('#layer_cart_product_quantity').text(product.quantity); $('.layer_cart_img').html('<img class="layer_cart_img img-responsive" src="' + product.image + '" alt="' + product.name + '" title="' + product.name + '" />'); var n = parseInt($(window).scrollTop()) + 'px'; $('.layer_cart_overlay').css('width','100%'); $('.layer_cart_overlay').css('height','100%'); $('.layer_cart_overlay').show(); $('#layer_cart').css({'top': n}).fadeIn('fast'); crossselling_serialScroll(); }, //genarally update the display of the cart updateCart : function(jsonData){ //user errors display if (jsonData.hasError) { var errors = ''; for (error in jsonData.errors) //IE6 bug fix if (error != 'indexOf') errors += $('<div />').html(jsonData.errors[error]).text() + "\n"; if (!!$.prototype.fancybox) $.fancybox.open([ { type: 'inline', autoScale: true, minHeight: 30, content: '<p class="fancybox-error">' + errors + '</p>' } ], { padding: 0 }); else alert(errors); } else { ajaxCart.updateCartEverywhere(jsonData); ajaxCart.hideOldProducts(jsonData); ajaxCart.displayNewProducts(jsonData); ajaxCart.refreshVouchers(jsonData); //update 'first' and 'last' item classes $('.cart_block .products dt').removeClass('first_item').removeClass('last_item').removeClass('item'); $('.cart_block .products dt:first').addClass('first_item'); $('.cart_block .products dt:not(:first,:last)').addClass('item'); $('.cart_block .products dt:last').addClass('last_item'); } }, //update general cart informations everywhere in the page updateCartEverywhere : function(jsonData){ $('.ajax_cart_total').text($.trim(jsonData.productTotal)); if (parseFloat(jsonData.shippingCostFloat) > 0) $('.ajax_cart_shipping_cost').text(jsonData.shippingCost); else if (typeof(freeShippingTranslation) != 'undefined') $('.ajax_cart_shipping_cost').html(freeShippingTranslation); $('.ajax_cart_tax_cost').text(jsonData.taxCost); $('.cart_block_wrapping_cost').text(jsonData.wrappingCost); $('.ajax_block_cart_total').text(jsonData.total); $('.ajax_block_products_total').text(jsonData.productTotal); $('.ajax_total_price_wt').text(jsonData.total_price_wt); if (parseFloat(jsonData.freeShippingFloat) > 0) { $('.ajax_cart_free_shipping').html(jsonData.freeShipping); $('.freeshipping').fadeIn(0); } else if (parseFloat(jsonData.freeShippingFloat) == 0) $('.freeshipping').fadeOut(0); this.nb_total_products = jsonData.nbTotalProducts; if (parseInt(jsonData.nbTotalProducts) > 0) { $('.ajax_cart_no_product').hide(); $('.ajax_cart_quantity').text(jsonData.nbTotalProducts); $('.ajax_cart_quantity').fadeIn('slow'); $('.ajax_cart_total').fadeIn('slow'); if (parseInt(jsonData.nbTotalProducts) > 1) { $('.ajax_cart_product_txt').each( function (){ $(this).hide(); }); $('.ajax_cart_product_txt_s').each( function (){ $(this).show(); }); } else { $('.ajax_cart_product_txt').each( function (){ $(this).show(); }); $('.ajax_cart_product_txt_s').each( function (){ $(this).hide(); }); } } else { $('.ajax_cart_quantity, .ajax_cart_product_txt_s, .ajax_cart_product_txt, .ajax_cart_total').each(function(){ $(this).hide(); }); $('.ajax_cart_no_product').show('slow'); } }};function HoverWatcher(selector){ this.hovering = false; var self = this; this.isHoveringOver = function(){ return self.hovering; } $(selector).hover(function(){ self.hovering = true; }, function(){ self.hovering = false; })}function crossselling_serialScroll(){ if (!!$.prototype.bxSlider) $('#blockcart_caroucel').bxSlider({ minSlides: 2, maxSlides: 4, slideWidth: 178, slideMargin: 20, moveSlides: 1, infiniteLoop: false, hideControlOnEnd: true, pager: false });} Edited January 27, 2015 by netark2 (see edit history) Link to comment Share on other sites More sharing options...
web-port.pl Posted January 27, 2015 Share Posted January 27, 2015 Solution for Prestashop 1.6.0.11 - AJAX CART no mod for core code aby fields in customization: /** 2007-2015 PrestaShop** NOTICE OF LICENSE** This source file is subject to the Academic Free License (AFL 3.0)* that is bundled with this package in the file LICENSE.txt.* It is also available through the world-wide-web at this URL:* http://opensource.org/licenses/afl-3.0.php* If you did not receive a copy of the license and are unable to* obtain it through the world-wide-web, please send an email* to [email protected] so we can send you a copy immediately.** DISCLAIMER** Do not edit or add to this file if you wish to upgrade PrestaShop to newer* versions in the future. If you wish to customize PrestaShop for your* needs please refer to http://www.prestashop.com for more information.** @author PrestaShop SA <[email protected]>* @copyright 2007-2015 PrestaShop SA* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)* International Registered Trademark & Property of PrestaShop SA*/$(document).ready(function(){ ajaxCart.overrideButtonsInThePage(); $(document).on('click', '.block_cart_collapse', function(e){ e.preventDefault(); ajaxCart.collapse(); }); $(document).on('click', '.block_cart_expand', function(e){ e.preventDefault(); ajaxCart.expand(); }); var cart_qty = 0; var current_timestamp = parseInt(new Date().getTime() / 1000); if (typeof $('.ajax_cart_quantity').html() == 'undefined' || (typeof generated_date != 'undefined' && generated_date != null && (parseInt(generated_date) + 30) < current_timestamp)) ajaxCart.refresh(); else cart_qty = parseInt($('.ajax_cart_quantity').html()); /* roll over cart */ var cart_block = new HoverWatcher('#header .cart_block'); var shopping_cart = new HoverWatcher('#header .shopping_cart'); var is_touch_enabled = false; if ('ontouchstart' in document.documentElement) is_touch_enabled = true; $(document).on('click', '#header .shopping_cart > a:first', function(e){ e.preventDefault(); e.stopPropagation(); // Simulate hover when browser says device is touch based if (is_touch_enabled) { if ($(this).next('.cart_block:visible').length && !cart_block.isHoveringOver()) $("#header .cart_block").stop(true, true).slideUp(450); else if (ajaxCart.nb_total_products > 0 || cart_qty > 0) $("#header .cart_block").stop(true, true).slideDown(450); return; } else window.location.href = $(this).attr('href'); }); $("#header .shopping_cart a:first").hover( function(){ if (ajaxCart.nb_total_products > 0 || cart_qty > 0) $("#header .cart_block").stop(true, true).slideDown(450); }, function(){ setTimeout(function(){ if (!shopping_cart.isHoveringOver() && !cart_block.isHoveringOver()) $("#header .cart_block").stop(true, true).slideUp(450); }, 200); } ); $("#header .cart_block").hover( function(){ }, function(){ setTimeout(function(){ if (!shopping_cart.isHoveringOver()) $("#header .cart_block").stop(true, true).slideUp(450); }, 200); } ); $(document).on('click', '.delete_voucher', function(e){ e.preventDefault(); $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, async: true, cache: false, url:$(this).attr('href') + '?rand=' + new Date().getTime() }); $(this).parent().parent().remove(); if ($('body').attr('id') == 'order' || $('body').attr('id') == 'order-opc') { if (typeof(updateAddressSelection) != 'undefined') updateAddressSelection(); else location.reload(); } }); $(document).on('click', '#cart_navigation input', function(e){ $(this).prop('disabled', 'disabled').addClass('disabled'); $(this).closest("form").get(0).submit(); }); $(document).on('click', '#layer_cart .cross, #layer_cart .continue, .layer_cart_overlay', function(e){ e.preventDefault(); $('.layer_cart_overlay').hide(); $('#layer_cart').fadeOut('fast'); }); $('#columns #layer_cart, #columns .layer_cart_overlay').detach().prependTo('#columns');});//JS Object : update the cart by ajax actionsvar ajaxCart = { nb_total_products: 0, //override every button in the page in relation to the cart overrideButtonsInThePage : function(){ //for every 'add' buttons... $(document).on('click', '.ajax_add_to_cart_button', function(e){ e.preventDefault(); var idProduct = parseInt($(this).data('id-product')); var minimalQuantity = parseInt($(this).data('minimal_quantity')); if (!minimalQuantity) minimalQuantity = 1; if ($(this).prop('disabled') != 'disabled') ajaxCart.add(idProduct, null, false, this, minimalQuantity); }); //for product page 'add' button... $(document).on('click', '#add_to_cart button', function(e){ e.preventDefault(); ajaxCart.add($('#product_page_product_id').val(), $('#idCombination').val(), true, null, $('#quantity_wanted').val(), null); }); //for 'delete' buttons in the cart block... $(document).on('click', '.cart_block_list .ajax_cart_block_remove_link', function(e){ e.preventDefault(); // Customized product management var customizationId = 0; var productId = 0; var productAttributeId = 0; var customizableProductDiv = $($(this).parent().parent()).find("div[data-id^=deleteCustomizableProduct_]"); var idAddressDelivery = false; if (customizableProductDiv && $(customizableProductDiv).length) { var ids = customizableProductDiv.data('id').split('_'); if (typeof(ids[1]) != 'undefined') { customizationId = parseInt(ids[1]); productId = parseInt(ids[2]); if (typeof(ids[3]) != 'undefined') productAttributeId = parseInt(ids[3]); if (typeof(ids[4]) != 'undefined') idAddressDelivery = parseInt(ids[4]); } } // Common product management if (!customizationId) { //retrieve idProduct and idCombination from the displayed product in the block cart var firstCut = $(this).parent().parent().data('id').replace('cart_block_product_', ''); firstCut = firstCut.replace('deleteCustomizableProduct_', ''); ids = firstCut.split('_'); productId = parseInt(ids[0]); if (typeof(ids[1]) != 'undefined') productAttributeId = parseInt(ids[1]); if (typeof(ids[2]) != 'undefined') idAddressDelivery = parseInt(ids[2]); } // Removing product from the cart ajaxCart.remove(productId, productAttributeId, customizationId, idAddressDelivery); }); }, // try to expand the cart expand : function(){ if ($('.cart_block_list').hasClass('collapsed')) { $('.cart_block_list.collapsed').slideDown({ duration: 450, complete: function(){ $(this).parent().show(); // parent is hidden in global.js::accordion() $(this).addClass('expanded').removeClass('collapsed'); } }); // save the expand statut in the user cookie $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseDir + 'modules/blockcart/blockcart-set-collapse.php' + '?rand=' + new Date().getTime(), async: true, cache: false, data: 'ajax_blockcart_display=expand', complete: function(){ $('.block_cart_expand').fadeOut('fast', function(){ $('.block_cart_collapse').fadeIn('fast'); }); } }); } }, // try to collapse the cart collapse : function(){ if ($('.cart_block_list').hasClass('expanded')) { $('.cart_block_list.expanded').slideUp('slow', function(){ $(this).addClass('collapsed').removeClass('expanded'); }); // save the expand statut in the user cookie $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseDir + 'modules/blockcart/blockcart-set-collapse.php' + '?rand=' + new Date().getTime(), async: true, cache: false, data: 'ajax_blockcart_display=collapse' + '&rand=' + new Date().getTime(), complete: function(){ $('.block_cart_collapse').fadeOut('fast', function(){ $('.block_cart_expand').fadeIn('fast'); }); } }); } }, // Fix display when using back and previous browsers buttons refresh : function(){ $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&ajax=true&token=' + static_token, success: function(jsonData) { ajaxCart.updateCart(jsonData); } }); }, // Update the cart information updateCartInformation : function (jsonData, addedFromProductPage){ ajaxCart.updateCart(jsonData); //reactive the button when adding has finished if (addedFromProductPage) { $('#add_to_cart button').removeProp('disabled').removeClass('disabled'); if (!jsonData.hasError || jsonData.hasError == false) $('#add_to_cart button').addClass('added'); else $('#add_to_cart button').removeClass('added'); } else $('.ajax_add_to_cart_button').removeProp('disabled'); }, // close fancybox updateFancyBox : function (){}, // add a product in the cart via ajax /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ add : function(idProduct, idCombination, addedFromProductPage, callerElement, quantity, whishlist) { var addBtn_val = $('#add_to_cart button').val(); if (addedFromProductPage) { //button change, disable and do status text $('#add_to_cart button').prop('disabled', 'disabled').addClass('disabled'); //$('#add_to_cart button').attr('disabled', true).removeClass('exclusive').addClass('exclusive_disabled').val("Processing..."); $('.filled').removeClass('filled'); //not depending on php backend to do validation but jquery $("form#customizationForm .customizationUploadLine :input").each(function() { if ($.trim($(this).val()).length == 0) { $(this).css("border", "red 1px solid"); $form_verify = false; $('#add_to_cart button').val(addBtn_val).removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); } else { $(this).removeAttr("style"); $(this).css("height", "30px"); $form_verify = true; } }); if($form_verify) { var cform = $("form#customizationForm"); var cform_data = cform.serialize(); var cform_action = cform.attr("action"); var cform_method = cform.attr("method"); var cform_enctype = cform.attr("enctype"); //use ajax send the customizationForm data, will still be successful even though there is error on PHP side. $.ajax({ type: cform_method, headers: { "cache-control": "no-cache" }, url: cform_action, cache: false, data: cform_data, success: function(response) { //when customizationForm is successfully submitted, proceed to adding product to cart emptyCustomizations(); // adding product now $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&add=1&ajax=true&qty=' + ((quantity && quantity != null) ? quantity : '1') + '&id_product=' + idProduct + '&token=' + static_token + ( (parseInt(idCombination) && idCombination != null) ? '&ipa=' + parseInt(idCombination): ''), success: function(jsonData,textStatus,jqXHR) { // add appliance to whishlist module if (whishlist && !jsonData.errors) WishlistAddProductCart(whishlist[0], idProduct, idCombination, whishlist[1]); //== Pokazywanie okna po dodaniu do koszyka oraz wyczyszczenie listy z wgranymi fotkami /*----------------------------------------------------------------------------------------------------------------------*/ if (!jsonData.hasError) { /*-----------------------------------------------------------------------------------------------------*/ $('#add_to_cart').css('display','none !important'); $('#add_to_cart button').val(addBtn_val).removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); //$('#add_to_cart button').removeProp('disabled').removeClass('disabled'); $('#previews div').html(''); $('.parameters_info').removeClass('show_parameters_info'); /*-----------------------------------------------------------------------------------------------------*/ if (contentOnly) { window.parent.ajaxCart.updateCartInformation(jsonData, addedFromProductPage); } else { ajaxCart.updateCartInformation(jsonData, addedFromProductPage); } if (jsonData.crossSelling) $('.crossseling').html(jsonData.crossSelling); if (idCombination) $(jsonData.products).each(function(){ if (this.id != undefined && this.id == parseInt(idProduct) && this.idCombination == parseInt(idCombination)) if (contentOnly) window.parent.ajaxCart.updateLayer(this); else ajaxCart.updateLayer(this); }); else $(jsonData.products).each(function(){ if (this.id != undefined && this.id == parseInt(idProduct)) if (contentOnly) window.parent.ajaxCart.updateLayer(this); else ajaxCart.updateLayer(this); }); if (contentOnly) parent.$.fancybox.close(); } else { if (contentOnly) { window.parent.ajaxCart.updateCart(jsonData); } else { ajaxCart.updateCart(jsonData); } if (addedFromProductPage) { $('#add_to_cart button').val(addBtn_val).removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); //$('#add_to_cart button').removeProp('disabled').removeClass('disabled'); } else { $(callerElement).removeProp('disabled'); } } /*----------------------------------------------------------------------------------------------------------------------*/ // add the picture to the cart var $element = $(callerElement).parent().parent().find('a.product_image img,a.product_img_link img'); if (!$element.length) $element = $('#bigpic'); var $picture = $element.clone(); var pictureOffsetOriginal = $element.offset(); if ($picture.size()) $picture.css({'position': 'absolute', 'top': pictureOffsetOriginal.top, 'left': pictureOffsetOriginal.left}); var pictureOffset = $picture.offset(); if ($('#cart_block')[0] && $('#cart_block').offset().top && $('#cart_block').offset().left) var cartBlockOffset = $('#cart_block').offset(); else var cartBlockOffset = $('#shopping_cart').offset(); // Check if the block cart is activated for the animation if (cartBlockOffset != undefined && $picture.size()) { $picture.appendTo('body'); $picture.css({ 'position': 'absolute', 'top': $picture.css('top'), 'left': $picture.css('left'), 'z-index': 4242 }) .animate({ 'width': $element.attr('width')*0.66, 'height': $element.attr('height')*0.66, 'opacity': 0.2, 'top': cartBlockOffset.top + 30, 'left': cartBlockOffset.left + 705 }, 1000) .fadeOut(100, function() { ajaxCart.updateCartInformation(jsonData, addedFromProductPage); }); } else ajaxCart.updateCartInformation(jsonData, addedFromProductPage); $('#add_to_cart button').val("Successfully Added!").css("background-color","#74bd00").delay(2000).queue(function(){ $(this).val(addBtn_val).css("background-color","black"); }); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert("Impossible to add the product to the cart.\n\ntextStatus: '" + textStatus + "'\nerrorThrown: '" + errorThrown + "'\nresponseText:\n" + XMLHttpRequest.responseText); //reactive the button when adding has finished if (addedFromProductPage) $('#add_to_cart button').val(addBtn_val).removeAttr('disabled').addClass('exclusive').removeClass('exclusive_disabled'); //$('#add_to_cart button').removeProp('disabled').removeClass('disabled'); else $(callerElement).removeProp('disabled'); } }); }, error: function(response) { alert("error: " + response.error); } }); } else { alert("Please fill in the required fields"); } } else { $(callerElement).attr('disabled', true); } if ($('#cart_block_list').hasClass('collapsed')) this.expand(); },/*----------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ //remove a product from the cart via ajax remove : function(idProduct, idCombination, customizationId, idAddressDelivery){ //send the ajax request to the server $.ajax({ type: 'POST', headers: { "cache-control": "no-cache" }, url: baseUri + '?rand=' + new Date().getTime(), async: true, cache: false, dataType : "json", data: 'controller=cart&delete=1&id_product=' + idProduct + '&ipa=' + ((idCombination != null && parseInt(idCombination)) ? idCombination : '') + ((customizationId && customizationId != null) ? '&id_customization=' + customizationId : '') + '&id_address_delivery=' + idAddressDelivery + '&token=' + static_token + '&ajax=true', success: function(jsonData) { ajaxCart.updateCart(jsonData); if ($('body').attr('id') == 'order' || $('body').attr('id') == 'order-opc') deleteProductFromSummary(idProduct+'_'+idCombination+'_'+customizationId+'_'+idAddressDelivery); }, error: function() { var error = 'ERROR: unable to delete the product'; if (!!$.prototype.fancybox) { $.fancybox.open([ { type: 'inline', autoScale: true, minHeight: 30, content: error } ], { padding: 0 }); } else alert(error); } }); }, //hide the products displayed in the page but no more in the json data hideOldProducts : function(jsonData){ //delete an eventually removed product of the displayed cart (only if cart is not empty!) if ($('.cart_block_list:first dl.products').length > 0) { var removedProductId = null; var removedProductData = null; var removedProductDomId = null; //look for a product to delete... $('.cart_block_list:first dl.products dt').each(function(){ //retrieve idProduct and idCombination from the displayed product in the block cart var domIdProduct = $(this).data('id'); var firstCut = domIdProduct.replace('cart_block_product_', ''); var ids = firstCut.split('_'); //try to know if the current product is still in the new list var stayInTheCart = false; for (aProduct in jsonData.products) { //we've called the variable aProduct because IE6 bug if this variable is called product //if product has attributes if (jsonData.products[aProduct]['id'] == ids[0] && (!ids[1] || jsonData.products[aProduct]['idCombination'] == ids[1])) { stayInTheCart = true; // update the product customization display (when the product is still in the cart) ajaxCart.hideOldProductCustomizations(jsonData.products[aProduct], domIdProduct); } } //remove product if it's no more in the cart if (!stayInTheCart) { removedProductId = $(this).data('id'); if (removedProductId != null) { var firstCut = removedProductId.replace('cart_block_product_', ''); var ids = firstCut.split('_'); $('dt[data-id=' + removedProductId + ']').addClass('strike').fadeTo('slow', 0, function(){ $(this).slideUp('slow', function(){ $(this).remove(); // If the cart is now empty, show the 'no product in the cart' message and close detail if($('.cart_block:first dl.products dt').length == 0) { $("#header .cart_block").stop(true, true).slideUp(200); $('.cart_block_no_products:hidden').slideDown(450); $('.cart_block dl.products').remove(); } }); }); $('dd[data-id="cart_block_combination_of_' + ids[0] + (ids[1] ? '_'+ids[1] : '') + (ids[2] ? '_'+ids[2] : '') + '"]').fadeTo('fast', 0, function(){ $(this).slideUp('fast', function(){ $(this).remove(); }); }); } } }); } }, hideOldProductCustomizations : function (product, domIdProduct){ var customizationList = $('ul[data-id=customization_' + product['id] + '_' + product['idCombination'] + '"]'); if(customizationList.length > 0) { $(customizationList).find("li").each(function(){ $(this).find("div").each(function(){ var customizationDiv = $(this).data('id'); var tmp = customizationDiv.replace('deleteCustomizableProduct_', ''); var ids = tmp.split('_'); if ((parseInt(product.idCombination) == parseInt(ids[2])) && !ajaxCart.doesCustomizationStillExist(product, ids[0])) $('div[data-id=' + customizationDiv + ']').parent().addClass('strike').fadeTo('slow', 0, function(){ $(this).slideUp('slow'); $(this).remove(); }); }); }); } var removeLinks = $('.deleteCustomizableProduct[data-id=' + domIdProduct + ']').find('.ajax_cart_block_remove_link'); if (!product.hasCustomizedDatas && !removeLinks.length) $('div[data-id=' + domIdProduct + ']' + ' span.remove_link').html('<a class="ajax_cart_block_remove_link" rel="nofollow" href="' + baseUri + '?controller=cart&delete=1&id_product=' + product['id'] + '&ipa=' + product['idCombination'] + '&token=' + static_token + '"> </a>'); if (product.is_gift) $('div[data-id=' + domIdProduct + ']' + ' span.remove_link').html(''); }, doesCustomizationStillExist : function (product, customizationId){ var exists = false; $(product.customizedDatas).each(function(){ if (this.customizationId == customizationId) { exists = true; // This return does not mean that we found nothing but simply break the loop return false; } }); return (exists); }, //refresh display of vouchers (needed for vouchers in % of the total) refreshVouchers : function (jsonData){ if (typeof(jsonData.discounts) == 'undefined' || jsonData.discounts.length == 0) $('.vouchers').hide(); else { $('.vouchers tbody').html(''); for (i=0;i<jsonData.discounts.length;i++) { if (parseFloat(jsonData.discounts.price_float) > 0) { var delete_link = ''; if (jsonData.discounts.code.length) delete_link = '<a class="delete_voucher" href="'+jsonData.discounts.link+'" title="'+delete_txt+'"><i class="icon-remove-sign"></i></a>'; $('.vouchers tbody').append($( '<tr class="bloc_cart_voucher" data-id="bloc_cart_voucher_'+jsonData.discounts.id+'">' +' <td class="quantity">1x</td>' +' <td class="name" title="'+jsonData.discounts.description+'">'+jsonData.discounts.name+'</td>' +' <td class="price">-'+jsonData.discounts.price+'</td>' +' <td class="delete">' + delete_link + '</td>' +'</tr>' )); } } $('.vouchers').show(); } }, // Update product quantity updateProductQuantity : function (product, quantity){ $('dt[data-id=cart_block_product_' + product.id + '_' + (product.idCombination ? product.idCombination : '0')+ '_' + (product.idAddressDelivery ? product.idAddressDelivery : '0') + '] .quantity').fadeTo('fast', 0, function(){ $(this).text(quantity); $(this).fadeTo('fast', 1, function(){ $(this).fadeTo('fast', 0, function(){ $(this).fadeTo('fast', 1, function(){ $(this).fadeTo('fast', 0, function(){ $(this).fadeTo('fast', 1); }); }); }); }); }); }, //display the products witch are in json data but not already displayed displayNewProducts : function(jsonData){ //add every new products or update displaying of every updated products $(jsonData.products).each(function(){ //fix ie6 bug (one more item 'undefined' in IE6) if (this.id != undefined) { //create a container for listing the products and hide the 'no product in the cart' message (only if the cart was empty) if ($('.cart_block:first dl.products').length == 0) { $('.cart_block_no_products').before('<dl class="products"></dl>'); $('.cart_block_no_products').hide(); } //if product is not in the displayed cart, add a new product's line var domIdProduct = this.id + '_' + (this.idCombination ? this.idCombination : '0') + '_' + (this.idAddressDelivery ? this.idAddressDelivery : '0'); var domIdProductAttribute = this.id + '_' + (this.idCombination ? this.idCombination : '0'); if ($('dt[data-id=cart_block_product_' + domIdProduct + ']').length == 0) { var productId = parseInt(this.id); var productAttributeId = (this.hasAttributes ? parseInt(this.attributes) : 0); var content = '<dt class="unvisible" data-id="cart_block_product_' + domIdProduct + '">'; var name = $.trim($('<span />').html(this.name).text()); name = (name.length > 12 ? name.substring(0, 10) + '...' : name); content += '<a class="cart-images" href="' + this.link + '" title="' + name + '"><img src="' + this.image_cart + '" alt="' + this.name +'"></a>'; content += '<div class="cart-info"><div class="product-name">' + '<span class="quantity-formated"><span class="quantity">' + this.quantity + '</span> x </span><a href="' + this.link + '" title="' + this.name + '" class="cart_block_product_name">' + name + '</a></div>'; if (this.hasAttributes) content += '<div class="product-atributes"><a href="' + this.link + '" title="' + this.name + '">' + this.attributes + '</a></div>'; if (typeof(freeProductTranslation) != 'undefined') content += '<span class="price">' + (parseFloat(this.price_float) > 0 ? this.priceByLine : freeProductTranslation) + '</span></div>'; if (typeof(this.is_gift) == 'undefined' || this.is_gift == 0) content += '<span class="remove_link"><a rel="nofollow" class="ajax_cart_block_remove_link" href="' + baseUri + '?controller=cart&delete=1&id_product=' + productId + '&token=' + static_token + (this.hasAttributes ? '&ipa=' + parseInt(this.idCombination) : '') + '"> </a></span>'; else content += '<span class="remove_link"></span>'; content += '</dt>'; if (this.hasAttributes) content += '<dd data-id="cart_block_combination_of_' + domIdProduct + '" class="unvisible">'; if (this.hasCustomizedDatas) content += ajaxCart.displayNewCustomizedDatas(this); if (this.hasAttributes) content += '</dd>'; $('.cart_block dl.products').append(content); } //else update the product's line else { var jsonProduct = this; if($.trim($('dt[data-id=cart_block_product_' + domIdProduct + '] .quantity').html()) != jsonProduct.quantity || $.trim($('dt[data-id=cart_block_product_' + domIdProduct + '] .price').html()) != jsonProduct.priceByLine) { // Usual product if (!this.is_gift) $('dt[data-id=cart_block_product_' + domIdProduct + '] .price').text(jsonProduct.priceByLine); else $('dt[data-id=cart_block_product_' + domIdProduct + '] .price').html(freeProductTranslation); ajaxCart.updateProductQuantity(jsonProduct, jsonProduct.quantity); // Customized product if (jsonProduct.hasCustomizedDatas) { customizationFormatedDatas = ajaxCart.displayNewCustomizedDatas(jsonProduct); if (!$('ul[data-id=customization_' + domIdProductAttribute + ']').length) { if (jsonProduct.hasAttributes) $('dd[data-id=cart_block_combination_of_' + domIdProduct + ']').append(customizationFormatedDatas); else $('.cart_block dl.products').append(customizationFormatedDatas); } else { $('ul[data-id=customization_' + domIdProductAttribute + ']').html(''); $('ul[data-id=customization_' + domIdProductAttribute + ']').append(customizationFormatedDatas); } } } } $('.cart_block dl.products .unvisible').slideDown(450).removeClass('unvisible'); var removeLinks = $('dt[data-id=cart_block_product_' + domIdProduct + ']').find('a.ajax_cart_block_remove_link'); if (this.hasCustomizedDatas && removeLinks.length) $(removeLinks).each(function(){ $(this).remove(); }); } }); }, displayNewCustomizedDatas : function(product){ var content = ''; var productId = parseInt(product.id); var productAttributeId = typeof(product.idCombination) == 'undefined' ? 0 : parseInt(product.idCombination); var hasAlreadyCustomizations = $('ul[data-id=customization_' + productId + '_' + productAttributeId + ']').length; if (!hasAlreadyCustomizations) { if (!product.hasAttributes) content += '<dd data-id="cart_block_combination_of_' + productId + '" class="unvisible">'; if ($('ul[data-id=customization_' + productId + '_' + productAttributeId + ']').val() == undefined) content += '<ul class="cart_block_customizations" data-id="customization_' + productId + '_' + productAttributeId + '">'; } $(product.customizedDatas).each(function(){ var done = 0; customizationId = parseInt(this.customizationId); productAttributeId = typeof(product.idCombination) == 'undefined' ? 0 : parseInt(product.idCombination); content += '<li name="customization"><div class="deleteCustomizableProduct" data-id="deleteCustomizableProduct_' + customizationId + '_' + productId + '_' + (productAttributeId ? productAttributeId : '0') + '"><a rel="nofollow" class="ajax_cart_block_remove_link" href="' + baseUri + '?controller=cart&delete=1&id_product=' + productId + '&ipa=' + productAttributeId + '&id_customization=' + customizationId + '&token=' + static_token + '"></a></div>'; // Give to the customized product the first textfield value as name $(this.datas).each(function(){ if (this['type'] == CUSTOMIZE_TEXTFIELD) { $(this.datas).each(function(){ if (this['index'] == 0) { content += ' ' + this.truncatedValue.replace(/<br \/>/g, ' '); done = 1; return false; } }) } }); // If the customized product did not have any textfield, it will have the customizationId as name if (!done) content += customizationIdMessage + customizationId; if (!hasAlreadyCustomizations) content += '</li>'; // Field cleaning if (customizationId) { $('#uploadable_files li div.customizationUploadBrowse img').remove(); $('#text_fields input').attr('value', ''); } }); if (!hasAlreadyCustomizations) { content += '</ul>'; if (!product.hasAttributes) content += '</dd>'; } return (content); }, updateLayer : function(product){ $('#layer_cart_product_title').text(product.name); $('#layer_cart_product_attributes').text(''); if (product.hasAttributes && product.hasAttributes == true) $('#layer_cart_product_attributes').html(product.attributes); $('#layer_cart_product_price').text(product.price); $('#layer_cart_product_quantity').text(product.quantity); $('.layer_cart_img').html('<img class="layer_cart_img img-responsive" src="' + product.image + '" alt="' + product.name + '" title="' + product.name + '" />'); var n = parseInt($(window).scrollTop()) + 'px'; $('.layer_cart_overlay').css('width','100%'); $('.layer_cart_overlay').css('height','100%'); $('.layer_cart_overlay').show(); $('#layer_cart').css({'top': n}).fadeIn('fast'); crossselling_serialScroll(); }, //genarally update the display of the cart updateCart : function(jsonData){ //user errors display if (jsonData.hasError) { var errors = ''; for (error in jsonData.errors) //IE6 bug fix if (error != 'indexOf') errors += $('<div />').html(jsonData.errors[error]).text() + "\n"; if (!!$.prototype.fancybox) $.fancybox.open([ { type: 'inline', autoScale: true, minHeight: 30, content: '<p class="fancybox-error">' + errors + '</p>' } ], { padding: 0 }); else alert(errors); } else { ajaxCart.updateCartEverywhere(jsonData); ajaxCart.hideOldProducts(jsonData); ajaxCart.displayNewProducts(jsonData); ajaxCart.refreshVouchers(jsonData); //update 'first' and 'last' item classes $('.cart_block .products dt').removeClass('first_item').removeClass('last_item').removeClass('item'); $('.cart_block .products dt:first').addClass('first_item'); $('.cart_block .products dt:not(:first,:last)').addClass('item'); $('.cart_block .products dt:last').addClass('last_item'); } }, //update general cart informations everywhere in the page updateCartEverywhere : function(jsonData){ $('.ajax_cart_total').text($.trim(jsonData.productTotal)); if (parseFloat(jsonData.shippingCostFloat) > 0) $('.ajax_cart_shipping_cost').text(jsonData.shippingCost); else if (typeof(freeShippingTranslation) != 'undefined') $('.ajax_cart_shipping_cost').html(freeShippingTranslation); $('.ajax_cart_tax_cost').text(jsonData.taxCost); $('.cart_block_wrapping_cost').text(jsonData.wrappingCost); $('.ajax_block_cart_total').text(jsonData.total); $('.ajax_block_products_total').text(jsonData.productTotal); $('.ajax_total_price_wt').text(jsonData.total_price_wt); if (parseFloat(jsonData.freeShippingFloat) > 0) { $('.ajax_cart_free_shipping').html(jsonData.freeShipping); $('.freeshipping').fadeIn(0); } else if (parseFloat(jsonData.freeShippingFloat) == 0) $('.freeshipping').fadeOut(0); this.nb_total_products = jsonData.nbTotalProducts; if (parseInt(jsonData.nbTotalProducts) > 0) { $('.ajax_cart_no_product').hide(); $('.ajax_cart_quantity').text(jsonData.nbTotalProducts); $('.ajax_cart_quantity').fadeIn('slow'); $('.ajax_cart_total').fadeIn('slow'); if (parseInt(jsonData.nbTotalProducts) > 1) { $('.ajax_cart_product_txt').each( function (){ $(this).hide(); }); $('.ajax_cart_product_txt_s').each( function (){ $(this).show(); }); } else { $('.ajax_cart_product_txt').each( function (){ $(this).show(); }); $('.ajax_cart_product_txt_s').each( function (){ $(this).hide(); }); } } else { $('.ajax_cart_quantity, .ajax_cart_product_txt_s, .ajax_cart_product_txt, .ajax_cart_total').each(function(){ $(this).hide(); }); $('.ajax_cart_no_product').show('slow'); } }};function HoverWatcher(selector){ this.hovering = false; var self = this; this.isHoveringOver = function(){ return self.hovering; } $(selector).hover(function(){ self.hovering = true; }, function(){ self.hovering = false; })}function crossselling_serialScroll(){ if (!!$.prototype.bxSlider) $('#blockcart_caroucel').bxSlider({ minSlides: 2, maxSlides: 4, slideWidth: 178, slideMargin: 20, moveSlides: 1, infiniteLoop: false, hideControlOnEnd: true, pager: false });} 2 Link to comment Share on other sites More sharing options...
bomby Posted February 22, 2015 Share Posted February 22, 2015 Hi, i tried the code you have posted above for 1.6.0.11 but the "Save" button is still visible Link to comment Share on other sites More sharing options...
web-port.pl Posted February 22, 2015 Share Posted February 22, 2015 (edited) The JS CODE is to mod the behavior of cart - then you need cut code for save button or hide in css - that's all Edited February 22, 2015 by netark2 (see edit history) Link to comment Share on other sites More sharing options...
bomby Posted February 22, 2015 Share Posted February 22, 2015 When I click on "Add to cart", the ajax loading button appears and it keeps spinning - while the page is not loading. nothing is saved/added to cart. Link to comment Share on other sites More sharing options...
web-port.pl Posted February 22, 2015 Share Posted February 22, 2015 URL of shop please I make test ok? Link to comment Share on other sites More sharing options...
ABANGWEB Posted April 3, 2015 Share Posted April 3, 2015 The JS CODE is to mod the behavior of cart - then you need cut code for save button or hide in css - that's all Any solution for version 1.6.0.14 ? Link to comment Share on other sites More sharing options...
web-port.pl Posted April 4, 2015 Share Posted April 4, 2015 Any solution for version 1.6.0.14 ? You can adapt this for 1.6.0.14 witch out problem Link to comment Share on other sites More sharing options...
web-port.pl Posted April 4, 2015 Share Posted April 4, 2015 cut and copy before and after line /*----------------------------------------------------------------------------------------------*/ to desired function in JS file Link to comment Share on other sites More sharing options...
wiseprt Posted April 14, 2015 Share Posted April 14, 2015 Hello i used your modified code for prestashop 1.6.0.14 but i have the same problem with @bomby the button keeps spinning. I have some console errors if this is enough to find the issue. (see attached screenshot) Link to comment Share on other sites More sharing options...
cagrie Posted April 14, 2015 Share Posted April 14, 2015 I advise all people here to buy zelarg's perfect one page checkout button. it is worth the €39 you spend. perfect support too, he'll solve your problems via email. Link to comment Share on other sites More sharing options...
wiseprt Posted April 14, 2015 Share Posted April 14, 2015 (edited) I advise all people here to buy zelarg's perfect one page checkout button. it is worth the €39 you spend. perfect support too, he'll solve your problems via email. Hi cagrie thanks for info, but i would like to have a "free" solution if is possible. Mainly my issue is that i have made the customtext field required, but even when i put something in the textarea, after i press the save button got the error that i have to fill in all the required fields! I am 100% sure that i have no other required fields. Is this a known issue? Best Regards Edited April 14, 2015 by wiseprt (see edit history) Link to comment Share on other sites More sharing options...
web-port.pl Posted April 15, 2015 Share Posted April 15, 2015 Mod only ajax-cart.js !!! Link to comment Share on other sites More sharing options...
nunorosado Posted April 21, 2015 Share Posted April 21, 2015 URL of shop please I make test ok? When I click on "Add to cart", the ajax loading button appears and it keeps spinning - while the page is not loading. nothing is saved/added to cart. I have the same problem can you help me ? thanks Link to comment Share on other sites More sharing options...
Desean Posted June 24, 2015 Share Posted June 24, 2015 The JS CODE is to mod the behavior of cart - then you need cut code for save button or hide in css - that's all Thanks! It is work ) Link to comment Share on other sites More sharing options...
web-port.pl Posted June 24, 2015 Share Posted June 24, 2015 When I click on "Add to cart", the ajax loading button appears and it keeps spinning - while the page is not loading. nothing is saved/added to cart. I have the same problem can you help me ? thanks cut and copy before and after line /*----------------------------------------------------------------------------------------------*/ to desired function in JS file Link to comment Share on other sites More sharing options...
web-port.pl Posted June 24, 2015 Share Posted June 24, 2015 Please post every SOLUTION to every version Prestashop Link to comment Share on other sites More sharing options...
white dove Posted July 11, 2015 Share Posted July 11, 2015 Hi All I have carried out the steps in post #133, but the strange thing is works once then cannot be repeated the second time. I have to delete the files then ftp them again and it works! Ideally I am looking for an Ajax-cart turned on solution but my prestashop version is 1.6.0.14. Critically important this can work, as my products require personalised labels and the save button is an extra step the customer doesnt need. Thanks in advance Link to comment Share on other sites More sharing options...
Yngvi Posted July 19, 2015 Share Posted July 19, 2015 Hi I also have the same problem as the previous poster. The solution works, but I can only add one product to the cart. If I add a personalized product and then try to add another normal product to the cart, it will not let me. Link to comment Share on other sites More sharing options...
web-port.pl Posted July 19, 2015 Share Posted July 19, 2015 Works perfect on default theme in prestashop 1.6.0.9 and 1.6.0.14 tested. Please provied url of shop. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now