Merge pull request #101 from thelia/frontend

Frontend
This commit is contained in:
Manuel Raynaud
2013-11-12 02:16:42 -08:00
31 changed files with 397 additions and 247 deletions

View File

@@ -58,6 +58,11 @@
<default key="_controller">Thelia\Controller\Front\DefaultController::noAction</default>
<default key="_view">account-password</default>
</route>
<route id="customer.order.pdf.delivery" path="/account/order/pdf/delivery/{order_id}">
<default key="_controller">Thelia\Controller\Front\OrderController::generateDeliveryPdf</default>
<requirement key="order_id">\d+</requirement>
</route>
<!-- end customer routes -->
<!-- customer address routes -->
@@ -152,10 +157,6 @@
</route>
<!-- end order management process -->
<route id="mail.test" path="/mail/test">
<default key="_controller">Thelia\Controller\Front\Mail::test</default>
</route>
<!-- contact management -->
<route id="contact.send" path="/contact" methods="post">
<default key="_controller">Thelia\Controller\Front\ContactController::sendAction</default>

View File

@@ -202,48 +202,28 @@ class OrderController extends BaseAdminController
public function generateInvoicePdf($order_id)
{
return $this->generatePdf($order_id, ConfigQuery::read('pdf_invoice_file', 'invoice'));
if (null !== $response = $this->checkAuth(AdminResources::ORDER, AccessManager::UPDATE)) return $response;
return $this->generateBackOfficeOrderPdf($order_id, ConfigQuery::read('pdf_invoice_file', 'invoice'));
}
public function generateDeliveryPdf($order_id)
{
return $this->generatePdf($order_id, ConfigQuery::read('pdf_delivery_file', 'delivery'));
if (null !== $response = $this->checkAuth(AdminResources::ORDER, AccessManager::UPDATE)) return $response;
return $this->generateBackOfficeOrderPdf($order_id, ConfigQuery::read('pdf_delivery_file', 'delivery'));
}
protected function generatePdf($order_id, $fileName)
private function generateBackOfficeOrderPdf($order_id, $fileName)
{
if (null !== $response = $this->checkAuth(AdminResources::ORDER, array(), AccessManager::UPDATE)) return $response;
$html = $this->renderRaw(
$fileName,
array(
if(null === $response = $this->generateOrderPdf($order_id, $fileName)){
$this->redirect(URL::getInstance()->absoluteUrl($this->getRoute("admin.order.update.view", array(
'order_id' => $order_id
),
TemplateHelper::getInstance()->getActivePdfTemplate()->getPath()
);
$order = OrderQuery::create()->findPk($order_id);
try {
$pdfEvent = new PdfEvent($html);
$this->dispatch(TheliaEvents::GENERATE_PDF, $pdfEvent);
if ($pdfEvent->hasPdf()) {
return Response::create($pdfEvent->getPdf(), 200,
array(
'Content-type' => "application/pdf",
'Content-Disposition' => sprintf('Attachment;filename=%s.pdf', $order->getRef()),
));
}
} catch (\Exception $e) {
\Thelia\Log\Tlog::getInstance()->error(sprintf('error during generating invoice pdf for order id : %d with message "%s"', $order_id, $e->getMessage()));
))));
}
$this->redirect(URL::getInstance()->absoluteUrl($this->getRoute("admin.order.update.view", array(
'order_id' => $order_id
))));
return $response;
}
}

View File

@@ -22,6 +22,8 @@
/*************************************************************************************/
namespace Thelia\Controller;
use Thelia\Core\Event\PdfEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\HttpFoundation\Response;
use Symfony\Component\DependencyInjection\ContainerAware;
@@ -31,7 +33,9 @@ use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Router;
use Thelia\Core\Security\SecurityContext;
use Thelia\Core\Template\TemplateHelper;
use Thelia\Core\Translation\Translator;
use Thelia\Model\OrderQuery;
use Thelia\Tools\URL;
use Thelia\Tools\Redirect;
use Thelia\Core\Template\ParserContext;
@@ -52,7 +56,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class BaseController extends ContainerAware
abstract class BaseController extends ContainerAware
{
/**
@@ -73,6 +77,21 @@ class BaseController extends ContainerAware
return new Response($json_data, $status, array('content-type' => 'application/json'));
}
/**
* @param $pdf
* @param $fileName
* @param $status
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function pdfResponse($pdf, $fileName, $status = 200)
{
return Response::create($pdf, $status,
array(
'Content-type' => "application/pdf",
'Content-Disposition' => sprintf('Attachment;filename=%s.pdf', $fileName),
));
}
/**
* Dispatch a Thelia event
*
@@ -207,6 +226,35 @@ class BaseController extends ContainerAware
}
}
protected function generateOrderPdf($order_id, $fileName)
{
$html = $this->renderRaw(
$fileName,
array(
'order_id' => $order_id
),
TemplateHelper::getInstance()->getActivePdfTemplate()->getPath()
);
$order = OrderQuery::create()->findPk($order_id);
try {
$pdfEvent = new PdfEvent($html);
$this->dispatch(TheliaEvents::GENERATE_PDF, $pdfEvent);
if ($pdfEvent->hasPdf()) {
return $this->pdfResponse($pdfEvent->getPdf(), $order->getRef());
}
} catch (\Exception $e) {
\Thelia\Log\Tlog::getInstance()->error(sprintf('error during generating invoice pdf for order id : %d with message "%s"', $order_id, $e->getMessage()));
}
}
/**
*
* redirect request to the specified url
@@ -311,20 +359,28 @@ class BaseController extends ContainerAware
}
/**
*
* return an instance of SmartyParser
*
* Caution : maybe there is still not default template defined.
*
* @return ParserInterface instance parser
* @return a ParserInterface instance parser
*/
protected function getParser()
{
return $this->container->get("thelia.parser");
}
abstract protected function getParser($template = null);
protected function render($inline)
{
return $this->getParser()->fetch(sprintf("string:%s", $inline));
}
/**
* Render the given template, and returns the result as an Http Response.
*
* @param $templateName the complete template name, with extension
* @param array $args the template arguments
* @param int $status http code status
* @return \Thelia\Core\HttpFoundation\Response
*/
abstract protected function render($templateName, $args = array(), $status = 200);
/**
* Render the given template, and returns the result as a string.
*
* @param $templateName the complete template name, with extension
* @param array $args the template arguments
* @param null $templateDir
*
* @return string
*/
abstract protected function renderRaw($templateName, $args = array(), $templateDir = null);
}

