diff --git a/admin-dev/ajax-tab.php b/admin-dev/ajax-tab.php new file mode 100755 index 000000000..f6abe3658 --- /dev/null +++ b/admin-dev/ajax-tab.php @@ -0,0 +1,91 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +define('_PS_ADMIN_DIR_', getcwd()); +define('PS_ADMIN_DIR', _PS_ADMIN_DIR_); // Retro-compatibility + +include(_PS_ADMIN_DIR_.'/../config/config.inc.php'); +include(_PS_ADMIN_DIR_.'/functions.php'); + + +include(_PS_ADMIN_DIR_.'/init.php'); + +if (empty($tab) and !sizeof($_POST)) +{ + $tab = 'AdminHome'; + $_POST['tab'] = 'AdminHome'; + $_POST['token'] = Tools::getAdminTokenLite($tab); +} + if ($id_tab = checkingTab($tab)) + { + $isoUser = Language::getIsoById(intval($cookie->id_lang)); + + + if (Validate::isLoadedObject($adminObj)) + { + $adminObj->ajax = true; + if ($adminObj->checkToken()) + { + // the differences with index.php is here + + $adminObj->ajaxPreProcess(); + $action = Tools::getValue('action'); + + // no need to use displayConf() here + + if (!empty($action) AND method_exists($adminObj, 'ajaxProcess'.Tools::toCamelCase($action)) ) + $adminObj->{'ajaxProcess'.Tools::toCamelCase($action)}(); + else + $adminObj->ajaxProcess(); + + // @TODO We should use a displayAjaxError + $adminObj->displayErrors(); + if (!empty($action) AND method_exists($adminObj, 'displayAjax'.Tools::toCamelCase($action)) ) + $adminObj->{'displayAjax'.$action}(); + else + $adminObj->displayAjax(); + + } + else + { + // If this is an XSS attempt, then we should only display a simple, secure page + ob_clean(); + + // ${1} in the replacement string of the regexp is required, because the token may begin with a number and mix up with it (e.g. $17) + $url = preg_replace('/([&?]token=)[^&]*(&.*)?$/', '${1}'.$adminObj->token.'$2', $_SERVER['REQUEST_URI']); + if (false === strpos($url, '?token=') AND false === strpos($url, '&token=')) + $url .= '&token='.$adminObj->token; + + // we can display the correct url + // die(Tools::jsonEncode(array(translate('Invalid security token'),$url))); + die(Tools::jsonEncode(translate('Invalid security token'))); + } + } + } + + + diff --git a/admin-dev/ajax.php b/admin-dev/ajax.php index 4e9b5abd6..eeaa2f5a6 100644 --- a/admin-dev/ajax.php +++ b/admin-dev/ajax.php @@ -688,7 +688,7 @@ if (Tools::isSubmit('getAdminHomeElement')) if (Tools::isSubmit('getChildrenCategories') && Tools::getValue('id_category_parent')) { - $children_categories = Category::getChildrenWithNbSelectedSubCatForProduct(Tools::getValue('id_category_parent'), Tools::getValue('id_product', 0), Tools::getValue('post_selected_cat', null), $cookie->id_lang); + $children_categories = Category::getChildrenWithNbSelectedSubCat(Tools::getValue('id_category_parent'), Tools::getValue('selectedCat', array()), $cookie->id_lang); die(Tools::jsonEncode($children_categories)); } diff --git a/admin-dev/functions.php b/admin-dev/functions.php index b045e5c28..1c7a0503f 100644 --- a/admin-dev/functions.php +++ b/admin-dev/functions.php @@ -207,10 +207,9 @@ function createDir($path, $rights) function checkPSVersion() { - libxml_set_streams_context(stream_context_create(array('http' => array('timeout' => 3)))); - if ($feed = @simplexml_load_file('http://www.prestashop.com/xml/version.xml') AND _PS_VERSION_ < $feed->version->num) - return array('name' => $feed->version->name, 'link' => $feed->download->link); - return false; + $upgrader = new Upgrader(); + + return $upgrader->checkPSVersion(); } function translate($string) diff --git a/admin-dev/index.php b/admin-dev/index.php index b164e1459..008b47508 100644 --- a/admin-dev/index.php +++ b/admin-dev/index.php @@ -52,7 +52,7 @@ if (empty($tab) and !sizeof($_POST)) ? '' : '').' '.$item['name'].((sizeof($tabs) - 1 > $key) ? '' : ''); - + // @TODO : a way to desactivate this feature echo''; + if (Tools::isSubmit('categoryBox')) + { + $postCat = Tools::getValue('categoryBox'); + $selectedCat = Category::getSimpleCategories($this->_defaultFormLanguage, false, true, 'AND c.`id_category` IN ('.(empty($postCat) ? '1' : implode(',', $postCat)).')'); + echo ''; + } + if ($obj->id) + $selectedCat = Product::getProductCategoriesFull($obj->id, $this->_defaultFormLanguage); + else if(!Tools::isSubmit('categoryBox')) + $selectedCat[] = array('id_category' => 1, 'name' => $this->l('Home')); + echo ' + + + + + '; + // Translations are not automatic for the moment ;) + $trads = array( + 'Home' => $this->l('Home'), + 'selected' => $this->l('selected'), + 'Collapse All' => $this->l('Collapse All'), + 'Expand All' => $this->l('Expand All'), + 'Check All' => $this->l('Check All'), + 'Uncheck All' => $this->l('Uncheck All') + ); + echo Helper::renderAdminCategorieTree($trads, $selectedCat).' + +
'.$this->l('SEO').''.$this->l('Click here to improve product\'s rank in search engines (SEO)').'
@@ -2719,7 +2759,7 @@ class AdminProducts extends AdminTab '.$this->l('Meta title:').' '; - foreach ($this->_languages as $language) + foreach ($this->_languages AS $language) echo '
@@ -2894,18 +2934,10 @@ class AdminProducts extends AdminTab '; $categoryBox = Tools::getValue('categoryBox', array()); - echo ' - $(function() { - $.ajax({ - type: \'POST\', - url: \'ajax_category_list.php\', - data: \''.(sizeof($categoryBox) > 0 ? 'categoryBox='.serialize($categoryBox).'&' : '').'id_product='.$obj->id.'&id_category_default='.($this->getFieldValue($obj, 'id_category_default') ? $this->getFieldValue($obj, 'id_category_default') : Tools::getValue('id_category', 1)).'&id_category='.(int)(Tools::getValue('id_category')).'&token='.$this->token.'\', - async : true, - success: function(msg) { $(\'#tr_categories\').replaceWith(msg); } - }); - });'; + } function displayFormImages($obj, $token = NULL) diff --git a/admin-dev/tabs/AdminStores.php b/admin-dev/tabs/AdminStores.php index 396c08d4a..917d4bc18 100644 --- a/admin-dev/tabs/AdminStores.php +++ b/admin-dev/tabs/AdminStores.php @@ -112,6 +112,11 @@ class AdminStores extends AdminTab if ((int)($country->contains_states) AND !$id_state) $this->_errors[] = Tools::displayError('An address located in a country containing states must have a state selected.'); + $latitude = (int)(Tools::getValue('latitude')); + $longitude = (int)(Tools::getValue('longitude')); + if(empty($latitude) OR empty($longitude)) + $this->_errors[] = Tools::displayError('Latitude and longitude are required.'); + /* Check zip code */ if ($country->need_zip_code) { @@ -227,6 +232,7 @@ class AdminStores extends AdminTab
/ + *

'.$this->l('Store coords, eg. 45.265469 / -47.226478').'

diff --git a/admin-dev/tabs/AdminThemes.php b/admin-dev/tabs/AdminThemes.php index 938ff03aa..a35d3fff4 100644 --- a/admin-dev/tabs/AdminThemes.php +++ b/admin-dev/tabs/AdminThemes.php @@ -266,6 +266,7 @@ class AdminThemes extends AdminPreferences Configuration::updateValue('PS_IMG_UPDATE_TIME', time()); if (!empty($val) AND !$this->_isThemeCompatible($val)) // don't submit if errors unset($_POST['submitThemes'.$this->table]); + Tools::clearCache($smarty); parent::postProcess(); } } diff --git a/admin-dev/tabs/AdminTranslations.php b/admin-dev/tabs/AdminTranslations.php index 90e2ecbab..baba819e0 100644 --- a/admin-dev/tabs/AdminTranslations.php +++ b/admin-dev/tabs/AdminTranslations.php @@ -157,7 +157,7 @@ class AdminTranslations extends AdminTab } } if ($bool) - Tools::redirectLink(self::$currentIndex.'&conf=14&token='.$this->token); + Tools::redirectAdmin(self::$currentIndex.'&conf=14&token='.$this->token); $this->_errors[] = $this->l('a part of the data has been copied but some language files could not be found or copied'); } diff --git a/admin-dev/tabs/AdminUpgrade.php b/admin-dev/tabs/AdminUpgrade.php new file mode 100755 index 000000000..d429103f3 --- /dev/null +++ b/admin-dev/tabs/AdminUpgrade.php @@ -0,0 +1,1798 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +include_once(_PS_ADMIN_DIR_.'/tabs/AdminPreferences.php'); + +class AdminUpgrade extends AdminPreferences +{ + public $ajax = false; + public $nextResponseType = 'json'; // json, xml + public $next = 'N/A'; + + /** + * set to false if the current step is a loop + * + * @var boolean + */ + public $stepDone = true; + public $error ='0'; + public $nextDesc = '.'; + public $nextParams = array(); + public $nextQuickInfo = array(); + public $currentParams = array(); + public $autoupgradePath = ''; + /** + * autoupgradeDir + * + * @var string directory relative to admin dir + */ + public $autoupgradeDir = 'autoupgrade'; + public $latestRootDir = ''; + public $prodRootDir = ''; + public $rootWritable = false; + public $svnDir = 'svn'; + public $destDownloadFilename = 'prestashop.zip'; + public $toUpgradeFileList = array(); + public $backupFileList = array(); + public $sampleFileList = array(); + private $backupIgnoreFiles = array(); + private $backupIgnoreAbsoluteFiles = array(); + private $excludeFilesFromUpgrade = array(); + private $excludeAbsoluteFilesFromUpgrade = array(); + +/** + * int loopBackupFiles : if your server has a low memory size, lower this value + * @TODO remove the static, add a const, and use it like this : min(AdminUpgrade::DEFAULT_LOOP_ADD_FILE_TO_ZIP,Configuration::get('LOOP_ADD_FILE_TO_ZIP'); + */ + public static $loopBackupFiles = 1000; +/** + * int loopUpgradeFiles : if your server has a low memory size, lower this value + */ + public static $loopUpgradeFiles = 1000; +/** + * intloopRemoveSamples : if your server has a low memory size, lower this value + */ + public static $loopRemoveSamples = 1000; + +// public static $skipAction = array('unzip'=>'listSampleFiles'); + public static $skipAction; + public $useSvn; + + protected $_includeContainer = false; + + public function __construct() + { + @set_time_limit(0); + @ini_set('max_execution_time', '0'); + + $this->init(); + parent::__construct(); + } + + /** + * _setFields function to set fields (only when we need it). + * + * @return void + */ + private function _setFields() + { + $this->_fieldsAutoUpgrade['PS_AUTOUP_DONT_SAVE_IMAGES'] = array( + 'title' => $this->l('Don\'t save images'), 'cast' => 'intval', 'validation' => 'isBool', + 'type' => 'bool', 'desc'=>$this->l('You can exclude the image directory from backup if you already saved it by an other method. (not recommended)'), + ); + + $this->_fieldsAutoUpgrade['PS_AUTOUP_KEEP_DEFAULT_THEME'] = array( + 'title' => $this->l('Keep theme "prestashop"'), 'cast' => 'intval', 'validation' => 'isBool', + 'type' => 'bool', 'desc'=>$this->l('if you have customized prestashop default theme, you can protect it from upgrade (not recommended)'), + ); + + $this->_fieldsAutoUpgrade['PS_AUTOUP_KEEP_TRAD'] = array( + 'title' => $this->l('Don\'t keep translations'), 'cast' => 'intval', 'validation' => 'isBool', + 'type' => 'bool', 'desc'=>$this->l('If set too yes, you will keep all your translations'), + ); + // allow manual mode only for dev + if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) + $this->_fieldsAutoUpgrade['PS_AUTOUP_MANUAL_MODE'] = array( + 'title' => $this->l('Manual mode'), 'cast' => 'intval', 'validation' => 'isBool', + 'type' => 'bool', 'desc'=>$this->l('Check this if you want to stop after each step'), + ); + + if (defined('_PS_ALLOW_UPGRADE_UNSTABLE_') AND _PS_ALLOW_UPGRADE_UNSTABLE_ AND function_exists('svn_checkout')) + { + $this->_fieldsAutoUpgrade['PS_AUTOUP_USE_SVN'] = array( + 'title' => $this->l('Use Subversion'), 'cast' => 'intval', 'validation' => 'isBool', + 'type' => 'bool', 'desc' => $this->l('check this if you want to use unstable svn instead of official release'), + ); + } + } + + /** + * isUpgradeAllowed checks if all server configuration is valid for upgrade + * + * @return void + */ + public function isUpgradeAllowed() + { + $allowed = (ConfigurationTest::test_fopen() && $this->rootWritable); + + if (!defined('_PS_MODE_DEV_') OR !_PS_MODE_DEV_) + $allowed &= $this->upgrader->autoupgrade; + + return $allowed; + } + + /** + * init to build informations we need + * + * @return void + */ + public function init() + { + // For later use, let's set up prodRootDir and adminDir + // This way it will be easier to upgrade a different path if needed + $this->prodRootDir = _PS_ROOT_DIR_; + $this->adminDir = _PS_ADMIN_DIR_; + + // test writable recursively + if (ConfigurationTest::test_dir($this->prodRootDir,true)) + $this->rootWritable = true; + + // checkPSVersion will be not + $this->upgrader = new Upgrader(true); + $this->upgrader->checkPSVersion(); + // If you have defined this somewhere, you know what you do + if (defined('_PS_ALLOW_UPGRADE_UNSTABLE_') AND _PS_ALLOW_UPGRADE_UNSTABLE_ AND function_exists('svn_checkout')) + { + $this->useSvn = Configuration::get('PS_AUTOUP_USE_SVN'); + } + else + $this->useSvn = false; + + // from $_POST or $_GET + $this->action = Tools::getValue('action'); + $this->currentParams = Tools::getValue('params'); + + // If not exists in this sessions, "create" + // session handling : from current to next params + if (isset($this->currentParams['removeList'])) + $this->nextParams['removeList'] = $this->currentParams['removeList']; + + if (isset($this->currentParams['filesToUpgrade'])) + $this->nextParams['filesToUpgrade'] = $this->currentParams['filesToUpgrade']; + + $this->backupDbFilename = Configuration::get('UPGRADER_BACKUPDB_FILENAME'); + $this->backupFilesFilename = Configuration::get('UPGRADER_BACKUPFILES_FILENAME'); + + $this->autoupgradePath = $this->adminDir.DIRECTORY_SEPARATOR.$this->autoupgradeDir; + + if (!file_exists($this->autoupgradePath)) + if (!@mkdir($this->autoupgradePath,0777)) + $this->_errors[] = Tools::displayError(sprintf($this->l('unable to create directory %s'),$this->autoupgradePath)); + + $latest = $this->autoupgradePath.DIRECTORY_SEPARATOR.'latest'; + if (!file_exists($latest)) + if (!@mkdir($latest,0777)) + $this->_errors[] = Tools::displayError(sprintf($this->l('unable to create directory %s'),$latest)); + + $this->latestRootDir = $latest.DIRECTORY_SEPARATOR.'prestashop'; + $this->adminDir = str_replace($this->prodRootDir,'',$this->adminDir); + // @TODO future option + // $this->testRootDir = $this->autoupgradePath.DIRECTORY_SEPARATOR.'test'; + + /* optional skips */ + $this->dontBackupImages = Configuration::get('PS_AUTOUP_DONT_SAVE_IMAGES'); + $this->keepDefaultTheme = Configuration::get('PS_AUTOUP_KEEP_DEFAULT_THEME'); + $this->keepTrad = Configuration::get('PS_AUTOUP_KEEP_TRAD'); + $this->manualMode = Configuration::get('PS_AUTOUP_MANUAL_MODE'); + // We can add any file or directory in the exclude dir : theses files will be not removed or overwritten + // @TODO cache should be ignored recursively, but we have to reconstruct it after upgrade + // - compiled from smarty + // - .svn + $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty_v2/compile"; + $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty_v2/cache"; + $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty/compile"; + $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty/cache"; + + $this->excludeFilesFromUpgrade[] = '.'; + $this->excludeFilesFromUpgrade[] = '..'; + $this->excludeFilesFromUpgrade[] = '.svn'; + $this->excludeFilesFromUpgrade[] = 'install'; + $this->excludeFilesFromUpgrade[] = 'settings.inc.php'; + $this->excludeFilesFromUpgrade[] = 'autoupgrade'; + $this->backupIgnoreFiles[] = '.'; + $this->backupIgnoreFiles[] = '..'; + $this->backupIgnoreFiles[] = '.svn'; + $this->backupIgnoreFiles[] = 'autoupgrade'; + + if ($this->dontBackupImages) + $this->backupIgnoreAbsoluteFiles[] = "/img"; + + + if ($this->keepDefaultTheme) + $this->excludeAbsoluteFilesFromUpgrade[] = "/themes/prestashop"; + + if ($this->keepTrad) + $this->excludeFilesFromUpgrade[] = "translations"; + } + + /** + * getFilePath return the path to the zipfile containing prestashop. + * + * @return void + */ + private function getFilePath() + { + return $this->autoupgradePath.DIRECTORY_SEPARATOR.$this->destDownloadFilename; + } + + public function postProcess() + { + $this->_setFields(); + + if (!empty($_POST)) + $this->_postConfig($this->_fieldsAutoUpgrade); + } + + public function ajaxProcessUpgradeNow() + { + $this->nextDesc = 'Starting upgrade ...'; + $this->next = 'desactiveShop'; + } + public function ajaxProcessSvnExport() + { + if ($this->useSvn) + { + // first of all, delete the content of the latest root dir just in case + if (is_dir($this->latestRootDir)) + Tools::deleteDirectory($this->latestRootDir, false); + + if (!file_exists($this->latestRootDir)) + { + @mkdir($this->latestRootDir); + } + + if (svn_export($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->svnDir, $this->latestRootDir)) + { + + // export means svn means install-dev and admin-dev. + // let's rename admin to the correct admin dir + // and rename install-dev to install + $adminDir = str_replace($this->prodRootDir, '', $this->adminDir); + rename($this->latestRootDir.DIRECTORY_SEPARATOR.'install-dev', $this->latestRootDir.DIRECTORY_SEPARATOR.'install'); + rename($this->latestRootDir.DIRECTORY_SEPARATOR.'admin-dev', $this->latestRootDir.DIRECTORY_SEPARATOR.$adminDir); + + // Unsetting to force listing + unset($this->nextParams['removeList']); + $this->next = "removeSamples"; + $this->nextDesc = $this->l('Export svn complete. removing sample files...'); + return true; + } + else + { + $this->next = 'error'; + $this->nextDesc = $this->l('error when svn export '); + } + } + } + + public function ajaxProcessUnzip(){ + // @TODO : not require_once like that. + $filepath = $this->getFilePath(); + $destExtract = $this->autoupgradePath.DIRECTORY_SEPARATOR.'latest'; + if (file_exists($destExtract)) + Tools::deletedirectory($destExtract); + + if (Tools::ZipExtract($filepath,$destExtract)) + { + $adminDir = str_replace($this->prodRootDir, '', $this->adminDir); + rename($this->latestRootDir.DIRECTORY_SEPARATOR.'admin', $this->latestRootDir.DIRECTORY_SEPARATOR.$adminDir); + // Unsetting to force listing + unset($this->nextParams['removeList']); + $this->next = "removeSamples"; + $this->nextDesc = $this->l('Extract complete. removing sample files...'); + return true; + } + else{ + $this->next = "error"; + $this->nextDesc = sprintf($this->l('unable to extract %2$s into %2$s ...'),$filepath,$destExtract); + return true; + } + } + + + /** + * _listSampleFiles will make a recursive call to scandir() function + * and list all file which match to the $fileext suffixe (this can be an extension or whole filename) + * + * @TODO maybe $regex instead of $fileext ? + * @param string $dir directory to look in + * @param string $fileext suffixe filename + * @return void + */ + private function _listSampleFiles($dir, $fileext = '.jpg'){ + $res = true; + $dir = rtrim($dir,'/').DIRECTORY_SEPARATOR; + + $toDel = scandir($dir); + // copied (and kind of) adapted from AdminImages.php + foreach ($toDel AS $file) + { + if ($file!='.' AND $file != '..' AND $file != '.svn') + { + + if (preg_match('#'.preg_quote($fileext,'#').'$#i',$file)) + { + $this->sampleFileList[] = $dir.$file; + } + else if (is_dir($dir.$file)) + { + $res &= $this->_listSampleFiles($dir.$file); + } + } + } + return $res; + } + + public function _listBackupFiles($dir) + { + $allFiles = scandir($dir); + foreach ($allFiles as $file) + { + $fullPath = $dir.DIRECTORY_SEPARATOR.$file; + + if (!$this->_skipFile($file, $fullPath,'backup')) + { + if (is_dir($fullPath)) + $this->_listBackupFiles($fullPath); + else + $this->backupFileList[] = $fullPath; + } + else + $this->backupIgnoreFiles[] = $fullPath; + + } + } + + public function _listFilesToUpgrade($dir) + { + $allFiles = scandir($dir); + foreach ($allFiles as $file) + { + $fullPath = $dir.DIRECTORY_SEPARATOR.$file; + + if (!$this->_skipFile($file, $fullPath, "upgrade")) + { + if (is_dir($fullPath)) + { + // if is_dir, we will create it :)e it :) + $this->toUpgradeFileList[] = $fullPath; + if (strpos($dir.DIRECTORY_SEPARATOR.$file, 'install') === false) + { + $this->_listFilesToUpgrade($fullPath); + } + } + else + $this->toUpgradeFileList[] = $fullPath; + } + } + + $this->nextParams['filesToUpgrade'] = $this->toUpgradeFileList; + } + + public function ajaxProcessDesactiveShop() + { + $this->ShopActiveValue = Configuration::get('PS_SHOP_ENABLE'); + Configuration::updateValue('PS_SHOP_ENABLE',0); + if ($this->useSvn) + { + $this->next = 'svnCheckout'; + $this->nextDesc = $this->l('switching to svn checkout (useSvn set to true)'); + } + else + { + $this->next = 'download'; + $this->nextDesc = $this->l('Shop desactivated. Now downloading (this can takes some times )...'); + } + } + + public function ajaxProcessUpgradeFiles(){ + // @TODO : + $this->nextParams = $this->currentParams; + if (!isset($this->nextParams['filesToUpgrade'])) + $this->_listFilesToUpgrade($this->latestRootDir); + + // later we could choose between _PS_ROOT_DIR_ or _PS_TEST_DIR_ + $this->destUpgradePath = $this->prodRootDir; + + // upgrade files one by one like for the backup + // with a 1000 loop because it's funny + // @TODO : + // foreach files in latest, copy + $this->next = 'upgradeFiles'; + if (!is_array($this->nextParams['filesToUpgrade'])) + { + error($this->nextParams); + $this->next = 'error'; + $this->nextDesc = $this->l('filesToUpgrade is not an array'); + $this->nextQuickInfo[] = $this->l('filesToUpgrade is not an array'); + return false; + } + + // @TODO : does not upgrade files in modules, translations if they have not a correct md5 (or crc32, or whatever) from previous version + for ($i=0;$inextParams['filesToUpgrade'])<=0) + { + $this->next = 'upgradeDb'; + $this->nextDesc = $this->l('All files upgraded. Now upgrading database'); + $this->nextResponseType = 'xml'; + break; + } + + //$file = array_shift($this->nextParams['filesToUpgrade']); + $file = array_shift($this->nextParams['filesToUpgrade']); + if (!$this->upgradeThisFile($file)) + { + // put the file back to the begin of the list + $totalFiles = array_unshift($this->nextParams['filesToUpgrade'],$file); + $this->next = 'error'; + $this->nextQuickInfo[] = sprintf($this->l('error when trying to upgrade %s'),$file); + break; + } + else{ + // @TODO : maybe put several files at the same times ? + $this->nextDesc = sprintf($this->l('%2$s files left to upgrade.'),$file,sizeof($this->nextParams['filesToUpgrade'])); + } + } + } + + /** + * model_doUpgrade prepare the call to doUpgrade.php file (like model.php) + * + * @return void + */ + public function _modelDoUpgrade() + { + // a. set logger + // it will be used later + global $logger; + $logger = new FileLogger(); + if (function_exists('date_default_timezone_set')) + date_default_timezone_set('Europe/Paris'); + // use autoupgrade as log dir + $logger->setFilename($this->latestRootDir.'/'.date('Ymd').'_autoupgrade.log'); + + // init env. + @set_time_limit(0); + @ini_set('max_execution_time', '0'); + // setting the memory limit to 128M only if current is lower + $memory_limit = ini_get('memory_limit'); + if (substr($memory_limit,-1) != 'G' + AND ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128) + OR is_numeric($memory_limit) AND (intval($memory_limit) < 131072)) + ){ + @ini_set('memory_limit','128M'); + } + + /* Redefine REQUEST_URI if empty (on some webservers...) */ + if (!isset($_SERVER['REQUEST_URI']) || $_SERVER['REQUEST_URI'] == '') + $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME']; + + if ($tmp = strpos($_SERVER['REQUEST_URI'], '?')) + $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $tmp); + + $_SERVER['REQUEST_URI'] = str_replace('//', '/', $_SERVER['REQUEST_URI']); + + /////////////////////// + // Copy from model.php + /////////////////////// + $upgrader = $this->upgrader; + $upgrader->checkPSVersion(); + + define('INSTALL_VERSION', $upgrader->version_num); + // now the install dir to use is in a subdirectory of the admin dir + define('INSTALL_PATH', realpath($this->latestRootDir.DIRECTORY_SEPARATOR.'install')); + + define('PS_INSTALLATION_IN_PROGRESS', true); + // Note : we don't need ToolsInstall.php + // include_once(INSTALL_PATH.'/classes/ToolsInstall.php'); + + define('SETTINGS_FILE', $this->prodRootDir . '/config/settings.inc.php'); + define('DEFINES_FILE', $this->prodRootDir .'/config/defines.inc.php'); + define('INSTALLER__PS_BASE_URI', substr($_SERVER['REQUEST_URI'], 0, -1 * (strlen($_SERVER['REQUEST_URI']) - strrpos($_SERVER['REQUEST_URI'], '/')) - strlen(substr(dirname($_SERVER['REQUEST_URI']), strrpos(dirname($_SERVER['REQUEST_URI']), '/')+1)))); + + // Note : INSTALLER__PS_BASE_URI_ABSOLUTE is not used for upgrade + // define('INSTALLER__PS_BASE_URI_ABSOLUTE', 'http://'.ToolsInstall::getHttpHost(false, true).INSTALLER__PS_BASE_URI); + + // XML Header + header('Content-Type: text/xml'); + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'doUpgrade.php'); + + ////////////////////////////// + // End of copy from model.php + ////////////////////////////// + + } + + public function ajaxProcessUpgradeDb(){ + // @TODO : 1/2/3 have to be done at the beginning !!!!!!!!!!!!!!!!!!!!!! + + // use something like actual in install-dev + // Notice : xml used here ... + + // 1) confirm version is correct(DB) + // install/model.php?method=getVersionFromDb&language=0 + // later + + // 2) confirm config is correct (r/w rights) + // install/model.php?method=checkConfig&firsttime=0 + // later + + // 3) save current activated modules in nextParams, or don't desactivate them ? + // @TODO + // 4) upgrade + // install/model.php?_=1309193641470&method=doUpgrade&customModule=desactivate + if (isset($this->currentParams['customModule'])) + $_GET['customModule'] = $this->currentParams['customModule']; + + if (!$this->_modelDoUpgrade()) + { + $this->next = 'error'; + $this->nextDesc = $this->l('error during upgrade Db'); + } + + // 5) compare activated modules and reactivate them + // @TODO + + } + + + /** + * upgradeThisFile + * + * @param mixed $file + * @return void + */ + public function upgradeThisFile($file) + { + // @TODO : later, we could handle customization with some kind of diff functions + // for now, just copy $file in str_replace($this->latestRootDir,_PS_ROOT_DIR_) + // $file comes from scandir function, no need to lost time and memory with file_exists() + if ($this->_skipFile('', $file,'upgrade')) + { + $this->nextQuickInfo[] = $this->l('%s ignored'); + return true; + } + else + { + $dest = str_replace($this->latestRootDir, $this->destUpgradePath,$file); + + if (is_dir($file)) + { + if (!file_exists($dest)) + { + if (@mkdir($dest)) + { + $this->nextQuickInfo[] = sprintf($this->l('created dir %2$s. %3$s files left to upgrade.'),$file, $dest, sizeof($this->nextParams['filesToUpgrade'])); + return true; + } + else + { + $this->next = 'error'; + $this->nextQuickInfo[] = sprintf($this->l('error when creating directory %s'),$dest); + $this->nextDesc = sprintf($this->l('error when creating directory %s'),$dest); + return false; + } + } + else + { + // directory already exists + return true; + } + } + else + { + if (copy($file,$dest)) + { + $this->nextQuickInfo[] = sprintf($this->l('copied %1$s in %2$s. %3$s files left to upgrade.'),$file, $dest, sizeof($this->nextParams['filesToUpgrade'])); + return true; + } + else + { + $this->next = 'error'; + $this->nextQuickInfo[] = sprintf($this->l('error for copy %1$s in %2$s'),$file,$dest); + $this->nextDesc = sprintf($this->l('error for copy %1$s in %2$s'),$file,$dest); + return false; + } + } + } + + } + + public function ajaxProcessRollback() + { + // 1st, need to analyse what was wrong. + + $this->nextParams = $this->currentParams; + if (!empty($this->backupFilesFilename)) + { + $this->next = 'restoreFiles'; + $this->status = 'ok'; + $this->nextDesc = $this->l('Files restored, now restoring database.'); + } + else + { + if (!empty($this->backupDbFilename)) + { + $this->next = 'restoreDb'; + $this->status = 'ok'; + $this->nextDesc = $this->l('Database restored'); + } + else + { + // 2nd case if upgradeFiles made an error + // 3rd case if no upgrade has been done + // all theses cases are handled by the method ajaxRequestRollback() + $this->next = ''; // next is empty : nothing next :) + $this->status = 'ok'; + $this->nextDesc = $this->l('All your site is restored... '); + } + } + } + + /** + * ajaxProcessRestoreFiles restore the previously saved files. + * + * @return boolean true if succeed + */ + public function ajaxProcessRestoreFiles() + { + // @TODO : workaround max_execution_time / ajax batch unzip + if (!empty($this->backupFilesFilename)) + { + // cleanup current PS tree + $list = $this->_listArchivedFiles(); + if (count($list) > 0) + { + $this->_cleanUp($this->prodRootDir.'/'); + $this->nextQuickInfo[] = $this->l('root directory cleaned.'); + + $filepath = $this->backupFilesFilename; + $destExtract = $this->prodRootDir; + + if (self::ZipExtract($filepath, $destExtract)) + { + // once it's restored, delete the file ! + unlink($this->backupFilesFilename); + Configuration::updateValue('UPGRADER_BACKUPFILES_FILENAME', ''); + if (!empty($this->backupDbFilename)) + { + $this->nextDesc = $this->l('Files restored. No database backup found. Restoration done.'); + $this->next = ''; + } + else + { + $this->nextDesc = $this->l('Files restored.'); + $this->next = 'rollback'; + } + return true; + } + else + { + $this->next = "error"; + $this->nextDesc = sprintf($this->l('unable to extract $1$s into %2$s .'), $filepath, $destExtract); + return false; + } + } + } + else + { + $this->next = 'error'; + $this->nextDesc = $this->l('no known backup. nothing to restore.'); + return false; + } + } + + /** + * try to restore db backup file + * @return type : hey , what you expect ? well mysql errors array ..... + * @TODO : maybe this could be in the Backup class + */ + public function ajaxProcessRestoreDb() + { + $exts = explode('.', $this->backupDbFilename); + $fileext = $exts[count($exts)-1]; + $requests = array(); + $errors = array(); + $content = ''; + switch ($fileext) + { + case 'bz': + case 'bz2': + if ($fp = bzopen($this->backupDbFilename, 'r')) + { + while(!feof($fp)) + $content .= bzread($fp, filesize($this->backupDbFilename)); + bzclose($fp); + } + break; + case 'gz': + if ($fp = gzopen($this->backupDbFilename, 'r')) + { + while(!feof($fp)) + $content = gzread($fp, filesize($this->backupDbFilename)); + gzclose($fp); + } + break; + // default means sql ? + default : + if ($fp = fopen($this->backupDbFilename, 'r')) + { + while(!feof($fp)) + $content = fread($fp, filesize($this->backupDbFilename)); + fclose($fp); + } + } + + if ($content=='') + return false; + + // preg_match_all is better than preg_split (what is used in doUpgrade.php) + // This way we avoid extra blank lines + // option s (PCRE_DOTALL) added + // @TODO need to check if a ";" in description could block that (I suppose it can at the end of a line) + preg_match_all('/.*;[\n]\+/s', $content, $requests); + /* @TODO maybe improve regex pattern ... */ + $db = Db::getInstance(); + if (count($requests)>0) + { + foreach ($requests as $request) + if (!empty($request)) + if (!$db->Execute($request)) + $this->nextQuickInfo[] = $db->getMsgError(); + + // once it's restored, delete the file ! + unlink($this->backupDbFilename); + Configuration::updateValue('UPGRADER_BACKUPDB_FILENAME',''); + } + else + $this->nextQuickInfo[] = $this->l('Nothing to restore (no request found)'); + + $this->next = 'rollback'; + $this->nextDesc = 'Database restore done.'; + } + + public function ajaxProcessBackupDb() + { + $backup = new Backup(); + // for backup db, use autoupgrade directory + // @TODO : autoupgrade must not be static + $backup->setCustomBackupPath('autoupgrade'); + // maybe for big tables we should save them in more than one file ? + $res = $backup->add(); + if ($res) + { + Configuration::updateValue('UPGRADER_BACKUPDB_FILENAME', $backup->id); + + $this->next = 'upgradeFiles'; + $this->nextDesc = sprintf($this->l('Database backup done in %s. Now updating files'),$backup->id); + } + // if an error occur, we assume the file is not saved + } + + public function ajaxProcessBackupFiles() + { + $this->nextParams = $this->currentParams; + $this->stepDone = false; + ///////////////////// + + if (!isset($this->nextParams['filesForBackup'])) + { + $list = $this->_listBackupFiles($this->prodRootDir); + $this->nextQuickInfo[] = sprintf($this->l('%s Files to backup.'), sizeof($this->backupFileList)); + $this->nextParams['filesForBackup'] = $this->backupFileList; + + // delete old backup, create new + if (file_exists($this->backupFilesFilename)) + unlink($this->backupFilesFilename); + + $time = time(); + $this->backupFilesFilename = $this->autoupgradePath . DIRECTORY_SEPARATOR . 'backupfile-'.date('Y-m-d').'-'.$time.'.zip'; + + Configuration::updateValue('UPGRADER_BACKUPFILES_FILENAME', $this->backupFilesFilename); + $this->nextQuickInfo[] = sprintf($this->l('backup files initialized in %s'), $this->backupFilesFilename); + } + + ///////////////////// + $this->next = 'backupFiles'; + // @TODO : display % instead of this + $this->nextDesc = sprintf($this->l('Backup files in progress. %s files left'), sizeof($this->nextParams['filesForBackup'])); + if (is_array($this->nextParams['filesForBackup'])) + { + // @TODO later + // 1) calculate crc32 of next file + // 2) use the provided xml with crc32 calculated from previous versions ? + // or simply use the latest dir ? + //$current = crc32(file_get_contents($file)); + //$file = $this->nextParams['filesForBackup'][0]; + //$latestFile = str_replace(_PS_ROOT_DIR_,$this->latestRootDir,$file); + + // if (file_exists($latestFile)) + // $latest = crc32($latestFile); + // else + // $latest = ''; + + $zip = new ZipArchive(); + if ($zip->open($this->backupFilesFilename, ZIPARCHIVE::CREATE)) + { + $this->next = 'backupFiles'; + // @TODO all in one time will be probably too long + // 1000 ok during test, but 10 by 10 to be sure + $this->stepok = false; + // @TODO min(self::$loopBackupFiles, sizeof()) + for($i=0;$inextParams['filesForBackup'])<=0) + { + $this->stepok = true; + $this->status = 'ok'; + $this->next = 'backupDb'; + $this->nextDesc = $this->l('All files saved. Now backup Database'); + $this->nextQuickInfo[] = $this->l('all files have been added to archive.'); + break; + } + // filesForBackup already contains all the correct files + $file = array_shift($this->nextParams['filesForBackup']); + $archiveFilename = str_replace($this->prodRootDir,'',$file); + // @TODO : maybe put several files at the same times ? + if ($zip->addFile($file,$archiveFilename)) + $this->nextQuickInfo[] = sprintf($this->l('%1$s added to archive. %2$s left.'),$file, sizeof($this->nextParams['filesForBackup'])); + else + { + // if an error occur, it's more safe to delete the corrupted backup + if (file_exists($this->backupFilesFilename)) + unlink($this->backupFilesFilename); + $this->next = 'error'; + $this->nextDesc = sprintf($this->l('error when trying to add %1$s to archive %2$s.'),$file, $backupFilePath); + break; + } + } + $zip->close(); + return true; + } + else{ + $this->next = 'error'; + $this->nextDesc = $this->l('unable to open archive'); + return false; + } + } + else + { + $this->next = 'backupDb'; + $this->nextDesc = 'All files saved. Now backup Database'; + return true; + } + // 4) save for display. + } + + + private function _removeOneSample($removeList) + { + if (is_array($removeList) AND sizeof($removeList)>0) + { + if (file_exists($removeList[0]) AND unlink($removeList[0])) + { + $item = array_shift($removeList); + $this->next = 'removeSamples'; + $this->nextParams['removeList'] = $removeList; + $this->nextQuickInfo[] = sprintf($this->l('%1$s removed. %2$s items left'), $item, sizeof($removeList)); + } + else + { + $this->next = 'error'; + $this->nextParams['removeList'] = $removeList; + $this->nextQuickInfo[] = sprintf($this->l('error when removing %1$s, %2$s items left'), $removeList[0], sizeof($removeList)); + return false; + } + } + return true; + } + + public function ajaxProcessRemoveSamples(){ + $this->stepDone = false; + // @TODO : list exaustive list of files to remove : + // all images from img dir exept admin ? + // all images like logo, favicon, ?. + // all custom image from modules ? + // all custom image from theme ? + if (!isset($this->currentParams['removeList'])) + { + $this->_listSampleFiles($this->autoupgradePath.'/latest/prestashop/img', 'jpg'); + $this->_listSampleFiles($this->autoupgradePath.'/latest/prestashop/modules/editorial/', 'homepage_logo.jpg'); + // @TODO handle this bad thing + $this->nextQuickInfo[] = sprintf($this->l('Starting to remove %1$s sample files'), sizeof($this->sampleFileList)); + $this->nextParams['removeList'] = $this->sampleFileList; + } + + + // @TODO : removing @, adding if file_exists +// @unlink(_PS_ROOT_DIR_.'modules'.DIRECTORY_SEPARATOR.'editorial'.DIRECTORY_SEPARATOR.'editorial.xml'); +// @unlink(_PS_ROOT_DIR_.'modules'.DIRECTORY_SEPARATOR.'editorial'.DIRECTORY_SEPARATOR.'homepage_logo.jpg'); // homepage custom ? +// @unlink(_PS_ROOT_DIR_.'img'.DIRECTORY_SEPARATOR.'logo.jpg'); +// @unlink(_PS_ROOT_DIR_.'img'.DIRECTORY_SEPARATOR.'favicon.ico'); + $resRemove = true; + for($i=0;$inextParams['removeList']) <= 0 ) + { + $this->stepDone = true; + $this->next = 'backupFiles'; + $this->nextDesc = $this->l('All sample files removed. Now backup files.'); + // break the loop, all sample already removed + return true; + } + $resRemove &= $this->_removeOneSample($this->nextParams['removeList']); + if (!$resRemove) + break; + } + + return $resRemove; + } + + public function ajaxProcessSvnCheckout() + { + $this->nextParams = $this->currentParams; + if ($this->useSvn){ + $svnLink = 'http://svn.prestashop.com/trunk'; + $dest = $this->autoupgradePath . DIRECTORY_SEPARATOR . $this->svnDir; + + $svnStatus = svn_status($dest); + if (is_array($svnStatus)) + { + if (sizeof($svnStatus) == 0) + { + $this->next = 'svnExport'; + $this->nextDesc = sprintf($this->l('working copy already %s up-to-date. now exporting it into latest dir'),$dest); + } + else + { + // we assume no modification has been done + // @TODO a svn revert ? + if ($svnUpdate = svn_update($dest)) + { + $this->next = 'svnExport'; + $this->nextDesc = sprintf($this->l('SVN Update done for working copy %s . now exporting it into latest...'),$dest); + } + } + } + else + { + // no valid status found + // @TODO : is 0777 good idea ? + if (!file_exists($dest)) + if (!@mkdir($dest,0777)) + { + $this->next = 'error'; + $this->nextDesc = sprintf($this->l('unable to create directory %s'),$dest); + return false; + } + + if (svn_checkout($svnLink, $dest)) + { + $this->next = 'svnExport'; + $this->nextDesc = sprintf($this->l('SVN Checkout done from %s . now exporting it into latest...'),$svnLink); + return true; + } + else + { + $this->next = 'error'; + $this->nextDesc = $this->l('SVN Checkout error...'); + } + } + } + else + { + $this->next = 'error'; + $this->nextDesc = $this->l('not allowed to use svn'); + } + } + + public function ajaxProcessDownload() + { + if (@ini_get('allow_url_fopen')) + { + $res = $this->upgrader->downloadLast($this->autoupgradePath,$this->destDownloadFilename); + if ($res){ + $this->next = 'unzip'; + $this->nextDesc = $this->l('Download complete. Now extracting'); + } + else + { + $this->next = 'error'; + $this->nextDesc = $this->l('Error during download'); + } + } + else + { + // @TODO : ftp mode + $this->next = 'error'; + $this->nextDesc = sprintf($this->l('you need allow_url_fopen for automatic download. You can also manually upload it in %s'),$this->autoupgradePath.$this->destDownloadFilename); + } + } + + public function buildAjaxResult() + { + $return['error'] = $this->error; + $return['stepDone'] = $this->stepDone; + $return['next'] = $this->next; + $return['status'] = $this->next == 'error' ? 'error' : 'ok'; + $return['nextDesc'] = $this->nextDesc; + if (!empty($this->nextParams)) + $return['nextParams'] = $this->nextParams; + else + $return['nextParams'] = array(); + + $return['nextParams']['typeResult'] = $this->nextResponseType; + + $return['nextQuickInfo'] = $this->nextQuickInfo; + return Tools::jsonEncode($return); + } + + /** + * displayConf + * + * @return void + */ + public function displayConf() + { + if (version_compare(_PS_VERSION_,'1.4.4.0','<') AND false) + { + $this->_errors[] = Tools::displayError('This class depends of several files modified in 1.4.4.0 version and should not be used in an older version'); + } + parent::displayConf(); + + } + + public function ajaxPreProcess() + { + if (Tools::getValue('responseType') == 'json') + header('Content-Type: application/json'); + $action = (Tools::getValue('action')); + + if (isset(self::$skipAction[strtolower($action)])) + { + $this->next = self::$skipAction[$action]; + $this->nextDesc = sprintf($this->l('action %s skipped'),$action); + $this->nextQuickInfo[] = sprintf($this->l('action %s skipped'),$action); + unset($_POST['action']); + } + else if (!method_exists(get_class($this), 'ajaxProcess'.$action)) + { + $this->nextDesc = sprintf($this->l('action "%1$s" non trouvée '), $action); + $this->next = 'error'; + $this->error = '1'; + } + + if ($this->apacheModExists('mod_evasive')) + sleep(1); + } + /** + * apacheModExists return true if the apache module $name is loaded + * @TODO move this method in class Information (when it will exist) + * + * @param string $name module name + * @return boolean true if exists + */ + function apacheModExists($name) + { + static $apacheModuleList = null; + + if (!is_array($apacheModuleList)) + $apacheModuleList = apache_get_modules(); + + // we need strpos (example can be evasive20 + foreach($apacheModuleList as $module) + if (strpos($name, $module)!==false) + return true; + + return false; + } + + private function _getJsErrorMsgs() + { + $INSTALL_VERSION = $this->upgrader->version_num; + $ret = ' +var txtError = new Array(); +txtError[0] = "'.$this->l('Required field').'"; +txtError[1] = "'.$this->l('Too long!').'"; +txtError[2] = "'.$this->l('Fields are different!').'"; +txtError[3] = "'.$this->l('This email adress is wrong!').'"; +txtError[4] = "'.$this->l('Impossible to send the email!').'"; +txtError[5] = "'.$this->l('Can\'t create settings file, if /config/settings.inc.php exists, please give the public write permissions to this file, else please create a file named settings.inc.php in config directory.').'"; +txtError[6] = "'.$this->l('Can\'t write settings file, please create a file named settings.inc.php in config directory.').'"; +txtError[7] = "'.$this->l('Impossible to upload the file!').'"; +txtError[8] = "'.$this->l('Data integrity is not valided. Hack attempt?').'"; +txtError[9] = "'.$this->l('Impossible to read the content of a MySQL content file.').'"; +txtError[10] = "'.$this->l('Impossible the access the a MySQL content file.').'"; +txtError[11] = "'.$this->l('Error while inserting data in the database:').'"; +txtError[12] = "'.$this->l('The password is incorrect (alphanumeric string at least 8 characters).').'"; +txtError[14] = "'.$this->l('A Prestashop database already exists, please drop it or change the prefix.').'"; +txtError[15] = "'.$this->l('This is not a valid file name.').'"; +txtError[16] = "'.$this->l('This is not a valid image file.').'"; +txtError[17] = "'.$this->l('Error while creating the /config/settings.inc.php file.').'"; +txtError[18] = "'.$this->l('Error:').'"; +txtError[19] = "'.$this->l('This PrestaShop database already exists. Please revalidate your authentication informations to the database.').'"; +txtError[22] = "'.$this->l('An error occurred while resizing the picture.').'"; +txtError[23] = "'.$this->l('Database connection is available!').'"; +txtError[24] = "'.$this->l('Database Server is available but database is not found').'"; +txtError[25] = "'.$this->l('Database Server is not found. Please verify the login, password and server fields.').'"; +txtError[26] = "'.$this->l('An error occurred while sending email, please verify your parameters.').'"; +txtError[37] = "'.$this->l('Impossible to write the image /img/logo.jpg. If this image already exists, please delete it.').'"; +txtError[38] = "'.$this->l('The uploaded file exceeds the upload_max_filesize directive in php.ini').'"; +txtError[39] = "'.$this->l('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form').'"; +txtError[40] = "'.$this->l('The uploaded file was only partially uploaded').'"; +txtError[41] = "'.$this->l('No file was uploaded.').'"; +txtError[42] = "'.$this->l('Missing a temporary folder').'"; +txtError[43] = "'.$this->l('Failed to write file to disk').'"; +txtError[44] = "'.$this->l('File upload stopped by extension').'"; +txtError[45] = "'.$this->l('Cannot convert your database\'s data to utf-8.').'"; +txtError[46] = "'.$this->l('Invalid shop name').'"; +txtError[47] = "'.$this->l('Your firstname contains some invalid characters').'"; +txtError[48] = "'.$this->l('Your lastname contains some invalid characters').'"; +txtError[49] = "'.$this->l('Your database server does not support the utf-8 charset.').'"; +txtError[50] = "'.$this->l('Your MySQL server doesn\'t support this engine, please use another one like MyISAM').'"; +txtError[51] = "'.$this->l('The file /img/logo.jpg is not writable, please CHMOD 755 this file or CHMOD 777').'"; +txtError[52] = "'.$this->l('Invalid catalog mode').'"; +txtError[999] = "'.$this->l('No error code available').'"; +//upgrader +txtError[27] = "'.$this->l('This installer is too old.').'"; +txtError[28] = "'.sprintf($this->l('You already have the %s version.'),$INSTALL_VERSION).'"; +txtError[29] = "'.$this->l('There is no older version. Did you delete or rename the config/settings.inc.php file?').'"; +txtError[30] = "'.$this->l('The config/settings.inc.php file was not found. Did you delete or rename this file?').'"; +txtError[31] = "'.$this->l('Can\'t find the sql upgrade files. Please verify that the /install/sql/upgrade folder is not empty)').'"; +txtError[32] = "'.$this->l('No upgrade is possible.').'"; +txtError[33] = "'.$this->l('Error while loading sql upgrade file.').'"; +txtError[34] = "'.$this->l('Error while inserting content into the database').'"; +txtError[35] = "'.$this->l('Unfortunately,').'"; +txtError[36] = "'.$this->l('SQL errors have occurred.').'"; +txtError[37] = "'.$this->l('The config/defines.inc.php file was not found. Where did you move it?').'";'; + return $ret; + } + + public function displayAjax(){ + echo $this->buildAjaxResult(); + } + + private function _displayRollbackForm() + { + echo '
'.$this->l('Rollback').' +
'; + if (empty($this->backupFilesFilename) AND empty($this->backupDbFilename)) + echo $this->l('No rollback available'); + else if (!empty($this->backupFilesFilename) OR !empty($this->backupDbFilename)) + { + echo ''; + } + if (!empty($this->backupFilesFilename)) + echo '
restoreFiles '.sprintf($this->l('click to restore %s'),$this->backupFilesFilename).'
'; + if (!empty($this->backupDbFilename)) + echo '
restoreDb '.sprintf($this->l('click to restore %s'), $this->backupDbFilename).'
'; + + echo '
'; + } + + private function _displayUpgraderForm() + { + $pleaseUpdate = $this->upgrader->checkPSVersion(); + + echo '
'; + echo ''.$this->l('Your current configuration').''; + echo ''.$this->l('root directory').' : '.$this->prodRootDir.'

'; + + if ($this->rootWritable) + $srcRootWritable = '../img/admin/enabled.gif'; + else + $srcRootWritable = '../img/admin/disabled.gif'; + echo ''.$this->l('Root directory').' : '.' '.($this->rootWritable?$this->l('root directory is fully writable'):$this->l('root directory is not writable recursively')).'.

'; + + if ($this->upgrader->needUpgrade) + { + if ($this->upgrader->autoupgrade) + $srcAutoupgrade = '../img/admin/enabled.gif'; + else + $srcAutoupgrade = '../img/admin/disabled.gif'; + echo ''.$this->l('Autoupgrade allowed').' : '.' '.($this->upgrader->autoupgrade?$this->l('This release allow autoupgrade.'):$this->l('This release does not allow autoupgrade')).'.

'; + } + + if (Configuration::get('PS_SHOP_ENABLE')) + { + $srcShopStatus = '../img/admin/enabled.gif'; + $label = $this->l('Active'); + } + else + { + $srcShopStatus = '../img/admin/disabled.gif'; + $label = $this->l('Inactive'); + } + echo ''.$this->l('Shop status').' : '.''.$label.'

'; + + $max_exec_time = ini_get('max_execution_time'); + if ($max_exec_time == 0) + $srcExecTime = '../img/admin/enabled.gif'; + else + $srcExecTime = '../img/admin/warning.gif'; + echo ''.$this->l('php time limit').' : '.''.($max_exec_time == 0?$this->l('disabled'):$max_exec_time.' '.$this->l('seconds')).'

'; + + if ($this->rootWritable) + $srcRootWritable = '../img/admin/enabled.gif'; + else + $srcRootWritable = '../img/admin/disabled.gif'; + echo ''.$this->l('Root directory').' : '.' '.($this->rootWritable?$this->l('writable recursively'):$this->l('not writable recursively')).'.

'; + + echo ''.$this->l('Modify your options').''; + echo '
'; + + echo '
'; + + echo '
'.$this->l('Update').''; + + + echo '
+

'.sprintf($this->l('Your current prestashop version : %s '),_PS_VERSION_).'

'; + echo '

'.sprintf($this->l('Last version is %1$s (%2$s) '), $this->upgrader->version_name, $this->upgrader->version_num).'

'; + + // @TODO : this should be checked when init() + if ($this->isUpgradeAllowed()) { + if ($pleaseUpdate) { + echo '
  • information '.$this->l('Latest Prestashop version available is:').' '.$pleaseUpdate['name'].'
  • '; + } +// echo ''; +// echo ''; + echo '
    '; + if ($this->upgrader->needUpgrade) + { + echo ''.$this->l('Upgrade PrestaShop now !').''; + } + else + { + echo '

    '.$this->l('Your shop is already up to date').'

    '; + } + + echo'
    + '; + + echo '
    '; + + + echo '
    '; + + if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) + { + echo '
    '.$this->l('Step').''; + echo '

    '.$this->l('Upgrade steps').'

    '; + echo '
    '; + echo 'desactiveShop'; + echo 'download'; + echo 'unzip'; // unzip in autoupgrade/latest + echo 'removeSamples'; // remove samples (iWheel images) + echo 'backupFiles'; // backup files + echo 'backupDb'; + echo 'upgradeFiles'; + echo 'upgradeDb'; + echo '
    '; + + if (defined('_PS_ALLOW_UPGRADE_UNSTABLE_') AND _PS_ALLOW_UPGRADE_UNSTABLE_ ) + { + echo '

    Development tools

    '; + } + } + + echo '
    '; + echo'
    quick info
    '; + // for upgradeDb + echo '

    '; + echo '

    '; + } + else + echo '

    '.$this->l('Your current configuration does not allow upgrade.').'

    '; + + echo '
    '; +/* echo '
    + Error +
    no error yet
    +
    '; + * + */ + // information to keep will be in #infoStep + // temporary infoUpdate will be in #tmpInformation + echo ''; + } + public function display() + { + $this->displayWarning('This function is experimental. It\'s currently recommended to make a backup of your files and database.'); + + global $currentIndex; + if ($this->apacheModExists('mod_evasive')) + sleep(1); + // update['name'] = version name + // update['num'] = only the version + // update['link'] = download link + // @TODO + if ($this->useSvn AND FALSE) + echo '

    '.$this->l('Unstable upgrade').'

    +

    '.$this->l('Your current configuration indicate you want to upgrade your system from the unstable development branch, with no version number. If you upgrade, you will not be able to follow the official release process anymore').'.

    +
    '; + + $this->_displayUpgraderForm(); + echo '
    '; + $this->_displayRollbackForm(); + + echo '
    '; + $this->_displayForm('autoUpgradeOptions',$this->_fieldsAutoUpgrade,''.$this->l('Options').'', 'my-autoupgrade-option',''); + echo ''; + } + + private function _getJsInit() + { + global $currentIndex; + $js = ''; + $js .= ' +function ucFirst(str) { + if (str.length > 0) { + return str[0].toUpperCase() + str.substring(1); + } + else { + return str; + } +} + +function cleanInfo(){ + $("#infoStep").html("reset
    "); +} + +function updateInfoStep(msg){ + if (msg) + { + $("#infoStep").html(msg); + $("#infoStep").attr({ scrollTop: $("#infoStep").attr("scrollHeight") }); + } +} + +function addError(msg){ + if (msg) + $("#errorWindow").html(msg); +} + +function addQuickInfo(arrQuickInfo){ + if (arrQuickInfo) + { + $("#quickInfo").show(); + for(i=0;i"); + + $("#quickInfo").attr({ scrollTop: $("#quickInfo").attr("scrollHeight") }); + } +}'; + + if ($this->manualMode) + $js .= 'var manualMode = true;'; + else + $js .= 'var manualMode = false;'; + + $js .= ' + +$(document).ready(function(){ + $(".upgradestep").click(function(e) + { + e.preventDefault(); + // $.scrollTo("#options") + }); + + // more convenient to have that param for handling success and error + var requestParams; + + // set timeout to 5 minutes (download can be long)? + $.ajaxSetup({timeout:300000}); + + + // prepare available button here, without params ? + prepareNextButton("#upgradeNow",{}); + prepareNextButton("#rollback",{}); + prepareNextButton("#restoreDb",{}); + prepareNextButton("#restoreFiles",{}); + +}); + +/** + * parseXMLResult is used to handle the return value of the doUpgrade method + * + */ +function parseXMLResult(xmlRet) +{ + ret = $(xmlRet); + ret = ret.find("action")[0]; + if (ret.getAttribute("result") == "ok") + { + $("#dbResultCheck") + .addClass("ok") + .removeClass("fail") + .html("

    '.$this->l('upgrade complete. Please check your front-office (try to make an order, check theme)').'

    ") + .show("slow"); + $("#dbCreateResultCheck") + .hide("slow"); + + // difference with the original function + ret = {next:"upgradeComplete",nextParams:""}; + + } + else + { + $("#dbResultCheck") + .addClass("fail") + .removeClass("ok") + .html(txtError[parseInt(ret.getAttribute("error"))]) + .show("slow"); + $("#dbCreateResultCheck") + .hide("slow"); + + // propose rollback if there is an error + if (confirm(txtError[parseInt(ret.getAttribute("error"))]+"\r\n\r\n'.$this->l('Do you want to rollback ?').'")) + ret = {next:"rollback","nextParams":nextParams}; + } + + return ret +}; + +/** + * afterBackupDb display the button + * + */ +function afterBackupDb() +{ + $("#restoreDbContainer").html("restoreDb '.$this->l('click to restore database').'"); + prepareNextButton("#restoreDb",{}); +} + +function afterRestoreDb() +{ + $("#restoreDbContainer").html(""); +} + +function afterRestoreFiles() +{ + $("#restoreFilesContainer").html(""); +} + +function afterBackupFiles() +{ + $("#restoreFilesContainer").html("
    restoreFiles '.$this->l('click to restore files').'"); + prepareNextButton("#restoreFiles",{}); + +} + +function doAjaxRequest(action, nextParams){ + req = $.ajax({ + type:"POST", + url : "'.str_replace('index','ajax-tab',$currentIndex).'", + async: true, + data : { + dir:"'.$this->adminDir.'", + ajaxMode : "1", + token : "'.$this->token.'", + tab : "AdminUpgrade", + action : action, + params : nextParams + }, + success : function(res,textStatus,jqXHR) + { + if (nextParams.typeResult == "xml") + { + xmlRes = parseXMLResult(res); + res = {}; + res.next = xmlRes.next; + // if xml, we keep the next params + nextParams = myNext; + + // res.status = "ok", + } + else + { + res = $.parseJSON(res); + if (res.status == "ok") + { + // a + $("#"+action).addClass("done"); + if (res.stepDone) + $("#"+action).addClass("stepok"); + + // if a function "after[action name]" exists, it should be called. + // This is used for enabling restore buttons for example + funcName = "after"+ucFirst(action); + if (typeof funcName == "string" && + eval("typeof " + funcName) == "function") { + + eval(funcName+"()"); + } + + handleSuccess(res,nextParams.typeResult); + } + else + { + // display progression + $("#"+action).addClass("done"); + $("#"+action).addClass("steperror"); + handleError(res); + } + } + }, + error: function(res,textStatus,jqXHR) + { + if (textStatus == "timeout" && action == "download") + { + updateInfoStep("'.$this->l('Your server can\'t download the file. Please upload it first by ftp in your admin/autoupgrade directory').'"); + } + else + { + //console.log(res); + //console.log(jqXHR); + updateInfoStep("[Server Error] Status message : " + textStatus); + } + } + }); + }; + +/** + * prepareNextButton make the button button_selector available, and update the nextParams values + * + * @param button_selector $button_selector + * @param nextParams $nextParams + * @return void + */ +function prepareNextButton(button_selector, nextParams) +{ +// myNext; + myNext = nextParams; + $(button_selector).unbind(); + $(button_selector).click(function(e){ + e.preventDefault(); + $("#currentlyProcessing").show(); +'; + if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) + $js .= 'addQuickInfo(["[DEV] request : "+$(this).attr("id")]);'; + $js .= ' + action = button_selector.substr(1); + res = doAjaxRequest(action, nextParams); + }); +} + +/** + * handleSuccess + * res = {error:, next:, nextDesc:, nextParams:, nextQuickInfo:,status:"ok"} + * @param res $res + * @return void + */ +function handleSuccess(res) +{ + if (res.next != "") + { + updateInfoStep(res.nextDesc); + addQuickInfo(res.nextQuickInfo); + + $("#"+res.next).addClass("nextStep"); + if (manualMode) + { + prepareNextButton("#"+res.next,res.nextParams); + alert("manually go to "+res.next+" button "); + } + else + { + // @TODO : + // 1) instead of click(), call a function. + doAjaxRequest(res.next,res.nextParams); + // 2) remove all step link (or show them only in dev mode) + // 3) when steps link displayed, they should change color when passed + } + } + else + { + // Way To Go, end of upgrade process + addQuickInfo(["End of upgrade process"]); + } +} + +// res = {nextParams, NextDesc} +function handleError(res) +{ + // display error message in the main process thing + updateInfoStep(res.nextDesc); + addQuickInfo(res.nextQuickInfo); + // In case the rollback button has been desactivated, just re-enable it + prepareNextButton("#rollback",res.nextParams); + // ask if you want to rollback + // @TODO !!! + if (confirm(res.NextDesc+"\r\r'.$this->l('Do you want to rollback ?').'")) + { + if (manualMode) + alert("'.$this->l('Please go manually go to rollback button').'"); + else + { + $("#rollback").click(); + } + + } +} +'; + return $js; + } + private function _cleanUp($path) + { + // as we need theses files for restore operation, we can't remove them. + // They will be overwritten + $skipDirs = array('backups', 'pclzip', 'autoupgrade', '.', '..', '.svn'); + $skipFiles = array('autoload.php', 'init.php', 'settings.inc.php', 'config.inc.php', 'Tools.php', 'AdminUpgrade.php', 'ajax-tab.php'); + if (is_dir($path)) + { + $fp = opendir($path); + while ($file = readdir($fp)) + { + if (!in_array($file, $skipDirs) AND !$this->_skipFile('', $path.$file, 'backup')) + { + $fullpath = $path.$file; + if (is_dir($fullpath)) + $this->_cleanUp($fullpath.'/'); + else + { + if (!in_array($file, $skipFiles)) + { + unlink($fullpath); + } + } + } + } + closedir($fp); + /* fortunately not empty dir won't be removed by the following */ + @rmdir($path); + } + else + if (!$this->_skipFile($file, '', 'backup')) unlink($path); + + return true; + } + + /** + * @desc extract a zip file to the given directory + * @return bool success + * we need a copy of it to be able to restore without keeping Tools and Autoload stuff + */ + private static function ZipExtract($fromFile, $toDir) + { + if (!file_exists($toDir)) + if (!@mkdir($toDir,0777)) + { + $this->next = 'error'; + $this->nextDesc = sprintf($this->l('unable to create directory %s'),$toDir); + return false; + } + + if (class_exists('ZipArchive', false)) + { + $zip = new ZipArchive(); + if ($zip->open($fromFile) === true AND $zip->extractTo($toDir) AND $zip->close()) + return true; + return false; + } + else + { + + if (!class_exists('PclZip',false)) + require_once($this->prodRootDir.'/tools/pclzip/pclzip.lib.php'); + + $zip = new PclZip($fromFile); + $list = $zip->extract(PCLZIP_OPT_PATH, $toDir); + foreach ($list as $extractedFile) + if ($extractedFile['status'] != 'ok') + return false; + + return true; + } + } + + private function _listArchivedFiles() + { + if (!empty($this->nextParams['backupFilesFilepath'])) + { + if (class_exists('ZipArchive', false)) + { + $files=array(); + if ($zip = zip_open($this->currentParams['backupFilesFilepath'])) + { + while ($entry=zip_read($zip)) + $files[] = zip_entry_name($entry); + + zip_close($zip); + } + } + else + { + require_once($this->prodRootDir.'/tools/pclzip/pclzip.lib.php'); + if ($zip = new PclZip($this->currentParams['backupFilesFilepath'])) + return $zip->listContent(); + } + } + return false; + } + + /** + * bool _skipFile : check whether a file is in backup or restore skip list + * + * @param type $file : current file or directory name eg:'.svn' , 'settings.inc.php' + * @param type $fullpath : current file or directory fullpath eg:'/home/web/www/prestashop/img' + * @param type $way : 'backup' , 'upgrade' + */ + private function _skipFile($file,$fullpath,$way='backup') + { + $fullpath = str_replace('\\','/', $fullpath); // wamp compliant + $rootpath = str_replace('\\','/', $this->prodRootDir); + switch ($way) + { + case 'backup': + if (in_array($file, $this->backupIgnoreFiles)) + return true; + + foreach($this->backupIgnoreAbsoluteFiles as $path) + if ($file == 'img') + if (strpos($fullpath, $rootpath.$path) !== false) + return true; + break; + + case 'upgrade': + if (in_array($file, $this->excludeFilesFromUpgrade)) + return true; + + foreach ($this->excludeAbsoluteFilesFromUpgrade as $path) + if (strpos($fullpath, $rootpath.$path) !== false) + return true; + break; + // default : if it's not a backup or an upgrade, juste skip the file + default: + return false; + } + } +} + diff --git a/admin-dev/tabs/AdminWebservice.php b/admin-dev/tabs/AdminWebservice.php index a5064cfbd..bfef21577 100755 --- a/admin-dev/tabs/AdminWebservice.php +++ b/admin-dev/tabs/AdminWebservice.php @@ -37,7 +37,6 @@ class AdminWebservice extends AdminTab $this->lang = false; $this->edit = true; $this->delete = true; - $this->id_lang_default = Configuration::get('PS_LANG_DEFAULT'); $this->fieldsDisplay = array( @@ -93,6 +92,13 @@ class AdminWebservice extends AdminTab $warnings[] = $this->l('If possible, it is preferable to use SSL (https) for webservice calls, as it avoids the security issues of type "man in the middle".'); $this->displayWarning($warnings); + + foreach ($this->_list as $k => $item) + if ($item['is_module'] && $item['class_name'] && $item['module_name'] && + ($instance = Module::getInstanceByName($item['module_name'])) && + !$instance->useNormalPermissionBehaviour()) + unset($this->_list[$k]); + parent::displayList(); } public function displayForm($isMainTab = true) @@ -221,6 +227,8 @@ echo ' { if (Tools::getValue('key') && strlen(Tools::getValue('key')) < 32) $this->_errors[] = Tools::displayError($this->l('Key length must be 32 character long')); + if (WebserviceKey::keyExists(Tools::getValue('key')) && !Tools::getValue('id_webservice_account')) + $this->_errors[] = Tools::displayError($this->l('Key already exists')); return parent::postProcess(); } diff --git a/admin-dev/themes/flashyturtle/admin.css b/admin-dev/themes/flashyturtle/admin.css index bdc012462..ab0a01999 100644 --- a/admin-dev/themes/flashyturtle/admin.css +++ b/admin-dev/themes/flashyturtle/admin.css @@ -59,3 +59,10 @@ a.action_module{color: #488C40;text-decoration: underline;} a.header_module_toggle{font-weight: bold;color: #812143;display:block;} a.module_toggle_all{color:#FFF;text-decoration:none;display:inherit;} .nbr_module{float:right;margin-right:10px;font-style:italic;font-size:12px;color: #812143;} + +.autoupgradeSteps div { line-height: 30px; } +.upgradestep { margin-right: 5px;padding-left: 10px; padding-right: 5px;} +#upgradeNow.stepok, .autoupgradeSteps a.stepok { background-image: url("../img/admin/enabled.gif");background-position: left center;background-repeat: no-repeat;padding-left: 15px;} +#upgradeNow {-moz-border-bottom-colors: none;-moz-border-image: none;-moz-border-left-colors: none;-moz-border-right-colors: none;-moz-border-top-colors: none;border-color: #FFF6D3 #DFD5AF #DFD5AF #FFF6D3;border-right: 1px solid #DFD5AF;border-style: solid;border-width: 1px;color: #268CCD;font-size: medium;padding: 5px;} +.button-autoupgrade {-moz-border-bottom-colors: none;-moz-border-image: none;-moz-border-left-colors: none;-moz-border-right-colors: none;-moz-border-top-colors: none;border-color: #FFF6D3 #DFD5AF #DFD5AF #FFF6D3;border-right: 1px solid #DFD5AF;border-style: solid;border-width: 1px;color: #268CCD;font-size: medium;padding: 5px;} +.processing {overflow: auto;} diff --git a/admin-dev/themes/oldschool/admin.css b/admin-dev/themes/oldschool/admin.css index a141bfc6b..a1b138ef4 100644 --- a/admin-dev/themes/oldschool/admin.css +++ b/admin-dev/themes/oldschool/admin.css @@ -53,4 +53,11 @@ select {border: 1px solid #E0D0B1} a.action_module{color: #268CCD;text-decoration: underline;} a.header_module_toggle{font-weight: bold;color: #268CCD;display:block;} a.module_toggle_all{color: #268CCD;} -.nbr_module{float:right;margin-right:10px;font-style:italic;font-size:12px;color: #268CCD;} \ No newline at end of file +.nbr_module{float:right;margin-right:10px;font-style:italic;font-size:12px;color: #268CCD;} + +.autoupgradeSteps div { line-height: 30px; } +.upgradestep { margin-right: 5px;padding-left: 10px; padding-right: 5px;} +#upgradeNow.stepok, .autoupgradeSteps a.stepok { background-image: url("../img/admin/enabled.gif");background-position: left center;background-repeat: no-repeat;padding-left: 15px;} +#upgradeNow {-moz-border-bottom-colors: none;-moz-border-image: none;-moz-border-left-colors: none;-moz-border-right-colors: none;-moz-border-top-colors: none;border-color: #FFF6D3 #DFD5AF #DFD5AF #FFF6D3;border-right: 1px solid #DFD5AF;border-style: solid;border-width: 1px;color: #268CCD;font-size: medium;padding: 5px;} +.button-autoupgrade {-moz-border-bottom-colors: none;-moz-border-image: none;-moz-border-left-colors: none;-moz-border-right-colors: none;-moz-border-top-colors: none;border-color: #FFF6D3 #DFD5AF #DFD5AF #FFF6D3;border-right: 1px solid #DFD5AF;border-style: solid;border-width: 1px;color: #268CCD;font-size: medium;padding: 5px;} +.processing {overflow: auto;} diff --git a/admin-dev/themes/origins/admin.css b/admin-dev/themes/origins/admin.css index 04b4768a5..6c1532ec1 100644 --- a/admin-dev/themes/origins/admin.css +++ b/admin-dev/themes/origins/admin.css @@ -57,3 +57,9 @@ a.header_module_toggle{font-weight: bold;color: #268CCD;display:block;} a.module_toggle_all{color: #268CCD;} .nbr_module{float:right;margin-right:10px;font-style:italic;font-size:12px;color: #268CCD;} +.autoupgradeSteps div { line-height: 30px; } +.upgradestep { margin-right: 5px;padding-left: 10px; padding-right: 5px;} +#upgradeNow.stepok, .autoupgradeSteps a.stepok { background-image: url("../img/admin/enabled.gif");background-position: left center;background-repeat: no-repeat;padding-left: 15px;} +#upgradeNow {-moz-border-bottom-colors: none;-moz-border-image: none;-moz-border-left-colors: none;-moz-border-right-colors: none;-moz-border-top-colors: none;border-color: #FFF6D3 #DFD5AF #DFD5AF #FFF6D3;border-right: 1px solid #DFD5AF;border-style: solid;border-width: 1px;color: #268CCD;font-size: medium;padding: 5px;} +.button-autoupgrade {-moz-border-bottom-colors: none;-moz-border-image: none;-moz-border-left-colors: none;-moz-border-right-colors: none;-moz-border-top-colors: none;border-color: #FFF6D3 #DFD5AF #DFD5AF #FFF6D3;border-right: 1px solid #DFD5AF;border-style: solid;border-width: 1px;color: #268CCD;font-size: medium;padding: 5px;} +.processing {overflow: auto;} diff --git a/classes/AdminTab.php b/classes/AdminTab.php index 8decf6609..0d61fd91a 100644 --- a/classes/AdminTab.php +++ b/classes/AdminTab.php @@ -159,6 +159,8 @@ abstract class AdminTabCore protected $_includeVars = false; protected $_includeContainer = true; + public $ajax = false; + public static $tabParenting = array( 'AdminProducts' => 'AdminCatalog', 'AdminCategories' => 'AdminCatalog', @@ -233,6 +235,14 @@ abstract class AdminTabCore return str_replace('"', '"', ($addslashes ? addslashes($str) : stripslashes($str))); } + /** + * ajaxDisplay is the default ajax return sytem + * + * @return void + */ + public function displayAjax() + { + } /** * Manage page display (form, list...) */ @@ -506,6 +516,24 @@ abstract class AdminTabCore return true; } + /** + * ajaxPreProcess is a method called in ajax-tab.php before displayConf(). + * + * @return void + */ + public function ajaxPreProcess() + { + } + + /** + * ajaxProcess is the default handle method for request with ajax-tab.php + * + * @return void + */ + public function ajaxProcess() + { + } + /** * Manage page processing */ @@ -1107,9 +1135,9 @@ abstract class AdminTabCore public function displayConf() { if ($conf = Tools::getValue('conf')) - echo '
    - - '.$this->_conf[(int)($conf)].' + echo ' +
    + '.$this->_conf[(int)($conf)].'
    '; } diff --git a/classes/Alias.php b/classes/Alias.php index bfb386534..3bfc13100 100644 --- a/classes/Alias.php +++ b/classes/Alias.php @@ -70,7 +70,7 @@ class AliasCore extends ObjectModel FROM `'._DB_PREFIX_.'alias` WHERE `search` LIKE \''.pSQL($search).'\''); } - + public function getAliases() { $aliases = Db::getInstance()->ExecuteS(' diff --git a/classes/Attachment.php b/classes/Attachment.php index 561e8f4fe..a3f235f50 100644 --- a/classes/Attachment.php +++ b/classes/Attachment.php @@ -37,7 +37,7 @@ class AttachmentCore extends ObjectModel public $position; protected $fieldsRequired = array('file', 'mime'); - protected $fieldsSize = array('file' => 40, 'mime' => 64, 'file_name' => 128); + protected $fieldsSize = array('file' => 40, 'mime' => 128, 'file_name' => 128); protected $fieldsValidate = array('file' => 'isGenericName', 'mime' => 'isCleanHtml', 'file_name' => 'isGenericName'); protected $fieldsRequiredLang = array('name'); diff --git a/classes/Cart.php b/classes/Cart.php index e1920040e..4828dc171 100644 --- a/classes/Cart.php +++ b/classes/Cart.php @@ -1232,7 +1232,10 @@ class CartCore extends ObjectModel { $moduleName = $carrier->external_module_name; $module = Module::getInstanceByName($moduleName); - if (key_exists('id_carrier', $module)) + + if (Validate::isLoadedObject($module)) + { + if (array_key_exists('id_carrier', $module)) $module->id_carrier = $carrier->id; if($carrier->need_range) $shipping_cost = $module->getOrderShippingCost($this, $shipping_cost); @@ -1243,6 +1246,9 @@ class CartCore extends ObjectModel if ($shipping_cost === false) return false; } + else + return false; + } // Apply tax if (isset($carrierTax)) @@ -1327,7 +1333,7 @@ class CartCore extends ObjectModel $groups = Customer::getGroupsStatic($this->id_customer); - if (($discountObj->id_customer OR $discountObj->id_group) AND ($this->id_customer != $discountObj->id_customer AND !in_array($discountObj->id_group, $groups))) + if (($discountObj->id_customer OR $discountObj->id_group) AND ((($this->id_customer != $discountObj->id_customer) OR ($this->id_customer == 0)) AND !in_array($discountObj->id_group, $groups))) { if (!$customer->isLogged()) return Tools::displayError('You cannot use this voucher.').' - '.Tools::displayError('Please log in.'); @@ -1699,6 +1705,8 @@ class CartCore extends ObjectModel { $carrier = new Carrier((int)$id_carrier, Configuration::get('PS_LANG_DEFAULT')); $shippingMethod = $carrier->getShippingMethod(); + if (!$carrier->range_behavior) + return true; if ($shippingMethod == Carrier::SHIPPING_METHOD_FREE) return true; diff --git a/classes/Category.php b/classes/Category.php index ee4d7461b..e863e1ecf 100644 --- a/classes/Category.php +++ b/classes/Category.php @@ -179,6 +179,16 @@ class CategoryCore extends ObjectModel return $ret; } + /** + * @see ObjectModel::toggleStatus() + */ + public function toggleStatus() + { + $result = parent::toggleStatus(); + Module::hookExec('categoryUpdate'); + return $result; + } + /** * Recursive scan of subcategories * @@ -594,37 +604,19 @@ class CategoryCore extends ObjectModel * @param int $id_lang * @return array */ - public static function getChildrenWithNbSelectedSubCatForProduct($id_parent, $id_product = 0, $ids_categories = null, $id_lang) + public static function getChildrenWithNbSelectedSubCat($id_parent, $selectedCat, $id_lang) { - $categories_product_str = ''; - if ($id_product) - { - $categories_product = Db::getInstance()->ExecuteS(' - SELECT `id_category` - FROM `'._DB_PREFIX_.'category_product` - WHERE `id_product` = '.(int)$id_product); - if (sizeof($categories_product)) - foreach ($categories_product as $category_product) - $categories_product_str .= $category_product['id_category'].','; - } - else - { - $categories_product = array(); - $categories_product_str = $ids_categories; - } - $categories_product_str = rtrim($categories_product_str, ','); - return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' - SELECT c.`id_category`, cl.`name`, IF(( + SELECT c.`id_category`, c.`level_depth`, cl.`name`, IF(( SELECT COUNT(*) FROM `'._DB_PREFIX_.'category` c2 WHERE c2.`id_parent` = c.`id_category` - ) > 0, 1, 0) AS has_children, '.($categories_product_str ? '( + ) > 0, 1, 0) AS has_children, '.($selectedCat ? '( SELECT count(c3.`id_category`) FROM `'._DB_PREFIX_.'category` c3 WHERE c3.`nleft` > c.`nleft` AND c3.`nright` < c.`nright` - AND c3.`id_category` IN ('.$categories_product_str.') + AND c3.`id_category` IN ('.$selectedCat.') )' : '0').' AS nbSelectedSubCat FROM `'._DB_PREFIX_.'category` c LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON c.`id_category` = cl.`id_category` diff --git a/classes/CompareProduct.php b/classes/CompareProduct.php new file mode 100644 index 000000000..af3129b22 --- /dev/null +++ b/classes/CompareProduct.php @@ -0,0 +1,198 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +class CompareProduct extends ObjectModel +{ + public $id; + + public $id_product; + + public $id_guest; + + public $id_customer; + + public $date_add; + + public $date_upd; + + protected $fieldRequired = array( + 'id_product', + 'id_guest', + 'id_customer'); + + protected $fieldsValidate = array( + 'id_product' => 'isUnsignedInt', + 'id_guest' => 'isUnsignedInt', + 'id_customer' => 'isUnsignedInt' + ); + + protected $table = 'compare_product'; + + protected $identifier = 'id_compare_product'; + + + /** + * Get all compare products of the guest + * @param int $id_guest + * @return array + */ + public static function getGuestCompareProducts($id_guest) + { + $results = Db::getInstance()->ExecuteS(' + SELECT DISTINCT `id_product` + FROM `'._DB_PREFIX_.'compare_product` + WHERE `id_guest` = '.(int)($id_guest)); + + $compareProducts = null; + + foreach($results as $result) + $compareProducts[] = $result['id_product']; + + return $compareProducts; + } + + + /** + * Add a compare product for the guest + * @param int $id_guest, int $id_product + * @return boolean + */ + public static function addGuestCompareProduct($id_guest, $id_product) + { + return Db::getInstance()->Execute(' + INSERT INTO `'._DB_PREFIX_.'compare_product` (`id_product`, `id_guest`, `date_add`, `date_upd`) + VALUES ('.(int)($id_product).', '.(int)($id_guest).', NOW(), NOW()) + '); + } + + + /** + * Remove a compare product for the guest + * @param int $id_guest, int $id_product + * @return boolean + */ + public static function removeGuestCompareProduct($id_guest, $id_product) + { + return Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'compare_product` WHERE `id_guest` = '.(int)($id_guest).' AND `id_product` = '.(int)($id_product)); + } + + + /** + * Get the number of compare products of the guest + * @param int $id_guest + * @return int + */ + public static function getGuestNumberProducts($id_guest) + { + return (int)(Db::getInstance()->getValue(' + SELECT count(`id_compare_product`) + FROM `'._DB_PREFIX_.'compare_product` + WHERE `id_guest` = '.(int)($id_guest)));; + } + + + /** + * Get all comapare products of the customer + * @param int $id_customer + * @return array + */ + public static function getCustomerCompareProducts($id_customer) + { + $results = Db::getInstance()->ExecuteS(' + SELECT DISTINCT `id_product` + FROM `'._DB_PREFIX_.'compare_product` + WHERE `id_customer` = '.(int)($id_customer)); + + $compareProducts = null; + + foreach($results as $result) + $compareProducts[] = $result['id_product']; + + return $compareProducts; + } + + + /** + * Add a compare product for the customer + * @param int $id_customer, int $id_product + * @return boolean + */ + public static function addCustomerCompareProduct($id_customer, $id_product) + { + return Db::getInstance()->Execute('INSERT INTO `'._DB_PREFIX_.'compare_product` (`id_product`, `id_customer`, `date_add`, `date_upd`) VALUES ('.(int)($id_product).', '.(int)($id_customer).', NOW(), NOW())'); + } + + + /** + * Remove a compare product for the customer + * @param int $id_customer, int $id_product + * @return boolean + */ + public static function removeCustomerCompareProduct($id_customer, $id_product) + { + return Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'compare_product` WHERE `id_customer` = '.(int)($id_customer).' AND `id_product` = '.(int)($id_product)); + } + + + /** + * Get the number of compare products of the customer + * @param int $id_customer + * @return int + */ + public static function getCustomerNumberProducts($id_customer) + { + return (int)(Db::getInstance()->getValue(' + SELECT count(`id_compare_product`) + FROM `'._DB_PREFIX_.'compare_product` + WHERE `id_customer` = '.(int)($id_customer))); + } + + + /** + * Clean entries which are older than the period + * @param string $period + * @return void + */ + public static function cleanCompareProducts($period = 'week') + { + if ($period === 'week') + $interval = '1 WEEK'; + elseif ($period === 'month') + $interval = '1 MONTH'; + elseif ($period === 'year') + $interval = '1 YEAR'; + else + return; + + if ($interval != null) + { + Db::getInstance()->Execute(' + DELETE FROM `'._DB_PREFIX_.'compare_product` + WHERE date_upd < DATE_SUB(NOW(), INTERVAL '.pSQL($interval).')'); + } + } +} \ No newline at end of file diff --git a/install-dev/classes/ConfigurationTest.php b/classes/ConfigurationTest.php similarity index 70% rename from install-dev/classes/ConfigurationTest.php rename to classes/ConfigurationTest.php index 6b5492e2d..f74539405 100644 --- a/install-dev/classes/ConfigurationTest.php +++ b/classes/ConfigurationTest.php @@ -20,14 +20,14 @@ * * @author PrestaShop SA * @copyright 2007-2011 PrestaShop SA -* @version Release: $Revision: 7040 $ +* @version Release: $Revision$ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ -class ConfigurationTest +class ConfigurationTestCore { - static function check($tests) + static function check($tests) { $res = array(); foreach ($tests AS $key => $test) @@ -35,7 +35,7 @@ class ConfigurationTest return $res; } - static function run($ptr, $arg = 0) + static function run($ptr, $arg = 0) { if (call_user_func(array('ConfigurationTest', 'test_'.$ptr), $arg)) return ('ok'); @@ -43,32 +43,32 @@ class ConfigurationTest } // Misc functions - static function test_phpversion() + static function test_phpversion() { return version_compare(substr(phpversion(), 0, 3), '5.0', '>='); } - static function test_mysql_support() + static function test_mysql_support() { return function_exists('mysql_connect'); } - static function test_magicquotes() + static function test_magicquotes() { return !ini_get('magic_quotes_gpc'); } - static function test_upload() + static function test_upload() { return ini_get('file_uploads'); } - static function test_fopen() + static function test_fopen() { return ini_get('allow_url_fopen'); } - static function test_system($funcs) + static function test_system($funcs) { foreach ($funcs AS $func) if (!function_exists($func)) @@ -76,17 +76,17 @@ class ConfigurationTest return true; } - static function test_gd() + static function test_gd() { return function_exists('imagecreatetruecolor'); } - static function test_register_globals() + static function test_register_globals() { return !ini_get('register_globals'); } - static function test_gz() + static function test_gz() { if (function_exists('gzencode')) return !(@gzencode('dd') === false); @@ -94,7 +94,7 @@ class ConfigurationTest } // is_writable dirs - static function test_dir($dir, $recursive = false) + static function test_dir($dir, $recursive = false) { if (!file_exists($dir) OR !$dh = opendir($dir)) return false; @@ -119,107 +119,112 @@ class ConfigurationTest } // is_writable files - static function test_file($file) + static function test_file($file) { return (file_exists($file) AND is_writable($file)); } - static function test_config_dir($dir) + static function test_config_dir($dir) { return self::test_dir($dir); } - static function test_sitemap($dir) + static function test_sitemap($dir) { return self::test_file($dir); } - static function test_root_dir($dir) + static function test_root_dir($dir) { return self::test_dir($dir); } - static function test_log_dir($dir) + static function test_log_dir($dir) { return self::test_dir($dir); } - static function test_admin_dir($dir) + static function test_admin_dir($dir) { return self::test_dir($dir); } - static function test_img_dir($dir) + static function test_img_dir($dir) { return self::test_dir($dir, true); } - static function test_module_dir($dir) + static function test_module_dir($dir) { return self::test_dir($dir, true); } - static function test_tools_dir($dir) + static function test_tools_dir($dir) { return self::test_dir($dir); } - static function test_cache_dir($dir) + static function test_cache_dir($dir) { return self::test_dir($dir); } - static function test_tools_v2_dir($dir) + static function test_tools_v2_dir($dir) { return self::test_dir($dir); } - static function test_cache_v2_dir($dir) + static function test_cache_v2_dir($dir) { return self::test_dir($dir); } - static function test_download_dir($dir) + static function test_download_dir($dir) { return self::test_dir($dir); } - static function test_mails_dir($dir) + static function test_mails_dir($dir) { return self::test_dir($dir, true); } - static function test_translations_dir($dir) + static function test_translations_dir($dir) { return self::test_dir($dir, true); } - static function test_theme_lang_dir($dir) + static function test_theme_lang_dir($dir) { if (!file_exists($dir)) return true; return self::test_dir($dir, true); } - static function test_theme_cache_dir($dir) + static function test_theme_cache_dir($dir) { if (!file_exists($dir)) return true; return self::test_dir($dir, true); } - static function test_customizable_products_dir($dir) + static function test_customizable_products_dir($dir) { return self::test_dir($dir); } - static function test_virtual_products_dir($dir) + static function test_virtual_products_dir($dir) { return self::test_dir($dir); } - static function test_mcrypt() + static function test_mcrypt() { return function_exists('mcrypt_encrypt'); } + + static function test_dom() + { + return extension_loaded('Dom'); + } } diff --git a/classes/Helper.php b/classes/Helper.php new file mode 100755 index 000000000..85ab54aec --- /dev/null +++ b/classes/Helper.php @@ -0,0 +1,118 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +/* + * TODO : move HTML code in template files + */ + +class HelperCore +{ + public static $translationsKeysForAdminCategorieTree = array( + 'Home', 'selected', 'selecteds', 'Collapse All', 'Expand All', 'Check All', 'Uncheck All' + ); + + /** + * + * @param type $trads values of translations keys + * For the moment, translation are not automatic + * @param type $selected_cat array of selected categories + * Format + * Array + ( + [0] => 1 + [1] => 2 + ) + * OR + Array + ( + [1] => Array + ( + [id_category] => 1 + [name] => Home page + [link_rewrite] => home + ) + ) + * @param type $input_name name of input + * @return string + */ + public static function renderAdminCategorieTree($trads, $selected_cat = array(), $input_name = 'categoryBox') + { + $html = ' + + + + + + + + '; + + $html .= ' + + '; + + $home_is_selected = false; + foreach($selected_cat AS $cat) + { + if (is_array($cat)) + { + if ($cat['id_category'] != 1) + $html .= ''; + else + $home_is_selected = true; + } + else + { + if ($cat != 1) + $html .= ''; + else + $home_is_selected = true; + } + } + $html .= ' +
      +
    • + '.$trads['Home'].' +
        +
      •  
      • +
      +
    • +
    '; + return $html; + } +} diff --git a/classes/Image.php b/classes/Image.php index 0ee5e3439..954ee4873 100644 --- a/classes/Image.php +++ b/classes/Image.php @@ -452,7 +452,17 @@ class ImageCore extends ObjectModel public function createImgFolder() { if (!file_exists(_PS_PROD_IMG_DIR_.$this->getImgFolder())) - return @mkdir(_PS_PROD_IMG_DIR_.$this->getImgFolder(), 0755, true); + { + // Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both. + $success = @mkdir(_PS_PROD_IMG_DIR_.$this->getImgFolder(), 0755, true) + || @chmod(_PS_PROD_IMG_DIR_.$this->getImgFolder(), 0755); + + // Create an index.php file in the new folder + if ($success + && !file_exists(_PS_PROD_IMG_DIR_.$this->getImgFolder().'index.php') + && file_exists($this->source_index)) + return @copy($this->source_index, _PS_PROD_IMG_DIR_.$this->getImgFolder().'index.php'); + } return true; } @@ -511,6 +521,51 @@ class ImageCore extends ObjectModel } return $result; } -} - + public static function testFileSystem() + { + $safe_mode = ini_get('safe_mode'); + if ($safe_mode) + return false; + $folder1 = _PS_PROD_IMG_DIR_.'testfilesystem/'; + $test_folder = $folder1.'testsubfolder/'; + if (file_exists($test_folder)) + { + @rmdir($test_folder); + @rmdir($folder1); + } + if (file_exists($test_folder)) + return false; + @mkdir($test_folder, 0755, true); + @chmod($test_folder, 0755); + if (!is_writeable($test_folder)) + return false; + @rmdir($test_folder); + @rmdir($folder1); + if (file_exists($folder1)) + return false; + return true; + } + + /** + * Returns the path where a product image should be created (without file format) + * + * @return string path + */ + public function getPathForCreation() + { + if (!$this->id) + return false; + if (Configuration::get('PS_LEGACY_IMAGES')) + { + if (!$this->id_product) + return false; + $path = $this->id_product.'-'.$this->id; + } + else + { + $path = $this->getImgPath(); + $this->createImgFolder(); + } + } +} \ No newline at end of file diff --git a/classes/Language.php b/classes/Language.php index da77de3d7..73ce86008 100644 --- a/classes/Language.php +++ b/classes/Language.php @@ -103,7 +103,8 @@ class LanguageCore extends ObjectModel return ($resUpdateSQL AND Tools::generateHtaccess(dirname(__FILE__).'/../.htaccess', (int)(Configuration::get('PS_REWRITING_SETTINGS')), (int)(Configuration::get('PS_HTACCESS_CACHE_CONTROL')), - Configuration::get('PS_HTACCESS_SPECIFIC') + Configuration::get('PS_HTACCESS_SPECIFIC'), + (int)Configuration::get('PS_HTACCESS_DISABLE_MULTIVIEWS') )); } @@ -118,7 +119,8 @@ class LanguageCore extends ObjectModel return (Tools::generateHtaccess(dirname(__FILE__).'/../.htaccess', (int)(Configuration::get('PS_REWRITING_SETTINGS')), (int)(Configuration::get('PS_HTACCESS_CACHE_CONTROL')), - Configuration::get('PS_HTACCESS_SPECIFIC') + Configuration::get('PS_HTACCESS_SPECIFIC'), + (int)Configuration::get('PS_HTACCESS_DISABLE_MULTIVIEWS') )); } @@ -290,7 +292,8 @@ class LanguageCore extends ObjectModel foreach($tables as $table) foreach($table as $t) - $langTables[] = $t; + if ($t != _DB_PREFIX_.'configuration_lang') + $langTables[] = $t; Db::getInstance()->Execute('SET @id_lang_default = (SELECT c.`value` FROM `'._DB_PREFIX_.'configuration` c WHERE c.`name` = \'PS_LANG_DEFAULT\' LIMIT 1)'); $return = true; @@ -403,7 +406,8 @@ class LanguageCore extends ObjectModel return Tools::generateHtaccess(dirname(__FILE__).'/../.htaccess', (int)(Configuration::get('PS_REWRITING_SETTINGS')), (int)(Configuration::get('PS_HTACCESS_CACHE_CONTROL')), - Configuration::get('PS_HTACCESS_SPECIFIC') + Configuration::get('PS_HTACCESS_SPECIFIC'), + (int)Configuration::get('PS_HTACCESS_DISABLE_MULTIVIEWS') ); } @@ -426,7 +430,8 @@ class LanguageCore extends ObjectModel Tools::generateHtaccess(dirname(__FILE__).'/../.htaccess', (int)(Configuration::get('PS_REWRITING_SETTINGS')), (int)(Configuration::get('PS_HTACCESS_CACHE_CONTROL')), - Configuration::get('PS_HTACCESS_SPECIFIC') + Configuration::get('PS_HTACCESS_SPECIFIC'), + (int)Configuration::get('PS_HTACCESS_DISABLE_MULTIVIEWS') ); return $result; @@ -566,7 +571,8 @@ class LanguageCore extends ObjectModel return Tools::generateHtaccess(dirname(__FILE__).'/../.htaccess', (int)(Configuration::get('PS_REWRITING_SETTINGS')), (int)(Configuration::get('PS_HTACCESS_CACHE_CONTROL')), - Configuration::get('PS_HTACCESS_SPECIFIC') + Configuration::get('PS_HTACCESS_SPECIFIC'), + (int)Configuration::get('PS_HTACCESS_DISABLE_MULTIVIEWS') ); } diff --git a/classes/Manufacturer.php b/classes/Manufacturer.php index 1721a5544..5d69fe31a 100644 --- a/classes/Manufacturer.php +++ b/classes/Manufacturer.php @@ -77,6 +77,7 @@ class ManufacturerCore extends ObjectModel protected $webserviceParameters = array( 'fields' => array( + 'active' => array(), 'link_rewrite' => array('getter' => 'getLink', 'setter' => false), ), 'associations' => array( @@ -374,16 +375,19 @@ class ManufacturerCore extends ObjectModel $ids = array(); foreach ($id_addresses as $id) $ids[] = (int)$id['id']; - Db::getInstance()->ExecuteS(' + $result1 = (Db::getInstance()->ExecuteS(' UPDATE `'._DB_PREFIX_.'address` SET id_manufacturer = 0 WHERE id_manufacturer = '.(int)$this->id.' - AND deleted = 0'); - return (Db::getInstance()->ExecuteS(' + AND deleted = 0') !== false); + $result2 = true; + if (count($ids)) + $result2 = (Db::getInstance()->ExecuteS(' UPDATE `'._DB_PREFIX_.'address` SET id_customer = 0, id_supplier = 0, id_manufacturer = '.(int)$this->id.' WHERE id_address IN('.implode(',', $ids).') AND deleted = 0') !== false); + return ($result1 && $result2); } } diff --git a/classes/Module.php b/classes/Module.php index 2684bb27d..8db1c6474 100644 --- a/classes/Module.php +++ b/classes/Module.php @@ -523,6 +523,11 @@ abstract class ModuleCore return false; } + public static function configXmlStringFormat($string) + { + return str_replace('\'', '\\\'', Tools::htmlentitiesDecodeUTF8($string)); + } + /** * Return available modules * @@ -567,12 +572,12 @@ abstract class ModuleCore $item->warning = ''; foreach ($xml_module as $k => $v) $item->$k = (string) $v; - $item->displayName = Module::findTranslation($xml_module->name, $xml_module->displayName, (string)$xml_module->name); - $item->description = Module::findTranslation($xml_module->name, $xml_module->description, (string)$xml_module->name); - $item->author = Module::findTranslation($xml_module->name, $xml_module->author, (string)$xml_module->name); + $item->displayName = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->displayName), (string)$xml_module->name); + $item->description = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->description), (string)$xml_module->name); + $item->author = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->author), (string)$xml_module->name); if (isset($xml_module->confirmUninstall)) - $item->confirmUninstall = Module::findTranslation($xml_module->name, $xml_module->confirmUninstall, (string)$xml_module->name); + $item->confirmUninstall = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->confirmUninstall), (string)$xml_module->name); $item->active = 0; $moduleList[$moduleListCursor] = $item; @@ -792,8 +797,22 @@ abstract class ModuleCore { $context = Context::getContext(); $hookArgs = array('cookie' => $context->cookie, 'cart' => $context->cart); - $billing = new Address((int)($context->cart->id_address_invoice)); $output = ''; + + $result = self::getPaymentModules(); + + if ($result) + foreach ($result AS $module) + if (($moduleInstance = Module::getInstanceByName($module['name'])) AND is_callable(array($moduleInstance, 'hookpayment'))) + if (!$moduleInstance->currencies OR ($moduleInstance->currencies AND sizeof(Currency::checkPaymentCurrencies($moduleInstance->id)))) + $output .= call_user_func(array($moduleInstance, 'hookpayment'), $hookArgs); + return $output; + } + + public static function getPaymentModules() + { + $context = Context::getContext(); + $billing = new Address($context->cart->id_address_invoice); $list = Context::getContext()->shop->getListOfID(); $sql = 'SELECT DISTINCT h.`id_hook`, m.`name`, hm.`position` FROM `'._DB_PREFIX_.'module_country` mc @@ -810,13 +829,7 @@ abstract class ModuleCore AND hm.id_shop IN('.implode(', ', $list).') GROUP BY hm.id_hook, hm.id_module ORDER BY hm.`position`, m.`name` DESC'; - $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql); - if ($result) - foreach ($result AS $k => $module) - if (($moduleInstance = Module::getInstanceByName($module['name'])) AND is_callable(array($moduleInstance, 'hookpayment'))) - if (!$moduleInstance->currencies OR ($moduleInstance->currencies AND sizeof(Currency::checkPaymentCurrencies($moduleInstance->id)))) - $output .= call_user_func(array($moduleInstance, 'hookpayment'), $hookArgs); - return $output; + return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql); } /** @@ -1115,13 +1128,7 @@ abstract class ModuleCore protected function _clearCache($template, $cacheId = NULL, $compileId = NULL) { - $context = Context::getContext(); - /* Use Smarty 3 API calls */ - if (!Configuration::get('PS_FORCE_SMARTY_2')) /* PHP version > 5.1.2 */ - return $context->smarty->clearCache($template ? $this->_getApplicableTemplateDir($template).$template : NULL, $cacheId, $compileId); - /* or keep a backward compatibility if PHP version < 5.1.2 */ - else - return $context->smarty->clear_cache($template ? $this->_getApplicableTemplateDir($template).$template : NULL, $cacheId, $compileId); + Tools::clearCache(Context::getContext()->smarty); } protected function _generateConfigXml() diff --git a/classes/MySQL.php b/classes/MySQL.php index f6fd468c0..01e95ffc9 100644 --- a/classes/MySQL.php +++ b/classes/MySQL.php @@ -137,11 +137,19 @@ class MySQLCore extends Db } /** - * @see DbCore::tryToConnect() + * tryToConnect return 0 if the connection succeed and the database can be selected. + * @since 1.4.4.0, the parameter $newDbLink (default true) has been added. + * + * @param string $server mysql server name + * @param string $user mysql user + * @param string $pwd mysql user password + * @param string $db mysql database name + * @param boolean $newDbLink if set to true, the function will not create a new link if one already exists. + * @return integer */ - static public function tryToConnect($server, $user, $pwd, $db) + static public function tryToConnect($server, $user, $pwd, $db, $newDbLink = true) { - if (!$link = @mysql_connect($server, $user, $pwd)) + if (!$link = @mysql_connect($server, $user, $pwd, $newDbLink)) return 1; if (!@mysql_select_db($db, $link)) return 2; diff --git a/classes/ObjectModel.php b/classes/ObjectModel.php index f054f2c05..dedd48143 100644 --- a/classes/ObjectModel.php +++ b/classes/ObjectModel.php @@ -408,7 +408,7 @@ abstract class ObjectModelCore $fields = array(); if($this->id_lang == NULL) - foreach (Language::getLanguages() as $language) + foreach (Language::getLanguages(false) as $language) $this->makeTranslationFields($fields, $fieldsArray, $language['id_lang']); else $this->makeTranslationFields($fields, $fieldsArray, $this->id_lang); diff --git a/classes/Order.php b/classes/Order.php index 77771d6a9..e4cce191e 100644 --- a/classes/Order.php +++ b/classes/Order.php @@ -293,7 +293,14 @@ class OrderCore extends ObjectModel /* Update order */ $shippingDiff = $this->total_shipping - $cart->getOrderShippingCost(); $this->total_products -= $productPriceWithoutTax; + + // After upgrading from old version + // total_products_wt is null + // removing a product made order total negative + // and don't recalculating totals (on getTotalProductsWithTaxes) + if ($this->total_products_wt != 0) $this->total_products_wt -= $productPrice; + $this->total_shipping = $cart->getOrderShippingCost(); /* It's temporary fix for 1.3 version... */ diff --git a/classes/PaymentModule.php b/classes/PaymentModule.php index bc653c69d..fcf1db588 100644 --- a/classes/PaymentModule.php +++ b/classes/PaymentModule.php @@ -105,7 +105,7 @@ abstract class PaymentModuleCore extends Module $order->id_customer = (int)($cart->id_customer); $order->id_address_invoice = (int)($cart->id_address_invoice); $order->id_address_delivery = (int)($cart->id_address_delivery); - $vat_address = new Address((int)($order->id_address_delivery)); + $vat_address = new Address((int)($order->{Configuration::get('PS_TAX_ADDRESS_TYPE')})); $order->id_currency = ($currency_special ? (int)($currency_special) : (int)($cart->id_currency)); $order->id_lang = (int)($cart->id_lang); $order->id_cart = (int)($cart->id); diff --git a/classes/Product.php b/classes/Product.php index 8ad1bd7e9..4de673e31 100644 --- a/classes/Product.php +++ b/classes/Product.php @@ -263,7 +263,7 @@ class ProductCore extends ObjectModel 'out_of_stock' => array('required' => true), 'new' => array(), 'cache_default_attribute' => array(), - 'id_default_image' => array('getter' => 'getCoverWs', 'setter' => false, 'xlink_resource' => array('resourceName' => 'images', 'subResourceName' => 'products')), + 'id_default_image' => array('getter' => 'getCoverWs', 'setter' => 'setCoverWs', 'xlink_resource' => array('resourceName' => 'images', 'subResourceName' => 'products')), 'id_default_combination' => array('getter' => 'getWsDefaultCombination', 'setter' => 'setWsDefaultCombination', 'xlink_resource' => array('resourceName' => 'combinations')), 'position_in_category' => array('getter' => 'getWsPositionInCategory', 'setter' => false), 'manufacturer_name' => array('getter' => 'getWsManufacturerName', 'setter' => false), @@ -285,6 +285,10 @@ class ProductCore extends ObjectModel 'id' => array('required' => true), 'id_feature_value' => array('required' => true, 'xlink_resource' => 'product_feature_values'), )), + 'tags' => array('resource' => 'tag', + 'fields' => array( + 'id' => array('required' => true), + )), ), ); @@ -3336,6 +3340,21 @@ class ProductCore extends ObjectModel return $result['id_image']; } + /** + * Webservice setter : set virtual field id_default_image in category + * + * @return bool + */ + public function setCoverWs($id_image) + { + Db::getInstance()->ExecuteS('UPDATE `'._DB_PREFIX_.'image` + SET `cover` = 0 WHERE `id_product` = '.(int)($this->id).' + '); + Db::getInstance()->ExecuteS('UPDATE `'._DB_PREFIX_.'image` + SET `cover` = 1 WHERE `id_product` = '.(int)($this->id).' AND `id_image` = '.(int)$id_image); + return true; + } + /** * Webservice getter : get image ids of current product for association * @@ -3350,6 +3369,15 @@ class ProductCore extends ObjectModel ORDER BY `position`'); } + public function getWsTags() + { + return Db::getInstance()->ExecuteS(' + SELECT `id_tag` as id + FROM `'._DB_PREFIX_.'product_tag` + WHERE `id_product` = '.(int)($this->id)); + } + + public function getWsManufacturerName() { return Manufacturer::getNameById((int)$this->id_manufacturer); diff --git a/classes/SpecificPrice.php b/classes/SpecificPrice.php index 5fb0f0bc4..41128615f 100644 --- a/classes/SpecificPrice.php +++ b/classes/SpecificPrice.php @@ -231,7 +231,12 @@ class SpecificPriceCore extends ObjectModel `id_country` IN(0, '.(int)($id_country).') AND `id_group` IN(0, '.(int)($id_group).') AND `from_quantity` = 1 AND - (`from` = \'0000-00-00 00:00:00\' OR (\''.$beginning.'\' >= `from` AND \''.$ending.'\' <= `to`)) AND + ( + (`from` = \'0000-00-00 00:00:00\' OR \''.$beginning.'\' >= `from`) + AND + (`to` = \'0000-00-00 00:00:00\' OR \''.$ending.'\' <= `to`) + ) + AND `reduction` > 0 ', false); $ids_product = array(); diff --git a/classes/Tools.php b/classes/Tools.php index 9a6cc1bac..1e8f3f284 100644 --- a/classes/Tools.php +++ b/classes/Tools.php @@ -1491,7 +1491,7 @@ class ToolsCore return Tools::getHttpHost(); } - public static function generateHtaccess($path, $rewrite_settings, $cache_control, $specific = '') + public static function generateHtaccess($path, $rewrite_settings, $cache_control, $specific = '', $disableMuliviews = false) { if (!$writeFd = @fopen($path, 'w')) return false; @@ -1531,7 +1531,8 @@ class ToolsCore $tab['RewriteRule'][$domain]['content']['^'.ltrim($uri['uri'], '/').'([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?/[_a-zA-Z0-9-]*\.jpg$'] = _PS_PROD_IMG_.'$1/$2/$3/$4/$5/$6/$7/$1$2$3$4$5$6$7$8.jpg [L]'; $tab['RewriteRule'][$domain]['content']['^'.ltrim($uri['uri'], '/').'([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?/[_a-zA-Z0-9-]*\.jpg$'] = _PS_PROD_IMG_.'$1/$2/$3/$4/$5/$6/$7/$8/$1$2$3$4$5$6$7$8$9.jpg [L]'; - $tab['RewriteRule'][$domain]['content']['^'.ltrim($uri['uri'], '/').'c/([0-9]+)(\-[_a-zA-Z0-9-]*)/[_a-zA-Z0-9-]*\.jpg$'] = 'img/c/$1$2.jpg [L]'; + $tab['RewriteRule']['content']['^c/([0-9]+)(\-[_a-zA-Z0-9-]*)/[_a-zA-Z0-9-]*\.jpg$'] = 'img/c/$1$2.jpg [L]'; + $tab['RewriteRule']['content']['^c/([a-zA-Z-]+)/[a-zA-Z0-9-]+\.jpg$'] = 'img/c/$1.jpg [L]'; if ($multilang) { @@ -1591,9 +1592,13 @@ class ToolsCore fwrite($writeFd, $specific); // RewriteEngine fwrite($writeFd, "\n\n"); - fwrite($writeFd, "\nRewriteEngine on\n\n"); -// fwrite($writeFd, $tab['RewriteRule']['comment']."\n"); - // Webservice needs apache_mod_rewrite in order to work + + if ($disableMuliviews) + fwrite($writeFd, "\n# Disable Multiviews\nOptions -Multiviews\n\n"); + + fwrite($writeFd, $tab['RewriteEngine']['comment']."\nRewriteEngine on\n\n"); + fwrite($writeFd, $tab['RewriteRule']['comment']."\n"); + // Webservice fwrite($writeFd, 'RewriteRule ^api/?(.*)$ '.__PS_BASE_URI__."webservice/dispatcher.php?url=$1 [QSA,L]\n"); fwrite($writeFd, "RewriteCond %{REQUEST_FILENAME} -s [OR]\nRewriteCond %{REQUEST_FILENAME} -l [OR]\nRewriteCond %{REQUEST_FILENAME} -d\nRewriteRule ^.*$ - [NC,L]\nRewriteRule ^.*\$ index.php [NC,L]\n"); @@ -1990,6 +1995,19 @@ FileETag INode MTime Size { return str_replace(array("\r\n", "\r", "\n"), '
    ', $str); } + + /** + * Clear cache for Smarty + * + * @param objet $smarty + */ + public static function clearCache($smarty) + { + if (!Configuration::get('PS_FORCE_SMARTY_2')) + $smarty->clearAllCache(); + else + $smarty->clear_all_cache(); + } } /** diff --git a/classes/Upgrader.php b/classes/Upgrader.php new file mode 100644 index 000000000..e4a5012b8 --- /dev/null +++ b/classes/Upgrader.php @@ -0,0 +1,138 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +class UpgraderCore{ + const DEFAULT_CHECK_VERSION_DELAY_HOURS = 24; + /** + * link contains hte url where to download the file + * + * @var string + */ + private $needUpgrade = false; + private $noRefresh = false; + + public $version_name; + public $version_num; + public $link; + public $autoupgrade; + + public function __get($var) + { + if($var == 'needUpgrade') + return $this->isLastVersion(); + } + /** + * we need to checkPSVersion when we use that class + * @param boolean noRefresh if true, checkPSVersion will not refresh its information + * @return object Upgrader + */ + public function __construct($noRefresh = false) + { + $this->noRefresh = (bool)$noRefresh; + } + + /** + * downloadLast download the last version of PrestaShop and save it in $dest/$filename + * + * @param string $dest directory where to save the file + * @param string $filename new filename + * @return boolean + * + * @TODO ftp if copy is not possible (safe_mode for example) + */ + public function downloadLast($dest, $filename = 'prestashop.zip') + { + if (empty($this->link)) + $this->checkPSVersion(); + + if (@copy($this->link, realpath($dest).DIRECTORY_SEPARATOR.$filename)) + return true; + else + return false; + } + public function isLastVersion() + { + if (empty($this->link)) + $this->checkPSVersion(); + + return $this->needUpgrade; + + } + + /** + * checkPSVersion ask to prestashop.com if there is a new version. return an array if yes, false otherwise + * + * @return mixed + */ + public function checkPSVersion($force = false) + { + if (empty($this->link)) + { + $lastCheck = Configuration::get('PS_LAST_VERSION_CHECK'); + // if we use the autoupgrade process, we will never refresh it + // except if no check has been done before + if (!($this->autoUpgrade AND $lastCheck) AND ($force OR ($lastCheck < time() - (3600 * Upgrader::DEFAULT_CHECK_VERSION_DELAY_HOURS))) ) + { + libxml_set_streams_context(stream_context_create(array('http' => array('timeout' => 3)))); + if ($feed = @simplexml_load_file('http://www.prestashop.com/xml/version.xml')) + { + $this->version_name = (string)$feed->version->name; + $this->version_num = (string)$feed->version->num; + $this->link = (string)$feed->download->link; + $this->autoupgrade = (int)$feed->autoupgrade; + $configLastVersion = array( + 'name' => $this->version_name, + 'num' => $this->version_num, + 'link' => $this->link, + 'autoupgrade' => $this->autoupgrade + ); + Configuration::updateValue('PS_LAST_VERSION',serialize($configLastVersion)); + Configuration::updateValue('PS_LAST_VERSION_CHECK',time()); + } + } + else + { + $lastVersionCheck = unserialize(Configuration::get('PS_LAST_VERSION')); + $this->version_name = $lastVersionCheck['name']; + $this->version_num = $lastVersionCheck['num']; + $this->link = $lastVersionCheck['link']; + $this->autoupgrade = $lastVersionCheck['autoupgrade']; + } + } + // retro-compatibility : + // return array(name,link) if you don't use the last version + // false otherwise + if (version_compare(_PS_VERSION_, $this->version_num, '<')) + { + $this->needUpgrade = true; + return array('name' => $this->version_name, 'link' => $this->link); + } + else + return false; + } + +} diff --git a/classes/WebserviceRequest.php b/classes/WebserviceRequest.php index b05e2183a..1f8123600 100644 --- a/classes/WebserviceRequest.php +++ b/classes/WebserviceRequest.php @@ -1356,7 +1356,7 @@ class WebserviceRequestCore $this->setError(400, 'id is duplicate in request', 89); return false; } - if ($xmlEntities->count() != count($ids)) + if (count($xmlEntities) != count($ids)) { $this->setError(400, 'id is required when modifying a resource', 90); return false; diff --git a/controllers/CategoryController.php b/controllers/CategoryController.php index e93e70420..0696876b9 100644 --- a/controllers/CategoryController.php +++ b/controllers/CategoryController.php @@ -151,6 +151,11 @@ class CategoryControllerCore extends FrontController 'thumbSceneSize' => Image::getSize('thumb_scene'), 'homeSize' => Image::getSize('home') )); + + if (isset(self::$cookie->id_customer)) + self::$smarty->assign('compareProducts', CompareProduct::getCustomerCompareProducts((int)self::$cookie->id_customer)); + elseif (isset(self::$cookie->id_guest)) + self::$smarty->assign('compareProducts', CompareProduct::getGuestCompareProducts((int)self::$cookie->id_guest)); } } diff --git a/controllers/CompareController.php b/controllers/CompareController.php index 33643c86b..1d800b8f4 100644 --- a/controllers/CompareController.php +++ b/controllers/CompareController.php @@ -31,23 +31,74 @@ class CompareControllerCore extends FrontController { parent::setMedia(); $this->addCSS(_THEME_CSS_DIR_.'/comparator.css'); + + if (Configuration::get('PS_COMPARATOR_MAX_ITEM') > 0) + Tools::addJS(_THEME_JS_DIR_.'products-comparison.js'); + } + + public function preProcess() + { + parent::preProcess(); + + //Add or remove product with Ajax + if (Tools::getValue('ajax') AND Tools::getValue('id_product') AND Tools::getValue('action')) + { + if (Tools::getValue('action') == 'add') + { + if (isset(self::$cookie->id_customer)) + { + if(CompareProduct::getCustomerNumberProducts(self::$cookie->id_customer) < Configuration::get('PS_COMPARATOR_MAX_ITEM')) + CompareProduct::addCustomerCompareProduct((int)self::$cookie->id_customer, (int)Tools::getValue('id_product')); + else + die('0'); + } + else + { + if ((isset(self::$cookie->id_guest) AND CompareProduct::getGuestNumberProducts(self::$cookie->id_guest) < Configuration::get('PS_COMPARATOR_MAX_ITEM'))) + CompareProduct::addGuestCompareProduct((int)self::$cookie->id_guest, (int)Tools::getValue('id_product')); + else + die('0'); + } + } + elseif (Tools::getValue('action') == 'remove') + { + if (isset(self::$cookie->id_customer)) + CompareProduct::removeCustomerCompareProduct((int)self::$cookie->id_customer, (int)Tools::getValue('id_product')); + elseif (isset(self::$cookie->id_guest)) + CompareProduct::removeGuestCompareProduct((int)self::$cookie->id_guest, (int)Tools::getValue('id_product')); + else + die('0'); + } + else + die('0'); + + die('1'); + } } public function process() { parent::process(); + //Clean compare product table + CompareProduct::cleanCompareProducts('week'); + $hasProduct = false; - $product_list = Tools::getValue('compare_product_list'); - $postProducts = isset($product_list) ? rtrim($product_list,'|') : ''; if (!Configuration::get('PS_COMPARATOR_MAX_ITEM')) return Tools::redirect('index.php?controller=404'); - if ($postProducts) - { + if ($product_list = Tools::getValue('compare_product_list') AND $postProducts = (isset($product_list) ? rtrim($product_list,'|') : '')) $ids = array_unique(explode('|', $postProducts)); + elseif (isset(self::$cookie->id_customer)) + $ids = CompareProduct::getCustomerCompareProducts(self::$cookie->id_customer); + elseif(isset(self::$cookie->id_guest)) + $ids = CompareProduct::getGuestCompareProducts(self::$cookie->id_guest); + else + $ids = null; + if ($ids) + { if (sizeof($ids) > 0) { if (sizeof($ids) > Configuration::get('PS_COMPARATOR_MAX_ITEM')) diff --git a/controllers/OrderDetailController.php b/controllers/OrderDetailController.php index 0f58fc116..38c56b900 100644 --- a/controllers/OrderDetailController.php +++ b/controllers/OrderDetailController.php @@ -146,6 +146,7 @@ class OrderDetailControllerCore extends FrontController 'messages' => Message::getMessagesByOrderId((int)($order->id)), 'CUSTOMIZE_FILE' => _CUSTOMIZE_FILE_, 'CUSTOMIZE_TEXTFIELD' => _CUSTOMIZE_TEXTFIELD_, + 'isRecyclable' => Configuration::get('PS_RECYCLABLE_PACK'), 'use_tax' => Configuration::get('PS_TAX'), 'group_use_tax' => (Group::getPriceDisplayMethod($customer->id_default_group) == PS_TAX_INC), 'customizedDatas' => $customizedDatas)); diff --git a/controllers/ParentOrderController.php b/controllers/ParentOrderController.php index 7f1338e62..dd1f95d38 100644 --- a/controllers/ParentOrderController.php +++ b/controllers/ParentOrderController.php @@ -360,7 +360,9 @@ class ParentOrderControllerCore extends FrontController $this->context->smarty->assign(array( 'checked' => $this->_setDefaultCarrierSelection($carriers), 'carriers' => $carriers, - 'default_carrier' => (int)(Configuration::get('PS_CARRIER_DEFAULT')), + 'default_carrier' => (int)(Configuration::get('PS_CARRIER_DEFAULT')) + )); + self::$smarty->assign(array( 'HOOK_EXTRACARRIER' => Module::hookExec('extraCarrier', array('address' => $address)), 'HOOK_BEFORECARRIER' => Module::hookExec('beforeCarrier', array('carriers' => $carriers)) )); diff --git a/controllers/ProductController.php b/controllers/ProductController.php index 0ebfa12c5..2ce27999e 100644 --- a/controllers/ProductController.php +++ b/controllers/ProductController.php @@ -28,6 +28,8 @@ class ProductControllerCore extends FrontController { protected $product; + public $php_self = 'product.php'; + protected $canonicalURL; public function setMedia() { @@ -49,11 +51,28 @@ class ProductControllerCore extends FrontController $this->addJS(_PS_JS_DIR_.'jquery/jquery.jqzoom.js'); } } + + public function canonicalRedirection() + { + // Automatically redirect to the canonical URL if the current in is the right one + // $_SERVER['HTTP_HOST'] must be replaced by the real canonical domain + if (Validate::isLoadedObject($this->product)) + { + $canonicalURL = self::$link->getProductLink($this->product); + if (!preg_match('/^'.Tools::pRegexp($canonicalURL, '/').'([&?].*)?$/', Tools::getProtocol().$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) + { + header('HTTP/1.0 301 Moved'); + if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) + die('[Debug] This page has moved
    Please use the following URL instead: '.$canonicalURL.''); + Tools::redirectLink($canonicalURL); + } + } + } public function preProcess() { if ($id_product = (int)Tools::getValue('id_product')) - $this->product = new Product($id_product, true, $this->context->language->id, $this->id_current_shop); + $this->product = new Product($id_product, true, $this->context->language->id); if (!Validate::isLoadedObject($this->product)) { @@ -61,42 +80,16 @@ class ProductControllerCore extends FrontController header('Status: 404 Not Found'); } else - { - // Automatically redirect to the canonical URL if the current in is the right one - // $_SERVER['HTTP_HOST'] must be replaced by the real canonical domain - if (Validate::isLoadedObject($this->product)) - { - $canonicalURL = $this->context->link->getProductLink($this->product); - if (!preg_match('/^'.Tools::pRegexp($canonicalURL, '/').'([&?].*)?$/i', Tools::getProtocol().$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) - { - header('HTTP/1.0 301 Moved'); - if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) - die('[Debug] This page has moved
    Please use the following URL instead: '.$canonicalURL.''); - Tools::redirectLink($canonicalURL); - } - } - } + $this->canonicalRedirection(); parent::preProcess(); - - if((int)(Configuration::get('PS_REWRITING_SETTINGS'))) - if ($id_product = (int)Tools::getValue('id_product')) - { - $rewrite_infos = Product::getUrlRewriteInformations((int)$id_product); - - $default_rewrite = array(); - foreach ($rewrite_infos AS $infos) - $default_rewrite[$infos['id_lang']] = $this->context->link->getProductLink((int)$id_product, $infos['link_rewrite'], $infos['category_rewrite'], $infos['ean13'], (int)$infos['id_lang']); - - $this->context->smarty->assign('lang_rewrite_urls', $default_rewrite); - } } public function process() { parent::process(); - if (!$id_product = (int)(Tools::getValue('id_product')) OR !Validate::isUnsignedId($id_product)) + if (!Validate::isLoadedObject($this->product)) $this->errors[] = Tools::displayError('Product not found'); else { @@ -105,7 +98,7 @@ class ProductControllerCore extends FrontController || !file_exists(dirname(__FILE__).'/../'.Tools::getValue('ad').'/ajax.php'))) { header('HTTP/1.1 404 page not found'); - $this->errors[] = Tools::displayError('Pproduct is no longer available.'); + $this->errors[] = Tools::displayError('Product is no longer available.'); } elseif (!$this->product->checkAccess(isset($this->context->customer) ? $this->context->customer->id : 0)) $this->errors[] = Tools::displayError('You do not have access to this product.'); @@ -116,9 +109,6 @@ class ProductControllerCore extends FrontController if (!$this->product->active) $this->context->smarty->assign('adminActionDisplay', true); - /* rewrited url set */ - $rewrited_url = $this->context->link->getProductLink($this->product->id, $this->product->link_rewrite); - /* Product pictures management */ require_once('images.inc.php'); $this->context->smarty->assign('customizationFormTarget', Tools::safeOutput(urldecode($_SERVER['REQUEST_URI']))); @@ -152,16 +142,11 @@ class ProductControllerCore extends FrontController 'pictures' => $pictures, 'textFields' => $textFields)); - $productPriceWithTax = Product::getPriceStatic($id_product, true, NULL, 6); - if (Product::$_taxCalculationMethod == PS_TAX_INC) - $productPriceWithTax = Tools::ps_round($productPriceWithTax, 2); - - $productPriceWithoutEcoTax = (float)($productPriceWithTax - $this->product->ecotax); $configs = Configuration::getMultiple(array('PS_ORDER_OUT_OF_STOCK', 'PS_LAST_QTIES')); /* Features / Values */ $features = $this->product->getFrontFeatures($this->context->language->id); - $attachments = $this->product->getAttachments($this->context->language->id); + $attachments = ($this->product->cache_has_attachments) ? $this->product->getAttachments($this->context->language->id) : array(); /* Category */ $category = false; @@ -169,13 +154,13 @@ class ProductControllerCore extends FrontController { if (isset($regs[2]) AND is_numeric($regs[2])) { - if (Product::idIsOnCategoryId((int)($this->product->id), array('0' => array('id_category' => (int)($regs[2]))))) - $category = new Category((int)($regs[2]), (int)$this->context->cookie->id_lang); + if (Product::idIsOnCategoryId($this->product->id, array('0' => array('id_category' => (int)$regs[2])))) + $category = new Category($regs[2], $this->context->language->id); } elseif (isset($regs[5]) AND is_numeric($regs[5])) { - if (Product::idIsOnCategoryId((int)($this->product->id), array('0' => array('id_category' => (int)($regs[5]))))) - $category = new Category((int)($regs[5]), (int)$this->context->cookie->id_lang); + if (Product::idIsOnCategoryId($this->product->id, array('0' => array('id_category' => (int)$regs[5])))) + $category = new Category($regs[5], $this->context->language->id); } } if (!$category) @@ -184,12 +169,13 @@ class ProductControllerCore extends FrontController if (isset($category) AND Validate::isLoadedObject($category)) { $this->context->smarty->assign(array( - 'path' => Tools::getPath((int)$category->id, $this->product->name, true), - 'category' => $category, - 'subCategories' => $category->getSubCategories($this->context->language->id, true), - 'id_category_current' => (int)($category->id), - 'id_category_parent' => (int)($category->id_parent), - 'return_category_name' => Tools::safeOutput($category->name))); + 'path' => Tools::getPath((int)$category->id, $this->product->name, true), + 'category' => $category, + 'subCategories' => $category->getSubCategories($this->context->language->id, true), + 'id_category_current' => (int)($category->id), + 'id_category_parent' => (int)($category->id_parent), + 'return_category_name' => Tools::safeOutput($category->name), + )); } else $this->context->smarty->assign('path', Tools::getPath((int)$this->product->id_category_default, $this->product->name)); @@ -197,7 +183,7 @@ class ProductControllerCore extends FrontController $this->context->smarty->assign('return_link', (isset($category->id) AND $category->id) ? Tools::safeOutput($this->context->link->getCategoryLink($category)) : 'javascript: history.back();'); $lang = Configuration::get('PS_LANG_DEFAULT'); - if (Pack::isPack((int)($this->product->id), (int)($lang)) AND !Pack::isInStock((int)($this->product->id), (int)($lang))) + if (Pack::isPack($this->product->id) AND !Pack::isInStock((int)$this->product->id, $lang)) $this->product->quantity = 0; $id_customer = (isset($this->context->customer) ? (int)($this->context->customer->id) : 0); @@ -209,8 +195,13 @@ class ProductControllerCore extends FrontController $tax = (float)(Tax::getProductTaxRate((int)($this->product->id), $this->context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')})); $this->context->smarty->assign('tax_rate', $tax); + $productPriceWithTax = Product::getPriceStatic($this->product->id, true, NULL, 6); + if (Product::$_taxCalculationMethod == PS_TAX_INC) + $productPriceWithTax = Tools::ps_round($productPriceWithTax, 2); + $productPriceWithoutEcoTax = (float)($productPriceWithTax - $this->product->ecotax); + $ecotax_rate = (float) Tax::getProductEcotaxRate($this->context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')}); - $ecotaxTaxAmount = Tools::ps_round($this->product->ecotax, 2); + $ecotaxTaxAmount = Tools::ps_round($this->product->ecotax, 2); if (Product::$_taxCalculationMethod == PS_TAX_INC && (int)Configuration::get('PS_TAX')) $ecotaxTaxAmount = Tools::ps_round($ecotaxTaxAmount * (1 + $ecotax_rate / 100), 2); @@ -221,13 +212,13 @@ class ProductControllerCore extends FrontController 'ecotax_tax_exc' => Tools::ps_round($this->product->ecotax, 2), 'ecotaxTax_rate' => $ecotax_rate, 'homeSize' => Image::getSize('home'), - 'product_manufacturer' => new Manufacturer((int)($this->product->id_manufacturer), Configuration::get('PS_LANG_DEFAULT')), + 'product_manufacturer' => new Manufacturer($this->product->id_manufacturer, $this->context->language->id), 'token' => Tools::getToken(false), - 'productPriceWithoutEcoTax' => (float)($productPriceWithoutEcoTax), + 'productPriceWithoutEcoTax' => (float)$productPriceWithoutEcoTax, 'features' => $features, 'attachments' => $attachments, 'allow_oosp' => $this->product->isAvailableWhenOutOfStock((int)($this->product->out_of_stock)), - 'last_qties' => (int)($configs['PS_LAST_QTIES']), + 'last_qties' => (int)Configuration::get('PS_LAST_QTIES'), 'group_reduction' => $group_reduction, 'col_img_dir' => _PS_COL_IMG_DIR_, )); @@ -241,7 +232,7 @@ class ProductControllerCore extends FrontController 'HOOK_PRODUCT_TAB_CONTENT' => Module::hookExec('productTabContent') )); - $images = $this->product->getImages((int)$this->context->cookie->id_lang); + $images = $this->product->getImages((int)$this->context->language->id); $productImages = array(); foreach ($images AS $k => $image) { @@ -252,7 +243,7 @@ class ProductControllerCore extends FrontController $cover['id_image'] = (Configuration::get('PS_LEGACY_IMAGES') ? ($this->product->id.'-'.$image['id_image']) : $image['id_image']); $cover['id_image_only'] = (int)($image['id_image']); } - $productImages[(int)($image['id_image'])] = $image; + $productImages[(int)$image['id_image']] = $image; } if (!isset($cover)) $cover = array('id_image' => $this->context->language->iso_code.'-default', 'legend' => 'No picture', 'title' => 'No picture'); @@ -348,7 +339,7 @@ class ProductControllerCore extends FrontController $this->context->smarty->assign(array( 'no_tax' => Tax::excludeTaxeOption() OR !Tax::getProductTaxRate((int)$this->product->id, $this->context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')}), - 'customizationFields' => $this->product->getCustomizationFields($this->context->language->id) + 'customizationFields' => ($this->product->customizable) ? $this->product->getCustomizationFields($this->context->language->id) : false, )); // Pack management @@ -362,7 +353,7 @@ class ProductControllerCore extends FrontController 'outOfStockAllowed' => (int)(Configuration::get('PS_ORDER_OUT_OF_STOCK')), 'errors' => $this->errors, 'categories' => Category::getHomeCategories($this->context->language->id), - 'have_image' => Product::getCover((int)(Tools::getValue('id_product'))), + 'have_image' => (isset($cover) ? (int)$cover['id_image'] : false), 'tax_enabled' => Configuration::get('PS_TAX'), 'display_qties' => (int)(Configuration::get('PS_DISPLAY_QTIES')), 'display_ht' => !Tax::excludeTaxeOption(), @@ -383,7 +374,7 @@ class ProductControllerCore extends FrontController public function pictureUpload(Product $product, Cart $cart) { - if (!$fieldIds = $product->getCustomizationFieldIds()) + if (!$fieldIds = $this->product->getCustomizationFieldIds()) return false; $authorizedFileFields = array(); foreach ($fieldIds AS $fieldId) @@ -454,16 +445,15 @@ class ProductControllerCore extends FrontController foreach ($specificPrices AS $key => &$row) { $row['quantity'] = &$row['from_quantity']; - if ($row['price'] != 0) // The price may be directly set + // The price may be directly set + if ($row['price'] != 0) { $cur_price = (Product::$_taxCalculationMethod == PS_TAX_EXC ? $row['price'] : $row['price'] * (1 + $taxRate / 100)); if ($row['reduction_type'] == 'amount') - { $cur_price = Product::$_taxCalculationMethod == PS_TAX_INC ? $cur_price - $row['reduction'] : $cur_price - ($row['reduction'] / (1 + $taxRate / 100)); - } else { + else $cur_price = $cur_price * ( 1 - ($row['reduction'])); - } $row['real_value'] = $price - $cur_price; } @@ -481,4 +471,3 @@ class ProductControllerCore extends FrontController return $specificPrices; } } - diff --git a/css/jquery.treeview.css b/css/jquery.treeview.css new file mode 100755 index 000000000..9d9441dab --- /dev/null +++ b/css/jquery.treeview.css @@ -0,0 +1,73 @@ +.treeview, .treeview ul { + padding: 0; + margin: 0; + list-style: none; +} + +.treeview ul { + margin-top: 4px; +} + +.treeview .hitarea { + background: url(../img/admin/jquery-treeview/treeview-default.gif) -64px -25px no-repeat; + height: 16px; + width: 16px; + margin-left: -16px; + float: left; + cursor: pointer; +} +/* fix for IE6 */ +* html .hitarea { + display: inline; + float:none; +} + +.treeview li { + margin: 0; + padding: 3px 0pt 3px 16px; +} + +.treeview a.selected { + background-color: #eee; +} + +#treecontrol { margin: 1em 0; display: none; } + +.treeview .hover { color: gray; cursor: pointer; } + +.treeview li { background: url(../img/admin/jquery-treeview/treeview-default-line.gif) 0 0 no-repeat; } +.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; } + +.treeview .expandable-hitarea { background-position: -80px -3px; } + +.treeview li.last { background-position: 0 -1766px } +.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(../img/admin/jquery-treeview/treeview-default.gif); } +.treeview li.lastCollapsable { background-position: 0 -111px } +.treeview li.lastExpandable { background-position: -32px -67px } + +.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; } + +.treeview-red li { background-image: url(../img/admin/jquery-treeview/treeview-red-line.gif); } +.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(../img/admin/jquery-treeview/treeview-red.gif); } + +.treeview-black li { background-image: url(../img/admin/jquery-treeview/treeview-black-line.gif); } +.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(../img/admin/jquery-treeview/treeview-black.gif); } + +.treeview-gray li { background-image: url(../img/admin/jquery-treeview/treeview-gray-line.gif); } +.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(../img/admin/jquery-treeview/treeview-gray.gif); } + +.treeview-famfamfam li { background-image: url(../img/admin/jquery-treeview/treeview-famfamfam-line.gif); } +.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(../img/admin/jquery-treeview/treeview-famfamfam.gif); } + +.treeview .placeholder { + background: url(../img/admin/jquery-treeview/ajax-loader.gif) 0 0 no-repeat; + height: 16px; + width: 16px; + display: block; +} + +.filetree li { padding: 3px 0 2px 16px; } +.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; } +.filetree span.folder { background: url(../img/admin/jquery-treeview/folder.gif) 0 0 no-repeat; } +.filetree li.expandable span.folder { background: url(../img/admin/jquery-treeview/folder-closed.gif) 0 0 no-repeat; } +.filetree span.file { background: url(../img/admin/jquery-treeview/file.gif) 0 0 no-repeat; } diff --git a/img/admin/ajax-loader-big.gif b/img/admin/ajax-loader-big.gif new file mode 100644 index 000000000..d2afc328e Binary files /dev/null and b/img/admin/ajax-loader-big.gif differ diff --git a/img/admin/color_swatch.png b/img/admin/color_swatch.png new file mode 100644 index 000000000..6e6e85212 Binary files /dev/null and b/img/admin/color_swatch.png differ diff --git a/img/admin/jquery-treeview/ajax-loader.gif b/img/admin/jquery-treeview/ajax-loader.gif new file mode 100755 index 000000000..bc545850a Binary files /dev/null and b/img/admin/jquery-treeview/ajax-loader.gif differ diff --git a/img/admin/jquery-treeview/file.gif b/img/admin/jquery-treeview/file.gif new file mode 100755 index 000000000..7e6216798 Binary files /dev/null and b/img/admin/jquery-treeview/file.gif differ diff --git a/img/admin/jquery-treeview/folder-closed.gif b/img/admin/jquery-treeview/folder-closed.gif new file mode 100755 index 000000000..541107888 Binary files /dev/null and b/img/admin/jquery-treeview/folder-closed.gif differ diff --git a/img/admin/jquery-treeview/folder.gif b/img/admin/jquery-treeview/folder.gif new file mode 100755 index 000000000..2b31631ca Binary files /dev/null and b/img/admin/jquery-treeview/folder.gif differ diff --git a/img/admin/jquery-treeview/minus.gif b/img/admin/jquery-treeview/minus.gif new file mode 100755 index 000000000..47fb7b767 Binary files /dev/null and b/img/admin/jquery-treeview/minus.gif differ diff --git a/img/admin/jquery-treeview/plus.gif b/img/admin/jquery-treeview/plus.gif new file mode 100755 index 000000000..690662162 Binary files /dev/null and b/img/admin/jquery-treeview/plus.gif differ diff --git a/img/admin/jquery-treeview/treeview-black-line.gif b/img/admin/jquery-treeview/treeview-black-line.gif new file mode 100755 index 000000000..e5496877a Binary files /dev/null and b/img/admin/jquery-treeview/treeview-black-line.gif differ diff --git a/img/admin/jquery-treeview/treeview-black.gif b/img/admin/jquery-treeview/treeview-black.gif new file mode 100755 index 000000000..d549b9fc5 Binary files /dev/null and b/img/admin/jquery-treeview/treeview-black.gif differ diff --git a/img/admin/jquery-treeview/treeview-default-line.gif b/img/admin/jquery-treeview/treeview-default-line.gif new file mode 100755 index 000000000..37114d306 Binary files /dev/null and b/img/admin/jquery-treeview/treeview-default-line.gif differ diff --git a/img/admin/jquery-treeview/treeview-default.gif b/img/admin/jquery-treeview/treeview-default.gif new file mode 100755 index 000000000..a12ac52ff Binary files /dev/null and b/img/admin/jquery-treeview/treeview-default.gif differ diff --git a/img/admin/jquery-treeview/treeview-famfamfam-line.gif b/img/admin/jquery-treeview/treeview-famfamfam-line.gif new file mode 100755 index 000000000..6e289cecc Binary files /dev/null and b/img/admin/jquery-treeview/treeview-famfamfam-line.gif differ diff --git a/img/admin/jquery-treeview/treeview-famfamfam.gif b/img/admin/jquery-treeview/treeview-famfamfam.gif new file mode 100755 index 000000000..0cb178e89 Binary files /dev/null and b/img/admin/jquery-treeview/treeview-famfamfam.gif differ diff --git a/img/admin/jquery-treeview/treeview-gray-line.gif b/img/admin/jquery-treeview/treeview-gray-line.gif new file mode 100755 index 000000000..37600447d Binary files /dev/null and b/img/admin/jquery-treeview/treeview-gray-line.gif differ diff --git a/img/admin/jquery-treeview/treeview-gray.gif b/img/admin/jquery-treeview/treeview-gray.gif new file mode 100755 index 000000000..cfb8a2f09 Binary files /dev/null and b/img/admin/jquery-treeview/treeview-gray.gif differ diff --git a/img/admin/jquery-treeview/treeview-red-line.gif b/img/admin/jquery-treeview/treeview-red-line.gif new file mode 100755 index 000000000..df9e749a8 Binary files /dev/null and b/img/admin/jquery-treeview/treeview-red-line.gif differ diff --git a/img/admin/jquery-treeview/treeview-red.gif b/img/admin/jquery-treeview/treeview-red.gif new file mode 100755 index 000000000..3bbb3a157 Binary files /dev/null and b/img/admin/jquery-treeview/treeview-red.gif differ diff --git a/install-dev/classes/GetVersionFromDb.php b/install-dev/classes/GetVersionFromDb.php index d18c7b02a..a5d106065 100644 --- a/install-dev/classes/GetVersionFromDb.php +++ b/install-dev/classes/GetVersionFromDb.php @@ -463,7 +463,9 @@ class GetVersionFromDb // List keys $struct[$virtualTable]['@keys'] = array(); $sql = 'SHOW INDEX FROM ' . $table; - foreach (Db::getInstance()->executeS($sql) as $rowIndex) + $results = Db::getInstance()->executeS($sql); + if($results) + foreach ($results as $rowIndex) { $keyName = strtolower($rowIndex['Key_name']); $type = 'index'; diff --git a/install-dev/classes/ToolsInstall.php b/install-dev/classes/ToolsInstall.php index f5d2981fb..c6f2604a6 100644 --- a/install-dev/classes/ToolsInstall.php +++ b/install-dev/classes/ToolsInstall.php @@ -28,9 +28,15 @@ class ToolsInstall { public static function checkDB ($srv, $login, $password, $name, $posted = true, $engine = false) { - include_once(INSTALL_PATH.'/../classes/Validate.php'); - include_once(INSTALL_PATH.'/../classes/Db.php'); - include_once(INSTALL_PATH.'/../classes/MySQL.php'); + // Don't include theses files if classes are already defined + if (!class_exists('Validate', false)) + include_once(INSTALL_PATH.'/../classes/Validate.php'); + + if (!class_exists('Db', false)) + include_once(INSTALL_PATH.'/../classes/Db.php'); + + if (!class_exists('MySQL', false)) + include_once(INSTALL_PATH.'/../classes/MySQL.php'); if($posted) { diff --git a/install-dev/controller.js b/install-dev/controller.js index 2e528bd7b..579f8ad51 100644 --- a/install-dev/controller.js +++ b/install-dev/controller.js @@ -73,6 +73,9 @@ function showStep(aStep, way) .removeClass("selected") .removeClass("finished"); if (step < 6) { + if (step == 5) + $('#tabs li:nth-child(' + step + ')').addClass("finished"); + else $('#tabs li:nth-child(' + step + ')').addClass("selected"); $('#tabs li:lt(' + (step - 1) + ')').addClass("finished"); } @@ -106,7 +109,7 @@ function showStep(aStep, way) $('#tabs li:nth-child(1)').removeClass("selected").addClass("finished"); $('#tabs li:nth-child(2)').removeClass("selected").addClass("finished"); $('#tabs li:nth-child(3)').removeClass("selected").addClass("finished"); - $('#tabs li:nth-child(4)').addClass("selected").removeClass("finished"); + $('#tabs li:nth-child(4)').addClass("finished"); break; } @@ -276,26 +279,26 @@ function verifyAndSetRequire(firsttime) for (i = 0; i < testListRequired.length; i++){ result = testListRequired[i].getAttribute("result"); $($("div#sheet_require"+isUpdate+" > ul#required"+isUpdate+" .required")[i]) - .removeClass( (result == "fail") ? "ok" : "fail" ) + .removeClass( (result == "fail") ? "okBlock" : "errorBlock" ) .addClass(result); if (result == "fail") configIsOk = false; } - testListOptional = testLists[1].getElementsByTagName('test'); for (i = 0; i < testListOptional.length; i++){ result = testListOptional[i].getAttribute("result"); $($("div#sheet_require"+isUpdate+" > ul#optional"+isUpdate+" li.optional")[i]) - .removeClass( (result == "fail") ? "ok" : "fail" ) + .removeClass( (result == "fail") ? "okBlock" : "errorBlock" ) .addClass(result); } if (!configIsOk) { $('#btNext').attr({'disabled':'disabled','class':'button little disabled'}); - $('h3#resultConfig'+isUpdate).html(txtConfigIsNotOk).slideDown('slow'); + $('h3#resultConfig'+isUpdate).html(txtConfigIsNotOk).removeClass('okBlock').addClass('errorBlock').slideDown('slow'); $('h3#resultConfigHelper').show(); $("div#sheet_require"+isUpdate+" > ul").slideDown("1500"); + $('#stepList_2 li:contains("Etape 2")').addClass('ko'); } else { $("#btNext").removeAttr('disabled'); $('#btNext').removeClass('disabled'); @@ -305,9 +308,10 @@ function verifyAndSetRequire(firsttime) $("input#btNext").click(); else { - $('h3#resultConfig'+isUpdate).html(txtConfigIsOk).slideDown('slow'); + $('h3#resultConfig'+isUpdate).html(txtConfigIsOk).removeClass('errorBlock').addClass('okBlock').slideDown('slow'); $('h3#resultConfigHelper').hide(); $("div#sheet_require"+isUpdate+" > ul").slideDown("1500"); + $('#stepList_2 li:contains("Etape 2")').removeClass('ko'); } } } @@ -320,32 +324,38 @@ function verifyDbAccess () //local verifications if($("#dbServer[value=]").length > 0) { - $("#dbResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtDbServerEmpty).show('slow'); + $("#dbResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtDbServerEmpty).slideDown('slow'); + $('#stepList_3 li:contains("Etape 3")').addClass('ko'); return false; } else { - $("#dbResultCheck").removeClass("fail").removeClass("ok").removeClass('userInfos').html(''); + $("#dbResultCheck").removeClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(''); + $('#stepList_3 li:contains("Etape 3")').removeClass('ko'); } if($("#dbLogin[value=]").length > 0) { - $("#dbResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtDbLoginEmpty).show('slow'); + $("#dbResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtDbLoginEmpty).slideDown('slow'); + $('#stepList_3 li:contains("Etape 3")').addClass('ko'); return false; } else { - $("#dbResultCheck").removeClass("fail").removeClass("ok").removeClass('userInfos').html(''); + $("#dbResultCheck").removeClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(''); + $('#stepList_3 li:contains("Etape 3")').removeClass('ko'); } if($("#dbName[value=]").length > 0) { - $("#dbResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtDbNameEmpty).show('slow'); + $("#dbResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtDbNameEmpty).slideDown('slow'); + $('#stepList_3 li:contains("Etape 3")').addClass('ko'); return false; } else { - $("#dbResultCheck").removeClass("fail").removeClass("ok").removeClass('userInfos').html(''); + $("#dbResultCheck").removeClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(''); + $('#stepList_3 li:contains("Etape 3")').removeClass('ko'); } //external verifications and sets @@ -367,21 +377,23 @@ function verifyDbAccess () if (ret.getAttribute("result") == "ok") { $("#dbResultCheck") - .addClass("ok") - .removeClass("fail") + .addClass("okBlock") + .removeClass("errorBlock") .html(txtError[23]) - .show('slow'); + .slideDown('slow'); $("#dbCreateResultCheck") - .hide('slow'); + .slideUp('slow'); + $('#stepList_3 li:contains("Etape 3")').removeClass('ko'); } else { $("#dbResultCheck") - .addClass("fail") - .removeClass("ok") + .addClass("errorBlock") + .removeClass("okBlock") .html(txtError[parseInt(ret.getAttribute("error"))]) - .show('slow'); + .slideDown('slow'); $("#dbCreateResultCheck") - .hide('slow'); + .slideUp('slow'); + $('#stepList_3 li:contains("Etape 3")').addClass('ko'); } } } @@ -416,11 +428,12 @@ function createDB() action_ret = ret.getElementsByTagName('action')[0]; } catch (e) { $("#dbCreateResultCheck") - .addClass("fail") - .removeClass("ok") - .removeClass('userInfos') + .addClass("errorBlock") + .removeClass("okBlock") + .removeClass('infosBlock') .html(ret) .show(); + $('#stepList_3 li:contains("Etape 3")').addClass('ko'); return; } if (action_ret.getAttribute("result") == "ok") @@ -452,9 +465,9 @@ function createDB() if (action_ret.getAttribute("error") == "11") { $("#dbCreateResultCheck") - .addClass("fail") - .removeClass("ok") - .removeClass('userInfos') + .addClass("errorBlock") + .removeClass("okBlock") + .removeClass('infosBlock') .html( txtError[11]+ "
    \'"+ action_ret.getAttribute("sqlQuery") + "\'
    "+ @@ -465,12 +478,13 @@ function createDB() else { $("#dbCreateResultCheck") - .addClass("fail") - .removeClass("ok") - .removeClass('userInfos') + .addClass("errorBlock") + .removeClass("okBlock") + .removeClass('infosBlock') .html(txtError[parseInt(action_ret.getAttribute("error"))]) .show(); } + $('#stepList_3 li:contains("Etape 3")').addClass('ko'); } } }); @@ -482,29 +496,27 @@ function verifyMail() //local verifications if ($("#testEmail[value=]").length > 0) { - $("#mailResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtError[0]); + $("#mailResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtError[0]); return false; } else if (!verifMailREGEX.test( $("#testEmail").val() )) { - $("#mailResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtError[3]); + $("#mailResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtError[3]); return false; } else { - if (smtpChecked) { //local verifications if($("#smtpSrv[value=]").length > 0) { - $("#mailResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtSmtpSrvEmpty); + $("#mailResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtSmtpSrvEmpty); smtpIsOk = false; return false; } } - //external verifications and sets $.ajax( { @@ -528,13 +540,13 @@ function verifyMail() if (ret.getAttribute("result") == "ok") { - $("#mailResultCheck").addClass("ok").removeClass("fail").removeClass('userInfos').html(mailSended); + $("#mailResultCheck").addClass("okBlock").removeClass("errorBlock").removeClass('infosBlock').html(mailSended); mailIsOk = true; } else { mailIsOk = false; - $("#mailResultCheck").addClass("fail").removeClass("ok").removeClass('userInfos').html(txtError[26]); + $("#mailResultCheck").addClass("errorBlock").removeClass("okBlock").removeClass('infosBlock').html(txtError[26]); } } } @@ -559,13 +571,13 @@ function uploadLogo () { if(data.error != '') { - $("#resultInfosLogo").html( txtError[parseInt(data.error)] ).addClass("fail").show(); + $("#resultInfosLogo").html( txtError[parseInt(data.error)] ).addClass("errorBlock").show(); } else { $(this).attr('src', ps_base_uri + 'img/logo.jpg?' + (new Date())) $(this).show('slow'); - $("#resultInfosLogo").html("").removeClass("fail").hide(); + $("#resultInfosLogo").html("").removeClass("errorBlock").hide(); } }); } @@ -573,7 +585,7 @@ function uploadLogo () error: function (data, status, e) { $("#uploadedImage").attr('src', ps_base_uri + 'img/logo.jpg?' + (new Date())); - $("#resultInfosLogo").html("").addClass("fail"); + $("#resultInfosLogo").html("").addClass("errorBlock"); } } ) @@ -621,7 +633,7 @@ function ajaxRefreshField(nthField, idResultField, fieldsList, inputId) { $("#"+idResultField) .html( txtError[parseInt(fieldsList[nthField].getAttribute("error"))] ) - .addClass("fail") + .addClass("errorBlock") .show("slow"); if (validShopInfos) $("#"+inputId).focus(); @@ -631,7 +643,7 @@ function ajaxRefreshField(nthField, idResultField, fieldsList, inputId) { $("#"+idResultField) .html("") - .removeClass("fail") + .removeClass("errorBlock") .show("slow"); return true; } @@ -651,7 +663,7 @@ function verifyShopInfos() $.ajax( { url: "model.php", - async: false, + async: true, cache: false, data: "method=checkShopInfos"+ @@ -676,9 +688,7 @@ function verifyShopInfos() "&smtpPort="+ encodeURIComponent($("input#smtpPort").val())+ "&smtpEnc="+ encodeURIComponent($("select#smtpEnc option:selected").val())+ "&mailSubject="+ encodeURIComponent(mailSubject)+ - "&isoCodeLocalLanguage="+isoCodeLocalLanguage - , - + "&isoCodeLocalLanguage="+isoCodeLocalLanguage, success: function(ret) { fieldsList = ret.getElementsByTagName('shopConfig')[0].getElementsByTagName('field'); @@ -702,6 +712,7 @@ function verifyShopInfos() $('#endFirstName').html($('input#infosFirstname').val()); $('#endName').html($('input#infosName').val()); $('#endEmail').html($('input#infosEmail').val()); + showStep(5); } } } @@ -719,14 +730,14 @@ function autoCheckField(idField, idResultSpan, typeVerif) { $(idResultSpan) .show("slow") - .addClass("fail") + .addClass("errorBlock") .html(txtError[0]); } else { $(idResultSpan) .hide("slow") - .removeClass("fail") + .removeClass("errorBlock") .html(""); } } @@ -741,14 +752,14 @@ function autoCheckField(idField, idResultSpan, typeVerif) { $(idResultSpan) .show("slow") - .addClass("fail") + .addClass("errorBlock") .html(txtError[3]); } else { $(idResultSpan) .hide("slow") - .removeClass("fail") + .removeClass("errorBlock") .html(""); } } @@ -763,14 +774,14 @@ function autoCheckField(idField, idResultSpan, typeVerif) { $(idResultSpan) .show("slow") - .addClass("fail") + .addClass("errorBlock") .html(txtError[47]); } else { $(idResultSpan) .hide("slow") - .removeClass("fail") + .removeClass("errorBlock") .html(""); } } @@ -785,14 +796,14 @@ function autoCheckField(idField, idResultSpan, typeVerif) { $(idResultSpan) .show("slow") - .addClass("fail") + .addClass("errorBlock") .html(txtError[48]); } else { $(idResultSpan) .hide("slow") - .removeClass("fail") + .removeClass("errorBlock") .html(""); } } @@ -841,8 +852,7 @@ function doUpgrade() url: "model.php", cache: false, data: - "method=doUpgrade&customModule=" + customModule+ "" - , + "method=doUpgrade&customModule=" + customModule+ "", success: function(ret) { var ret; @@ -859,18 +869,19 @@ function doUpgrade() { requests = ret.getElementsByTagName('request'); $("#updateLog").empty(); - + $("#updateLog").hide(); $(requests).each(function() { - $("#updateLog").append("
    " + $(this).children("sqlQuery").text() + "

    "); + var html = "
    " + $(this).children("sqlQuery").text(); if($(this).attr("result") == "fail") { countSqlError++; - $("#updateLog").append("(" + $(this).children("sqlNumberError").text() + ") " + $(this).children("sqlMsgError").text() + "
    "); + html += "
    (" + $(this).children("sqlNumberError").text() + ") " + $(this).children("sqlMsgError").text() + "
    "; } + $("#updateLog").append(html+"

    "); }); if (ret.getAttribute("error") == "34") - $("#txtErrorUpdateSQL").html(txtError[35]+" "+countSqlError+" "+txtError[36]); + $("#txtErrorUpdateSQL").html(txtError[35]+" "+countSqlError+" "+txtError[36]).show(); showStep(9); } else @@ -905,29 +916,18 @@ $(document).ready( $("#container").show(); //ajax animation - $("#loader").ajaxStart( + $("#loaderSpace").ajaxStart( function() { - $(this).fadeIn(); - $("#btNext[disabled!=1], #btBack[disabled!=1]").attr("disabled", "disabled").addClass("disabled").addClass("lockedForAjax"); + $(this).fadeIn('slow'); + $(this).children('div').fadeIn('slow'); } ); - $("#loader").ajaxComplete( + $("#loaderSpace").ajaxComplete( function(e, xhr, settings) { - $(this).fadeOut(); - if (!errorOccured) - { - $(".lockedForAjax").removeAttr("disabled").removeClass("disabled").removeClass("lockedForAjax"); - if (step == 1) - $("#btNext[disabled!=1], #btBack[disabled!=1]").attr("disabled", "disabled").addClass("disabled").addClass("lockedForAjax"); - if (step == 6) - { - $('#btNext, #btBack').removeAttr('disabled').removeClass('disabled'); - if (!$('#btDisclaimerOk').is(':checked')) - $("#btNext[disabled!=1]").attr("disabled", "disabled").addClass("disabled").addClass("lockedForAjax"); - } - } + $(this).fadeOut('slow'); + $(this).children('div').fadeOut('slow'); errorOccured = false; } ); @@ -950,6 +950,7 @@ $(document).ready( ); //set SMTP pannels states + $("div#mailSMTPParam").hide(); $("#set_stmp").bind("click", function() { @@ -958,13 +959,10 @@ $(document).ready( case 0 : $("div#mailSMTPParam").slideUp('slow'); smtpChecked = false; - $("#mailResultCheck").addClass("userInfos").removeClass("ok").removeClass('fail').html(""); break; - case 1 : $("div#mailSMTPParam").slideDown('slow'); smtpChecked = true; - $("#mailResultCheck").addClass("userInfos").removeClass("ok").removeClass('fail').html(""); break; } } diff --git a/install-dev/img/ajax-loader.gif b/install-dev/img/ajax-loader.gif new file mode 100644 index 000000000..d2afc328e Binary files /dev/null and b/install-dev/img/ajax-loader.gif differ diff --git a/install-dev/img/bg-contentTitle.png b/install-dev/img/bg-contentTitle.png new file mode 100755 index 000000000..db326df21 Binary files /dev/null and b/install-dev/img/bg-contentTitle.png differ diff --git a/install-dev/img/bg-input-text.png b/install-dev/img/bg-input-text.png new file mode 100755 index 000000000..777517706 Binary files /dev/null and b/install-dev/img/bg-input-text.png differ diff --git a/install-dev/img/bg-li-headerLinks.png b/install-dev/img/bg-li-headerLinks.png new file mode 100755 index 000000000..da414a8dd Binary files /dev/null and b/install-dev/img/bg-li-headerLinks.png differ diff --git a/install-dev/img/bg-li-tabs-finished.png b/install-dev/img/bg-li-tabs-finished.png new file mode 100755 index 000000000..2a3e99d96 Binary files /dev/null and b/install-dev/img/bg-li-tabs-finished.png differ diff --git a/install-dev/img/bg-li-tabs.png b/install-dev/img/bg-li-tabs.png new file mode 100755 index 000000000..621237b7b Binary files /dev/null and b/install-dev/img/bg-li-tabs.png differ diff --git a/install-dev/img/bg-phone_block.png b/install-dev/img/bg-phone_block.png new file mode 100755 index 000000000..df8088484 Binary files /dev/null and b/install-dev/img/bg-phone_block.png differ diff --git a/install-dev/img/bg_blockInfoEnd.png b/install-dev/img/bg_blockInfoEnd.png new file mode 100755 index 000000000..fcc8d9a2a Binary files /dev/null and b/install-dev/img/bg_blockInfoEnd.png differ diff --git a/install-dev/img/bg_bt_blockInfoEnd.png b/install-dev/img/bg_bt_blockInfoEnd.png new file mode 100755 index 000000000..b23dd7c65 Binary files /dev/null and b/install-dev/img/bg_bt_blockInfoEnd.png differ diff --git a/install-dev/img/bg_li_stepList.png b/install-dev/img/bg_li_stepList.png new file mode 100755 index 000000000..c0efe40a8 Binary files /dev/null and b/install-dev/img/bg_li_stepList.png differ diff --git a/install-dev/img/bg_li_title.png b/install-dev/img/bg_li_title.png new file mode 100755 index 000000000..86b2c833c Binary files /dev/null and b/install-dev/img/bg_li_title.png differ diff --git a/install-dev/img/bg_loaderSpace.png b/install-dev/img/bg_loaderSpace.png new file mode 100755 index 000000000..f9da304b5 Binary files /dev/null and b/install-dev/img/bg_loaderSpace.png differ diff --git a/install-dev/img/bg_moduleTable_th.png b/install-dev/img/bg_moduleTable_th.png new file mode 100755 index 000000000..3c5db2d44 Binary files /dev/null and b/install-dev/img/bg_moduleTable_th.png differ diff --git a/install-dev/img/bt - Copie.png b/install-dev/img/bt - Copie.png new file mode 100755 index 000000000..291c6f85f Binary files /dev/null and b/install-dev/img/bt - Copie.png differ diff --git a/install-dev/img/bt-dsbl - Copie.png b/install-dev/img/bt-dsbl - Copie.png new file mode 100755 index 000000000..cb87b5c87 Binary files /dev/null and b/install-dev/img/bt-dsbl - Copie.png differ diff --git a/install-dev/img/bt-dsbl.png b/install-dev/img/bt-dsbl.png index cb87b5c87..4be0c2aef 100644 Binary files a/install-dev/img/bt-dsbl.png and b/install-dev/img/bt-dsbl.png differ diff --git a/install-dev/img/bt-hover.png b/install-dev/img/bt-hover.png index 9e682dcfa..36859ca9b 100644 Binary files a/install-dev/img/bt-hover.png and b/install-dev/img/bt-hover.png differ diff --git a/install-dev/img/bt.png b/install-dev/img/bt.png index 291c6f85f..b877cfe9a 100644 Binary files a/install-dev/img/bt.png and b/install-dev/img/bt.png differ diff --git a/install-dev/img/bt_off.png b/install-dev/img/bt_off.png new file mode 100755 index 000000000..9de735db7 Binary files /dev/null and b/install-dev/img/bt_off.png differ diff --git a/install-dev/img/bt_off_hover.png b/install-dev/img/bt_off_hover.png new file mode 100755 index 000000000..a8507e95d Binary files /dev/null and b/install-dev/img/bt_off_hover.png differ diff --git a/install-dev/img/logo.png b/install-dev/img/logo.png index 3dda499e8..8275cd876 100644 Binary files a/install-dev/img/logo.png and b/install-dev/img/logo.png differ diff --git a/install-dev/img/pict_error.png b/install-dev/img/pict_error.png new file mode 100755 index 000000000..1995f4523 Binary files /dev/null and b/install-dev/img/pict_error.png differ diff --git a/install-dev/img/pict_h3_infos.png b/install-dev/img/pict_h3_infos.png new file mode 100755 index 000000000..0d027aa06 Binary files /dev/null and b/install-dev/img/pict_h3_infos.png differ diff --git a/install-dev/img/pict_ok.png b/install-dev/img/pict_ok.png new file mode 100755 index 000000000..429fc1656 Binary files /dev/null and b/install-dev/img/pict_ok.png differ diff --git a/install-dev/img/visu_boBlock.png b/install-dev/img/visu_boBlock.png new file mode 100755 index 000000000..cf892cc2a Binary files /dev/null and b/install-dev/img/visu_boBlock.png differ diff --git a/install-dev/img/visu_foBlock.png b/install-dev/img/visu_foBlock.png new file mode 100755 index 000000000..8c09791dc Binary files /dev/null and b/install-dev/img/visu_foBlock.png differ diff --git a/install-dev/index.php b/install-dev/index.php index 6746eaa47..b8045fe79 100644 --- a/install-dev/index.php +++ b/install-dev/index.php @@ -245,18 +245,30 @@ if ($lm->getIncludeTradFilename())
    +
     
    -
    +
    -

    - -
    PrestaShop '.lang('Installer'); ?>
    -
    PrestaShop '.lang('Updater'); ?>
    -

    -
    1.  
    @@ -265,27 +277,28 @@ if ($lm->getIncludeTradFilename())

    - -
      -

    • -

    • -
    -
    - - getIsoCodeSelectedLang() == 'fr'): ?> -

    - '.lang('A question about PrestaShop or issues during installation or upgrade? Call us!').'
    '.lang('+33 (0)1.40.18.30.04'); ?> -

    - -
    +
    +
    -

    -


    +
    +

    + +
      +
    • Etape 1
    • +
    • Etape 2
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    • Etape 5
    • +
    +
    + +

    +


    -
    +
    +
    +

    -

    +
      +
    • Etape 1
    • +
    • Etape 2
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    • Etape 5
    • +
    +
    -

    +

    @@ -366,7 +388,7 @@ if ($lm->getIncludeTradFilename())

    - +

    • @@ -407,13 +429,24 @@ if ($lm->getIncludeTradFilename())
    -
    -

    +
    +
    +

    -

    +
      +
    • Etape 1
    • +
    • Etape 2
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    • Etape 5
    • +
    +
    + +
    +

    +

    -

    -

    +

    @@ -436,27 +469,32 @@ if ($lm->getIncludeTradFilename())

    +

    + + +

    +
    -

    -
    - +
    +

    +

    -

    +


    @@ -478,7 +516,7 @@ if ($lm->getIncludeTradFilename())

    - +

    @@ -494,27 +532,41 @@ if ($lm->getIncludeTradFilename())

    - - +   +

    -

    +

    -
    +
    +
    +

    -

    +
      +
    • Etape 1 ok
    • +
    • Etape 2 ok
    • +
    • Etape 3 ok
    • +
    • Etape 4
    • +
    • Etape 5
    • +
    +
    -

    +
    +

    -
    + + + * +
    - @@ -538,64 +590,96 @@ if ($lm->getIncludeTradFilename()) +

    - +
    - +
    + + + +

    + + -

    -
    + - +     - + +

    -
    + + + * +
    -
    + + + * +
    -
    + + + * +
    -
    + + + * +
    -
    + + + * +
    -
    +
    +
    +
    +

    +
    +
    getIncludeTradFilename()) ?> - - "; } echo '
    '; @@ -754,13 +840,8 @@ if ($lm->getIncludeTradFilename()) } ?> - - - - - + +
    -
    -
    -
    -

    -

    +
    + +
    +

    + +
      +
    • Etape 1 ok
    • +
    • Etape 2 ok
    • +
    • Etape 3 ok
    • +
    • Etape 4 ok
    • +
    • Etape 5
    • +
    +
    + +
    +

    - - - - +
     
    + + + - + @@ -831,23 +925,26 @@ if ($lm->getIncludeTradFilename())
     
     
     
     
    -

    - - - - - - - - - - +

    + +
    + +

    +

    + +
    +
    + +

    +

    + +
    +
    - @@ -856,9 +953,18 @@ if ($lm->getIncludeTradFilename())
    -
    -

    -

    +
    +
    +

    + +
      +
    • Etape 1
    • +
    • Etape 2
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    +
    +



    @@ -879,7 +985,7 @@ if ($lm->getIncludeTradFilename()) $(document).ready(function() { $.ajax({ url: 'xml/getNonNativeModules.php', - async: false, + async: true, dataType: "json", success: function (json) { @@ -962,20 +1068,20 @@ if ($lm->getIncludeTradFilename()) if (sizeof($upgradeFiles)) { echo ' - +
    - + '; uasort($upgradeFiles, 'sortnatversion'); $totalInstructions = 0; foreach ($upgradeFiles AS $file) { - echo ''; + echo ''; $totalInstructions += (int)$file['instructions']; } - echo ''; + echo ''; echo '
    '.lang('Upgrade file').''.lang('Modifications to process').''.lang('Modifications to process').'
    v'.$file['version'].($file['is_major'] ? ' '.lang('(major)') : '').''.(int)$file['instructions'].'
    v'.$file['version'].($file['is_major'] ? ' '.lang('(major)') : '').''.(int)$file['instructions'].'
    '.lang('TOTAL').''.(int)$totalInstructions.'
    '.lang('TOTAL').''.(int)$totalInstructions.'
    '; @@ -983,7 +1089,7 @@ if ($lm->getIncludeTradFilename()) $minutes = (int)($upgradeTime / 60); $seconds = (int)($upgradeTime - ($minutes * 60)); - echo '

    '.lang('Estimated time to complete the').' '.(int)$totalInstructions.' '.lang('modifications:').' '.(int)$minutes.' '.($minutes > 1 ? lang('minutes') : lang('minute')).' '.(int)$seconds.' '.($seconds > 1 ? lang('seconds') : lang('second')).'
    + echo '

    '.lang('Estimated time to complete the').' '.(int)$totalInstructions.' '.lang('modifications:').' '.(int)$minutes.' '.($minutes > 1 ? lang('minutes') : lang('minute')).' '.(int)$seconds.' '.($seconds > 1 ? lang('seconds') : lang('second')).'
    '.lang('Depending on your server and the size of your shop').'

    '; if ($majorReleases > 1) @@ -1011,7 +1117,7 @@ if ($lm->getIncludeTradFilename())

    '.lang('Hosting parameters').'

    '.lang('PrestaShop tries to automatically set the best settings for your server in order the update to be successful.').'

    - +
    @@ -1028,28 +1134,32 @@ if ($lm->getIncludeTradFilename())
    '.lang('PHP parameter').' '.lang('Description').''.ini_get('memory_limit').'
    -
    '; +
    '; if ($color == '#D9F2D0') - echo ' '.lang('All your settings seem to be OK, go for it!'); + echo ' '.lang('All your settings seem to be OK, go for it!'); elseif ($color == '#FFDEB7') - echo ' '.lang('Beware, your settings look correct but are not optimal, if you encounter problems (upgrade too long, memory error...), please ask your hosting provider to increase the values of these parameters (max_execution_time & memory_limit).'); + echo ' '.lang('Beware, your settings look correct but are not optimal, if you encounter problems (upgrade too long, memory error...), please ask your hosting provider to increase the values of these parameters (max_execution_time & memory_limit).'); elseif ($color == '#FAE2E3') - echo ' '.lang('We strongly recommend that you inform your hosting provider to modify the settings before process to the update.'); - - echo ' -

    '; - + echo ' '.lang('We strongly recommend that you inform your hosting provider to modify the settings before process to the update.'); + echo '
    '; ?>
    -
    +
    +
    +

    -

    - -

    +
      +
    • Etape 1 ok
    • +
    • Etape 2 ok
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    +
    +

    @@ -1058,7 +1168,7 @@ if ($lm->getIncludeTradFilename())

    - +

    • @@ -1099,21 +1209,44 @@ if ($lm->getIncludeTradFilename())
    -
    -

    +
    +
    +

    + +
      +
    • Etape 1 ok
    • +
    • Etape 2 ok
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    +
    +

    -

    -

    + +

    +
    +

    -
    -
    +
    +
    +

    -

    -

    -

    + +
      +
    • Etape 1 ok
    • +
    • Etape 2 ok
    • +
    • Etape 3
    • +
    • Etape 4
    • +
    +
    +
    + +
    + +

    -


    +

    getIncludeTradFilename()) { echo '

    '.lang('New features in PrestaShop v').INSTALL_VERSION.'

    - '; } ?> -

    - - - - - +
    + +
    + +
    + +

    +

    + +
    diff --git a/install-dev/langs/fr.php b/install-dev/langs/fr.php index e0e28351f..c19e04451 100644 --- a/install-dev/langs/fr.php +++ b/install-dev/langs/fr.php @@ -177,8 +177,8 @@ $_LANG['Did you know?'] = 'Le saviez-vous ?'; $_LANG['Prestashop and community offers over 40 different languages for free download on'] = 'Prestashop et sa communauté propose plus de 40 langues différentes en téléchargement gratuit sur'; $_LANG['Default country:'] = 'Pays par défaut :'; $_LANG['Shop\'s timezone:'] = 'Fuseau horaire de la boutique :'; -$_LANG['Your configuration is valid, click next to continue!'] = 'Votre configuration est valide,
    cliquez sur suivant pour continuer !'; -$_LANG['Your configuration is invalid. Please fix the issues below:'] = 'Votre configuration n\'est pas valide,
    merci de corriger ces problèmes :'; +$_LANG['Your configuration is valid, click next to continue!'] = 'Votre configuration est valide, cliquez sur suivant pour continuer !'; +$_LANG['Your configuration is invalid. Please fix the issues below:'] = 'Votre configuration n\'est pas valide, merci de corriger ces problèmes :'; $_LANG['You have to create a database, help available in readme_en.txt'] = 'Vous devez au préalable créer une base de données (aide disponible dans le fichier readme.txt)'; $_LANG['If you check this box and your mail configuration is wrong, your installation might be blocked. If so, please uncheck the box to go to the next step.'] = 'Cette option peut être bloquante si votre configuration e-mail est erronée, merci de la désactiver si vous ne pouvez pas passer à l\'étape suivante.'; $_LANG['Mcrypt is available (recommended)'] = 'Mcrypt est disponible (recommandé)'; diff --git a/install-dev/php/alter_productcomments_guest_index.php b/install-dev/php/alter_productcomments_guest_index.php new file mode 100644 index 000000000..49babefc4 --- /dev/null +++ b/install-dev/php/alter_productcomments_guest_index.php @@ -0,0 +1,39 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +function alter_productcomments_guest_index() +{ + Configuration::loadConfiguration(); + $productcomments = Module::getInstanceByName('productcomments'); + if (!$productcomments->id) + return; + + DB::getInstance()->Execute(' + ALTER TABLE `'._DB_PREFIX_.'product_comment` DROP INDEX `id_guest`, + ADD INDEX `id_guest` USING BTREE(`id_guest`);'); +} + diff --git a/install-dev/sql/db.sql b/install-dev/sql/db.sql index dc86ed16b..978905ab0 100644 --- a/install-dev/sql/db.sql +++ b/install-dev/sql/db.sql @@ -61,7 +61,7 @@ CREATE TABLE `PREFIX_attachment` ( `id_attachment` int(10) unsigned NOT NULL auto_increment, `file` varchar(40) NOT NULL, `file_name` varchar(128) NOT NULL, - `mime` varchar(64) NOT NULL, + `mime` varchar(128) NOT NULL, PRIMARY KEY (`id_attachment`) ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8; @@ -290,6 +290,16 @@ CREATE TABLE `PREFIX_cms_category_lang` ( KEY `category_name` (`name`) ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8; +CREATE TABLE `PREFIX_compare_product` ( + `id_compare_product` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_product` int(10) unsigned NOT NULL, + `id_guest` int(10) unsigned NOT NULL, + `id_customer` int(10) unsigned NOT NULL, + `date_add` datetime NOT NULL, + `date_upd` datetime NOT NULL, + PRIMARY KEY (`id_compare_product`) +) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8; + CREATE TABLE `PREFIX_configuration` ( `id_configuration` int(10) unsigned NOT NULL auto_increment, `id_group_shop` INT(11) UNSIGNED DEFAULT NULL, diff --git a/install-dev/sql/db_settings_lite.sql b/install-dev/sql/db_settings_lite.sql index 3db4af89c..c5358f99e 100644 --- a/install-dev/sql/db_settings_lite.sql +++ b/install-dev/sql/db_settings_lite.sql @@ -712,8 +712,8 @@ INSERT INTO `PREFIX_tab` (`id_tab`, `class_name`, `id_parent`, `position`) VALUE (53, 'AdminBackup', 9, 8),(57, 'AdminCMSContent', 9, 9),(64, 'AdminGenerator', 9, 10),(43, 'AdminSearch', -1, 0),(69, 'AdminInformation', 9, 11), (70, 'AdminPerformance', 8, 11),(71, 'AdminCustomerThreads', 29, 4),(72, 'AdminWebservice', 9, 12),(73, 'AdminStockMvt', 1, 9), (80, 'AdminAddonsCatalog', 7, 1),(81, 'AdminAddonsMyAccount', 7, 2),(83, 'AdminThemes', 7, 3),(84, 'AdminGeolocation', 8, 12), -(85, 'AdminTaxRulesGroup', 4, 3),(86, 'AdminLogs', 9, 13), (87, 'AdminCounty', 5, 4),(88,'AdminHome',-1,0),(89,'AdminShop', 0, 11), (90,'AdminGroupShop', 89, 1), -(91, 'AdminShopUrl', 89, 2); +(85, 'AdminTaxRulesGroup', 4, 3),(86, 'AdminLogs', 9, 13), (87, 'AdminCounty', 5, 4),(88,'AdminHome',-1,0),(89,'AdminUpgrade',9,14),(90,'AdminShop', 0, 11), (91,'AdminGroupShop', 90, 1), +(92, 'AdminShopUrl', 90, 2); INSERT INTO `PREFIX_access` (`id_profile`, `id_tab`, `view`, `add`, `edit`, `delete`) (SELECT 1, id_tab, 1, 1, 1, 1 FROM PREFIX_tab); @@ -730,11 +730,11 @@ INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (1, 61, 'Search Engines'),(1, 62, 'Referrers'),(1, 63, 'Groups'),(1, 64, 'Generators'),(1, 65, 'Shopping Carts'),(1, 66, 'Tags'),(1, 67, 'Search'), (1, 68, 'Attachments'),(1, 69, 'Configuration Information'),(1, 70, 'Performance'),(1, 71, 'Customer Service'),(1, 72, 'Webservice'),(1, 73, 'Stock Movements'), (1, 80, 'Modules & Themes Catalog'),(1, 81, 'My Account'),(1, 82, 'Stores'),(1, 83, 'Themes'),(1, 84, 'Geolocation'),(1, 85, 'Tax Rules'),(1, 86, 'Log'), -(1, 87, 'Counties'),(1, 88, 'Home'), (1, 89, 'Shops'), (1, 90, 'Group Shops'), (1, 91, 'Shop Urls'); +(1, 87, 'Counties'),(1, 88, 'Home'), (1, 89, 'Upgrade'),(1, 90, 'Shops'), (1, 91, 'Group Shops'), (1, 92, 'Shop Urls'); INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (2, 1, 'Catalogue'),(2, 2, 'Clients'),(2, 3, 'Commandes'),(2, 4, 'Paiement'),(2, 5, 'Transport'), -(2, 6, 'Stats'),(2, 7, 'Modules'),(2, 8, 'Préférences'),(2, 9, 'Outils'),(2, 10, 'Fabricants'),(2, 11, 'Attributs et groupes'),(2, 12, 'Adresses'),(2, 13, 'Statuts'), +(2, 6, 'Stats'),(2, 7, 'Modules'),(2, 8, 'Préférences'),(2, 9, 'Outils'),(2, 10, 'Marques'),(2, 11, 'Attributs et groupes'),(2, 12, 'Adresses'),(2, 13, 'Statuts'), (2, 14, 'Bons de réduction'),(2, 15, 'Devises'),(2, 16, 'Taxes'),(2, 17, 'Transporteurs'),(2, 18, 'Pays'),(2, 19, 'Zones'),(2, 20, 'Tranches de prix'), (2, 21, 'Tranches de poids'),(2, 22, 'Positions'),(2, 23, 'Base de données'),(2, 24, 'Emails'),(2, 26, 'Images'),(2, 27, 'Produits'),(2, 28, 'Contacts'), (2, 29, 'Employés'),(2, 30, 'Profils'),(2, 31, 'Permissions'),(2, 32, 'Langues'),(2, 33, 'Traductions'),(2, 34, 'Fournisseurs'),(2, 35, 'Onglets'), @@ -745,7 +745,7 @@ INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (2, 62, 'Sites affluents'),(2, 63, 'Groupes'),(2, 64, 'Générateurs'),(2, 65, 'Paniers'),(2, 66, 'Tags'),(2, 67, 'Recherche'), (2, 68, 'Documents joints'),(2, 69, 'Informations'),(2, 70, 'Performances'),(2, 71, 'SAV'),(2, 72, 'Service web'),(2, 73, 'Mouvements de Stock'), (2, 80, 'Catalogue de modules et thèmes'),(2, 81, 'Mon compte'),(2, 82, 'Magasins'),(2, 83, 'Thèmes'),(2, 84, 'Géolocalisation'),(2, 85, 'Règles de taxes'),(2, 86, 'Log'), -(2, 87, 'Comtés'),(2,88,'Accueil'), (2, 89, 'Boutiques'), (2, 90, 'Groupes de boutique'), (2, 91, 'URLs de boutique'); +(2, 87, 'Comtés'),(2,88,'Accueil'),(2, 89, 'Mise à jour'), (2, 90, 'Boutiques'), (2, 91, 'Groupes de boutique'), (2, 92, 'URLs de boutique'); INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (3, 1, 'Catálogo'),(3, 2, 'Clientes'),(3, 3, 'Pedidos'),(3, 4, 'Pago'),(3, 5, 'Transporte'), @@ -758,8 +758,8 @@ INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (3, 49, 'Vales'),(3, 51, 'Configuración'),(3, 52, 'Subcampos'),(3, 53, 'Copia de seguridad'),(3, 54, 'Mensajes de Orden'), (3, 55, 'Albaranes de entrega'),(3, 56, 'SEO & URLs'),(3, 57, 'CMS'),(3, 58, 'Mapeo de la imagen'),(3, 59, 'Mensajes del cliente'),(3, 60, 'Rastreo'), (3, 61, 'Motores de búsqueda'),(3, 62, 'Referido'),(3, 63, 'Grupos'),(3, 64, 'Generadores'),(3, 65, 'Carritos'),(3, 66, 'Etiquetas'),(3, 67, 'Búsqueda'),(3, 68, 'Adjuntos'), -(3, 69, 'Informations'),(3, 70, 'Rendimiento'),(3, 72, 'Web service'),(3, 71, 'Servicio al cliente'),(3, 73, 'Movimiento de Stock'), (3, 82, 'Tiendas'),(3, 83, 'Temas'),(3, 84, 'Geolocalización'),(3, 85, 'Reglas de Impuestos'),(3, 86, 'Log'), -(3, 87, 'Condados'),(3,88,'Home'), (3, 89, 'Shops'), (3, 90, 'Group Shops'), (3, 91, 'Shop Urls'); +(3, 69, 'Informaciones'),(3, 70, 'Rendimiento'),(3, 72, 'Web service'),(3, 71, 'Servicio al cliente'),(3, 73, 'Movimiento de Stock'), (3, 82, 'Tiendas'),(3, 83, 'Temas'),(3, 84, 'Geolocalización'),(3, 85, 'Reglas de Impuestos'),(3, 86, 'Log'), +(3, 87, 'Condados'),(3,88,'Home'),(3, 89, 'Mejorar'), (3, 90, 'Shops'), (3, 91, 'Group Shops'), (3, 92, 'Shop Urls'); INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (4, 1, 'Katalog'),(4, 2, 'Kunden'),(4, 3, 'Bestellungen'),(4, 4, 'Zahlung'), @@ -774,7 +774,7 @@ INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (4, 61, 'Suchmaschinen'),(4, 62, 'Referrer'),(4, 63, 'Gruppen'),(4, 64, 'Generatoren'),(4, 65, 'Warenkörbe'),(4, 66, 'Tags'),(4, 67, 'Suche'), (4, 68, 'Anhänge'),(4, 69, 'Konfigurationsinformationen'),(4, 70, 'Leistung'),(4, 71, 'Kundenservice'),(4, 72, 'Webservice'),(4, 73, 'Lagerbewegungen'), (4, 80, 'Module und Themenkatalog'),(4, 81, 'Mein Konto'),(4, 82, 'Shops'),(4, 83, 'Themen'),(4, 84, 'Geotargeting'),(4, 85, 'Steuerregeln'),(4, 86, 'Log'), -(4,87,'Counties'),(4,88,'Home'), (4, 89, 'Shops'), (4, 90, 'Group Shops'), (4, 91, 'Shop Urls'); +(4,87,'Counties'),(4,88,'Home'),(4, 89, 'Upgrade'), (4, 90, 'Shops'), (4, 91, 'Group Shops'), (4, 92, 'Shop Urls'); INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (5, 1, 'Catalogo'),(5, 2, 'Clienti'),(5, 3, 'Ordini'),(5, 4, 'Pagamento'), @@ -789,7 +789,7 @@ INSERT INTO `PREFIX_tab_lang` (`id_lang`, `id_tab`, `name`) VALUES (5, 61, 'Motori di ricerca'),(5, 62, 'Referenti'),(5, 63, 'Gruppi'),(5, 64, 'Generatori'),(5, 65, 'Carrelli shopping'),(5, 66, 'Tag'),(5, 67, 'Cerca'), (5, 68, 'Allegati'),(5, 69, 'Informazioni di configurazione'),(5, 70, 'Performance'),(5, 71, 'Servizio clienti'),(5, 72, 'Webservice'),(5, 73, 'Movimenti magazzino'), (5, 80, 'Moduli & Temi catalogo'),(5, 81, 'Il mio Account'),(5, 82, 'Negozi'),(5, 83, 'Temi'),(5, 84, 'Geolocalizzazione'),(5, 85, 'Regimi fiscali'),(5, 86, 'Log'), -(5,87,'Counties'),(5,88,'Home'), (5, 89, 'Shops'), (5, 90, 'Group Shops'), (5, 91, 'Shop Urls'); +(5,87,'Counties'),(5,88,'Home'),(5, 89, 'Aggiornamento'), (5, 90, 'Shops'), (5, 91, 'Group Shops'), (5, 92, 'Shop Urls'); INSERT IGNORE INTO `PREFIX_tab_lang` (`id_tab`, `id_lang`, `name`) (SELECT `id_tab`, id_lang, (SELECT tl.`name` diff --git a/install-dev/view.css b/install-dev/view.css index b610bfce0..09810edd1 100644 --- a/install-dev/view.css +++ b/install-dev/view.css @@ -1,594 +1,740 @@ @CHARSET "UTF-8"; -/* -purple #d41958 +/* **************************************************************************** + reset +**************************************************************************** */ +html{color:#000;background:#FFF;} +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;} +table{border-collapse:collapse;border-spacing:0;} +fieldset,img{border:0;} +address,caption,cite,code,dfn,em,th,var,optgroup{font-style:inherit;font-weight:inherit;} +del,ins{text-decoration:none;} +caption,th{text-align:left;} +h1,h2,h3,h4,h5,h6{font-size:100%;} +q:before,q:after{content:'';} +abbr,acronym{border:0;font-variant:normal;} +sup{vertical-align:baseline;} +sub{vertical-align:baseline;} +legend{color:#000;} +input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;} +input,button,textarea,select{font-size:100%;} +a {cursor:pointer;} -green #7eb423 -*/ - -body{ - background-image : url(img/bg-body.png); - font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; +.installModuleList { display: none; } +.installModuleList.selected { display: block; } +.clearfix:before, +.clearfix:after { + content: "."; + display: block; + height: 0; + overflow: hidden; } +.clearfix:after {clear: both;} +.clearfix {zoom: 1;} -a:link, a:active, a:visited{ - text-decoration:none; - color:#d41958; -} -a:hover{ - color:#7eb423; -} +/* **************************************************************************** + structure +**************************************************************************** */ #container{ - margin:1em auto 0 auto; - width:930px; - padding:10px 30px 0px 30px; - font-size:0.8em; - background : #456d01 url(img/bg-ctnr.png) top repeat-x; + position:relative; display:none; + margin:0 auto; + padding:0; + width:990px; + background :#fff; } + #header { + padding:6px 16px 16px 16px; + height:68px;/* 90 */ + background:#394049; + } #loaderSpace{ - height:24px; + display:none; + z-index: 100; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + background:transparent url(img/bg_loaderSpace.png) repeat 0 0; } div#loader{ - float:right; - background-image:url(../img/loadingAnimation.gif); - height:13px; - width:208px; - color:white; display:none; + margin: 450px 0 0 440px; + height:128px; + width:128px; + color:#fff; + background-image:url(img/ajax-loader.gif); } div#leftpannel{ float:left; - width:250px; - margin-top: 15px; + margin:65px 30px 0 30px; + width:220px; } -div#leftpannel div#help{ - width:175px; - height:129px; - margin:20px 0; - padding:5px; - background:url('img/bg_help.png') no-repeat; - font-family:Arial, sans-serif; + div#sheets { + float:left; + margin-top:65px; + min-height:400px; + width:700px; + background-color:#fff; } -div#leftpannel div#help img.ico_help{float:left; margin:5px;} -div#leftpannel div#help div.content{ - float:right; - width:125px; + * html div#sheets { + height: 400px; } -div#leftpannel div#help div.content p.title{color:#fff;font-weight:bold;font-size:10.5pt;margin:6pt 0 3px 0;} -div#leftpannel div#help div.content p.title_down{color:#383838;font-size:8pt;margin:0;} -div#leftpannel div#help div.content ul{margin:10px 0;padding:0;} -div#leftpannel div#help div.content ul li{clear:both;padding-bottom:5px;list-style-type:none;} -div#leftpannel div#help div.content ul li img, - div#leftpannel div#help div.content ul li a{ float:left; } -div#leftpannel div#help div.content ul li a{ - display:block; - margin-left:6px; + #sheets div.sheet{ + /*display:none;*/ + padding:1em; + width:650px; +} + + div#buttons{ + clear:both; + margin:0 0 0 295px; + height:70px; + width:650px; +} + * html div#buttons { + margin-bottom:60px; + margin-top:-30px; + } + #btNext {float:right;} + +ul#footer{ + margin-top:5px; + list-style-type:none; + text-align:center; + margin-bottom:2px; color:#fff; - font-weight:bold; - line-height:17px; - vertical-align:middle; - text-decoration:underline; } + +/* **************************************************************************** + generics styles +**************************************************************************** */ +body{ + font:normal 13px/18px Arial, Helvetica, sans-serif; + color:#333; + background:#e1e2e2; +} + +/* title */ +h1 {font-size:24px;} +h2 { + padding-bottom:20px; + font-size:18px; +} +h3 { + padding-bottom:20px; + font-size:16px; +} +h4 { + padding-bottom:20px; + font-size:14px; +} + +/* text */ +p {padding-bottom:20px;} +#sheets ul { + margin-left: 15px; + padding-bottom:20px; + list-style-type:square; +} + +/* link */ +a, a:active, a:visited { + color:#d41958; + text-decoration:none; +} + a:hover {text-decoration:underline;} + +sup.required {color: red;} + +/*buttons */ + + +/* form */ +input.button { + padding:0 30px; + height:31px; + line-height:31px; + color:#fff; + text-shadow:0 1px 0 #0d7903; + background:#039701 url(img/bt.png) repeat-x 0 0; + border:1px solid #ccc; + -moz-border-radius: 5px; + -webkit-border-radius:5px; + border-radius: 5px; + box-shadow:0 1px #666; +} + input.button:hover { + background:#039701 url(img/bt-hover.png) repeat-x 0 0; + cursor:pointer; +} + input#btBack { + color:#666; + text-shadow:0 1px 0 #fff; + background-image:url(img/bt_off.png); +} + input#btBack:hover {background-image:url(img/bt_off_hover.png);} + +input.button.disabled { + color:#666; + text-shadow:0 1px 0 #fff; + background:#ccc url(img/bt-dsbl.png) repeat-x 0 0; +} + +input.text { + padding:0 6px; + height:22px; + width:218px;/* 230 */ + background:#fff img(img/bg-input-text.png) repeat-x 0 0; + border:1px solid #ccc; +} +select { + width: 232px; + border:1px solid #ccc; +} + +div.field { + padding:10px 0; + border-bottom:1px solid #ccc; +} + div.field label { + display:inline-block; + width:190px; + vertical-align: top; +} + div.field label.radiolabel {width:auto;} + div.field span.contentinput { + display:inline-block; + width:245px; + vertical-align: top; +} + div.field .userInfos { + display:inline-block; + width:200px; + font-size:11px; + font-style:italic; + color:#999; +} + +.okBlock { + padding:20px 20px 20px 38px; + background:#b7e2a7 url(img/pict_ok.png) no-repeat 15px 21px; + border:1px solid #85c10c; +} + +.errorBlock { + padding:20px 20px 20px 38px; + background:#ffebe8 url(img/pict_error.png) no-repeat 15px 21px; + border:1px solid #cc0000; +} + +.infosBlock { + padding:14px 25px 14px 35px; + font-weight:normal; + font-size:13px; + line-height:18px; + background:#f8f8f8 url(img/pict_h3_infos.png) no-repeat 10px 13px; + border:1px solid #ccc; +} + +.okBlock h1, +.okBlock h2, +.okBlock h3, +.errorBlock h1, +.errorBlock h2, +.errorBlock h3, +.infosBlock h1, +.infosBlock h2, +.infosBlock h3 { + padding-bottom:5px; +} + + +/* **************************************************************************** + HEADER +**************************************************************************** */ +#header #headerLinks {float:right;} + #header #headerLinks li { + display:inline-block; + padding:0 12px; + vertical-align: top; + background:transparent url(img/bg-li-headerLinks.png) no-repeat right 2px; +} + #header #headerLinks li.last {background:none;} + #header #headerLinks li a { + color:#fff; + text-decoration:none; +} + #header #headerLinks li a:hover {text-decoration:underline;} + #header #headerLinks #phone_block { + padding:0 0 0 46px; + line-height:14px; + color:#fff; + text-shadow:0 1px 0 #333; + background:transparent url(img/bg-phone_block.png) no-repeat 0 0; +} + #header #headerLinks #phone_block div { + padding:7px 15px 8px 0; + background:transparent url(img/bg-phone_block.png) no-repeat right top; +} + +#header #PrestaShopLogo { + float:left; + margin:5px 0 0 10px; + height: 51px; + width: 192px; + text-indent: -5000px; + background:transparent url(img/logo.png) no-repeat 0 0; +} + +#header #infosSup { + display:none; + float:left; + margin:10px 0 0 50px; +} + + +/* **************************************************************************** + LEFTPANEL +**************************************************************************** */ +div#leftpannel div#help{display:none;} + ol#tabs{ list-style-type:none; margin:0; padding:0; } + ol#tabs li{ + padding:9px 0 9px 16px; + font-size:14px; + color:#adadad; + } + ol#tabs li.selected{ + color:#000; + background : url(img/bg-li-tabs.png) no-repeat 1px 15px; + } + ol#tabs li.finished{ + color:#78a531; + background : url(img/bg-li-tabs-finished.png) no-repeat 0 12px; + } -ol#tabs li{ - background-color:#CFE5BD; - font-size:1em; - height:25px; - padding-top:10px; - clear:both; - background-color:#699d0f; - color:white; + +/* **************************************************************************** + FOOTER +**************************************************************************** */ +ul#footer li { + display:inline; font-weight:bold; + font-size:12px; + color:#666; } -ol#tabs li.selected{ - background : url(img/bg-tab.png) repeat-x; - height:36px; - padding-top:23px; +ul#footer a:link, ul#footer a:active, ul#footer a:visited { + color:#666; + text-decoration:none; } - -ol#tabs li.finished{ - font-weight:normal; -} -ol#tabs li span { - display:block; - padding-left:20px; - margin-left:20px; - height:18px; -} - -ol#tabs li span.number1 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/01-gd100.png', sizingMethod='crop'); -} -html>body ol#tabs li.selected span.number1 { - filter: none; - background: url('img/01-pt100.png') no-repeat; + ul#footer a:hover{ + color:#333; + text-decoration:underline; } -ol#tabs li.selected span.number1 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/01-gd100.png', sizingMethod='crop'); +/* **************************************************************************** + SHEET +**************************************************************************** */ +#sheets div.sheet { + display: none; + padding: 14px; + width: 650px; } -html>body ol#tabs li.selected span.number1 { - filter: none; - background: url('img/01-gd100.png') no-repeat; -} - - - -ol#tabs li.finished span.number1 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/01-pt70.png', sizingMethod='crop'); -} -html>body ol#tabs li.finished span.number1 { - filter: none; - background: url('img/01-pt70.png') no-repeat; -} - -ol#tabs li span.number2 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/02-pt100.png', sizingMethod='crop'); -} -html>body ol#tabs li span.number2 { - filter: none; - background: url('img/02-pt100.png') no-repeat; -} - - - -ol#tabs li.selected span.number2 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/02-gd100.png', sizingMethod='crop'); -} -html>body ol#tabs li.selected span.number2 { - filter: none; - background: url('img/02-gd100.png') no-repeat; -} - - -ol#tabs li.finished span.number2 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/02-pt70.png', sizingMethod='crop'); -} -html>body ol#tabs li.finished span.number2 { - filter: none; - background: url('img/02-pt70.png') no-repeat; -} - -ol#tabs li span.number3 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/03-pt100.png', sizingMethod='crop'); -} -html>body ol#tabs li span.number3 { - filter: none; - background: url('img/03-pt100.png') no-repeat; -} - -ol#tabs li.selected span.number3 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/03-gd100.png', sizingMethod='crop'); -} -html>body ol#tabs li.selected span.number3 { - filter: none; - background: url('img/03-gd100.png') no-repeat; -} - -ol#tabs li.finished span.number3 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/03-pt70.png', sizingMethod='crop'); -} -html>body ol#tabs li.finished span.number3 { - filter: none; - background: url('img/03-pt70.png') no-repeat; -} - -ol#tabs li span.number4 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/04-pt100.png', sizingMethod='crop'); -} -html>body ol#tabs li span.number4 { - filter: none; - background: url('img/04-pt100.png') no-repeat; -} - -ol#tabs li.selected span.number4 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/04-gd100.png', sizingMethod='crop'); -} -html>body ol#tabs li.selected span.number4 { - filter: none; - background: url('img/04-gd100.png') no-repeat; -} - -ol#tabs li.finished span.number4 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/04-pt70.png', sizingMethod='crop'); -} -html>body ol#tabs li.finished span.number4 { - filter: none; - background: url('img/04-pt70.png') no-repeat; -} - -ol#tabs li span.number5 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/05-pt100.png', sizingMethod='crop'); -} -html>body ol#tabs li span.number5 { - filter: none; - background: url('img/05-pt100.png') no-repeat; -} - -ol#tabs li.selected span.number5 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/05-gd100.png', sizingMethod='crop'); -} -html>body ol#tabs li.selected span.number5 { - filter: none; - background: url('img/05-gd100.png') no-repeat; -} - -ol#tabs li.finished span.number5 { - background:none; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/05-pt70.png', sizingMethod='crop'); -} -html>body ol#tabs li.finished span.number5 { - filter: none; - background: url('img/05-pt70.png') no-repeat; -} - -div#sheets { - float:left; - background-color:white; - margin-top:15px; - min-height:400px; - -} -* html div#sheets { - height: 400px; -} - -#sheets div.sheet{ - display:none; - width:650px; - padding:1em; -} - -h1{ - color:#7EB423; - margin:0; - text-align:center; -} - -h2{ - color:#7EB423; - font-size:1.3em; - margin:0pt 0pt 0.5em; - text-transform:uppercase; - font-weight:bold; -} - -h3{ - color:#d41958; - margin:2em 0; - font-size:0.9em; -} -p{ - margin : 0.5em 0; -} - #sheets div#sheet_lang{ display:block; } - -ul#langList { - list-style-type:none; + .sheet .contentTitle { + position:absolute; + top:90px; + left:0; + padding:15px 25px 10px 38px; + height:28px;/* 53 */ + width:927px;/* 990 */ + background:transparent url(img/bg-contentTitle.png) repeat-x 0 0; } - -ul#langList img { - margin:0 2px; + .sheet .contentTitle .stepList { + position:absolute; + top:7px; + right:20px; + list-style-type:none !important; } + .sheet .contentTitle .stepList li { + float:left; + height:42px; + width:42px; + text-indent:-5000px; + background:transparent url(img/bg_li_stepList.png) no-repeat 0 0; + } + .sheet .contentTitle .stepList li.ok {background-position:0 -50px;} + .sheet .contentTitle .stepList li.ko {background-position:0 -100px;} -input.button { - background:transparent url(img/bt.png) no-repeat scroll 0%; - border:medium none; - color:white; - font-size:0.97em; + li.title { + margin:0; font-weight:bold; - margin:0pt 0.1em; - height:26px; - width:177px; - padding-bottom:0.3em; -} -input.button.little{ - background : url(img/boutonpt-on.png) no-repeat; - height:23px; - width:102px; } -input.button:hover { - background : url(img/bt-hover.png) no-repeat; +/* INSTALLATION ***************************************************************************** */ +/* ETAPE 1 - lang ********************************************************** */ +#formSetMethod {padding-bottom:20px;} + #formSetMethod p {padding-bottom:0;} + +ul#langList {list-style-type:none;} + +/* ETAPE 2 - required ******************************************************* */ +#sheet_require #req_bt_refresh {float:right;} +#sheet_require #btTestDB {float:right;} + +/*h3#resultConfig { + padding:20px 20px 20px 38px; + background:#ffebe8 url(img/pict_error.png) no-repeat 15px 21px; + border:1px solid #cc0000; +}*/ + +ul#required, +ul#optional {list-style-type:none;} + ul#required li, + ul#optional li { + padding:6px 8px 4px 8px; + background:#f8f8f8; } -input.button.little:hover{ - background : url(img/boutonpt-over.png) no-repeat; + ul#required li.title, + ul#optional li.title { + margin-top: 20px; + padding:4px 8px; + background:#f8f8f8 url(img/bg_li_title.png) repeat-x 0 0; +} + ul#required li.required , + ul#optional li.optional{ + border-top:1px solid #fff; + border-bottom:1px solid #ccc; +} + ul#required li.ok, + ul#optional li.ok{ + background:#f8f8f8 url(img/pict_ok.png) no-repeat 100% 10px; +} + ul#required li.fail, + ul#optional li.fail { + background:#f8f8f8 url(img/pict_error.png) no-repeat 100% 8px; } -input.button.disabled { - background : url(img/bt-dsbl.png) no-repeat; -} -input.button.little.disabled{ - background : url(img/boutonpt-disabled.png) no-repeat; +/* ETAPE 3 - DB ************************************************************* */ +#sheet_db { + padding:0 !important; + width:678px !important; } - -label.disabled, p.disabled{ - color:gray; +#formCheckSQL p, +#mailSMTPParam p { + /* + USELESS + padding:10px 0; + border-top:1px solid #fff; + border-bottom:1px solid #ccc;*/ +} +#formCheckSQL p.first {border-top:none;} +#formCheckSQL p.last {border-bottom:none;} +/*USELESS #formCheckSQL p#dbResultCheck {border:none;}*/ +#formCheckSQL p label, +#mailSMTPParam p label { + display:inline-block; + width:230px; } -input.text { - border:1px gray solid; - width:175px; -} -input.text.required { - border-color:#D41958; +#dbPart, +#dbTableParam, +#mailPart { + margin-bottom:15px; + padding:14px; + width:650px; + background:#f8f8f8; } -div#buttons{ - clear:both; - margin-right:2px; - margin-bottom:0px; - margin-top:0px; - text-align:right; - height:70px; -} - -* html div#buttons { - margin-bottom:60px; - margin-top:-30px; -} - -div#buttons input{ - margin-top :5px; - margin-left :5px; -} - -div#sheet_require ul, div#sheet_require_update ul{ - list-style-type:none; -} - -div#sheets .ok{ - padding-left: 20px; - background: url(img/ok.gif) left no-repeat; -} - -div#sheets .fail{ - font-weight:bold; - padding-left: 20px; - background: url(img/bad.gif) left no-repeat; - color:#D41958; -} - -.userInfos{ - color:gray; +#mailSMTPParam {margin-bottom:10px;} + #mailSMTPParam #configsmtp span { + padding-left:15px; + font-size:11px; font-style:italic; - font-size:0.85em; -} -p.userInfos.aligned{ - margin-left:160px; + color:#999; } -div#mailSMTPParam{ - display:none; -} - -img#uploadedImage{ - border:3px dashed #E0E0E0; - margin:auto; - padding:3px; -} -ul#footer{ - margin-top:5px; - list-style-type:none; - text-align:center; - font-size:0.7em; - margin-bottom:2px; - color:white; -} -ul#footer li{ - display:inline; -} - -ul#footer a:link, ul#footer a:active, ul#footer a:visited{ - text-decoration:none; - color:white; -} -ul#footer a:hover{ - color:#7eb423; +#mailPart .userInfos { + padding-left:18px; + font-size:11px; + font-style:italic; + color:#999; } -label.aligned{ - width:245px; - float:left; - display:block; - text-align:right; - margin-right:1em; +/* ETAPE 4 - infos ********************************************************* */ +#sheet_infos { + padding:0 !important; + width:678px !important; } -input.aligned{ - margin-left:258px; -} -* html input.aligned{ - margin-left:0; -} -span.aligned{ - margin-left:258px; -} -div.field { - margin-bottom:1.5em; -} -span.result{ - display:none; -} -div#disclaimerDivCertify{ - text-align:center; -} -div#updateLog{ - height:200px; - width:100%; - border:gray 1px dashed; - overflow:auto; - display:none; -} - -table#resultInstall{ - width:100%; - margin:10px auto 5px auto; +#contentInfosNotification { + padding-left:190px; border:none; } -table#resultInstall td{ - border-bottom:3px solid #FFF; - background:#F5FFE4; - padding:5px; -} -table#resultInstall td.label{ - width:35%; - text-align:right; -} -table#resultInstall td.resultEnd{width:65%;color:#D41956;font-weight:bold;} -p#alignedLogo{ - text-align:center; +#contentInfosNotification label { + width:auto; + font-size:11px; } -form.aligned{ - border:1px dashed gray; +#infosShopBlock, +#benefitsBlock { + margin-bottom:15px; + padding:14px; + width:650px; + background:#f8f8f8; +} + +#inputFileLogo {margin-left:190px;} + +.moduleTable { + padding: 5px; + width: 650px; + background:#fff; + border: 1px solid #CCC; + border-bottom:none; +} + .moduleTable tr { + border-bottom: 1px solid #CCC; +} + .moduleTable th { + font-size:13; + color:#000; + text-shadow:0 1px 0 #fff; + background:#cfcfcf url(img/bg_moduleTable_th.png) repeat-x 0 0; +} + .moduleTable .field { + padding:10px 0; + border-bottom:none; +} + .moduleTable .field label { + display:inline-block; + padding-left:10px; + width:180px;/* 190 */ +} + .moduleTable .field label.radiolabel {width:auto;} + .moduleTable .field span.contentinput { + display:inline-block; + width:245px; + font-size: 11px; + font-style:italic; + color:#999; +} + +#paypal_uk_form_form_dateOfEstablishment_year, +#paypal_de_form_dateOfEstablishment_year, +#paypal_es_form_dateOfEstablishment_year, +#paypal_it_form_dateOfEstablishment_year, +#paypal_gb_form_dateOfEstablishment_year, +#paypal_se_form_dateOfEstablishment_year, +#paypal_fr_form_dateOfEstablishment_year + +#moneybookers_uk_form_dateOfBirth_year, +#moneybookers_de_form_dateOfBirth_year, +#moneybookers_es_form_dateOfBirth_year, +#moneybookers_it_form_dateOfBirth_year, +#moneybookers_gb_form_dateOfBirth_year, +#moneybookers_se_form_dateOfBirth_year, +#moneybookers_fr_form_dateOfBirth_year { + margin-right:10px; + width:60px !important; +} + +#paypal_uk_form_dateOfEstablishment_month, +#paypal_uk_form_dateOfEstablishment_day, +#paypal_de_form_dateOfEstablishment_month, +#paypal_de_form_dateOfEstablishment_day, +#paypal_es_form_dateOfEstablishment_month, +#paypal_es_form_dateOfEstablishment_day, +#paypal_it_form_dateOfEstablishment_month, +#paypal_it_form_dateOfEstablishment_day, +#paypal_gb_form_dateOfEstablishment_month, +#paypal_gb_form_dateOfEstablishment_day, +#paypal_se_form_dateOfEstablishment_month, +#paypal_se_form_dateOfEstablishment_day, + +#moneybookers_uk_form_dateOfBirth_month, +#moneybookers_uk_form_dateOfBirth_day, +#moneybookers_de_form_dateOfBirth_month, +#moneybookers_de_form_dateOfBirth_day, +#moneybookers_es_form_dateOfBirth_month, +#moneybookers_es_form_dateOfBirth_day, +#moneybookers_it_form_dateOfBirth_month, +#moneybookers_it_form_dateOfBirth_day, +#moneybookers_gb_form_dateOfBirth_month, +#moneybookers_gb_form_dateOfBirth_day, +#moneybookers_se_form_dateOfBirth_month, +#moneybookers_se_form_dateOfBirth_day, +#moneybookers_fr_form_dateOfBirth_month, +#moneybookers_fr_form_dateOfBirth_day { + margin-right:10px; + width:45px !important; +} + +#resultInfosPasswordRepeat {color:#cc0000;} + +/* ETAPE 5 - end *********************************************************** */ +#resultInstall {margin-bottom:25px;} + #resultInstall td {padding:7px 6px;} + #resultInstall tr.odd {background:#f8f8f8;} + #resultInstall td.resultEnd {color:#666;} + +.blockInfoEnd { + float:left; + margin:34px 20px 22px 0; padding:10px; - width:60%; + width:292px;/* 312 */ + background:#fff url(img/bg_blockInfoEnd.png) repeat-x 0 0; + border:1px solid #ccc; + -moz-border-radius: 5px; + -webkit-border-radius:5px; + border-radius: 5px; + box-shadow:0 1px #d9d9d9; +} +.blockInfoEnd.last {margin-right:0;} + .blockInfoEnd p { + font:italic 11px/14px Georgia, Arial, Sans-serif; + color:#666; +} + .blockInfoEnd img { + float:left; + margin:0 14px 5px 0; +} + .blockInfoEnd a.BO, + .blockInfoEnd a.FO { + float:right; + padding:0 0 0 12px; + height:33px; + line-height:33px; + color:#fff; + background:#039701 url(img/bg_bt_blockInfoEnd.png) no-repeat 0 0; + border:1px solid #019700; + -moz-border-radius: 5px; + -webkit-border-radius:5px; + border-radius: 5px; +} + .blockInfoEnd a.BO span , + .blockInfoEnd a.FO span { + display:inline-block; + padding:0 32px 0 0; + height:33px; + line-height:33px; + color:#fff; + background:#039701 url(img/bg_bt_blockInfoEnd.png) no-repeat 100% 0; + } + +#prestastore, +#prestastore_update { + height:170px; + width:645px; + border:1px solid #ccc; + -moz-border-radius: 5px; + -webkit-border-radius:5px; + border-radius: 5px +} + +/* MISE A JOUR ********************************************************************************* */ + +/* ETAPE 1 - disclaimer **************************************************** */ + +/* ETAPE 2 - require_update ************************************************ */ +#disclaimerDivCertify {margin-bottom:20px;} + +#upgradeProcess table { + padding: 5px; + width: 650px; + background:#fff; + border: 1px solid #CCC; + border-bottom:none; +} + #upgradeProcess tr { + border-bottom: 1px solid #CCC; +} + #upgradeProcess th, + #upgradeProcess td{padding:3px 5px;} + #upgradeProcess th { + font-size:13; + color:#000; + text-shadow:0 1px 0 #fff; + background:#cfcfcf url(img/bg_moduleTable_th.png) repeat-x 0 0; +} + +#upgradeProcess .infosBlock { margin:20px 0; -} -form.aligned p{ -height:30px; -} -form.aligned label { - display:block; - width:150px; - float:left; -} -form.aligned input.text { - display:block; - width:150px; - float:left; + padding:14px 25px; + background:#F8F8F8; } -p.aligned{ - text-align:center; +ul#required_update, +ul#optional_update {list-style-type:none;} + ul#required_update li, + ul#optional_update li { + padding:6px 8px 4px 8px; + background:#f8f8f8; } -li.title{ + ul#required_update li.title, + ul#optional_update li.title { + margin-top: 20px; + padding:4px 8px; + background:#f8f8f8 url(img/bg_li_title.png) repeat-x 0 0; +} + ul#required_update li.required , + ul#optional_update li.optional{ + border-top:1px solid #fff; + border-bottom:1px solid #ccc; +} + ul#required_update li.fail, + ul#optional_update li.fail { + background:#f8f8f8 url(img/pict_error.png) no-repeat 100% 8px; + } + ul#required_update li.ok, + ul#optional_update li.ok{ + background:#f8f8f8 url(img/pict_ok.png) no-repeat 100% 10px; + } +#sheet_require_update #req_bt_refresh_update {float:right;} + +/* ETAPE 3 - updateErrors ************************************************** */ + +/* ETAPE 4 - end_update **************************************************** */ +#updateLog { + height: 200px; + overflow: scroll; + border: 1px solid #E1E2E2; +} +#updateLog .fail { font-weight:bold; - margin:0.5em 0; + color: red; } -#infosFirstname{ - text-transform:capitalize; -} -div.request{ - border-top:1px gray dotted; - margin-top:10px; - padding-top:10px; -} -div#PrestaShopLogo{ - background:none; - width:233px; - height:68px; - text-indent:-1000px; - margin:0 auto; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/logo.png', sizingMethod='crop'); -} -html>body div#PrestaShopLogo { - filter: none; - background: url(img/logo.png) left no-repeat; +.request { + border-bottom: 1px solid #E1E2E2; } -div.installerVersion, div.updaterVersion { - color:#FFFFFF; - font-size:14px; - text-align:left; - padding:10px; - text-transform:uppercase; -} -p#dbResultCheck{ - height:auto; -} -div#resultEnd{ - clear:both; -} +/* **************************************************************************** + xxxxx +**************************************************************************** */ + + + + + -div#noJavaScript{ - margin: 100px 200px 20px 200px; - padding: 100px 30px; - background-color: white; - text-align: center; -} -a#access, a#access_update, span#box_admin{ - display:block; - width:300px; - height:150px; - background:url('img/btn-installeur.png') top left; - font-family:Arial, sans-serif; -} -a#access:hover,a#access_update:hover{background:url('img/btn-installeur.png') bottom left;} -a#access.BO{float:left;} -a#access.FO{float:right;} -a#access span{display:block;} -a#access span.title{margin:5px 15px;font-size:18pt;font-weight:bold;color:#FFF;} -a#access span.description{margin:10px 20px;color:#FFF;height:63px;} -a#access span.message{margin-left:20px;font-weight:bold;color:#FFF;} -a#access_update{float:left;} -a#access_update span{display:block;} -a#access_update span.title{margin:5px 15px;font-size:18pt;font-weight:bold;color:#FFF;} -a#access_update span.description{margin:10px 20px;color:#FFF;height:63px;} -a#access_update span.message{margin-left:20px;font-weight:bold;color:#FFF;} -h3.no-margin{margin:0;} -iframe#prestastore{width:100%;height:430px;border:none;margin:0px;} -iframe#prestastore_update{clear:both;width:100%;height:430px;border:none;margin-top:15px;} -p#php5_nok { - color:#fff; -} -p#php5_nok a { - color:#fff; - font-weight:bold; - text-decoration:underline; -} -#resultConfigHelper a{ - text-decoration:underline; -} -#phone_block{ - font-size: 16px; - color: #fff; - height: 25px; - width: 225px; - margin-left: 3px; -} -#phone_block span{ - font-size: 11px; - display: block; - width: 185px; -} -.versionInfo{ - color: #D41958; -} \ No newline at end of file diff --git a/install-dev/xml/checkConfig.php b/install-dev/xml/checkConfig.php index 1b4ce6068..7dafbc176 100644 --- a/install-dev/xml/checkConfig.php +++ b/install-dev/xml/checkConfig.php @@ -26,7 +26,7 @@ */ header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date dans le passé -include_once(INSTALL_PATH.'/classes/ConfigurationTest.php'); +include_once(INSTALL_PATH.'/../classes/ConfigurationTest.php'); // Functions list to test with 'test_system' $funcs = array('fopen', 'fclose', 'fread', 'fwrite', 'rename', 'file_exists', 'unlink', 'rmdir', 'mkdir', 'getcwd', 'chdir', 'chmod'); diff --git a/install-dev/xml/doUpgrade.php b/install-dev/xml/doUpgrade.php index 127a29573..fbc63f305 100644 --- a/install-dev/xml/doUpgrade.php +++ b/install-dev/xml/doUpgrade.php @@ -31,8 +31,11 @@ $engineType = 'ENGINE_TYPE'; if (function_exists('date_default_timezone_set')) date_default_timezone_set('Europe/Paris'); -define('_PS_MODULE_DIR_', realpath(INSTALL_PATH).'/../modules/'); -define('_PS_INSTALLER_PHP_UPGRADE_DIR_', realpath(INSTALL_PATH).'/php/'); + define('_PS_MODULE_DIR_', realpath(INSTALL_PATH.'/../').'/modules/'); + +if(!defined('_PS_INSTALLER_PHP_UPGRADE_DIR_')) + define('_PS_INSTALLER_PHP_UPGRADE_DIR_', INSTALL_PATH.DIRECTORY_SEPARATOR.'php/'); + // Only if loyalty module is installed require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'update_module_loyalty.php'); // desactivate non-native module @@ -104,6 +107,8 @@ require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'alter_cms_block.php'); require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'alter_blocklink.php'); +require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'alter_productcomments_guest_index.php'); + require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'update_module_loyalty.php'); require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'update_module_followup.php'); @@ -249,6 +254,7 @@ foreach($neededUpgradeFiles AS $version) $file = INSTALL_PATH.'/sql/upgrade/'.$version.'.sql'; if (!file_exists($file)) { + error_log('here?'.$file); $logger->logError('Error while loading sql upgrade file.'); die(''."\n"); } diff --git a/js/admin-categories-tree.js b/js/admin-categories-tree.js new file mode 100755 index 000000000..53a1dbdb4 --- /dev/null +++ b/js/admin-categories-tree.js @@ -0,0 +1,246 @@ +/* +* 2007-2011 PrestaShop +* +* NOTICE OF LICENSE +* +* This source file is subject to the Open Software License (OSL 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/osl-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 +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +var readyToExpand = true; +var needCheckAll = false; +var needUncheckAll = false; +var interval = null; +var id = 0; +var arrayCatToExpand = new Array(); + +$(document).ready(function(){ + $("#categories-treeview").treeview({ + url : 'ajax.php', + toggle: function () { callbackToggle($(this)); }, + ajax : { + type: 'POST', + async: true, + data: { + getChildrenCategories : true, + selectedCat: selectedCat + } + } + }); + + $('#categories-treeview li#1 span').trigger('click'); + + $('#expand_all').click( function () { + expandAllCategories(); + return false; + }); + + $('#collapse_all').click( function () { + collapseAllCategories(); + return false; + }); + + $('#check_all').click( function () { + needCheckAll = true; + checkAllCategories(); + return false; + }); + + $('#uncheck_all').click( function () { + needUncheckAll = true; + uncheckAllCategories(); + return false; + }); +}); + +function callbackToggle(element) +{ + if (!element.is('.expandable')) + return false; + + if (element.children('ul').children('li.collapsable').length != 0) + closeChildrenCategories(element); +} + +function closeChildrenCategories(element) +{ + var arrayLevel = new Array(); + + if (element.children('ul').find('li.collapsable').length == 0) + return false; + + element.children('ul').find('li.collapsable').each(function() { + var level = $(this).children('span.category_level').html(); + if (arrayLevel[level] == undefined) + arrayLevel[level] = new Array(); + + arrayLevel[level].push($(this).attr('id')); + }); + + for(i=arrayLevel.length-1;i!=0;i--) + if (arrayLevel[i] != undefined) + for(j=0;j= arrayCatToExpand.length && readyToExpand) + { + if (!setCategoryToExpand()) + { + clearInterval(interval); + // delete interval value + interval = null; + readyToExpand = false; + if (needCheckAll) + { + checkAllCategories(); + needCheckAll = false; + } + else if (needUncheckAll) + { + uncheckAllCategories(); + needUncheckAll = false; + } + } + else + readyToExpand = true; + } + + if (readyToExpand) + { + if ($('li#'+arrayCatToExpand[id]+'.hasChildren').length > 0) + readyToExpand = false; + $('li#'+arrayCatToExpand[id]+'.expandable:visible span.category_label').trigger('click'); + id++; + } +} + +function collapseAllCategories() +{ + closeChildrenCategories($('li#1')); +} + +function checkAllCategories() +{ + if (needExpandAllCategories()) + expandAllCategories(); + else + { + $('input[name="categoryBox[]"]').not(':checked').each(function () { + $(this).attr('checked', 'checked'); + clickOnCategoryBox($(this)); + }); + } +} + +function uncheckAllCategories() +{ + if (needExpandAllCategories()) + expandAllCategories(); + else + { + $('input[name="categoryBox[]"]:checked').each(function () { + $(this).removeAttr('checked'); + clickOnCategoryBox($(this)); + }); + } +} + +function clickOnCategoryBox(category) +{ + if (category.is(':checked')) + { + $('select#id_category_default').append(''); + updateNbSubCategorySelected(category, true); + if ($('select#id_category_default option').length > 0) + { + $('select#id_category_default').show(); + $('#no_default_category').hide(); + } + } + else + { + $('select#id_category_default option[value='+category.val()+']').remove(); + updateNbSubCategorySelected(category, false); + if ($('select#id_category_default option').length == 0) + { + $('select#id_category_default').hide(); + $('#no_default_category').show(); + } + } +} + +function updateNbSubCategorySelected(category, add) +{ + var currentSpan = category.parent().parent().parent().children('.nb_sub_cat_selected'); + var parentNbSubCategorySelected = currentSpan.children('.nb_sub_cat_selected_value').html(); + + if (add) + var newValue = parseInt(parentNbSubCategorySelected)+1; + else + var newValue = parseInt(parentNbSubCategorySelected)-1; + + currentSpan.children('.nb_sub_cat_selected_value').html(newValue); + currentSpan.children('.nb_sub_cat_selected_word').html(selectedLabel); + + if (newValue == 0) + currentSpan.hide(); + else + currentSpan.show(); + + if (currentSpan.parent().children('.nb_sub_cat_selected').length != 0) + updateNbSubCategorySelected(currentSpan.parent().children('input'), add); +} \ No newline at end of file diff --git a/js/jquery/treeview/jquery.treeview.async.js b/js/jquery/treeview/jquery.treeview.async.js new file mode 100755 index 000000000..541bbe134 --- /dev/null +++ b/js/jquery/treeview/jquery.treeview.async.js @@ -0,0 +1,85 @@ +/* + * Async Treeview 0.1 - Lazy-loading extension for Treeview + * + * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ + * + * Copyright (c) 2007 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id$ + * + */ + +;(function($) { + +function load(settings, root, child, container) { + function createNode(parent) { + var id_category = this.id_category; + var checked = false; + $('input[name="'+inputName+'[]"][type=hidden]').each( function () { + if ($(this).attr('value') == id_category) + { + checked = true; + $(this).remove(); + } + }); + var current = $("
  • ").attr("id", this.id_category || "").html(" " + this.name +" " + this.level_depth +" ("+this.nbSelectedSubCat+" "+selectedLabel+")").appendTo(parent); + if (this.classes) { + current.children("span").addClass(this.classes); + } + if (this.has_children > 0) { + var branch = $("
      ").hide().appendTo(current); + current.addClass("hasChildren"); + createNode.call({ + classes: "placeholder", + name: " ", + children:[] + }, branch); + branch.children().children('.nb_sub_cat_selected').remove(); + } + } + $.ajax($.extend(true, { + url: settings.url, + dataType: "json", + data: { + id_category_parent: root + }, + success: function(response) { + child.empty(); + $.each(response, createNode, [child]); + $(container).treeview({ + add: child + }); + readyToExpand = true; + } + }, settings.ajax)); +} + +var proxied = $.fn.treeview; +$.fn.treeview = function(settings) { + if (!settings.url) { + return proxied.apply(this, arguments); + } + var container = this; + if (!container.children().size()) + load(settings, "source", this, container); + var userToggle = settings.toggle; + return proxied.call(this, $.extend({}, settings, { + collapsed: true, + toggle: function() { + var $this = $(this); + if ($this.hasClass("hasChildren")) { + var childList = $this.removeClass("hasChildren").find("ul"); + load(settings, this.id, childList, container); + } + if (userToggle) { + userToggle.apply(this, arguments); + } + } + })); +}; + +})(jQuery); diff --git a/js/jquery/treeview/jquery.treeview.edit.js b/js/jquery/treeview/jquery.treeview.edit.js new file mode 100755 index 000000000..f3c580b3f --- /dev/null +++ b/js/jquery/treeview/jquery.treeview.edit.js @@ -0,0 +1,37 @@ +(function($) { + var CLASSES = $.treeview.classes; + var proxied = $.fn.treeview; + $.fn.treeview = function(settings) { + settings = $.extend({}, settings); + if (settings.add) { + return this.trigger("add", [settings.add]); + } + if (settings.remove) { + return this.trigger("remove", [settings.remove]); + } + return proxied.apply(this, arguments).bind("add", function(event, branches) { + $(branches).prev() + .removeClass(CLASSES.last) + .removeClass(CLASSES.lastCollapsable) + .removeClass(CLASSES.lastExpandable) + .find(">.hitarea") + .removeClass(CLASSES.lastCollapsableHitarea) + .removeClass(CLASSES.lastExpandableHitarea); + $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, $(this).data("toggler")); + }).bind("remove", function(event, branches) { + var prev = $(branches).prev(); + var parent = $(branches).parent(); + $(branches).remove(); + prev.filter(":last-child").addClass(CLASSES.last) + .filter("." + CLASSES.expandable).replaceClass(CLASSES.last, CLASSES.lastExpandable).end() + .find(">.hitarea").replaceClass(CLASSES.expandableHitarea, CLASSES.lastExpandableHitarea).end() + .filter("." + CLASSES.collapsable).replaceClass(CLASSES.last, CLASSES.lastCollapsable).end() + .find(">.hitarea").replaceClass(CLASSES.collapsableHitarea, CLASSES.lastCollapsableHitarea); + if (parent.is(":not(:has(>))") && parent[0] != this) { + parent.parent().removeClass(CLASSES.collapsable).removeClass(CLASSES.expandable) + parent.siblings(".hitarea").andSelf().remove(); + } + }); + }; + +})(jQuery); \ No newline at end of file diff --git a/js/jquery/treeview/jquery.treeview.js b/js/jquery/treeview/jquery.treeview.js new file mode 100755 index 000000000..8cc4ec9f0 --- /dev/null +++ b/js/jquery/treeview/jquery.treeview.js @@ -0,0 +1,256 @@ +/* + * Treeview 1.5pre - jQuery plugin to hide and show branches of a tree + * + * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ + * http://docs.jquery.com/Plugins/Treeview + * + * Copyright (c) 2007 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id$ + * + */ + +;(function($) { + + // TODO rewrite as a widget, removing all the extra plugins + $.extend($.fn, { + swapClass: function(c1, c2) { + var c1Elements = this.filter('.' + c1); + this.filter('.' + c2).removeClass(c2).addClass(c1); + c1Elements.removeClass(c1).addClass(c2); + return this; + }, + replaceClass: function(c1, c2) { + return this.filter('.' + c1).removeClass(c1).addClass(c2).end(); + }, + hoverClass: function(className) { + className = className || "hover"; + return this.hover(function() { + $(this).addClass(className); + }, function() { + $(this).removeClass(className); + }); + }, + heightToggle: function(animated, callback) { + animated ? + this.animate({ height: "toggle" }, animated, callback) : + this.each(function(){ + jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); + if(callback) + callback.apply(this, arguments); + }); + }, + heightHide: function(animated, callback) { + if (animated) { + this.animate({ height: "hide" }, animated, callback); + } else { + this.hide(); + if (callback) + this.each(callback); + } + }, + prepareBranches: function(settings) { + if (!settings.prerendered) { + // mark last tree items + this.filter(":last-child:not(ul)").addClass(CLASSES.last); + // collapse whole tree, or only those marked as closed, anyway except those marked as open + this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide(); + } + // return all items with sublists + return this.filter(":has(>ul)"); + }, + applyClasses: function(settings, toggler) { + // TODO use event delegation + this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) { + // don't handle click events on children, eg. checkboxes + if ( this == event.target ) + toggler.apply($(this).next()); + }).add( $("a", this) ).hoverClass(); + + if (!settings.prerendered) { + // handle closed ones first + this.filter(":has(>ul:hidden)") + .addClass(CLASSES.expandable) + .replaceClass(CLASSES.last, CLASSES.lastExpandable); + + // handle open ones + this.not(":has(>ul:hidden)") + .addClass(CLASSES.collapsable) + .replaceClass(CLASSES.last, CLASSES.lastCollapsable); + + // create hitarea if not present + var hitarea = this.find("div." + CLASSES.hitarea); + if (!hitarea.length) + hitarea = this.prepend("
      ").find("div." + CLASSES.hitarea); + hitarea.removeClass().addClass(CLASSES.hitarea).each(function() { + var classes = ""; + $.each($(this).parent().attr("class").split(" "), function() { + classes += this + "-hitarea "; + }); + $(this).addClass( classes ); + }) + } + + // apply event to hitarea + this.find("div." + CLASSES.hitarea).click( toggler ); + }, + treeview: function(settings) { + + settings = $.extend({ + cookieId: "treeview" + }, settings); + + if ( settings.toggle ) { + var callback = settings.toggle; + settings.toggle = function() { + return callback.apply($(this).parent()[0], arguments); + }; + } + + // factory for treecontroller + function treeController(tree, control) { + // factory for click handlers + function handler(filter) { + return function() { + // reuse toggle event handler, applying the elements to toggle + // start searching for all hitareas + toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { + // for plain toggle, no filter is provided, otherwise we need to check the parent element + return filter ? $(this).parent("." + filter).length : true; + }) ); + return false; + }; + } + // click on first element to collapse tree + $("a:eq(0)", control).click( handler(CLASSES.collapsable) ); + // click on second to expand tree + $("a:eq(1)", control).click( handler(CLASSES.expandable) ); + // click on third to toggle tree + $("a:eq(2)", control).click( handler() ); + } + + // handle toggle event + function toggler() { + $(this) + .parent() + // swap classes for hitarea + .find(">.hitarea") + .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) + .end() + // swap classes for parent li + .swapClass( CLASSES.collapsable, CLASSES.expandable ) + .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + // find child lists + .find( ">ul" ) + // toggle them + .heightToggle( settings.animated, settings.toggle ); + if ( settings.unique ) { + $(this).parent() + .siblings() + // swap classes for hitarea + .find(">.hitarea") + .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) + .end() + .replaceClass( CLASSES.collapsable, CLASSES.expandable ) + .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + .find( ">ul" ) + .heightHide( settings.animated, settings.toggle ); + } + } + this.data("toggler", toggler); + + function serialize() { + function binary(arg) { + return arg ? 1 : 0; + } + var data = []; + branches.each(function(i, e) { + data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0; + }); + $.cookie(settings.cookieId, data.join(""), settings.cookieOptions ); + } + + function deserialize() { + var stored = $.cookie(settings.cookieId); + if ( stored ) { + var data = stored.split(""); + branches.each(function(i, e) { + $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ](); + }); + } + } + + // add treeview class to activate styles + this.addClass("treeview"); + + // prepare branches and find all tree items with child lists + var branches = this.find("li").prepareBranches(settings); + + switch(settings.persist) { + case "cookie": + var toggleCallback = settings.toggle; + settings.toggle = function() { + serialize(); + if (toggleCallback) { + toggleCallback.apply(this, arguments); + } + }; + deserialize(); + break; + case "location": + var current = this.find("a").filter(function() { + return this.href.toLowerCase() == location.href.toLowerCase(); + }); + if ( current.length ) { + // TODO update the open/closed classes + var items = current.addClass("selected").parents("ul, li").add( current.next() ).show(); + if (settings.prerendered) { + // if prerendered is on, replicate the basic class swapping + items.filter("li") + .swapClass( CLASSES.collapsable, CLASSES.expandable ) + .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + .find(">.hitarea") + .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ); + } + } + break; + } + + branches.applyClasses(settings, toggler); + + // if control option is set, create the treecontroller and show it + if ( settings.control ) { + treeController(this, settings.control); + $(settings.control).show(); + } + + return this; + } + }); + + // classes used by the plugin + // need to be styled via external stylesheet, see first example + $.treeview = {}; + var CLASSES = ($.treeview.classes = { + open: "open", + closed: "closed", + expandable: "expandable", + expandableHitarea: "expandable-hitarea", + lastExpandableHitarea: "lastExpandable-hitarea", + collapsable: "collapsable", + collapsableHitarea: "collapsable-hitarea", + lastCollapsableHitarea: "lastCollapsable-hitarea", + lastCollapsable: "lastCollapsable", + lastExpandable: "lastExpandable", + last: "last", + hitarea: "hitarea" + }); + +})(jQuery); \ No newline at end of file diff --git a/js/jquery/treeview/jquery.treeview.sortable.js b/js/jquery/treeview/jquery.treeview.sortable.js new file mode 100755 index 000000000..3fddc6320 --- /dev/null +++ b/js/jquery/treeview/jquery.treeview.sortable.js @@ -0,0 +1,378 @@ +/* + * jQuery UI Sortable + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * ui.base.js + * + * Revision: $Id$ + */ +;(function($) { + + if (window.Node && Node.prototype && !Node.prototype.contains) { + Node.prototype.contains = function (arg) { + return !!(this.compareDocumentPosition(arg) & 16); + }; + } + + + $.widget("ui.sortableTree", $.extend($.ui.mouse, { + init: function() { + + //Initialize needed constants + var self = this, o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortableTree"); + + //Get the items + this.refresh(); + + //Let's determine the parent's offset + if(!(/(relative|absolute|fixed)/).test(this.element.css('position'))) this.element.css('position', 'relative'); + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this.mouseInit(); + + //Prepare cursorAt + if(o.cursorAt && o.cursorAt.constructor == Array) + o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] }; + + }, + plugins: {}, + ui: function(inst) { + return { + helper: (inst || this)["helper"], + position: (inst || this)["position"].current, + absolutePosition: (inst || this)["position"].absolute, + instance: this, + options: this.options, + element: this.element, + item: (inst || this)["currentItem"], + sender: inst ? inst.element : null + }; + }, + propagate: function(n,e,inst) { + $.ui.plugin.call(this, n, [e, this.ui(inst)]); + this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]); + }, + serialize: function(o) { + + var items = $(this.options.items, this.element).not('.ui-sortableTree-helper'); //Only the items of the sortable itself + var str = []; o = o || {}; + + items.each(function() { + var res = ($(this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); + if(res) str.push((o.key || res[1])+'[]='+(o.key ? res[1] : res[2])); + }); + + return str.join('&'); + + }, + toArray: function(attr) { + var items = $(this.options.items, this.element).not('.ui-sortableTree-helper'); //Only the items of the sortable itself + var ret = []; + + items.each(function() { ret.push($(this).attr(attr || 'id')); }); + return ret; + }, + enable: function() { + this.element.removeClass("ui-sortableTree-disabled"); + this.options.disabled = false; + }, + disable: function() { + this.element.addClass("ui-sortableTree-disabled"); + this.options.disabled = true; + }, + /* Be careful with the following core functions */ + intersectsWith: function(item) { + + var x1 = this.position.absolute.left - 10, x2 = x1 + 10, + y1 = this.position.absolute.top - 10, y2 = y1 + 10; + var l = item.left, r = l + item.width, + t = item.top, b = t + item.height; + + return ( l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b ); // Top Half + + }, + intersectsWithEdge: function(item) { + var y1 = this.position.absolute.top - 10, y2 = y1 + 10; + var t = item.top, b = t + item.height; + + if(!this.intersectsWith(item.item.parents(".ui-sortableTree").data("sortableTree").containerCache)) return false; + + if (!( t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half + + if(y2 > t && y1 < t) return 1; //Crosses top edge + if(y1 < b && y2 > b) return 2; //Crosses bottom edge + + return false; + + }, + refresh: function() { + this.refreshItems(); + this.refreshPositions(); + }, + refreshItems: function() { + + this.items = []; + this.containers = [this]; + var items = this.items; + var queries = [$(this.options.items, this.element)]; + + if(this.options.connectWith) { + for (var i = this.options.connectWith.length - 1; i >= 0; i--){ + var cur = $(this.options.connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortableTree'); + if(inst && !inst.options.disabled) { + queries.push($(inst.options.items, inst.element)); + this.containers.push(inst); + } + }; + }; + } + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i].each(function() { + $.data(this, 'sortableTree-item', true); // Data for target checking (mouse manager) + items.push({ + item: $(this), + width: 0, height: 0, + left: 0, top: 0 + }); + }); + }; + + }, + refreshPositions: function(fast) { + for (var i = this.items.length - 1; i >= 0; i--){ + if(!fast) this.items[i].height = this.items[i].item.outerHeight(); + this.items[i].top = this.items[i].item.offset().top; + }; + for (var i = this.containers.length - 1; i >= 0; i--){ + var p =this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height= this.containers[i].element.outerHeight(); + }; + }, + destroy: function() { + + this.element + .removeClass("ui-sortableTree ui-sortableTree-disabled") + .removeData("sortableTree") + .unbind(".sortableTree"); + this.mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) + this.items[i].item.removeData("sortableTree-item"); + + }, + contactContainers: function(e) { + for (var i = this.containers.length - 1; i >= 0; i--){ + + if(this.intersectsWith(this.containers[i].containerCache)) { + if(!this.containers[i].containerCache.over) { + + if(this.currentContainer != this.containers[i]) { + + //When entering a new container, we will find the item with the least distance and append our item near it + var dist = 10000; var itemWithLeastDistance = null; var base = this.position.absolute.top; + for (var j = this.items.length - 1; j >= 0; j--) { + if(!this.containers[i].element[0].contains(this.items[j].item[0])) continue; + var cur = this.items[j].top; + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + } + } + + itemWithLeastDistance ? this.rearrange(e, itemWithLeastDistance) : this.rearrange(e, null, this.containers[i].element); + this.propagate("change", e); //Call plugins and callbacks + this.containers[i].propagate("change", e, this); //Call plugins and callbacks + this.currentContainer = this.containers[i]; + + } + + this.containers[i].propagate("over", e, this); + this.containers[i].containerCache.over = 1; + } + } else { + if(this.containers[i].containerCache.over) { + this.containers[i].propagate("out", e, this); + this.containers[i].containerCache.over = 0; + } + } + + }; + }, + mouseStart: function(e,el) { + + if(this.options.disabled || this.options.type == 'static') return false; + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + var currentItem = null, nodes = $(e.target).parents().each(function() { + if($.data(this, 'sortableTree-item')) { + currentItem = $(this); + return false; + } + }); + if($.data(e.target, 'sortableTree-item')) currentItem = $(e.target); + + if(!currentItem) return false; + if(this.options.handle) { + var validHandle = false; + $(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; }); + if(!validHandle) return false; + } + + this.currentItem = currentItem; + + var o = this.options; + this.currentContainer = this; + this.refresh(); + + //Create and append the visible helper + this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : this.currentItem.clone(); + if(!this.helper.parents('body').length) this.helper.appendTo("body"); //Add the helper to the DOM if that didn't happen already + this.helper.css({ position: 'absolute', clear: 'both' }).addClass('ui-sortableTree-helper'); //Position it absolutely and add a helper class + + //Prepare variables for position generation + $.extend(this, { + offsetParent: this.helper.offsetParent(), + offsets: { absolute: this.currentItem.offset() } + }); + + //Save the first time position + $.extend(this, { + position: { + current: { left: e.pageX, top: e.pageY }, + absolute: { left: e.pageX, top: e.pageY }, + dom: this.currentItem.prev()[0] + }, + clickOffset: { left: -5, top: -5 } + }); + + this.propagate("start", e); //Call plugins and callbacks + this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Save and store the helper proportions + + for (var i = this.containers.length - 1; i >= 0; i--) { + this.containers[i].propagate("activate", e, this); + } //Post 'activate' events to possible containers + + //Prepare possible droppables + if($.ui.ddmanager) $.ui.ddmanager.current = this; + if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e); + + this.dragging = true; + return true; + + }, + mouseStop: function(e) { + + if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt); //remove sort indicator + this.propagate("stop", e); //Call plugins and trigger callbacks + + //If we are using droppables, inform the manager about the drop + var dropped = ($.ui.ddmanager && !this.options.dropBehaviour) ? $.ui.ddmanager.drop(this, e) : false; + if(!dropped && this.newPositionAt) this.newPositionAt[this.direction == 'down' ? 'before' : 'after'](this.currentItem); //Append to element to its new position + + if(this.position.dom != this.currentItem.prev()[0]) this.propagate("update", e); //Trigger update callback if the DOM position has changed + if(!this.element[0].contains(this.currentItem[0])) { //Node was moved out of the current element + this.propagate("remove", e); + for (var i = this.containers.length - 1; i >= 0; i--){ + if(this.containers[i].element[0].contains(this.currentItem[0])) { + this.containers[i].propagate("update", e, this); + this.containers[i].propagate("receive", e, this); + } + }; + }; + + //Post events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i].propagate("deactivate", e, this); + if(this.containers[i].containerCache.over) { + this.containers[i].propagate("out", e, this); + this.containers[i].containerCache.over = 0; + } + } + + this.dragging = false; + if(this.cancelHelperRemoval) return false; + this.helper.remove(); + + return false; + + }, + mouseDrag: function(e) { + + //Compute the helpers position + this.position.current = { top: e.pageY + 5, left: e.pageX + 5 }; + this.position.absolute = { left: e.pageX + 5, top: e.pageY + 5 }; + + //Interconnect with droppables + if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); + var intersectsWithDroppable = false; + $.each($.ui.ddmanager.droppables, function() { + if(this.isover) intersectsWithDroppable = true; + }); + + //Rearrange + if(intersectsWithDroppable) { + if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt); + } else { + for (var i = this.items.length - 1; i >= 0; i--) { + + if(this.currentItem[0].contains(this.items[i].item[0])) continue; + + var intersection = this.intersectsWithEdge(this.items[i]); + if(!intersection) continue; + + this.direction = intersection == 1 ? "down" : "up"; + this.rearrange(e, this.items[i]); + this.propagate("change", e); //Call plugins and callbacks + break; + } + } + + //Post events to containers + this.contactContainers(e); + + this.propagate("sort", e); //Call plugins and callbacks + this.helper.css({ left: this.position.current.left+'px', top: this.position.current.top+'px' }); // Stick the helper to the cursor + return false; + + }, + rearrange: function(e, i, a) { + if(i) { + if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt); + this.newPositionAt = i.item; + this.options.sortIndication[this.direction].call(this.currentItem, this.newPositionAt); + } else { + //Append + } + } + })); + + $.extend($.ui.sortableTree, { + defaults: { + items: '> *', + zIndex: 1000, + distance: 1 + }, + getter: "serialize toArray" + }); + + + +})(jQuery); diff --git a/mails/es/order_merchant_comment.html b/mails/es/order_merchant_comment.html index 836a8c4c4..e72a4f650 100644 --- a/mails/es/order_merchant_comment.html +++ b/mails/es/order_merchant_comment.html @@ -5,7 +5,34 @@ Mensaje de {shop_name} - - + + + + + + + + + + + + + + + + + + + + +
      + {shop_name} +
       
      Hola {firstname} {lastname},
       
      Mensaje de {shop_name}
       
      + Has recibido un nuevo mensaje sobre el pedido n°{id_order} : +

      + {message} +
       
      + {shop_name} desarrollado por PrestaShop™ +
      - \ No newline at end of file + diff --git a/mails/es/order_merchant_comment.txt b/mails/es/order_merchant_comment.txt index e69de29bb..fc67ac6b1 100644 --- a/mails/es/order_merchant_comment.txt +++ b/mails/es/order_merchant_comment.txt @@ -0,0 +1,10 @@ +Hola {firstname} {lastname}, + +Has recibido un mensaje sobre el pedido n°{id_order} : +{message} + +Puedes, en cualquier momento, consultar tus antiguos mensajes en Seguimiento de pedido. + + + +{shop_url} desarrollado por PrestaShop™ \ No newline at end of file diff --git a/modules/authorizeaim/authorizeaim.php b/modules/authorizeaim/authorizeaim.php index 64a76ebff..832978e0b 100755 --- a/modules/authorizeaim/authorizeaim.php +++ b/modules/authorizeaim/authorizeaim.php @@ -68,7 +68,7 @@ class authorizeAIM extends PaymentModule if ($params['objOrder']->module != $this->name) return; - if ($params['objOrder']->getCurrentState() != _PS_OS_ERROR_) + if ($params['objOrder']->getCurrentState() != Configuration::get('PS_OS_ERROR')) $this->context->smarty->assign(array('status' => 'ok', 'id_order' => intval($params['objOrder']->id))); else $this->context->smarty->assign('status', 'failed'); diff --git a/modules/authorizeaim/validation.php b/modules/authorizeaim/validation.php index 5470d565a..1bb4716fa 100755 --- a/modules/authorizeaim/validation.php +++ b/modules/authorizeaim/validation.php @@ -77,9 +77,9 @@ else $authorizeaim = new authorizeaim(); $message = $response[3]; if ($response[0] == 1) - $authorizeaim->validateOrder((int)$cart->id, _PS_OS_PAYMENT_, (float)$response[9], $authorizeaim->displayName, $message, NULL, NULL, false, $customer->secure_key); + $authorizeaim->validateOrder((int)$cart->id, Configuration::get('PS_OS_PAYMENT'), (float)$response[9], $authorizeaim->displayName, $message, NULL, NULL, false, $customer->secure_key); else - $authorizeaim->validateOrder((int)$cart->id, _PS_OS_ERROR_, (float)$response[9], $authorizeaim->displayName, $message, NULL, NULL, false, $customer->secure_key); + $authorizeaim->validateOrder((int)$cart->id, Configuration::get('PS_OS_ERROR'), (float)$response[9], $authorizeaim->displayName, $message, NULL, NULL, false, $customer->secure_key); Tools::redirect('index.php?controller=order-confirmation&id_module='.(int)$authorizeaim->id.'&id_cart='.(int)$cart->id.'&key='.$customer->secure_key); } diff --git a/modules/bankwire/bankwire.php b/modules/bankwire/bankwire.php index 0fa4a3b61..d72b1e59b 100644 --- a/modules/bankwire/bankwire.php +++ b/modules/bankwire/bankwire.php @@ -206,7 +206,7 @@ class BankWire extends PaymentModule $context = Context::getContext(); $state = $params['objOrder']->getCurrentState(); - if ($state == _PS_OS_BANKWIRE_ OR $state == _PS_OS_OUTOFSTOCK_) + if ($state == Configuration::get('PS_OS_BANKWIRE') OR $state == Configuration::get('PS_OS_OUTOFSTOCK')) $context->smarty->assign(array( 'total_to_pay' => Tools::displayPrice($params['total_to_pay'], $params['currencyObj'], false), 'bankwireDetails' => Tools::nl2br($this->details), diff --git a/modules/bankwire/validation.php b/modules/bankwire/validation.php index 9ff50d20c..cd85497ec 100644 --- a/modules/bankwire/validation.php +++ b/modules/bankwire/validation.php @@ -34,6 +34,17 @@ $bankwire = new BankWire(); if ($cart->id_customer == 0 OR $cart->id_address_delivery == 0 OR $cart->id_address_invoice == 0 OR !$bankwire->active) Tools::redirect('index.php?controller=order&step=1'); +// Check that this payment option is still available in case the customer changed his address just before the end of the checkout process +$authorized = false; +foreach (Module::getPaymentModules() as $module) + if ($module['name'] == 'bankwire') + { + $authorized = true; + break; + } +if (!$authorized) + die(Tools::displayError('This payment method is not available.')); + $customer = new Customer((int)$cart->id_customer); if (!Validate::isLoadedObject($customer)) @@ -47,6 +58,6 @@ $mailVars = array( '{bankwire_address}' => nl2br(Configuration::get('BANK_WIRE_ADDRESS')) ); -$bankwire->validateOrder($cart->id, _PS_OS_BANKWIRE_, $total, $bankwire->displayName, NULL, $mailVars, (int)$currency->id, false, $customer->secure_key); +$bankwire->validateOrder($cart->id, Configuration::get('PS_OS_BANKWIRE'), $total, $bankwire->displayName, NULL, $mailVars, (int)$currency->id, false, $customer->secure_key); $order = new Order($bankwire->currentOrder); Tools::redirect('index.php?controller=order-confirmation&id_cart='.$cart->id.'&id_module='.$bankwire->id.'&id_order='.$bankwire->currentOrder.'&key='.$customer->secure_key); diff --git a/modules/blockcms/es.php b/modules/blockcms/es.php index 640817cf2..a9da3476f 100755 --- a/modules/blockcms/es.php +++ b/modules/blockcms/es.php @@ -19,6 +19,7 @@ $_MODULE['<{blockcms}prestashop>blockcms_f2a6c498fb90ee345d997f888fce3b18'] = 'B $_MODULE['<{blockcms}prestashop>blockcms_8f08c1af47e3e9611289c1882befc3a8'] = 'No existe ningún bloque CMS'; $_MODULE['<{blockcms}prestashop>blockcms_0a40c06f34e5c794a7f0d3085d17d63a'] = 'Lista de los bloques CMS de la derecha'; $_MODULE['<{blockcms}prestashop>blockcms_965be994da393e5aa15bd3a2444c6ccf'] = 'Configuración de los links CMS a pie de página'; +$_MODULE['<{blockcms}prestashop>blockcms_32c532e462a1f85b1b103ed9989a1aba'] = 'Mostrar \"Creado por PrestaShop\"'; $_MODULE['<{blockcms}prestashop>blockcms_fab8ca8250236ed20b96f9750e1eacc7'] = 'Mostrar links a pie de página'; $_MODULE['<{blockcms}prestashop>blockcms_49ee3087348e8d44e1feda1917443987'] = 'Nombre'; $_MODULE['<{blockcms}prestashop>blockcms_c9cc8cce247e49bae79f15173ce97354'] = 'Guardar'; diff --git a/modules/blockcms/fr.php b/modules/blockcms/fr.php index 97ea4985c..8a7e192c2 100755 --- a/modules/blockcms/fr.php +++ b/modules/blockcms/fr.php @@ -19,6 +19,7 @@ $_MODULE['<{blockcms}prestashop>blockcms_f2a6c498fb90ee345d997f888fce3b18'] = 'S $_MODULE['<{blockcms}prestashop>blockcms_8f08c1af47e3e9611289c1882befc3a8'] = 'Il n\'existe aucun bloc CMS'; $_MODULE['<{blockcms}prestashop>blockcms_0a40c06f34e5c794a7f0d3085d17d63a'] = 'Liste des blocs CMS de droite'; $_MODULE['<{blockcms}prestashop>blockcms_965be994da393e5aa15bd3a2444c6ccf'] = 'Configuration des liens CMS en pied de page'; +$_MODULE['<{blockcms}prestashop>blockcms_32c532e462a1f85b1b103ed9989a1aba'] = 'Afficher \"Propulsé par PrestaShop\"'; $_MODULE['<{blockcms}prestashop>blockcms_fab8ca8250236ed20b96f9750e1eacc7'] = 'Afficher les liens de bas de page'; $_MODULE['<{blockcms}prestashop>blockcms_49ee3087348e8d44e1feda1917443987'] = 'Nom'; $_MODULE['<{blockcms}prestashop>blockcms_c9cc8cce247e49bae79f15173ce97354'] = 'Enregistrer'; diff --git a/modules/blocklayered/blocklayered-ajax-back.php b/modules/blocklayered/blocklayered-ajax-back.php new file mode 100644 index 000000000..adaac79e3 --- /dev/null +++ b/modules/blocklayered/blocklayered-ajax-back.php @@ -0,0 +1,35 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registred Trademark & Property of PrestaShop SA +*/ + +/* Getting cookie or logout */ +include(dirname(__FILE__).'/../../config/config.inc.php'); +require_once(dirname(__FILE__).'/../../init.php'); +include(dirname(__FILE__).'/blocklayered.php'); + +$blockLayered = new BlockLayered(); +echo $blockLayered->ajaxCallBackOffice((isset($_GET['categoryBox']) AND is_array($_GET['categoryBox'])) ? $_GET['categoryBox'] : array(), +(isset($_GET['id_layered_filter']) AND !empty($_GET['id_layered_filter'])) ? (int)$_GET['id_layered_filter'] : array()); \ No newline at end of file diff --git a/modules/blocklayered/blocklayered.js b/modules/blocklayered/blocklayered.js index 65a20e227..00bac519d 100644 --- a/modules/blocklayered/blocklayered.js +++ b/modules/blocklayered/blocklayered.js @@ -47,6 +47,7 @@ $(document).ready(function() }); paginationButton(); + reloadContent(); }); function paginationButton() { diff --git a/modules/blocklayered/blocklayered.php b/modules/blocklayered/blocklayered.php index 62c648b7a..e07099703 100644 --- a/modules/blocklayered/blocklayered.php +++ b/modules/blocklayered/blocklayered.php @@ -37,7 +37,7 @@ class BlockLayered extends Module { $this->name = 'blocklayered'; $this->tab = 'front_office_features'; - $this->version = 1.3; + $this->version = 1.4; $this->author = 'PrestaShop'; $this->need_instance = 0; @@ -52,7 +52,10 @@ class BlockLayered extends Module if ($result = parent::install() AND $this->registerHook('leftColumn') AND $this->registerHook('header') AND $this->registerHook('categoryAddition') AND $this->registerHook('categoryUpdate') AND $this->registerHook('categoryDeletion')) { - Configuration::updateValue('PS_LAYERED_NAVIGATION_CHECKBOXES', 1); + Configuration::updateValue('PS_LAYERED_SHARE', 0); + Configuration::updateValue('PS_LAYERED_HIDE_0_VALUES', 0); + Configuration::updateValue('PS_LAYERED_SHOW_QTIES', 1); + $this->rebuildLayeredStructure(); } @@ -62,7 +65,12 @@ class BlockLayered extends Module public function uninstall() { /* Delete all configurations */ - Configuration::deleteByName('PS_LAYERED_NAVIGATION_CHECKBOXES'); + Configuration::deleteByName('PS_LAYERED_SHARE'); + Configuration::deleteByName('PS_LAYERED_HIDE_0_VALUES'); + Configuration::deleteByName('PS_LAYERED_SHOW_QTIES'); + Configuration::deleteByName('PS_LAYERED_BITLY_USERNAME'); + Configuration::deleteByName('PS_LAYERED_BITLY_API_KEY'); + return parent::uninstall(); } @@ -81,12 +89,29 @@ class BlockLayered extends Module $id_parent = (int)Tools::getValue('id_category', Tools::getValue('id_category_layered', 1)); if ($id_parent == 1) return; + $context = Context::getContext(); - $context->controller->addJS(($this->_path).'blocklayered.js'); + $context->controller->addJS($this->_path.'blocklayered.js'); $context->controller->addJS(_PS_JS_DIR_.'jquery/jquery-ui-1.8.10.custom.min.js'); - $context->controller->addCSS(($this->_path).'blocklayered.css', 'all'); $context->controller->addCSS(_PS_CSS_DIR_.'jquery-ui-1.8.10.custom.css', 'all'); - + $context->controller->addCSS(($this->_path).'blocklayered.css', 'all'); + } + + public function hookFooter($params) + { + if (basename($_SERVER['PHP_SELF']) == 'category.php') + return ' + '; } public function hookCategoryAddition($params) @@ -121,6 +146,8 @@ class BlockLayered extends Module public function getContent() { + global $cookie; + $errors = array(); $html = ''; @@ -130,11 +157,67 @@ class BlockLayered extends Module $this->rebuildLayeredCache(); $html .= ' -
      - - '.$this->l('Layered navigation database was initialized successfully').' +
      + '.$this->l('Layered navigation database was initialized successfully').'
      '; } + elseif (Tools::isSubmit('SubmitFilter')) + { + if (isset($_POST['id_layered_filter']) AND $_POST['id_layered_filter']) + Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'layered_filter WHERE id_layered_filter = '.(int)Tools::getValue('id_layered_filter')); + + if (Tools::getValue('scope') == 1) + { + Db::getInstance()->Execute('TRUNCATE TABLE '._DB_PREFIX_.'layered_filter'); + $categories = Db::getInstance()->ExecuteS('SELECT id_category FROM '._DB_PREFIX_.'category'); + foreach ($categories AS $category) + $_POST['categoryBox'][] = (int)$category['id_category']; + } + + if (sizeof($_POST['categoryBox'])) + { + Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'layered_category WHERE id_category IN ('.implode(',', $_POST['categoryBox']).')'); + + $filterValues = array(); + + $sqlToInsert = 'INSERT INTO '._DB_PREFIX_.'layered_category (id_category, id_value, type, position) VALUES '; + foreach ($_POST['categoryBox'] AS $id_category_layered) + { + $n = 0; + foreach ($_POST AS $key => $value) + if (substr($key, 0, 17) == 'layered_selection' AND $value == 'on') + { + $filterValues[$key] = $value; + + $n++; + if ($key == 'layered_selection_stock') + $sqlToInsert .= '('.(int)$id_category_layered.',NULL,\'quantity\','.(int)$n.'),'; + elseif ($key == 'layered_selection_subcategories') + $sqlToInsert .= '('.(int)$id_category_layered.',NULL,\'category\','.(int)$n.'),'; + elseif ($key == 'layered_selection_condition') + $sqlToInsert .= '('.(int)$id_category_layered.',NULL,\'condition\','.(int)$n.'),'; + elseif ($key == 'layered_selection_weight_slider') + $sqlToInsert .= '('.(int)$id_category_layered.',NULL,\'weight\','.(int)$n.'),'; + elseif ($key == 'layered_selection_manufacturer') + $sqlToInsert .= '('.(int)$id_category_layered.',NULL,\'manufacturer\','.(int)$n.'),'; + elseif (substr($key, 0, 21) == 'layered_selection_ag_') + $sqlToInsert .= '('.(int)$id_category_layered.','.(int)str_replace('layered_selection_ag_', '', $key).',\'id_attribute_group\','.(int)$n.'),'; + elseif (substr($key, 0, 23) == 'layered_selection_feat_') + $sqlToInsert .= '('.(int)$id_category_layered.','.(int)str_replace('layered_selection_feat_', '', $key).',\'id_feature\','.(int)$n.'),'; + } + $filterValues['categories'] = Tools::getValue('categoryBox'); + } + Db::getInstance()->Execute(rtrim($sqlToInsert, ',')); + + $valuesToInsert = array('name' => pSQL(Tools::getValue('layered_tpl_name')), 'filters' => pSQL(serialize($filterValues)), 'n_categories' => (int)sizeof($_POST['categoryBox']), 'date_add' => date('Y-m-d H:i:s')); + if (isset($_POST['id_layered_filter']) AND $_POST['id_layered_filter']) + $valuesToInsert['id_layered_filter'] = (int)Tools::getValue('id_layered_filter'); + + Db::getInstance()->AutoExecute(_DB_PREFIX_.'layered_filter', $valuesToInsert, 'INSERT'); + + echo '
      '.$this->l('Your filter').' "'.Tools::getValue('layered_tpl_name').'" '.((isset($_POST['id_layered_filter']) AND $_POST['id_layered_filter']) ? $this->l('was updated successfully.') : $this->l('was added successfully.')).'
      '; + } + } elseif (Tools::isSubmit('submitLayeredSettings')) { if (Tools::getValue('share_url')) @@ -150,10 +233,12 @@ class BlockLayered extends Module Configuration::updateValue('PS_LAYERED_BITLY_USERNAME', Tools::getValue('bitly_username')); Configuration::updateValue('PS_LAYERED_BITLY_API_KEY', Tools::getValue('bitly_api_key')); Configuration::updateValue('PS_LAYERED_SHARE', Tools::getValue('share_url')); + Configuration::updateValue('PS_LAYERED_HIDE_0_VALUES', Tools::getValue('ps_layered_hide_0_values')); + Configuration::updateValue('PS_LAYERED_SHOW_QTIES', Tools::getValue('ps_layered_show_qties')); + $html .= ' -
      - - '.$this->l('Settings saved successfully').' +
      + '.$this->l('Settings saved successfully').'
      '; } else @@ -161,14 +246,40 @@ class BlockLayered extends Module $html .= '
      '.$this->l('Settings not saved :').'
        '; - foreach($errors as $error) + foreach($errors AS $error) $html .= '
      • '.$error.'
      • '; - $html .= '
      '; + $html .= '
    +
  • '; } } + elseif (isset($_GET['deleteFilterTemplate'])) + { + $layeredValues = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' + SELECT filters + FROM '._DB_PREFIX_.'layered_filter + WHERE id_layered_filter = '.(int)$_GET['id_layered_filter']); - $html .= '

    '.$this->l('Layered navigation').'

    -

    '.$this->l('This module is in beta version and will be improved').'


    -
    - '.$this->l('10 upcoming improvements').' -
      -
    1. '.$this->l('Real-time refresh of the cache table').'
    2. -
    3. '.$this->l('Additional filters (prices, weight)').'
    4. -
    5. '.$this->l('Ability to manage filters by category in the module configuration').'
    6. -
    7. '.$this->l('Ability to hide filter groups with no values and filter values with 0 products').'
    8. -
    9. '.$this->l('Statistics and analysis').'
    10. -
    11. '.$this->l('Manage products sort & pagination').'
    12. -
    13. '.$this->l('Add a check on the category_group table').'
    14. -
    15. '.$this->l('SEO links & real time URL building (ability to give the URL to someone)').'
    16. -
    17. '.$this->l('Add more options in the module configuration').'
    18. -
    19. '.$this->l('Performances improvements').'
    20. -
    +
    + '.$this->l('Existing filters templates').''; + + $filtersTemplates = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('SELECT * FROM '._DB_PREFIX_.'layered_filter ORDER BY date_add DESC'); + if (sizeof($filtersTemplates)) + { + $html .= '

    '.sizeof($filtersTemplates).' '.$this->l('filters templates are configured:').'

    + + + + + + + + '; + + foreach ($filtersTemplates AS $filtersTemplate) + { + /* Clean request URI first */ + $_SERVER['REQUEST_URI'] = preg_replace('/&deleteFilterTemplate=[0-9]*&id_layered_filter=[0-9]*/', '', $_SERVER['REQUEST_URI']); + + $html .= ' + + + + + + + '; + } + + $html .= ' +
    IDNameCategoriesCreated onActions
    '.(int)$filtersTemplate['id_layered_filter'].''.$filtersTemplate['name'].''.(int)$filtersTemplate['n_categories'].''.Tools::displayDate($filtersTemplate['date_add'], (int)$cookie->id_lang, true).' + + +
    '; + } + else + $html .= $this->l('No filter template found.'); + + $html .= ' +

    + +
    + '.$this->l('Build your own filters template').' + + +
    '; + + $html.= ' +

    '.$this->l('Step 1/3 - Select categories').'

    +

    '.$this->l('Use this template for:').' + + + + +

    + +
    +
    +

    '.$this->l('Categories using this template').'

    +
      +
    1. '.$this->l('Select one ore more category using this filter template').'
    2. +
    3. '.$this->l('Press "Save this selection" or close the window to save').'
    4. +
    '; + + $trads = array(); + $selectedCat = array(); + foreach(Helper::$translationsKeysForAdminCategorieTree AS $key) + $trads[$key] = $this->l($key); + $html .= Helper::renderAdminCategorieTree($trads, $selectedCat, 'categoryBox'); + + $html .= ' +
    +
    +
    +
    +
    +
    +

    '.$this->l('Step 2/3 - Select filters').'

    +
    +
    +

    '.$this->l('Selected filters').' (0)

    +

    '.$this->l('No filters selected yet.').'

    +
      +
      +
      + '.$this->ajaxCallBackOffice().' +
      +
      +
      +
      + + + + +
      +
      +

      '.$this->l('Step 3/3 - Name your template').'

      +

      '.$this->l('Template name:').' ('.$this->l('only as a reminder').')

      +
      +
      +
      +
      + + +

      - '.$this->l('Cache initialization').'
      -
      -

      '.$this->l('Before using this module for the first time you have to initialize the cache').'

      -

      '.$this->l('Warning: This could take several minutes.').'

      - '.$this->l('If you do not, this cache table might become larger and larger (less efficient), and all the new choices (attributes, features) will not be offered to your visitors.').'

      -
      -

      -
      -

      -
      '.$this->l('Configuration').' -
      - -
      + + + + + + + + + + + + + + + + + +
      '.$this->l('Option').''.$this->l('Value').'
      '.$this->l('Hide filter values with no product is matching').' + '.$this->l('Yes').' + '.$this->l('Yes').' + '.$this->l('No').' + '.$this->l('No').' +
      '.$this->l('Show the number of matching products').' + '.$this->l('Yes').' + '.$this->l('Yes').' + '.$this->l('No').' + '.$this->l('No').' +
      '.$this->l('Allow customers to share URLs').' - + '.$this->l('Yes').' - -

      '.$this->l('By enabling this option, your visitors can share the URL of their research').'

      - -
      + '.$this->l('No').' +

      '.$this->l('To offer your customers short links, create an account on bit.ly, then copy and paste login and API key.').' '.$this->l('Sign Up').'

      @@ -240,6 +612,7 @@ class BlockLayered extends Module

      '; + return $html; } @@ -293,10 +666,13 @@ class BlockLayered extends Module if ($id_parent == 1) return; - if (!sizeof($selectedFilters['category'])) - $selectedFilters['category'][] = $id_parent; - $queryFilters = ''; + $parent = new Category((int)$id_parent); + if (!sizeof($selectedFilters['category'])) + $queryFilters .= ' AND p.id_product IN (SELECT id_product FROM '._DB_PREFIX_.'category_product cp + LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category) + WHERE 1 AND c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright.')'; + foreach ($selectedFilters AS $key => $filterValues) { if (!sizeof($filterValues)) @@ -326,20 +702,10 @@ class BlockLayered extends Module break; case 'category': - $parent = new Category($id_parent); - if (!sizeof($selectedFilters['category'])) - $queryFilters .= ' AND p.id_product IN ( SELECT id_product FROM '._DB_PREFIX_.'category_product cp - LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category) - WHERE 1 AND c.nleft >= parent->nleft AND c.nright <= parent->nright'; - else - { - $queryFilters .= ' AND p.id_product IN ( SELECT id_product FROM '._DB_PREFIX_.'category_product cp WHERE 1 AND cp.`id_category` = '.(int)$id_parent; - if (sizeof($selectedFilters['category'])) - $queryFilters .= ' OR '; + $queryFilters .= ' AND p.id_product IN (SELECT id_product FROM '._DB_PREFIX_.'category_product cp WHERE '; foreach ($selectedFilters['category'] AS $id_category) $queryFilters .= 'cp.`id_category` = '.(int)$id_category.' OR '; $queryFilters = rtrim($queryFilters, 'OR ').')'; - } break; case 'quantity': @@ -367,37 +733,31 @@ class BlockLayered extends Module } } - //id_category_layered = current displayed category - if (!sizeof($selectedFilters['category'])) - $queryFilters .= ' AND p.id_product IN ( - SELECT id_product FROM '._DB_PREFIX_.'category_product cp - WHERE cp.`id_category` = '.(int)$id_parent.')'; - /* Return only the number of products */ $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' SELECT COUNT(p.`id_product`) AS total FROM `'._DB_PREFIX_.'product` p WHERE 1 '.$queryFilters); - $this->nbr_products = isset($result) ? $result['total'] : 0; + $this->nbr_products = isset($result) ? (int)$result['total'] : 0; $n = (int)Tools::getValue('n', Configuration::get('PS_PRODUCTS_PER_PAGE')); - - $sql = 'SELECT p.id_product, p.out_of_stock, p.available_for_order, p.minimal_quantity, p.id_category_default, p.customizable, p.show_price, p.`weight`, + + $sql = 'SELECT p.id_product, p.on_sale, p.out_of_stock, p.available_for_order, p.minimal_quantity, p.id_category_default, p.customizable, p.show_price, p.`weight`, p.ean13, pl.available_later, pl.description_short, pl.link_rewrite, pl.name, i.id_image, il.legend, m.name manufacturer_name, p.condition, p.id_manufacturer, stock.quantity, DATEDIFF(p.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new FROM '._DB_PREFIX_.'product p '.$context->shop->sqlAsso('product', 'p').' + '.Product::sqlStock('p').' LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (pl.id_product = p.id_product'.$context->shop->sqlLang('pl').') - '.Product::sqlStock('p', 0).' LEFT JOIN '._DB_PREFIX_.'image i ON (i.id_product = p.id_product AND i.cover = 1) LEFT JOIN '._DB_PREFIX_.'image_lang il ON (i.id_image = il.id_image AND il.id_lang = '.(int)$context->language->id.') - LEFT JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) + LEFT JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) WHERE p.`active` = 1 AND pl.id_lang = '.(int)$context->language->id .$queryFilters. ' ORDER BY '.Tools::getProductsOrder('by', Tools::getValue('orderby')).' '.Tools::getProductsOrder('way', Tools::getValue('orderway')). - ' LIMIT '.(((int)(Tools::getValue('p', 1)) - 1) * $n.','.$n); + ' LIMIT '.(((int)Tools::getValue('p', 1) - 1) * $n.','.$n); $this->products = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql); return $this->products; @@ -415,11 +775,16 @@ class BlockLayered extends Module /* First we need to get all subcategories of current category */ $category = new Category((int)$id_parent); + $groups = FrontController::getCurrentCustomerGroups(); + $subCategories = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT c.id_category, c.id_parent, cl.name FROM '._DB_PREFIX_.'category c LEFT JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = c.id_category) + LEFT JOIN '._DB_PREFIX_.'category_group cg ON (cg.id_category = c.id_category) WHERE c.nleft > '.(int)$category->nleft.' and c.nright <= '.(int)$category->nright.' AND c.active = 1 AND c.id_parent = '.(int)$category->id.' AND cl.id_lang = '.(int)$context->language->id.' + AND cg.id_group '.pSQL(sizeof($groups) ? 'IN ('.implode(',', $groups).')' : '= 1').' + GROUP BY c.id_category ORDER BY c.position ASC'); $whereC = ' cp.`id_category` = '.(int)$id_parent.' OR '; @@ -440,7 +805,7 @@ class BlockLayered extends Module WHERE p.`active` = 1 AND p.`id_product` IN ( SELECT id_product FROM `'._DB_PREFIX_.'category_product` cp WHERE'.$whereC.')', false); $products = array(); - $db = Db::getInstance(); + $db = Db::getInstance(_PS_USE_SQL_SLAVE_); $weight = array(); while ($product = $db->nextRow($productsSQL)) { @@ -465,7 +830,7 @@ class BlockLayered extends Module } /* Get the filters for the current category */ - $filters = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('SELECT * FROM '._DB_PREFIX_.'layered_category WHERE id_category = '.(int)$id_parent); + $filters = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('SELECT * FROM '._DB_PREFIX_.'layered_category WHERE id_category = '.(int)$id_parent.' ORDER BY position ASC'); $filterBlocks = $f = $a = array(); foreach ($filters AS $filter) @@ -478,18 +843,17 @@ class BlockLayered extends Module case 'id_feature': $f[] = (int)$filter['id_value']; - $filterBlocks[(int)$filter['position']]['SQLvalues'] = Db::getInstance()->ExecuteS(' + $filterBlocks[(int)$filter['position']]['SQLvalues'] = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT fvl.id_feature_value, fvl.value FROM '._DB_PREFIX_.'feature_value fv LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = fv.id_feature_value) WHERE (fv.custom IS NULL OR fv.custom = 0) AND fv.id_feature = '.(int)$filterBlocks[(int)$filter['position']]['id_key'].' AND fvl.id_lang = '.(int)$context->language->id); - break; case 'id_attribute_group': $a[] = (int)$filter['id_value']; - $filterBlocks[(int)$filter['position']]['SQLvalues'] = Db::getInstance()->ExecuteS(' + $filterBlocks[(int)$filter['position']]['SQLvalues'] = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT al.id_attribute, al.name, a.color FROM '._DB_PREFIX_.'attribute a LEFT JOIN '._DB_PREFIX_.'attribute_lang al ON (al.id_attribute = a.id_attribute) @@ -501,7 +865,7 @@ class BlockLayered extends Module /* Get the feature block names & values */ if (sizeof($f)) { - $fNames = Db::getInstance()->ExecuteS(' + $fNames = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT id_feature, name FROM '._DB_PREFIX_.'feature_lang WHERE id_lang = '.(int)$context->language->id.' AND id_feature IN ('.implode(',', $f).')'); @@ -513,7 +877,7 @@ class BlockLayered extends Module /* Get the attribute block names & values */ if (sizeof($a)) { - $aNames = Db::getInstance()->ExecuteS(' + $aNames = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT ag.id_attribute_group, agl.public_name, ag.is_color_group FROM '._DB_PREFIX_.'attribute_group ag LEFT JOIN '._DB_PREFIX_.'attribute_group_lang agl ON (agl.id_attribute_group = ag.id_attribute_group) @@ -552,11 +916,14 @@ class BlockLayered extends Module $productCat = $this->filterProducts($products, $selectedFilters, 'category'); - //count nbr product in category + // Count number of products in each category foreach ($c AS $idSubCategory) foreach ($productCat AS $product) if (in_array($idSubCategory, $product['c'])) $filterBlock['values'][(int)$idSubCategory]['nbr']++; + + if (Configuration::get('PS_LAYERED_HIDE_0_VALUES') AND !$filterBlock['values'][(int)$idSubCategory]['nbr']) + unset($filterBlock['values'][(int)$subCat['id_category']]); } elseif ($filterBlock['type_lite'] == 'id_feature') { @@ -569,11 +936,14 @@ class BlockLayered extends Module { foreach ($productFeat AS $product) { - if (in_array($value['id_feature_value'], $product['f'])) + if (Configuration::get('PS_LAYERED_HIDE_0_VALUES') AND !in_array($value['id_feature_value'], $product['f'])) + continue; + else { $filterBlock['values'][(int)$value['id_feature_value']]['name'] = $value['value']; if (!isset($filterBlock['values'][(int)$value['id_feature_value']]['nbr'])) $filterBlock['values'][(int)$value['id_feature_value']]['nbr'] = 0; + if (in_array($value['id_feature_value'], $product['f'])) $filterBlock['values'][(int)$value['id_feature_value']]['nbr']++; } if (in_array($value['id_feature_value'], $product['f']) AND !isset($filterBlock['values'][(int)$value['id_feature_value']])) @@ -637,6 +1007,13 @@ class BlockLayered extends Module if (isset($selectedFilters['condition']) AND in_array($conditionKey, $selectedFilters['condition'])) $condition['checked'] = true; } + + if (Configuration::get('PS_LAYERED_HIDE_0_VALUES')) + { + foreach ($filterBlock['values'] AS $conditionKey2 => $condition2) + if (!$condition2['nbr']) + unset($filterBlock['values'][$conditionKey2]); + } } elseif ($filterBlock['type_lite'] == 'quantity') { @@ -655,6 +1032,13 @@ class BlockLayered extends Module if (isset($selectedFilters['quantity']) AND in_array($quantKey, $selectedFilters['quantity'])) $quantity['checked'] = true; } + + if (Configuration::get('PS_LAYERED_HIDE_0_VALUES')) + { + foreach ($filterBlock['values'] AS $quantKey2 => $quantity2) + if (!$quantity2['nbr']) + unset($filterBlock['values'][$quantKey2]); + } } elseif ($filterBlock['type_lite'] == 'manufacturer') { @@ -708,9 +1092,8 @@ class BlockLayered extends Module foreach ($selectedFilters AS $filters) $nFilters += sizeof($filters); - $params = '?'; - foreach ($_GET as $key => $val) + foreach($_GET AS $key => $val) $params .= $key.'='.$val.'&'; $share_url = $context->link->getCategoryLink((int)$category->id, $category->link_rewrite[(int)$context->language->id], $context->language->id).rtrim($params, '&'); @@ -718,7 +1101,7 @@ class BlockLayered extends Module $context->smarty->assign(array( 'display_share' => (int)Configuration::get('PS_LAYERED_SHARE'), 'share_url' => $this->getShortLink($share_url), - 'layered_use_checkboxes' => (int)Configuration::get('PS_LAYERED_NAVIGATION_CHECKBOXES'), + 'layered_show_qties' => (int)Configuration::get('PS_LAYERED_SHOW_QTIES'), 'id_category_layered' => (int)$id_parent, 'selected_filters' => $selectedFilters, 'n_filters' => (int)$nFilters, @@ -728,6 +1111,119 @@ class BlockLayered extends Module return $this->display(__FILE__, 'blocklayered.tpl'); } + public function ajaxCallBackOffice($categoryBox = array(), $id_layered_filter = NULL) + { + global $cookie; + + if (!empty($id_layered_filter)) + { + $layeredFilter = Db::getInstance()->getRow('SELECT * FROM '._DB_PREFIX_.'layered_filter WHERE id_layered_filter = '.(int)$id_layered_filter); + if ($layeredFilter AND isset($layeredFilter['filters']) AND !empty($layeredFilter['filters'])) + $layeredValues = unserialize($layeredFilter['filters']); + if (isset($layeredValues['categories']) AND sizeof($layeredValues['categories'])) + foreach ($layeredValues['categories'] AS $id_category) + $categoryBox[] = (int)$id_category; + } + + $attributeGroups = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' + SELECT ag.id_attribute_group, ag.is_color_group, agl.name, COUNT(DISTINCT(a.id_attribute)) n + FROM '._DB_PREFIX_.'attribute_group ag + LEFT JOIN '._DB_PREFIX_.'attribute_group_lang agl ON (agl.id_attribute_group = ag.id_attribute_group) + LEFT JOIN '._DB_PREFIX_.'attribute a ON (a.id_attribute_group = ag.id_attribute_group) + '.(sizeof($categoryBox) ? ' + LEFT JOIN '._DB_PREFIX_.'product_attribute_combination pac ON (pac.id_attribute = a.id_attribute) + LEFT JOIN '._DB_PREFIX_.'product_attribute pa ON (pa.id_product_attribute = pac.id_product_attribute) + LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = pa.id_product)' : '').' + WHERE agl.id_lang = '.(int)$cookie->id_lang. + (sizeof($categoryBox) ? ' AND cp.id_category IN ('.implode(',', $categoryBox).')' : '').' + GROUP BY ag.id_attribute_group'); + + $features = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' + SELECT fl.id_feature, fl.name, COUNT(DISTINCT(fv.id_feature_value)) n + FROM '._DB_PREFIX_.'feature_lang fl + LEFT JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature = fl.id_feature) + '.(sizeof($categoryBox) ? ' + LEFT JOIN '._DB_PREFIX_.'feature_product fp ON (fp.id_feature = fv.id_feature) + LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = fp.id_product)' : '').' + WHERE (fv.custom IS NULL OR fv.custom = 0) AND fl.id_lang = '.(int)$cookie->id_lang. + (sizeof($categoryBox) ? ' AND cp.id_category IN ('.implode(',', $categoryBox).')' : '').' + GROUP BY fl.id_feature'); + + $nElements = sizeof($attributeGroups) + sizeof($features) + 4; + if ($nElements > 20) + $nElements = 20; + + $html = ' +
      +

      '.$this->l('Available filters').' (0)

      +
        +
        • '.$this->l('Sub-categories filter').'
        +
        • '.$this->l('Product stock filter').'
        +
        • '.$this->l('Product condition filter').'
        +
        • '.$this->l('Product manufacturer filter').'
        +
        • '.$this->l('Product weight filter (slider)').'
        '; + + if (sizeof($attributeGroups)) + { + $html .= '
          '; + foreach ($attributeGroups AS $attributeGroup) + $html .= '
        • '.$this->l('Attribute group:').' '.$attributeGroup['name'].' ('.(int)$attributeGroup['n'].' '.($attributeGroup['n'] > 1 ? $this->l('attributes') : $this->l('attribute')).')'.($attributeGroup['is_color_group'] ? ' ' : '').'
        • '; + $html .= '
        '; + } + + if (sizeof($features)) + { + $html .= '
          '; + foreach ($features AS $feature) + $html .= '
        • '.$this->l('Feature:').' '.$feature['name'].' ('.(int)$feature['n'].' '.($feature['n'] > 1 ? $this->l('values') : $this->l('value')).')
        • '; + $html .= '
        '; + } + + $html .= ' +
        '; + + if (isset($layeredValues)) + { + $html .= ' + '; + } + + return $html; + } + public function ajaxCall() { $context = Context::getContext(); @@ -759,12 +1255,12 @@ class BlockLayered extends Module $context->smarty->assign('nb_products', $nbProducts); $pagination_infos = array( 'pages_nb' => (int)($pages_nb), - 'p' => (int)($p), - 'n' => (int)($n), - 'range' => (int)($range), - 'start' => (int)($start), - 'stop' => (int)($stop), - 'nArray' => $nArray = (int)(Configuration::get('PS_PRODUCTS_PER_PAGE')) != 10 ? array((int)(Configuration::get('PS_PRODUCTS_PER_PAGE')), 10, 20, 50) : array(10, 20, 50) + 'p' => (int)$p, + 'n' => (int)$n, + 'range' => (int)$range, + 'start' => (int)$start, + 'stop' => (int)$stop, + 'nArray' => $nArray = (int)Configuration::get('PS_PRODUCTS_PER_PAGE') != 10 ? array((int)Configuration::get('PS_PRODUCTS_PER_PAGE'), 10, 20, 50) : array(10, 20, 50) ); $context->smarty->assign($pagination_infos); @@ -776,21 +1272,16 @@ class BlockLayered extends Module 'productList' => $context->smarty->fetch(_PS_THEME_DIR_.'product-list.tpl'), 'pagination' => $context->smarty->fetch(_PS_THEME_DIR_.'pagination.tpl') )); - // return '
        '.$this->generateFiltersBlock($selectedFilters).'
        '.$smarty->fetch(_PS_THEME_DIR_.'product-list.tpl').'
        '; } public function rebuildLayeredStructure() { @set_time_limit(0); - // setting the memory limit to 128M only if current is lower + + /* Set memory limit to 128M only if current is lower */ $memory_limit = ini_get('memory_limit'); - if ( substr($memory_limit,-1) != 'G' - AND ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128) - OR is_numeric($memory_limit) AND (intval($memory_limit) < 131072)) - ) - { + if (substr($memory_limit,-1) != 'G' AND ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128) OR is_numeric($memory_limit) AND (intval($memory_limit) < 131072))) @ini_set('memory_limit','128M'); - } /* Delete and re-create the layered categories table */ Db::getInstance()->Execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_category'); @@ -803,27 +1294,31 @@ class BlockLayered extends Module `position` INT(10) UNSIGNED NOT NULL, PRIMARY KEY (`id_layered_category`), KEY `id_category` (`id_category`,`type`) - ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;'); + ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;'); /* MyISAM + latin1 = Smaller/faster */ + + Db::getInstance()->Execute(' + CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'layered_filter` ( + `id_layered_filter` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(64) NOT NULL, + `filters` TEXT NULL, + `n_categories` INT(10) UNSIGNED NOT NULL, + `date_add` DATETIME NOT NULL)'); } public function rebuildLayeredCache($productsIds = array(), $categoriesIds = array()) { @set_time_limit(0); - // setting the memory limit to 128M only if current is lower + + /* Set memory limit to 128M only if current is lower */ $memory_limit = ini_get('memory_limit'); - if (substr($memory_limit,-1) != 'G' - AND ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128) - OR is_numeric($memory_limit) AND (intval($memory_limit) < 131072)) - ) - { - @ini_set('memory_limit','129M'); - } + if (substr($memory_limit,-1) != 'G' AND ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128) OR is_numeric($memory_limit) AND (intval($memory_limit) < 131072))) + @ini_set('memory_limit','128M'); - $db = Db::getInstance(); + $db = Db::getInstance(_PS_USE_SQL_SLAVE_); $nCategories = array(); $doneCategories = array(); - $attributeGroups = Db::getInstance()->ExecuteS(' + $attributeGroups = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT a.id_attribute, a.id_attribute_group FROM '._DB_PREFIX_.'attribute a LEFT JOIN '._DB_PREFIX_.'product_attribute_combination pac ON (pac.id_attribute = a.id_attribute) @@ -837,7 +1332,7 @@ class BlockLayered extends Module while ($row = $db->nextRow($attributeGroups)) $attributeGroupsById[(int)$row['id_attribute']] = (int)$row['id_attribute_group']; - $features = Db::getInstance()->ExecuteS(' + $features = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT fv.id_feature_value, fv.id_feature FROM '._DB_PREFIX_.'feature_value fv LEFT JOIN '._DB_PREFIX_.'feature_product fp ON (fp.id_feature_value = fv.id_feature_value) @@ -922,7 +1417,7 @@ class BlockLayered extends Module $queryCategory .= '('.(int)$id_category.',NULL,\'weight\','.(int)$nCategories[(int)$id_category]++.'),'; $toInsert = true; } - /* + /* Filter by price (dev in progress) if (!isset($doneCategories[(int)$id_category]['p'])) { $doneCategories[(int)$id_category]['p'] = true; diff --git a/modules/blocklayered/blocklayered.tpl b/modules/blocklayered/blocklayered.tpl index 6dadd2c77..6ff108e56 100644 --- a/modules/blocklayered/blocklayered.tpl +++ b/modules/blocklayered/blocklayered.tpl @@ -77,21 +77,21 @@
          {if !isset($filter.slider)} {foreach from=$filter.values key=id_value item=value} - +
        • {if isset($filter.is_color_group) && $filter.is_color_group} {if isset($value.checked) && $value.checked}{/if} {else} - {if $layered_use_checkboxes} {/if} - {/if} - +
        • {/foreach} {else} - + +
          +
          @@ -80,7 +80,7 @@ {/if}

          {/if} -{if $order->recyclable} +{if $order->recyclable && isset($isRecyclable) && $isRecyclable}

           {l s='You have given permission to receive your order in recycled packaging.'}

          {/if} {if $order->gift} diff --git a/themes/prestashop/order-opc-new-account.tpl b/themes/prestashop/order-opc-new-account.tpl index a3876d3dc..daa4cb493 100644 --- a/themes/prestashop/order-opc-new-account.tpl +++ b/themes/prestashop/order-opc-new-account.tpl @@ -14,7 +14,7 @@
        - +

        {if isset($back)}{/if} diff --git a/themes/prestashop/order-opc.tpl b/themes/prestashop/order-opc.tpl index 818916eee..c15722a7c 100755 --- a/themes/prestashop/order-opc.tpl +++ b/themes/prestashop/order-opc.tpl @@ -81,7 +81,7 @@ {if $productNumber} {include file="$tpl_dir./shopping-cart.tpl"} - + {if $isLogged AND !$isGuest} {include file="$tpl_dir./order-address.tpl"} {else} diff --git a/themes/prestashop/product-compare.tpl b/themes/prestashop/product-compare.tpl index 9a6a9d50f..ae824b28c 100644 --- a/themes/prestashop/product-compare.tpl +++ b/themes/prestashop/product-compare.tpl @@ -31,7 +31,8 @@ var max_item = "{l s='You cannot add more than' js=1} {$comparator_max_item} {l s='product(s) in the product comparator' js=1}"; //]]> -

        + +

        diff --git a/themes/prestashop/product-list.tpl b/themes/prestashop/product-list.tpl index 72e03de13..66d9eb406 100644 --- a/themes/prestashop/product-list.tpl +++ b/themes/prestashop/product-list.tpl @@ -57,7 +57,7 @@ {/if} {l s='View'} {if isset($comparator_max_item) && $comparator_max_item} -

        +

        {/if}
        diff --git a/themes/prestashop/products-comparison.tpl b/themes/prestashop/products-comparison.tpl index 587ed7f33..4bdcbea8b 100644 --- a/themes/prestashop/products-comparison.tpl +++ b/themes/prestashop/products-comparison.tpl @@ -44,10 +44,11 @@
        {$product->name|truncate:27:'...'|escape:'htmlall':'UTF-8'}
        +
        {$product->name|escape:html:'UTF-8'} - +
        {if isset($product->show_price) && $product->show_price && !isset($restricted_country_mode) && !$PS_CATALOG_MODE}

        {convertPrice price=$product->getPrice($taxes_behavior)}

        @@ -82,7 +83,7 @@ {/if}

        - {l s='Remove'} + {l s='Remove'} {l s='View'} {if (!$product->hasAttributes() OR (isset($add_prod_display) AND ($add_prod_display == 1))) AND $product->minimal_quantity == 1 AND $product->customizable != 2 AND !$PS_CATALOG_MODE} {if ($product->quantity > 0 OR $product->allow_oosp)} diff --git a/translations/es/errors.php b/translations/es/errors.php index 17e7e55b2..c91614641 100644 --- a/translations/es/errors.php +++ b/translations/es/errors.php @@ -264,6 +264,7 @@ $_ERRORS['65c02cc2c82051fccca8e5b5647f03e5'] = 'No es un email válido'; $_ERRORS['ab57fd0432e25d5b3013133a1c910d56'] = 'KB'; $_ERRORS['e389fb6a0b1d8aba957ef5bd33929e86'] = 'etiqueta de campos no válida'; $_ERRORS['6cf73576720519e739771a4fa489410b'] = 'no se encuentra el idioma'; +$_ERRORS['60e8343766afd5e69c5797ea7380ce8e'] = 'Latitud y longitud son obligatorios'; $_ERRORS['ba2a9c6c8c77e03f83ef8bf543612275'] = 'longitud >'; $_ERRORS['4803e6b9e63dabf04de980788d6a13c4'] = 'línea'; $_ERRORS['49bd922182bd3518641589e3077eacd3'] = 'El enlace con la base de datos no se puede establecer'; @@ -347,7 +348,6 @@ $_ERRORS['f2ee6211fd44afca2f01ee2d1031d0e5'] = 'Por favor, inscríbase para ver $_ERRORS['f996dce5bdfb1b1094e41cf996c5fdae'] = 'por favor, especifique la URL del módulo'; $_ERRORS['a05b582431bd7063de0623ef76b14c73'] = 'Por favor, especifique prioridades'; $_ERRORS['27e12c3c443d7165ab71cd376a3b3f10'] = 'introduzca su código postal'; -$_ERRORS['c22042ba6792cfe142bf63f5a8c50ae8'] = 'producto no disponible actualmente'; $_ERRORS['f1cdcf26d9787f078f7fc0e0645858d7'] = 'Error fatal Prestashop: no hay soporte utf-8. Por favor, compruebe la configuración de su servidor.'; $_ERRORS['350bf1d858bae55fa9c344b39ea9afcd'] = 'no se puede cargar el producto'; $_ERRORS['a3451334219f0c7cac75275c0ac6346e'] = 'Producto ya no está disponible.'; @@ -363,7 +363,6 @@ $_ERRORS['edeb9e20655b946e4bee4ac44a6c0a7f'] = 'El servidor no dispone de permis $_ERRORS['5d7cc18ef21285f980cbada9adb9df5c'] = 'La conexión al servidor expiró, la filigrana no se ha podido aplicar a todas las imígenes.'; $_ERRORS['721b2acc2e54e77e36654bbc42a0747a'] = 'Lo sentimos, actualmente las copias de seguridad solo soportan bases de datos MySQL. Usted esta usando'; $_ERRORS['c45319ee556dc43ba15523c539c7e9d4'] = 'Lo sentimos, no es posible renovar su pedido'; -$_ERRORS['c3f365ea3ae0b35b814493fc72ff0458'] = 'el proveedor no existe'; $_ERRORS['35f55f4e657f542d5f27853332c46f80'] = 'Error de sintaxis con este motivo'; $_ERRORS['19a99b7aed449fbbedc3ce65483d6a3a'] = 'La pestaña no se puede encontrar'; $_ERRORS['cae059a6bd57c0b7d289ce097c060ba6'] = 'El archivo de la pestaña no puede encontrarse'; diff --git a/translations/fr/admin.php b/translations/fr/admin.php index 0f997a5b6..1c1896380 100644 --- a/translations/fr/admin.php +++ b/translations/fr/admin.php @@ -21,8 +21,8 @@ $_LANGADM['AdminAddresses77638e87a55b8747e79590defafa75c9'] = 'Code postal'; $_LANGADM['AdminAddresses57d056ed0984166336b7879c2af3657f'] = 'Ville'; $_LANGADM['AdminAddresses59716c97497eb9694541f7c3d37b1a4d'] = 'Pays'; $_LANGADM['AdminAddresses284b47b0bb63ae2df3b29f0e691d6fcf'] = 'Adresses'; -$_LANGADM['AdminAddresses2ac25f8f90ece36fa66024d7bbc235c9'] = 'Choisir le fabriquant'; -$_LANGADM['AdminAddressesd7ec0ec68dddc7f411a5171af7c70f43'] = 'Aucun fabricant disponible'; +$_LANGADM['AdminAddresses2ac25f8f90ece36fa66024d7bbc235c9'] = 'Choisir la marque'; +$_LANGADM['AdminAddressesd7ec0ec68dddc7f411a5171af7c70f43'] = 'Aucune marque disponible'; $_LANGADM['AdminAddressesce26601dac0dea138b7295f02b7620a7'] = 'Client'; $_LANGADM['AdminAddressesf90e807b74928118048a1a6fa65ebfe5'] = 'Email du client'; $_LANGADM['AdminAddresses919d1ffe6c1855e790a416efa7b4cc4e'] = 'Numéro d\'identification fiscale'; @@ -909,6 +909,8 @@ $_LANGADM['AdminGenerator15970c4fdbca1fc48c5b412d94e798c0'] = 'Optimisation'; $_LANGADM['AdminGenerator32d593fb52ab5e4ae3f16844b576867d'] = 'En cochant cette case, votre fichier .htaccess sera complété automatiquement avec des directives améliorant le cache et la compression.'; $_LANGADM['AdminGenerator1dec4f55522b828fe5dacf8478021a9e'] = 'URLs simplifiées'; $_LANGADM['AdminGenerator223cf855cfa657eeb99550e1acd8eaa3'] = 'N\'activez cette option que si le mode rewrite est activé sur votre serveur.'; +$_LANGADM['AdminGeneratoracaa02ab1d800ce9a0b3df2e4ab8909a'] = 'Désactiver l\'option apache multivues'; +$_LANGADM['AdminGenerator7dc12aaf3ebf9e01ef5b2ec91761c26a'] = 'N\'activez cette option que si vous rencontrez des problèmes avec la redirection d\'url de certaines pages.'; $_LANGADM['AdminGenerator8b1fa347125449d64bb72e2c723cd8bf'] = 'Configuration spécifique'; $_LANGADM['AdminGeneratord59b3e143646e3f3e28005adccdb36a3'] = 'Ajouter ici les directives spécifiques de votre hébergement (SetEnv PHP_VER 5, AddType x-mapp-php5 .php...).'; $_LANGADM['AdminGeneratorb696dfaf5a833f70d71d26d052c6eaa3'] = 'Générer le fichier \".htaccess\" en cliquant sur le bouton suivant :'; @@ -922,7 +924,7 @@ $_LANGADM['AdminGenerator8052c42ab3b8aa06a3f5f788a4ddccc2'] = 'fichier .htaccess $_LANGADM['AdminGenerator93f711fc90428ec9589a70706e1866a2'] = 'fichier vide dans le dossier'; $_LANGADM['AdminGenerator60e4943ad37920b1f95133fae1420b59'] = 'lui donner les permissions (CHMOD 666 sur les système Unix)'; $_LANGADM['AdminGenerator345d6249c20c6319bb09edaaf536744b'] = 'Génération du fichier robots'; -$_LANGADM['AdminGenerator3b823baba7abb920bd1c18104ae7537b'] = 'Votre fichier robots.txt DOIT être à la racine de votre site internet, et nul part ailleurs.'; +$_LANGADM['AdminGenerator3b823baba7abb920bd1c18104ae7537b'] = 'Votre fichier robots.txt DOIT être à la racine de votre site internet, et nulle part ailleurs.'; $_LANGADM['AdminGeneratorb65cc08420e484602c7c313336933452'] = 'Ex : http://www.monsite.com/robots.txt'; $_LANGADM['AdminGenerator2129c4f9bb14dcddabb6453bfbeff246'] = 'Cet outil va générer automatiquement le fichier \"robots.txt\" offrant la possibilité de refuser l\'accès à certaines pages aux moteurs de recherche.'; $_LANGADM['AdminGeneratorffd4c6a67eb0c56d04a5ebca5e8cbf80'] = 'Générer le fichier \"robots.txt\" en cliquant sur le bouton suivant :'; @@ -1113,6 +1115,16 @@ $_LANGADM['AdminImages6e9b08be274aa15f116c641e4c9b8599'] = 'Vous pouvez aussi d $_LANGADM['AdminImages1bd266b7c30df50f9b77b0e0f55f2878'] = 'Après avoir déplacé toutes vos images produit, pour des performances optimales allez aux '; $_LANGADM['AdminImagese686877843ac3c9f4c45aaea265fe59c'] = 'préférences produit'; $_LANGADM['AdminImages8b82bc51644c14c234bb3b635b2e2d1c'] = ' et changez \"Activer la compatibilité avec les anciennes images\" à NON.'; +$_LANGADM['AdminImagesff17d73fa2731689640e8afa0f591b0f'] = 'Les images JPEG ont une taille de fichier petite et une qualité standard. Les images PNG ont une taille de fichier plus importante, une meilleure qualité, et gèrent la transparence. Notez que dans tous les cas les fichiers image auront l\'extension .jpg.'; +$_LANGADM['AdminImagesff167676b1516b34e7f9be0fea5349d6'] = 'ATTENTION : Cette fonctionnalité peut ne pas être compatible avec votre thème ou avec certains modules. En particulier, le mode PNG n\'est pas compatible avec le module Filigrane. En cas de problème, désactivez cette fonctionnalité en sélectionnant \"Utiliser le JPEG\".'; +$_LANGADM['AdminImages42ceb344b0aaf896b362b0db70b46f98'] = 'Qualité d\'image'; +$_LANGADM['AdminImages2a911eb0d71d1b707a3f9d722a5935c2'] = 'Utiliser le JPEG'; +$_LANGADM['AdminImagesb8d0be967a9105f094abc811656ee660'] = 'Utiliser le PNG seulement si l\'image de base est au format PNG'; +$_LANGADM['AdminImages718e1e271056782b288616e916511980'] = 'Utiliser le PNG pour toutes les images'; +$_LANGADM['AdminImagesd46bafd645c490bd4be22c4226619db9'] = 'Qualité JPEG'; +$_LANGADM['AdminImagesb73770b303fc0f331eee23ad7add197c'] = 'Va de 0 (plus faible qualité, petite taille de fichier) à 100 (meilleure qualité, taille du fichier importante)'; +$_LANGADM['AdminImagesc5e26b2211d5ecbbeac96ea6e1cbb7c2'] = 'Qualité PNG'; +$_LANGADM['AdminImages2c1bbb0a5ff08c8011d6ea83084277ff'] = 'Va de 9 (plus faible qualité, petite taille de fichier) à 0 (meilleure qualité, taille du fichier importante)'; $_LANGADM['AdminImportaf1b98adf7f686b84cd0b443e022b7a0'] = 'Catégories'; $_LANGADM['AdminImport068f80c7519d0528fb08e82137a72131'] = 'Produits'; $_LANGADM['AdminImportb9208b03bcc9eb4a336258dcdcb66207'] = 'Déclinaisons'; @@ -1398,23 +1410,23 @@ $_LANGADM['AdminLogs0eaadb4fcb48a0a0ed7bc9868be9fbaa'] = 'Avertissement'; $_LANGADM['AdminLogs902b0d55fddef6f8d651fe1035b7d4bd'] = 'Erreur'; $_LANGADM['AdminLogs2d7a39ee844a8ac84031dcd289630dd9'] = 'Problème majeur (erreur critique)'; $_LANGADM['AdminManufacturersb718adec73e04ce3ec720dd11a06a308'] = 'ID'; -$_LANGADM['AdminManufacturersc0bd7654d5b278e65f21cf4e9153fdb4'] = 'Fabricant'; +$_LANGADM['AdminManufacturersc0bd7654d5b278e65f21cf4e9153fdb4'] = 'Marque'; $_LANGADM['AdminManufacturers20db0bfeecd8fe60533206a2b5e9891a'] = 'Prénom'; $_LANGADM['AdminManufacturers8d3f5eff9c40ee315d452392bed5309b'] = 'Nom'; $_LANGADM['AdminManufacturers77638e87a55b8747e79590defafa75c9'] = 'Code postal'; $_LANGADM['AdminManufacturers57d056ed0984166336b7879c2af3657f'] = 'Ville'; $_LANGADM['AdminManufacturers59716c97497eb9694541f7c3d37b1a4d'] = 'Pays'; -$_LANGADM['AdminManufacturers34c7cc7e30ac36bc5e108bc567aeef73'] = 'Adresses des fabricants'; +$_LANGADM['AdminManufacturers34c7cc7e30ac36bc5e108bc567aeef73'] = 'Adresses des marques'; $_LANGADM['AdminManufacturers49ee3087348e8d44e1feda1917443987'] = 'Nom'; $_LANGADM['AdminManufacturers8c2857a9ad1d8f31659e35e904e20fa6'] = 'Logo'; $_LANGADM['AdminManufacturers284b47b0bb63ae2df3b29f0e691d6fcf'] = 'Adresses'; $_LANGADM['AdminManufacturers068f80c7519d0528fb08e82137a72131'] = 'Produits'; $_LANGADM['AdminManufacturers00d23a76e43b46dae9ec7aa9dcbebb32'] = 'Activé'; -$_LANGADM['AdminManufacturers2377be3c2ad9b435ba277a73f0f1ca76'] = 'Fabricants'; +$_LANGADM['AdminManufacturers2377be3c2ad9b435ba277a73f0f1ca76'] = 'Marques'; $_LANGADM['AdminManufacturers6252c0f2c2ed83b7b06dfca86d4650bb'] = 'Caractères interdits :'; $_LANGADM['AdminManufacturersc1069a480848e06782b81b8bea9c0c94'] = 'Description courte :'; $_LANGADM['AdminManufacturersb5a7adde1af5c87d7fd797b6245c2a39'] = 'Description :'; -$_LANGADM['AdminManufacturers4ff771c5a62c10ddbe02b9b5357b3402'] = 'Charger le logo du fabricant à partir de votre ordinateur'; +$_LANGADM['AdminManufacturers4ff771c5a62c10ddbe02b9b5357b3402'] = 'Charger le logo de la marque à partir de votre ordinateur'; $_LANGADM['AdminManufacturers9e11e4b371570340ca07913bc4783a7a'] = 'Titre META'; $_LANGADM['AdminManufacturers3e053943605d9e4bf7dd7588ea19e9d2'] = 'Caractères interdits'; $_LANGADM['AdminManufacturers3f64b2beede1082fd32ddb0bf11a641f'] = 'Description META'; @@ -1867,6 +1879,9 @@ $_LANGADM['AdminPreferences1656072e927c8d3acd24359cbb648bb5'] = 'Activer le SSL' $_LANGADM['AdminPreferences8de64d6b49cebd2306af6ddbcd268700'] = 'Si votre hébergeur propose le protocole SSL, vous pouvez activer le cryptage SSL (https://) pour l\'identification des clients et le processus de commande'; $_LANGADM['AdminPreferencesed5454727fb14b9800ead242d0972184'] = 'Vérifier l\'IP dans le cookie'; $_LANGADM['AdminPreferences9cfc2e28ebe44b3e14f9d780d2150650'] = 'Vérifiez l\'adresse IP du cookie afin d\'éviter que votre cookie soit volé'; +$_LANGADM['AdminPreferencesc87330f475e4384552c0077927d26e1a'] = 'Durée de vie du cookie Front Office'; +$_LANGADM['AdminPreferences6d964e25aa6aa88c8353880e00202cf4'] = 'Indiquez le nombre d\'heures'; +$_LANGADM['AdminPreferencese673b146824251548feecf1f3929aceb'] = 'Durée de vie du cookie Back Office'; $_LANGADM['AdminPreferencese12874163bcb256726ddfe643aa53a63'] = 'Améliore la sécurité du Front Office'; $_LANGADM['AdminPreferencescce43372fe8624c0edf870f417557b84'] = 'Active ou désactive les tokens en front-office afin d\'améliorer la sécurité de PrestaShop'; $_LANGADM['AdminPreferences16c390c0fd1efc4f493a6a861aa22d2f'] = 'Bulles d\'aide Back-office'; @@ -2134,6 +2149,14 @@ $_LANGADM['AdminProducts119a7c88cf8f1c685c57981abff26f43'] = 'Accepter les comma $_LANGADM['AdminProductse5f7f63d66023847e693fd34bea09d41'] = 'Par défaut :'; $_LANGADM['AdminProducts0871f875dff8224be3247ccedea01024'] = 'voir dans'; $_LANGADM['AdminProductsd0834fcec6337785ee749c8f5464f6f6'] = 'Préférences'; +$_LANGADM['AdminProducts9d9aa88574c4dab04ddd8356c377357d'] = 'Catégorie par défaut :'; +$_LANGADM['AdminProducts3faccbfcb5f35451302dcaff3af6cd3f'] = 'Merci de cocher une catégorie afin de sélectionner la catégorie par défaut.'; +$_LANGADM['AdminProducts8cf04a9734132302f96da8e113e80ce5'] = 'Accueil'; +$_LANGADM['AdminProductsef7de3f485174ff47f061ad27d83d0ee'] = 'sélectionnée(s)'; +$_LANGADM['AdminProductsb56c3bda503a8dc4be356edb0cc31793'] = 'Tout étendre'; +$_LANGADM['AdminProducts5ffd7a335dd836b3373f5ec570a58bdc'] = 'Tout déplier'; +$_LANGADM['AdminProducts5e9df908eafa83cb51c0a3720e8348c7'] = 'Tout cocher'; +$_LANGADM['AdminProducts9747d23c8cc358c5ef78c51e59cd6817'] = 'Tout décocher'; $_LANGADM['AdminProductsd88946b678e4c2f251d4e292e8142291'] = 'SEO'; $_LANGADM['AdminProducts2651608f8f1c6f391f919be228a6ee62'] = 'Cliquez ici pour améliorer votre position dans les moteurs de recherche (SEO)'; $_LANGADM['AdminProducts7b250cb374c12c42a75227ba75df7779'] = 'Balise :'; @@ -2239,7 +2262,8 @@ $_LANGADM['AdminProductsd1a1006c2d7ebf87d5e4d934a138e5a5'] = 'Vous devez sauvega $_LANGADM['AdminProducts4492081ca02b059f9e8af4ddaf0f7292'] = 'Pack'; $_LANGADM['AdminProducts2811dedc85918c3e3ed0becd87cbb336'] = 'Vous ne pouvez pas ajouter de produits téléchargeables à un pack.'; $_LANGADM['AdminProductsc7a915a59b56dc898c0ae52b64bed0c5'] = 'Ajouter un objet au pack'; -$_LANGADM['AdminProducts9d9aa88574c4dab04ddd8356c377357d'] = 'Catégorie par défaut :'; +$_LANGADM['AdminProducts126ddccbd9f946b8cd46d88b304a2020'] = 'Merci de sélectionner au moins un produit'; +$_LANGADM['AdminProductsd764262872a3bfe2b0944d1826f43a88'] = 'Merci de mettre une quantité pour ajouter un produit.'; $_LANGADM['AdminProducts10cbdb4839f838ce30409739435a6070'] = 'Catalogue :'; $_LANGADM['AdminProductsb61bd19699eab41bbcdabc42f83af268'] = 'Pensez à changer la catégorie par défaut.'; $_LANGADM['AdminProducts74645ed4e5e25461a664d5f68ff19098'] = 'Cocher dans quelle(s) catégorie(s) le produit doit apparaître'; diff --git a/translations/fr/errors.php b/translations/fr/errors.php index 848d6946a..b9b8e84da 100644 --- a/translations/fr/errors.php +++ b/translations/fr/errors.php @@ -264,6 +264,7 @@ $_ERRORS['65c02cc2c82051fccca8e5b5647f03e5'] = 'n\'est pas un e-mail valide'; $_ERRORS['ab57fd0432e25d5b3013133a1c910d56'] = 'Ko'; $_ERRORS['e389fb6a0b1d8aba957ef5bd33929e86'] = 'le nom des champs sont invalides'; $_ERRORS['6cf73576720519e739771a4fa489410b'] = 'langage introuvable'; +$_ERRORS['60e8343766afd5e69c5797ea7380ce8e'] = 'Latitude et longitude sont nécessaires'; $_ERRORS['ba2a9c6c8c77e03f83ef8bf543612275'] = 'longueur >'; $_ERRORS['4803e6b9e63dabf04de980788d6a13c4'] = 'ligne'; $_ERRORS['49bd922182bd3518641589e3077eacd3'] = 'Impossible de se connecter à la base de données.'; @@ -347,7 +348,6 @@ $_ERRORS['f2ee6211fd44afca2f01ee2d1031d0e5'] = 'Merci de vous inscrire pour voir $_ERRORS['f996dce5bdfb1b1094e41cf996c5fdae'] = 'merci de spécifier l\'URL du module'; $_ERRORS['a05b582431bd7063de0623ef76b14c73'] = 'Veuillez spécifier les priorités'; $_ERRORS['27e12c3c443d7165ab71cd376a3b3f10'] = 'merci de saisir votre code postal.'; -$_ERRORS['c22042ba6792cfe142bf63f5a8c50ae8'] = 'ce produit n\'est plus disponible'; $_ERRORS['f1cdcf26d9787f078f7fc0e0645858d7'] = 'Erreur fatale : Format utf-8 non supporté. Merci de vérifier la configuration de votre serveur.'; $_ERRORS['350bf1d858bae55fa9c344b39ea9afcd'] = 'le produit ne peut pas être chargé'; $_ERRORS['a3451334219f0c7cac75275c0ac6346e'] = 'Le produit n\'est plus disponible.'; @@ -363,7 +363,6 @@ $_ERRORS['edeb9e20655b946e4bee4ac44a6c0a7f'] = 'Le serveur ne dispose pas des pe $_ERRORS['5d7cc18ef21285f980cbada9adb9df5c'] = 'Le serveur a expiré, le filigrane n\'est peut-être pas été appliqué à toutes vos images.'; $_ERRORS['721b2acc2e54e77e36654bbc42a0747a'] = 'Le système de backup ne gère actuellement que les bases de données MySQL'; $_ERRORS['c45319ee556dc43ba15523c539c7e9d4'] = 'Désolé, nous ne pouvons pas renouveler votre commande'; -$_ERRORS['c3f365ea3ae0b35b814493fc72ff0458'] = 'le fournisseur n\'existe pas'; $_ERRORS['35f55f4e657f542d5f27853332c46f80'] = 'Erreur de syntaxe avec ce motif'; $_ERRORS['19a99b7aed449fbbedc3ce65483d6a3a'] = 'L\'onglet ne peut être trouvé'; $_ERRORS['cae059a6bd57c0b7d289ce097c060ba6'] = 'Le fichier de l\'onglet ne peut être trouvé';