[*] BO : optimization of liveEdit system

[+] FO : new theme file for front-office layout.tpl, designers have now more possibilities

git-svn-id: http://dev.prestashop.com/svn/v1/branches/1.5.x@11235 b9a71923-0436-4b27-9f14-aed3839534dd
This commit is contained in:
mMarinetti
2011-12-14 18:18:57 +00:00
parent d905e14fde
commit 3fc8ef3d88
8 changed files with 310 additions and 186 deletions

View File

@@ -562,11 +562,11 @@ if (Tools::isSubmit('getHookableList'))
die('{"hasError" : true, "errors" : ["Live Edit : This functionnality has been disabled"]}');
/* PrestaShop demo mode*/
if (!strlen(Tools::getValue('hooks_list')))
if (!count(Tools::getValue('hooks_list')))
die('{"hasError" : true, "errors" : ["Live Edit : no module on this page"]}');
$modules_list = explode(',', Tools::getValue('modules_list'));
$hooks_list = explode(',', Tools::getValue('hooks_list'));
$modules_list = Tools::getValue('modules_list');
$hooks_list = Tools::getValue('hooks_list');
$hookableList = array();
foreach ($modules_list as $module)
@@ -629,35 +629,34 @@ if (Tools::isSubmit('saveHook'))
$res = true;
$hookableList = array();
foreach ($hooks_list as $hook)
// $_POST['hook'] is an array of id_module
$hooks_list = Tools::getValue('hook');
foreach ($hooks_list as $id_hook => $modules)
{
$hook = trim($hook);
if (!$hook)
continue;
$sql = 'DELETE FROM '._DB_PREFIX_.'hook_module
WHERE id_hook = ( SELECT id_hook
FROM '._DB_PREFIX_.'hook
WHERE `name` = \''.pSQL($hook).'\' LIMIT 1
)
// 1st, drop all previous hooked modules
$sql = 'DELETE FROM `'._DB_PREFIX_.'hook_module`
WHERE `id_hook` = '.(int)$id_hook.'
AND id_shop = '.$id_shop;
$res &= Db::getInstance()->execute($sql);
$hookedModules = explode(',', Tools::getValue($hook));
$i = 1;
$value = '';
$ids = array();
foreach ($hookedModules as $module)
// then prepare sql query to rehook all chosen modules(id_module, id_shop, id_hook, position)
// position is i (autoincremented)
foreach ($modules as $id_module)
{
$id = explode('_', $module);
if (!in_array($id[1], $ids))
if (!in_array($id_module, $ids))
{
$ids[] = $id[1];
$value .= '('.(int)$id[1].', '.$id_shop.', (SELECT id_hook FROM `'._DB_PREFIX_.'hook` WHERE `name` = \''.pSQL($hook).'\' LIMIT 0, 1), '.$i.'),';
$ids[] = $id_module;
$value .= '('.(int)$id_module.', '.$id_shop.', '.(int)$id_hook.', '.$i.'),';
}
$i++;
}
$value = rtrim($value, ',');
$res &= Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'hook_module (id_module, id_shop, id_hook, position) VALUES '.$value);
$res &= Db::getInstance()->execute('INSERT INTO `'._DB_PREFIX_.'hook_module`
(id_module, id_shop, id_hook, position)
VALUES '.$value);
}
if ($res)

View File

@@ -73,6 +73,9 @@ abstract class ControllerCore
protected $status = '';
protected $redirect_after = null;
/** hook_list is used with liveEdit */
public $hook_list = array();
/**
* check that the controller is available for the current user/visitor
*/

View File