View File

@@ -24,9 +24,13 @@ namespace Thelia\Controller\Front;
use Symfony\Component\Routing\Router;
use Thelia\Controller\BaseController;
use Thelia\Core\HttpFoundation\Response;
use Thelia\Core\Security\Exception\AuthenticationException;
use Thelia\Core\Template\TemplateHelper;
use Thelia\Model\AddressQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Model\ModuleQuery;
use Thelia\Tools\Redirect;
use Thelia\Tools\URL;
class BaseFrontController extends BaseController
@@ -88,12 +92,59 @@ class BaseFrontController extends BaseController
/**
* @return ParserInterface instance parser
*/
protected function getParser()
protected function getParser($template = null)
{
$parser = $this->container->get("thelia.parser");
$parser->setTemplate(ConfigQuery::getActiveTemplate());
// Define the template that should be used
$parser->setTemplate($template ?: TemplateHelper::getInstance()->getActiveFrontTemplate()->getPath());
return $parser;
}
/**
* Render the given template, and returns the result as an Http Response.
*
* @param $templateName the complete template name, with extension
* @param array $args the template arguments
* @param int $status http code status
* @return \Thelia\Core\HttpFoundation\Response
*/
protected function render($templateName, $args = array(), $status = 200)
{
return Response::create($this->renderRaw($templateName, $args), $status);
}
/**
* Render the given template, and returns the result as a string.
*
* @param $templateName the complete template name, with extension
* @param array $args the template arguments
* @param null $templateDir
*
* @return string
*/
protected function renderRaw($templateName, $args = array(), $templateDir = null)
{
// Add the template standard extension
$templateName .= '.html';
$session = $this->getSession();
// Prepare common template variables
$args = array_merge($args, array(
'locale' => $session->getLang()->getLocale(),
'lang_code' => $session->getLang()->getCode(),
'lang_id' => $session->getLang()->getId(),
'current_url' => $this->getRequest()->getUri()
));
// Render the template.
$data = $this->getParser($templateDir)->render($templateName, $args);
return $data;
}
}

View File

@@ -1,48 +0,0 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Controller\Front;
/**
* Class Mail
* @package Thelia\Controller\Front
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class Mail extends BaseFrontController
{
/**
* This is a demo how to send a mail using swiftmailer + smarty
*/
public function test()
{
$message = \Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('john@doe.com' => 'John Doe'))
->setTo(array('mraynaud@openstudio.fr' => 'name'))
->setBody($this->render('Here is the message itself'))
;
$this->getMailer()->send($message);
exit;
}
}

View File

@@ -23,6 +23,9 @@
namespace Thelia\Controller\Front;
use Propel\Runtime\Exception\PropelException;
use Thelia\Core\Event\PdfEvent;
use Thelia\Core\HttpFoundation\Response;
use Thelia\Core\Template\TemplateHelper;
use Thelia\Exception\TheliaProcessException;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Core\Event\Order\OrderEvent;
@@ -34,6 +37,7 @@ use Thelia\Log\Tlog;
use Thelia\Model\AddressQuery;
use Thelia\Model\AreaDeliveryModuleQuery;
use Thelia\Model\Base\OrderQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Model\ModuleQuery;
use Thelia\Model\Order;
use Thelia\Tools\URL;
@@ -67,7 +71,6 @@ class OrderController extends BaseFrontController
$deliveryModule = ModuleQuery::create()->findPk($deliveryModuleId);
/* check that the delivery address belongs to the current customer */
$deliveryAddress = AddressQuery::create()->findPk($deliveryAddressId);
if ($deliveryAddress->getCustomerId() !== $this->getSecurityContext()->getCustomerUser()->getId()) {
throw new \Exception("Delivery address does not belong to the current customer");
}
@@ -242,4 +245,20 @@ class OrderController extends BaseFrontController
return $order;
}
public function generateInvoicePdf($order_id)
{
/* check customer */
$this->checkAuth();
return $this->generateOrderPdf($order_id, ConfigQuery::read('pdf_invoice_file', 'invoice'));
}
public function generateDeliveryPdf($order_id)
{
/* check customer */
$this->checkAuth();
return $this->generateOrderPdf($order_id, ConfigQuery::read('pdf_delivery_file', 'delivery'));
}
}

View File