@@ -374,6 +374,13 @@ class FrontControllerCore extends Controller
public function initContent()
{
$this->process();
$this->context->smarty->assign(array(
'HOOK_HEADER' => Hook::exec('displayHeader'),
'HOOK_TOP' => Hook::exec('displayTop'),
'HOOK_LEFT_COLUMN' => Hook::exec('displayLeftColumn'),
'HOOK_RIGHT_COLUMN' => Hook::exec('displayRightColumn', array('cart' => $this->context->cart)),
));
}
public function initCursedPage()
@@ -393,23 +400,40 @@ class FrontControllerCore extends Controller
public function display()
{
Tools::safePostVars();
$this->context->smarty->assign('errors', $this->errors);
if ($this->display_header)
$this->context->smarty->display(_PS_THEME_DIR_.'header.tpl');
if ($this->template)
$this->context->smarty->display($this->template);
if ($this->display_footer)
$this->context->smarty->display(_PS_THEME_DIR_.'footer.tpl');
// live edit
if (Tools::isSubmit('live_edit') AND $ad = Tools::getValue('ad') AND (Tools::getValue('liveToken') == sha1(Tools::getValue('ad')._COOKIE_KEY_)))
// assign css_files and js_files at the very last time
if ((Configuration::get('PS_CSS_THEME_CACHE') OR Configuration::get('PS_JS_THEME_CACHE')) AND is_writable(_PS_THEME_DIR_.'cache'))
{
$this->context->smarty->assign(array('ad' => $ad, 'live_edit' => true));
$this->context->smarty->display(_PS_ALL_THEMES_DIR_.'live_edit.tpl');
// CSS compressor management
if (Configuration::get('PS_CSS_THEME_CACHE'))
$this->css_files = Media::cccCSS($this->css_files);
//JS compressor management
if (Configuration::get('PS_JS_THEME_CACHE'))
$this->js_files = Media::cccJs($this->js_files);
}
$this->context->smarty->assign('css_files', $this->css_files);
$this->context->smarty->assign('js_files', array_unique($this->js_files));
$this->context->smarty->assign(array(
'errors' => $this->errors,
'display_header' => $this->display_header,
'display_footer' => $this->display_footer,
'template' => $this->context->smarty->fetch($this->template),
));
if (Tools::isSubmit('live_edit'))
{
$this->context->smarty->assign('live_edit', $this->getLiveEditFooter());
}
$this->context->smarty->display(_PS_THEME_DIR_.'layout.tpl');
return true;
}
/* Display a maintenance page if shop is closed */
@@ -549,31 +573,37 @@ class FrontControllerCore extends Controller
'priceDisplayPrecision' => _PS_PRICE_DISPLAY_PRECISION_,
'content_only' => (int)Tools::getValue('content_only')
));
$this->context->smarty->assign(array(
'HOOK_HEADER' => Hook::exec('header'),
'HOOK_TOP' => Hook::exec('top'),
'HOOK_LEFT_COLUMN' => Hook::exec('leftColumn')
));
if ((Configuration::get('PS_CSS_THEME_CACHE') OR Configuration::get('PS_JS_THEME_CACHE')) AND is_writable(_PS_THEME_DIR_.'cache'))
{
// CSS compressor management
if (Configuration::get('PS_CSS_THEME_CACHE'))
$this->css_files = Media::cccCSS($this->css_files);
//JS compressor management
if (Configuration::get('PS_JS_THEME_CACHE'))
$this->js_files = Media::cccJs($this->js_files);
}
$this->context->smarty->assign('css_files', $this->css_files);
$this->context->smarty->assign('js_files', array_unique($this->js_files));
}
public function initFooter()
{
$this->context->smarty->assign(array(
'HOOK_RIGHT_COLUMN' => Hook::exec('rightColumn', array('cart' => $this->context->cart)),
'HOOK_FOOTER' => Hook::exec('footer'),
));
}
public function getLiveEditFooter(){
if (Tools::isSubmit('live_edit')
&& ($ad = Tools::getValue('ad'))
&& (Tools::getValue('liveToken') == sha1(Tools::getValue('ad')._COOKIE_KEY_))
)
{
$data = $this->context->smarty->createData();
$data->assign(array(
'ad' => $ad,
'live_edit' => true,
'hook_list' => $this->hook_list,
'id_shop' => $this->context->shop->getId(true)
));
return $this->context->smarty->createTemplate(_PS_ALL_THEMES_DIR_.'live_edit.tpl', $data)->fetch();
}
else
return '';
}
public function productSort()