@@ -33,6 +33,8 @@ use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\LangQuery;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Type\TypeCollection;
use Thelia\Type;
/**
* Language loop, to get a list of available languages
@@ -56,7 +58,14 @@ class Lang extends BaseLoop implements PropelSearchLoopInterface
return new ArgumentCollection(
Argument::createIntTypeArgument('id', null),
Argument::createIntListTypeArgument('exclude'),
Argument::createBooleanTypeArgument('default_only', false)
Argument::createBooleanTypeArgument('default_only', false),
new Argument(
'order',
new TypeCollection(
new Type\EnumListType(array('id', 'id_reverse', 'alpha', 'alpha_reverse', 'position', 'position_reverse'))
),
'position'
)
);
}
@@ -79,6 +88,30 @@ class Lang extends BaseLoop implements PropelSearchLoopInterface
}
$search->orderByPosition(Criteria::ASC);
$orders = $this->getOrder();
foreach ($orders as $order) {
switch ($order) {
case "id":
$search->orderById(Criteria::ASC);
break;
case "id_reverse":
$search->orderById(Criteria::DESC);
break;
case "alpha":
$search->orderByTitle(Criteria::ASC);
break;
case "alpha_reverse":
$search->orderByTitle(Criteria::DESC);
break;
case "position":
$search->orderByPosition(Criteria::ASC);
break;
case "position_reverse":
$search->orderByPosition(Criteria::DESC);
break;
}
}
return $search;

View File

@@ -25,7 +25,7 @@
<h1 id="main-label" class="page-header">{intl l="Change Password"}</h1>
{form name="thelia.front.customer.password.update"}
<form id="form-register" class="form-horizontal" action="{url path="/account/password"}" method="post" role="form">
<form id="form-register" class="form-horizontal" action="{url path="/account/password"}" method="post">
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/account"}" />
{/form_field}

View File

@@ -24,7 +24,7 @@
<h1 id="main-label" class="page-header">{intl l="Update Profile"}</h1>
{form name="thelia.front.customer.profile.update"}
<form id="form-register" class="form-horizontal" action="{url path="/account/update"}" method="post" role="form">
<form id="form-register" class="form-horizontal" action="{url path="/account/update"}" method="post">
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/account"}" />
{/form_field}

View File

@@ -158,7 +158,7 @@
<td>{format_date date=$CREATE_DATE}</td>
<td>{format_number number=$TOTAL_TAXED_AMOUNT} {loop type="currency" name="order.currency" id={$CURRENCY}}{$SYMBOL}{/loop}</td>
<td><span class="label-delivered">{loop type="order-status" name="order.status" id={$STATUS}}{$TITLE}{/loop}</span></td>
<td><a href="#" class="btn btn-order-details" data-toggle="tooltip" title="{intl l="View order %ref as pdf document" ref={$REF}}"><span class="icon-cloud-download"></span> {intl l="Order details"}</a></td>
<td><a href="{url path="/account/order/pdf/delivery/$ID"}" class="btn btn-order-details" data-toggle="tooltip" title="{intl l="View order %ref as pdf document" ref={$REF}}"><span class="icon-cloud-download"></span> {intl l="Order details"}</a></td>
</tr>
{/loop}

View File

@@ -24,7 +24,7 @@
<h1 id="main-label" class="page-header">{intl l="Address Update"}</h1>
{form name="thelia.front.address.update"}
{loop name="customer.update" type="address" customer="current" id="{$address_id}"}
<form id="form-address" class="form-horizontal" action="{url path="/address/update/{$address_id}"}" method="post" role="form">
<form id="form-address" class="form-horizontal" action="{url path="/address/update/{$address_id}"}" method="post">
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/account"}" />
{/form_field}

View File

@@ -23,7 +23,7 @@
<h1 id="main-label" class="page-header">{intl l="Create New Address"}</h1>
{form name="thelia.front.address.create"}
<form id="form-address" class="form-horizontal" action="{url path="/address/create"}" method="post" role="form">
<form id="form-address" class="form-horizontal" action="{url path="/address/create"}" method="post">
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/account"}" />
{/form_field}

View File

@@ -1,22 +1,23 @@
/* JQUERY PREVENT CONFLICT */
(function($) {
(function ($) {
/* ------------------------------------------------------------------
/* ------------------------------------------------------------------
callback Function -------------------------------------------------- */
var confirmCallback = {
'address.delete': function($elm){
$.post($elm.attr('href'), function(data){
if(data.success)
'address.delete': function ($elm) {
$.post($elm.attr('href'), function (data) {
if (data.success) {
$elm.closest('tr').remove();
else
} else {
bootbox.alert(data.message);
}
});
}
}
};
/* ------------------------------------------------------------------
/* ------------------------------------------------------------------
onLoad Function -------------------------------------------------- */
$(document).ready(function(){
$(document).ready(function () {
// Loader
var $loader = $('<div class="loader"></div>');
@@ -24,32 +25,29 @@
// Display loader if we do ajax call
$(document)
.ajaxStart(function() { $loader.show(); })
.ajaxStop(function(){ $loader.hide(); });
.ajaxStart(function () { $loader.show(); })
.ajaxStop(function () { $loader.hide(); });
// Main Navigation Hover
$('.nav-main')
.on('click.subnav', '[data-toggle=dropdown]', function(event){
if($(this).parent().hasClass('open') && $(this).is(event.target))
return false;
.on('click.subnav', '[data-toggle=dropdown]', function (event) {
if ($(this).parent().hasClass('open') && $(this).is(event.target)) { return false; }
})
.on('mouseenter.subnav', '.dropdown', function(event){
if($(this).hasClass('open'))
return;
.on('mouseenter.subnav', '.dropdown', function () {
if ($(this).hasClass('open')) { return; }
$(this).addClass('open');
})
.on('mouseleave.subnav', '.dropdown', function(){
.on('mouseleave.subnav', '.dropdown', function () {
var $this = $(this);
if(!$this.hasClass('open'))
return;
if (!$this.hasClass('open')) { return; }
//This will check if an input child has focus. If no then remove class open
if ($this.find(":input:focus").length == 0){
if ($this.find(":input:focus").length === 0) {
$this.removeClass('open');
} else {
$this.find(":input:focus").one('blur', function(){
$this.find(":input:focus").one('blur', function () {
$this.trigger('mouseleave.subnav');
});
}
@@ -61,56 +59,55 @@
});
// Confirm Dialog
$(document).on('click.confirm', '[data-confirm]', function (e) {
$(document).on('click.confirm', '[data-confirm]', function () {
var $this = $(this),
href = $this.attr('href'),
callback = $this.attr('data-confirm-callback'),
title = $this.attr('data-confirm') != '' ? $this.attr('data-confirm') : 'Are you sure?';
title = $this.attr('data-confirm') !== '' ? $this.attr('data-confirm') : 'Are you sure?';
bootbox.confirm(title, function(confirm) {
if(confirm){
//Check if callback and if it's a function
if (callback && $.isFunction(confirmCallback[callback])) {
confirmCallback[callback]($this);
bootbox.confirm(title, function (confirm) {
if (confirm) {
//Check if callback and if it's a function
if (callback && $.isFunction(confirmCallback[callback])) {
confirmCallback[callback]($this);
} else {
if (href) {
window.location.href = href;
} else {
if(href){
window.location.href = href;
} else {
// If forms
var $form = $this.closest("form");
if($form.size() > 0){
$form.submit();
}
// If forms
var $form = $this.closest("form");
if ($form.size() > 0) {
$form.submit();
}
}
}
});
}
});
return false;
});
// Toolbar
var $category_products = $('#category-products');
if($category_products.size() > 0){
var $category_products = $ ('#category-products');
if ($category_products.size() > 0) {
var $parent = $category_products.parent();
$parent.on('click.view-mode', '[data-toggle=view]', function(){
if( ($(this).hasClass('btn-grid') && $parent.hasClass('grid')) || ($(this).hasClass('btn-list') && $parent.hasClass('list')))
return;
$parent.on('click.view-mode', '[data-toggle=view]', function () {
if (($(this).hasClass('btn-grid') && $parent.hasClass('grid')) || ($(this).hasClass('btn-list') && $parent.hasClass('list'))) { return; }
// Add loader effect
$loader.show();
setTimeout(function(){ $parent.toggleClass('grid').toggleClass('list'); $loader.hide(); }, 400);
setTimeout(function () { $parent.toggleClass('grid').toggleClass('list'); $loader.hide(); }, 400);
return false;
});
}
};
// Login
var $form_login = $('#form-login');
if($form_login.size() > 0) {
$form_login.on('change.account', ':radio', function(){
if($(this).val() === '0')
if ($form_login.size() > 0) {
$form_login.on('change.account', ':radio', function () {
if ($(this).val() === '0')
$('#password', $form_login).val('').prop('disabled', true); // Disabled (new customer)
else
$('#password', $form_login).prop('disabled', false); // Enabled
@@ -119,19 +116,19 @@
// Mini Newsletter Subscription
var $form_newsletter = $('#form-newsletter-mini');
if($form_newsletter.size() > 0) {
$form_newsletter.on('submit.newsletter', function(){
if ($form_newsletter.size() > 0) {
$form_newsletter.on('submit.newsletter', function () {
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
data: $(this).serialize(),
dataType: 'json',
success: function(json) {
success: function (json) {
var $msg = '';
if(json.success){
if (json.success) {
$msg = json.message;
}else{
} else {
$msg = json.message;
}
bootbox.alert($msg);
@@ -153,14 +150,14 @@
content: function() {
return $('#form-forgotpassword').html();
}
}).on('click.btn-forgot', function(){
}).on('click.btn-forgot', function () {
$('.btn-forgot').click(function(){
$('.btn-forgot').click(function () {
alert('click form');
return false;
});
$('.btn-close').click(function(){
$('.btn-close').click(function () {
$forgot_password.popover('hide');
});
@@ -170,11 +167,11 @@
*/
//.Form Filters
$('#form-filters').each(function(){
$('#form-filters').each(function () {
var $form = $(this);
$form
.on('change.filter', ':checkbox', function(){
.on('change.filter', ':checkbox', function () {
$loader.show();
$form.submit();
})
@@ -182,19 +179,18 @@
});
// Product details Thumbnails
$('#product-gallery').each(function(){
$('#product-gallery').each(function () {
var $item = $('.item', this),
$thumbnails = $('.thumbnail', this),
$image = $('.product-image > img', this);
// Show Carousel control if needed
if($item.size() > 1){
if ($item.size() > 1) {
$('#product-thumbnails', this).carousel({interval: false}).find('.carousel-control').show();
}
$(this).on('click.thumbnails', '.thumbnail', function(){
if($(this).hasClass('active'))
return false;
$(this).on('click.thumbnails', '.thumbnail', function () {
if ($(this).hasClass('active')) { return false; }
$image.attr('src',$(this).attr('href'));
$thumbnails.removeClass('active');
@@ -205,9 +201,9 @@
});
// Payment Method
$('#payment-method').each(function(){
$('#payment-method').each(function () {
var $label = $('label', this);
$label.on('change', ':radio', function(){
$label.on('change', ':radio', function () {
$label.removeClass('active');
$label.filter('[for="' + $(this).attr('id') + '"]').addClass('active');
}).filter(':has(:checked)').addClass('active');
@@ -215,21 +211,14 @@
// Apply validation
$('#form-contact, #form-register, #form-address').validate({
highlight: function(element) {
highlight: function (element) {
$(element).closest('.form-group').addClass('has-error');
},
unhighlight: function(element) {
unhighlight: function (element) {
$(element).closest('.form-group').removeClass('has-error');
},
errorElement: 'span',
errorClass: 'help-block'/*,
errorPlacement: function(error, element) {
if(element.parent('.input-group').length || element.prop('type') === 'checkbox' || element.prop('type') === 'radio'){
error.prepend('<i class="icon-remove"></i> ').insertAfter(element.parent());
}else{
error.prepend('<i class="icon-remove"></i> ').insertAfter(element);
}
}*/
errorClass: 'help-block'
});
@@ -253,14 +242,14 @@
// Switch Quantity in product page
$("select", $(".product-options")).change(function(){
$select_quantity = $(this).find(":selected").attr("data-quantity");
var $old_price = $(this).find(":selected").attr("data-old-price");
var $old_price = $(this).find(":selected").attr("data-old-price");
var $best_price = $(this).find(":selected").attr("data-price");
var $best_price = $(this).find(":selected").attr("data-price");
$quantityInput.attr("max", $select_quantity);
// Show Out Of Stock OR In Stock
if($select_quantity == 0){
if ($select_quantity == 0) {
$btnAddToCart.attr("disabled", true);
$productMeta.removeClass("in-stock");
@@ -271,7 +260,7 @@
$outOfStock.show();
$inStock.hide();
}else{
} else {
$btnAddToCart.attr("disabled", false);
$productMeta.removeClass("out-of-stock");
@@ -283,38 +272,38 @@
$outOfStock.hide();
}
if(parseInt($quantityInput.val()) > parseInt($select_quantity)){
if (parseInt($quantityInput.val()) > parseInt($select_quantity)) {
$quantityInput.val($select_quantity);
}
if($old_price_container.size() > 0 ){
if ($old_price_container.size() > 0) {
$(".price", $old_price_container).html($old_price);
$(".price", $(".special-price")).html($best_price);
}else{
} else {
$(".price", $(".regular-price")).html($best_price);
}
}).change();
$quantityInput.focusout(function() {
$quantityInput.focusout(function () {
$quantityInput.attr("max", $select_quantity);
if(parseInt($quantityInput.val()) > parseInt($select_quantity)){
if (parseInt($quantityInput.val()) > parseInt($select_quantity)) {
$quantityInput.val($select_quantity);
}
});
}
$(".form-product").submit(function(){
$(".form-product").submit(function () {
var url_action = $(this).attr("action");
var $cartContainer = $(".cart-container");
$.ajax({type:"POST", data: $(this).serialize(), url:url_action,
$.ajax({type: "POST", data: $(this).serialize(), url: url_action,
success: function(data){
$cartContainer.html($(data).html());
$.ajax({url:"ajax/addCartMessage",
success: function(data){
success: function (data) {
bootbox.dialog({
message : data,
buttons : {}
@@ -322,7 +311,7 @@
}
});
},
error: function(){
error: function () {
console.log('Error.');
}
});
@@ -330,11 +319,11 @@
return false;
});
$('#limit-top').change(function(e){
$('#limit-top').change(function (e) {
window.location = $(this).val()
});
$('#sortby-top').change(function(e){
$('#sortby-top').change(function (e) {
window.location = $(this).val()
});

View File

@@ -6,6 +6,9 @@
// Collapse
.no-js .collapse { display: block!important; }
// Hide carousel arrow if no js
.no-js #carousel .carousel-control { display: none; }
// Loader (Overlay)
.loader {
position: fixed;

View File

@@ -78,7 +78,7 @@
// Icons (Accordion and Dropdown)
//.accordion-toggle,
.dropdown-toggle {
.js .dropdown-toggle {
&:after {
.icon(@chevron-down);
float:right;

View File

@@ -98,7 +98,7 @@
</td>
<td class="qty">
<div class="form-group group-qty">
<form action="{url path="/cart/update"}" method="post" role="form">
<form action="{url path="/cart/update"}" method="post">
<input type="hidden" name="cart_item" value="{$ITEM_ID}">
<select name="quantity" class="form-control" onchange="jQuery(this).parent('form').submit();">
{for $will=1 to $STOCK}

View File

@@ -16,7 +16,7 @@
{block name="contact-form"}
{form name="thelia.front.contact"}
<form id="form-contact" action="{url path="/contact"}" method="post" role="form">
<form id="form-contact" action="{url path="/contact"}" method="post">
{form_hidden_fields form=$form}
<fieldset id="contact-info" class="panel">
<div class="panel-heading">

View File

@@ -0,0 +1,25 @@
{extends file="layout.tpl"}
{* Body Class *}
{block name="body-class"}page-currency{/block}
{* Breadcrumb *}
{block name='no-return-functions' append}
{$breadcrumbs = [
['title' => {intl l="Currency"}, 'url'=>{url path="/currency"}]
]}
{/block}
{block name="main-content"}
<div class="main">
<article class="col-main" role="main" aria-labelledby="main-label">
<h1 id="main-label" class="page-header">{intl l="SELECT YOUR CURRENCY"}</h1>
<ul class="nav nav-tabs nav-justified" style="margin-bottom:60px;">
{loop type="currency" name="currency_available"}
<li{if $ID eq "{currency attr="id"}"} class="active"{/if}><a href="{url path="{navigate to="current"}" currency={$ISOCODE}}">{$SYMBOL} - {$NAME}</a></li>
{/loop}
</ul>
</article>
</div>
{/block}

View File

@@ -1,6 +1,6 @@
<section id="filters">
<h3>Find <span>a product</span></h3>
<form id="form-filters" action="" method="get" role="form">
<form id="form-filters" action="" method="get">
<div class="filter filter-type">
<fieldset>
<legend class="filter-heading">Type</legend>

View File

@@ -4,7 +4,7 @@
{intl l="Cart"} <span class="badge">{cart attr="count_item"}</span>
</a>
<div class="dropdown-menu cart-content">
<form id="form-cart-mini" action="{url path="/order/delivery"}" method="post" role="form">
<form id="form-cart-mini" action="{url path="/order/delivery"}" method="post">
<table class="table table-cart-mini">
<colgroup>
<col width="70">

View File

@@ -60,7 +60,7 @@
</div>
{if $hasBtn == true}
{form name="thelia.cart.add" }
<form id="form-product-details" action="{url path="/cart/add" }" method="post" role="form" class="form-product">
<form id="form-product-details" action="{url path="/cart/add" }" method="post" class="form-product">
{form_hidden_fields form=$form}
<input type="hidden" name="view" value="product">
<input type="hidden" name="product_id" value="{$ID}">

View File

@@ -0,0 +1,25 @@
{extends file="layout.tpl"}
{* Body Class *}
{block name="body-class"}page-language{/block}
{* Breadcrumb *}
{block name='no-return-functions' append}
{$breadcrumbs = [
['title' => {intl l="Language"}, 'url'=>{url path="/language"}]
]}
{/block}
{block name="main-content"}
<div class="main">
<article class="col-main" role="main" aria-labelledby="main-label">
<h1 id="main-label" class="page-header">{intl l="SELECT YOUR LANGUAGE"}</h1>
<ul class="nav nav-tabs nav-justified" style="margin-bottom:60px;">
{loop type="lang" name="lang_available"}
<li{if $ID eq "{lang attr="id"}"} class="active"{/if}><a href="{url path="{navigate to="current"}" lang={$CODE}}">{$TITLE}</a></li>
{/loop}
</ul>
</article>
</div>
{/block}

View File

@@ -1,6 +1,10 @@
{* Declare assets directory, relative to template base directory *}
{declare_assets directory='assets'}
{block name="no-return-functions"}{/block}
{assign var="company_name" value="{config key="company_name"}"}
{if not $company_name}
{assign var="company_name" value="{intl l='Thelia V2'}"}
{/if}
<!doctype html>
<!--
______ __ __ ______ __ __ ______
@@ -33,15 +37,16 @@ GNU General Public License : http://www.gnu.org/licenses/
<meta charset="utf-8">
{* Page Title *}
<title>{block name="page-title"}{strip}{if $breadcrumbs}{foreach from=$breadcrumbs|array_reverse item=breadcrumb}{$breadcrumb.title} - {/foreach}{/if}{config key="company_name"}{/strip}{/block}</title>
<title>{block name="page-title"}{strip}{if $breadcrumbs}{foreach from=$breadcrumbs|array_reverse item=breadcrumb}{$breadcrumb.title} - {/foreach}{/if}{$company_name}{/strip}{/block}</title>
{* Meta Tags *}
<meta name="description" content="">
<meta name="generator" content="{intl l='Thelia V2'}">
<meta name="robots" content="noindex,nofollow">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
{block name="meta"}{/block}
{block name="meta"}
<meta name="description" content="{$company_name}">
<meta name="robots" content="noindex,nofollow">
{/block}
{* Stylesheets *}
{stylesheets file='assets/less/styles.less' filters='less'}
@@ -54,14 +59,10 @@ GNU General Public License : http://www.gnu.org/licenses/
{images file='assets/img/favicon.ico'}<link rel="shortcut icon" type="image/x-icon" href="{$asset_url}">{/images}
{images file='assets/img/favicon.png'}<link rel="icon" type="image/png" href="{$asset_url}" />{/images}
<link rel="icon" href="/favicon.ico" type="image/x-icon">
{* HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries *}
<!--[if lt IE 9]>
<script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
{javascripts file='assets/js/libs/respond.min.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
@@ -85,7 +86,7 @@ GNU General Public License : http://www.gnu.org/licenses/
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{navigate to="index"}">{config key="company_name"}</a>
<a class="navbar-brand" href="{navigate to="index"}">{$company_name}</a>
</div>
<!-- Place everything within .nav-collapse to hide it until above 768px -->
@@ -102,18 +103,18 @@ GNU General Public License : http://www.gnu.org/licenses/
<a href="{url path="/login"}" class="login">{intl l="Log In!"}</a>
<div class="dropdown-menu">
{form name="thelia.front.customer.login"}
<form id="form-login-mini" action="{url path="/login"}" method="post" role="form" {form_enctype form=$form}>
<form id="form-login-mini" action="{url path="/login"}" method="post" {form_enctype form=$form}>
{form_hidden_fields form=$form}
{form_field form=$form field="email"}
<div class="form-group group-email">
<label for="{$label_attr.for}-mini">Email address</label>
<input type="email" name="{$name}" id="{$label_attr.for}-mini" class="form-control" aria-required="true" required>
<label for="{$label_attr.for}-mini">{intl l="Email address"}</label>
<input type="email" name="{$name}" id="{$label_attr.for}-mini" class="form-control" maxlength="255" aria-required="true" required>
</div>
{/form_field}
{form_field form=$form field="password"}
<div class="form-group group-password">
<label for="{$label_attr.for}-mini">Password</label>
<input type="password" name="{$name}" id="{$label_attr.for}-mini" class="form-control" aria-required="true" required>
<label for="{$label_attr.for}-mini">{intl l="Password"}</label>
<input type="password" name="{$name}" id="{$label_attr.for}-mini" class="form-control" maxlength="255" aria-required="true" required>
</div>
{/form_field}
{form_field form=$form field="account"}
@@ -145,8 +146,8 @@ GNU General Public License : http://www.gnu.org/licenses/
<header class="container" role="banner">
<div class="header">
<h1 class="logo">
<a href="{navigate to="index"}" title="{config key="company_name"}">
{images file='assets/img/logo.gif'}<img src="{$asset_url}" alt="{config key="company_name"}">{/images}
<a href="{navigate to="index"}" title="{$company_name}">
{images file='assets/img/logo.gif'}<img src="{$asset_url}" alt="{$company_name}">{/images}
</a>
</h1>
@@ -164,7 +165,7 @@ GNU General Public License : http://www.gnu.org/licenses/
</form>
</div>
<div class="language-switch" aria-labelledby="language-label">
<div class="language-switch" aria-labelledby="language-label" role="form">
<span id="language-label" class="dropdown-label">{intl l="Language:"}</span>
<a class="current dropdown-toggle" data-toggle="dropdown" href="{url path="/language"}">{lang attr="title"}</a>
<ul class="select dropdown-menu">
@@ -174,7 +175,7 @@ GNU General Public License : http://www.gnu.org/licenses/
</ul>
</div>
<div class="currency-switch" aria-labelledby="currency-label">
<div class="currency-switch" aria-labelledby="currency-label" role="form">
<span id="currency-label" class="dropdown-label">{intl l="Currency:"}</span>
<a class="current dropdown-toggle" data-toggle="dropdown" href="{url path="/currency"}">{currency attr="code"}</a>
<ul class="select dropdown-menu">
@@ -193,7 +194,7 @@ GNU General Public License : http://www.gnu.org/licenses/
<main class="main-container" role="main">
<div class="container">
{block name="breadcrumb"}{include file="misc/breadcrumb.tpl"}{/block}
{block name="main-content"}{/block}
<div id="content">{block name="main-content"}{/block}</div>
</div><!-- /.container -->
</main><!-- /.main-container -->
@@ -271,54 +272,60 @@ GNU General Public License : http://www.gnu.org/licenses/
<section class="block block-social">
<div class="block-heading"><h3 class="block-title">{intl l="Follow us"}</h3></div>
<div class="block-content">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<p>{intl l="Follow us introduction"}</p>
<ul role="presentation">
<li>
<a href="http://facebook.com" class="facebook" data-toggle="tooltip" data-placement="top" title="facebook" target="_blank">
<a href="http://facebook.com" rel="nofollow" class="facebook" data-toggle="tooltip" data-placement="top" title="{intl l="Facebook"}" target="_blank">
<span class="icon-stack">
<span class="icon-circle icon-stack-base"></span>
<span class="icon-facebook icon-light"></span>
</span>
<span class="visible-print">{intl l="Facebook"}</span>
</a>
</li>
<li>
<a href="http://twitter.com" class="twitter" data-toggle="tooltip" data-placement="top" title="twitter" target="_blank">
<a href="https://twitter.com" rel="nofollow" class="twitter" data-toggle="tooltip" data-placement="top" title="{intl l="Twitter"}" target="_blank">
<span class="icon-stack">
<span class="icon-circle icon-stack-base"></span>
<span class="icon-twitter icon-light"></span>
</span>
<span class="visible-print">{intl l="Twitter"}</span>
</a>
</li>
<li>
<a href="http://instagram.com" class="instagram" data-toggle="tooltip" data-placement="top" title="instagram" target="_blank">
<a href="http://instagram.com" rel="nofollow" class="instagram" data-toggle="tooltip" data-placement="top" title="{intl l="Instagram"}" target="_blank">
<span class="icon-stack">
<span class="icon-circle icon-stack-base"></span>
<span class="icon-instagram icon-light"></span>
</span>
<span class="visible-print">{intl l="Instagram"}</span>
</a>
</li>
<li>
<a href="http://google.com" class="google-plus" data-toggle="tooltip" data-placement="top" title="google+" target="_blank">
<a href="http://www.google.com" rel="nofollow" class="google-plus" data-toggle="tooltip" data-placement="top" title="{intl l="Google+"}" target="_blank">
<span class="icon-stack">
<span class="icon-circle icon-stack-base"></span>
<span class="icon-google-plus icon-light"></span>
</span>
<span class="visible-print">{intl l="Google+"}</span>
</a>
</li>
<li>
<a href="http://youtube.com" class="youtube" data-toggle="tooltip" data-placement="top" title="youtube" target="_blank">
<a href="http://www.youtube.com" rel="nofollow" class="youtube" data-toggle="tooltip" data-placement="top" title="{intl l="Youtube"}" target="_blank">
<span class="icon-stack">
<span class="icon-circle icon-stack-base"></span>
<span class="icon-youtube icon-light"></span>
</span>
<span class="visible-print">{intl l="Youtube"}</span>
</a>
</li>
<li>
<a href="#rss" class="rss" data-toggle="tooltip" data-placement="top" title="rss" target="_blank">
<a href="#rss" class="rss" rel="nofollow" data-toggle="tooltip" data-placement="top" title="{intl l="RSS"}" target="_blank">
<span class="icon-stack">
<span class="icon-circle icon-stack-base"></span>
<span class="icon-rss icon-light"></span>
</span>
<span class="visible-print">{intl l="RSS"}</span>
</a>
</li>
</ul>
@@ -328,14 +335,14 @@ GNU General Public License : http://www.gnu.org/licenses/
<section class="block block-newsletter">
<div class="block-heading"><h3 class="block-title">{intl l="Newsletter"}</h3></div>
<div class="block-content">
<p id="newletter-describe">{intl l="Sign up to receive our latest news."}</p>
<p id="newsletter-describe">{intl l="Sign up to receive our latest news."}</p>
{form name="thelia.front.newsletter"}
<form id="form-newsletter-mini" action="{url path="/newsletter"}" method="post" role="form">
<form id="form-newsletter-mini" action="{url path="/newsletter"}" method="post">
{form_hidden_fields form=$form}
{form_field form=$form field="email"}
<div class="form-group">
<label for="{$label_attr.for}-mini">{intl l="Email address"}</label>
<input type="email" name="{$name}" id="{$label_attr.for}-mini" class="form-control" placeholder="{intl l="Your email address"}" aria-describedby="newletter-describe" {if $required} aria-required="true" required{/if} autocomplete="off">
<input type="email" name="{$name}" id="{$label_attr.for}-mini" class="form-control" maxlength="255" placeholder="{intl l="Your email address"}" aria-describedby="newsletter-describe" {if $required} aria-required="true" required{/if} autocomplete="off">
</div>
{/form_field}
<button type="submit" class="btn btn-subscribe">{intl l="Subscribe"}</button>
@@ -349,7 +356,7 @@ GNU General Public License : http://www.gnu.org/licenses/
<section class="block block-contact" itemscope itemtype="http://schema.org/Organization">
<div class="block-heading"><h3 class="block-title">{intl l="Contact Us"}</h3></div>
<div class="block-content">
<meta itemprop="name" content="{config key="company_name"}">
<meta itemprop="name" content="{$company_name}">
<ul>
<li class="contact-address">
<address class="adr" itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">
@@ -387,7 +394,7 @@ GNU General Public License : http://www.gnu.org/licenses/
</ul>
</nav>
<section class="copyright">{intl l="Copyright"} &copy; <time datetime="{'Y-m-d'|date}">{'Y'|date}</time> <a href="http://www.thelia.net" rel="external">Thelia</a></section>
<section class="copyright">{intl l="Copyright"} &copy; <time datetime="{'Y-m-d'|date}">{'Y'|date}</time> <a href="http://thelia.net" rel="external">Thelia</a></section>
</div>
</div>
</footer><!-- /.footer-info -->

View File

@@ -16,7 +16,7 @@
<article class="col-main" role="main" aria-labelledby="main-label">
<h1 id="main-label" class="page-header">{intl l="Login"}</h1>
{form name="thelia.front.customer.login"}
<form id="form-login" action="{url path="/login"}" method="post" role="form" {form_enctype form=$form} novalidate>
<form id="form-login" action="{url path="/login"}" method="post" {form_enctype form=$form} novalidate>
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{navigate to="return_to"}"> {* the url the user is redirected to on login success *}

View File

@@ -11,7 +11,7 @@
<h1 id="main-label" class="page-header">{intl l="Newsletter Subscription"}</h1>
{form name="thelia.front.newsletter"}
<form id="form-newsletter" action="{url path="/newsletter"}" method="post" role="form">
<form id="form-newsletter" action="{url path="/newsletter"}" method="post">
{form_hidden_fields form=$form}
<p>{intl l="You want to subscribe to the newsletter? Please enter your email address below."}</p>
{form_field form=$form field="email"}
@@ -20,7 +20,7 @@
<div class="control-input">
<input type="email" name="{$name}" id="{$label_attr.for}" value="{$value}" class="form-control" maxlength="255" {if $required} aria-required="true" required{/if} autofocus>
{if $error}
<span class="help-block"><span class="icon-remove"></span> {$message}</span>
<span class="help-block">{$message}</span>
{elseif !$error && $value != ""}
<span class="help-block"><span class="icon-ok"></span> {intl l="Thanks for signing up! We'll keep you posted whenever we have any new updates."}</span>
{/if}

View File

@@ -28,7 +28,7 @@
{form name="thelia.order.delivery"}
{assign var="isPost" value="{$smarty.post|count}"}
<form id="form-cart-delivery" action="{url path="/order/delivery"}" method="post" role="form" {form_enctype form=$form}>
<form id="form-cart-delivery" action="{url path="/order/delivery"}" method="post" {form_enctype form=$form}>
{form_hidden_fields form=$form}

View File

@@ -29,7 +29,7 @@
{form name="thelia.order.coupon"}
<form id="form-coupon" action="{url path="/order/coupon"}" method="post" role="form" {form_enctype form=$form}>
<form id="form-coupon" action="{url path="/order/coupon"}" method="post" {form_enctype form=$form}>
{form_hidden_fields form=$form}
@@ -163,7 +163,7 @@
{/form}
{form name="thelia.order.payment"}
<form id="form-cart-payment" action="{url path="/order/invoice"}" method="post" role="form" {form_enctype form=$form}>
<form id="form-cart-payment" action="{url path="/order/invoice"}" method="post" {form_enctype form=$form}>
{form_hidden_fields form=$form}

View File

@@ -16,7 +16,7 @@
<article class="col-main" role="main" aria-labelledby="main-label">
<h1 id="main-label" class="page-header">{intl l="Password Forgotten"}</h1>
{form name="thelia.front.customer.lostpassword"}
<form id="form-forgotpassword" action="{url path="/password"}" method="post" role="form">
<form id="form-forgotpassword" action="{url path="/password"}" method="post">
<p>{intl l="Please enter your email address below."} {intl l="You will receive a link to reset your password."}</p>
{form_field form=$form field="email"}

View File

@@ -137,7 +137,7 @@
</div>
{form name="thelia.cart.add" }
<form id="form-product-details" action="{url path="/cart/add" }" method="post" role="form" class="form-product">
<form id="form-product-details" action="{url path="/cart/add" }" method="post" class="form-product">
{form_hidden_fields form=$form}
<input type="hidden" name="view" value="product">
<input type="hidden" name="product_id" value="{$ID}">

View File

@@ -15,7 +15,7 @@
<h1 id="main-label" class="page-header">{intl l="Create New Account"}</h1>
{form name="thelia.front.customer.create"}
<form id="form-register" class="form-horizontal" action="{url path="/register"}" method="post" role="form">
<form id="form-register" class="form-horizontal" action="{url path="/register"}" method="post">
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/account"}" /> {* the url the user is redirected to on registration success *}
{/form_field}

9
web/robots.txt Normal file
View File

@@ -0,0 +1,9 @@
# robots.txt for Thelia 2 (E-Commerce solution)
# @url: http://www.yourdomain.com
User-agent: *
Disallow: /admin
Disallow: /cart
Disallow: /404
#Sitemap: http://www.yourdomain.com/sitemap.xml