View File

@@ -62,7 +62,7 @@ class HookCore extends ObjectModel
return false;
$hook_alias_list = Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'hook_alias`');
foreach ($hook_alias_list as $ha)
self::$_hook_alias[strtolower($ha['alias'])] = $ha['name'];
self::$_hook_alias[strtolower($ha['name'])] = $ha['alias'];
return true;
}
@@ -220,7 +220,9 @@ class HookCore extends ObjectModel
// Get retrocompatible hook name
$retro_hook_name = Hook::getRetroHookName($hook_name);
// Get cookie and cart
if (!in_array($hook_name, Context::getContext()->controller->hook_list))
Context::getContext()->controller->hook_list[Hook::getIdByName($hook_name)] = $hook_name;
$live_edit = false;
if (!isset($hookArgs['cookie']) || !$hookArgs['cookie'])
$hookArgs['cookie'] = $context->cookie;

View File

@@ -3,123 +3,158 @@ var hooks_list = new Array();
var hookable_list = new Array();
var timer;
$(document).ready(function() {
$('body').css('margin-bottom', '45px');
$('#fancy').fancybox({
autoDimensions: true,
autoScale: true,
width: 300,
height: 300,
padding: 0,
hideOnOverlayClick: false,
hideOnContentClick: false,
showCloseButton: false
});
$('#live_edit_feedback_str').html('');
$('a').each(function() {
var href = $(this).attr('href');
var search = $(this).attr('search');
var hrefAdd = 'live_edit&liveToken=' + get('liveToken') + '&ad=' + get('ad') + '&id_shop=' + get('id_shop');
if (href != undefined && href != '#' && href.substr(0, baseDir.length) == baseDir) {
if (search.length == 0) {
$(this).attr('search', hrefAdd);
} else {
$(this).attr('search', search + '&' + hrefAdd);
}
}
});
getHookableList();
$('.unregisterHook').unbind('click').click(function() {
id = $(this).attr('id');
$(this).parent().parent().parent().fadeOut('slow', function() {
$(this).remove();
});
return false;
});
$('#cancelMove').unbind('click').click(function() {
$('#' + cancelMove + '').sortable('cancel');
return false;
});
$('#saveLiveEdit').unbind('click').click(function() {
saveModulePosition();
return false;
});
$('#closeLiveEdit').unbind('click').click(function() {
$("#live_edit_feedback_str").html('<div style="padding:10px;"><p style="margin-bottom:10px;">' + confirmClose + '</p><p style="height:1.6em;display:block"><a style="margin:auto;float:left" class="button" href="#" onclick="closeLiveEdit();">' + confirm + '</a><a style="margin:auto;float:right;" class="button" href="#" onclick="closeFancybox();">' + cancel + '</a></p></div>');
$("#fancy").attr('href', '#live_edit_feedback');
$("#fancy").trigger("click");
});
$('.add_module_live_edit').unbind('click').click(function() {
$("#live_edit_feedback_str").html('<div style="padding:10px"><img src="img/loadingAnimation.gif"></div>');
$("#fancy").attr('href', '#live_edit_feedback');
$("#fancy").trigger("click");
var id = $(this).attr('id');
getHookableModuleList(id.substr(4, id.length));
return false;
});
$('.dndHook').each(function() {
var id_hook = $(this).attr('id');
var new_target = '';
var old_target = '';
var cancel = false;
$('#' + id_hook + '').sortable({
opacity: 0.5,
cursor: 'move',
connectWith: '.dndHook',
receive: function(event, ui) {
if (new_target == '') {
new_target = event.target.id;
}
},
start: function(event, ui) {
new_target = ui.item[0].parentNode.id;
},
stop: function(event, ui) {
if (cancel) {
$(this).sortable('cancel');
} else {
old_target = event.target.id;
cancelMove = old_target;
if (new_target == '') new_target = old_target;
}
},
change: function(event, ui) {
new_target = $(ui.placeholder).parent().attr('id');
ids = ui.item[0].id.split('_');
if ($.inArray(ids[5], hookable_list[new_target]) != -1) {
cancel = false;
ui.placeholder.css({
visibility: 'visible',
border: '1px solid #72CB67',
background: '#DFFAD3'
});
} else {
ui.placeholder.css({
visibility: 'visible',
border: '1px solid #EC9B9B',
background: '#FAE2E3'
});
cancel = true;
}
}
});
$('#' + id_hook + '').disableSelection();
});
});
// do some place for submit button
$('body').css('margin-bottom', '45px');
// this is the result box, which will "pop up" the succeed or fail result
$('#fancy').fancybox({
autoDimensions: true,
autoScale: true,
width: 300,
height: 300,
padding: 0,
hideOnOverlayClick: false,
hideOnContentClick: false,
showCloseButton: false
});
$('#live_edit_feedback_str').html('');
// add liveToken in each link to navigate into the shop and keeping the liveedit mode
$('a').each(function() {
var href = $(this).attr('href');
var search = $(this).attr('search');
var hrefAdd = 'live_edit&liveToken=' + get('liveToken') + '&ad=' + get('ad') + '&id_shop=' + get('id_shop');
if (href != undefined && href != '#' && href.substr(0, baseDir.length) == baseDir) {
if (search.length == 0)
{
$(this).attr('search', hrefAdd);
}
else
{
$(this).attr('search', search + '&' + hrefAdd);
}
}
});
// populate
getHookableList();
$('.unregisterHook').unbind('click').click(function() {
id = $(this).attr('id');
$(this).parent().parent().parent().fadeOut('slow', function() {
$(this).remove();
});
return false;
});
$('#cancelMove').unbind('click').click(function() {
$('#' + cancelMove + '').sortable('cancel');
return false;
});
$('#saveLiveEdit').unbind('click').click(function() {
saveModulePosition();
return false;
});
$('#closeLiveEdit').unbind('click').click(function() {
$("#live_edit_feedback_str").html('<div style="padding:10px;"><p style="margin-bottom:10px;">' + confirmClose + '</p><p style="height:1.6em;display:block"><a style="margin:auto;float:left" class="button" href="#" onclick="closeLiveEdit();">' + confirm + '</a><a style="margin:auto;float:right;" class="button" href="#" onclick="closeFancybox();">' + cancel + '</a></p></div>');
$("#fancy").attr('href', '#live_edit_feedback');
$("#fancy").trigger("click");
});
$('.add_module_live_edit').unbind('click').click(function() {
$("#live_edit_feedback_str").html('<div style="padding:10px"><img src="img/loadingAnimation.gif"></div>');
$("#fancy").attr('href', '#live_edit_feedback');
$("#fancy").trigger("click");
var id = $(this).attr('id');
getHookableModuleList(id.substr(4, id.length));
return false;
});
$('.dndHook').each(function() {
var id_hook = $(this).attr('id');
var new_target_id = '';
var old_target = '';
var cancel = false;
$('#' + id_hook + '').sortable({
opacity: 0.5,
cursor: 'move',
connectWith: '.dndHook',
receive: function(event, ui) {
if (new_target_id == '') {
new_target_id = event.target.id;
}
},
start: function(event, ui) {
new_target_id = ui.item[0].parentNode.id;
},
stop: function(event, ui) {
if (cancel)
{
$(this).sortable('cancel');
}
else
{
old_target = event.target.id;
cancelMove = old_target;
if (new_target_id == '')
new_target_id = old_target;
ids = $(ui.item[0]).attr('id').split('_');
newHookId = $("input[value="+new_target_id+"]").attr('name').substr(10);
newHookId = newHookId.substr(0, newHookId.length -1);
new_id = ids[0] + "_" + newHookId + "_" + ids[2] + "_" + ids[3];
$(ui.item[0]).attr('id', new_id);
}
},
change: function(evartent, ui) {
new_target_id = $(ui.placeholder).parent().attr('id');
ids = ui.item[0].id.split('_');
if ($.inArray(ids[5], hookable_list[new_target_id]) != -1) {
cancel = false;
ui.placeholder.css({
visibility: 'visible',
border: '1px solid #72CB67',
background: '#DFFAD3'
});
}
else
{
ui.placeholder.css({
visibility: 'visible',
border: '1px solid #EC9B9B',
background: '#FAE2E3'
});
cancel = true;
}
}
});
// WTF
$('#' + id_hook + '').disableSelection();
});
});
// init hookable_list
function getHookableList() {
hooks_list = new Array();
$("input[name^=hook_list]}").each(function(e){
hooks_list.push($(this).val());
// +$(this).val();
});
$.ajax({
type: 'GET',
type: 'POST',
url: baseDir + ad + '/ajax.php',
async: true,
dataType: 'json',
data: 'ajax=true&getHookableList&hooks_list=' + hooks_list + '&modules_list=' + modules_list + '&id_shop=' + get('id_shop'),
data: {ajax:"true",
'getHookableList':1,
'hooks_list' : hooks_list,
modules_list : modules_list,
id_shop : get('id_shop')
},
success: function(jsonData) {
if (jsonData.hasError) {
var errors = '';
for (error in jsonData.errors) //IE6 bug fix
if (error != 'indexOf') errors += jsonData.errors[error] + "\n";
alert(errors);
} else hookable_list = jsonData;
if (error != 'indexOf')
errors += jsonData.errors[error] + "\n";
alert(errors);
}
else
hookable_list = jsonData;// create and fill input array
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$('#live_edit_feedback_str').html('<div class="live_edit_feed_back_ko"><img src="img/admin/error.png"><h3>TECHNICAL ERROR:</h3>' + loadFail + '<br><br><a style="margin:auto" class="button" href="#" onclick="closeFancybox();">' + close + '</a></div>');
@@ -149,6 +184,7 @@ function getHookableModuleList(hook) {
});
}
function saveModulePosition() {
$("input.dynamic-input-save-position").remove();
$("#live_edit_feedback_str").html('<div style="padding:10px"><img src="img/loadingAnimation.gif"></div>');
$("#fancy").attr('href', '#live_edit_feedback');
$("#fancy").trigger("click");
@@ -157,47 +193,56 @@ function saveModulePosition() {
str += '&' + hooks_list[i] + '=';
$('#' + hooks_list[i] + ' > .dndModule').each(function() {
ids = $(this).attr('id').split('_');
str += ids[1] + '_' + ids[3] + ',';
$("#liveEdit-action-form")
.append('<input class="dynamic-input-save-position" type="hidden" name="hook['+ids[1]+'][]" value="'+ids[3]+'" />');
});
str = str.substr(0, str.length - 1);
}
$("#liveEdit-action-form")
.append('<input class="dynamic-input-save-position" type="hidden" name="saveHook" value="1" />');
datas = $("#liveEdit-action-form").serializeArray();
$.ajax({
type: 'GET',
url: baseDir + ad + '/ajax.php',
type: 'POST',
url: baseDir + ad + "/ajax.php",
async: true,
dataType: 'json',
data: 'ajax=true&saveHook&hooks_list=' + hooks_list + str + '&id_shop=' + get('id_shop'),
data: datas,
success: function(jsonData) {
$('#live_edit_feedback_str').html('<div class="live_edit_feed_back_ok"><img src="img/admin/ok2.png"><h3>' + saveOK + '</h3><a style="margin:auto" class="exclusive" href="#" onclick="closeFancybox();">' + close + '</a></div>');
$('#live_edit_feedback_str').html('<div class="live_edit_feed_back_ok"><img src="img/admin/ok2.png"><h3>' + saveOK + '</h3><a style="margin:auto" class="exclusive" href="#" onclick="closeFancybox();">' + close + '</a></div>');
timer = setTimeout("hideFeedback()", 3000);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$('#live_edit_feedback_str').html('<div class="live_edit_feed_back_ko"><img src="img/admin/error.png"><h3>TECHNICAL ERROR:</h3>' + unableToSaveModulePosition + '<br><br><a style="margin:auto" class="button" href="#" onclick="closeFancybox();">' + close + '</a></div>');
}
});
}
)
return true;
}
function closeFancybox() {
clearTimeout(timer);
$.fancybox.close();
$('#live_edit_feedback_str').html('');
clearTimeout(timer);
$.fancybox.close();
$('#live_edit_feedback_str').html('');
}
function closeLiveEdit(){
window.location.href = window.location.protocol+'//'+window.location.host+window.location.pathname;
}
function hideFeedback() {
$('#live_edit_feed_back').fadeOut('slow', function() {
$.fancybox.close();
$('#live_edit_feedback_str').html('');
});
$('#live_edit_feed_back').fadeOut('slow', function() {
$.fancybox.close();
$('#live_edit_feedback_str').html('');
});
};
function get(name) {
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.href);
if (results == null) {
return "";
} else {
return results[1];
}
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.href);
if (results == null) {
return "";
}
else {
return results[1];
}
}

View File

@@ -24,4 +24,4 @@
* International Registered Trademark & Property of PrestaShop SA
*}
{$HOOK_HOME}
{$HOOK_HOME}

37
themes/default/layout.tpl Normal file
View File

@@ -0,0 +1,37 @@
{*
* 2007-2011 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 license@prestashop.com 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 <contact@prestashop.com>
* @copyright 2007-2011 PrestaShop SA
* @version Release: $Revision$
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*}
{if isset($display_header)}
{include file='./header.tpl' HOOK_HEADER=$HOOK_HEADER}
{/if}
{if isset($template)}
{$template}
{/if}
{if isset($display_footer)}
{include file='./footer.tpl'}
{/if}
{if isset($live_edit)}
{$live_edit}
{/if}

View File

@@ -24,8 +24,8 @@
* International Registered Trademark & Property of PrestaShop SA
*}
<script type="text/javascript">
{if isset($ad) && isset($live_edit)}
var ad = "{$smarty.get.ad}";
{if isset($smarty.get.ad) && isset($smarty.get.live_edit)}
var ad = "{$smarty.get.ad}";
{/if}
var lastMove = '';
var saveOK = '{l s='Module position saved'}';
@@ -40,8 +40,16 @@
</script>
<div style="width:100%;height:30px;padding-top:10px;background-color:#D0D3D8;border:solid 1px gray;position:fixed;bottom:0;left:0;opacity:0.7" onmouseover="$(this).css('opacity', 1);" onmouseout="$(this).css('opacity', 0.7);">
<input type="submit" value="{l s='Save'}" id="saveLiveEdit" class="exclusive" style="float:left">
<form id="liveEdit-action-form" action="./{$ad}/ajax.php" method="POST" >
<input type="hidden" name="ajax" value="true" />
<input type="hidden" name="id_shop" value="{$id_shop}" />
{foreach from=$hook_list key=hook_id item=hook_name}
<input class="hook_list" type="hidden" name="hook_list[{$hook_id}]"
value="{$hook_name}" />
{/foreach}
<input type="submit" value="{l s='Save'}" name="saveHook" id="saveLiveEdit" class="exclusive" style="float:left">
<input type="submit" value="{l s='Close Live edit'}" id="closeLiveEdit" class="button" style="float:left">
</form>
<div style="float:right;margin-right:20px;" id="live_edit_feed_back"></div>
</div>
<a href="#" style="display:none;" id="fancy"></a>