diff --git a/admin-dev/ajax.php b/admin-dev/ajax.php
index ee25cf7b3..bc742000a 100644
--- a/admin-dev/ajax.php
+++ b/admin-dev/ajax.php
@@ -868,3 +868,35 @@ if (array_key_exists('ajaxGroupsAttributesPositions', $_POST))
}
}
}
+
+/* Modify feature position */
+if (array_key_exists('ajaxFeaturesPositions', $_POST))
+{
+ $way = (int)(Tools::getValue('way'));
+ $id_feature = (int)(Tools::getValue('id_feature'));
+ $positions = Tools::getValue('feature');
+
+ $new_positions = array();
+ foreach($positions as $k => $v)
+ if (!empty($v))
+ $new_positions[] = $v;
+
+ foreach ($new_positions AS $position => $value)
+ {
+ // pos[1] = id_feature, pos[2] = old position
+ $pos = explode('_', $value);
+
+ if (isset($pos[1]) AND (int)$pos[1] === $id_feature)
+ {
+ if ($feature = new Feature((int)$pos[1]))
+ if (isset($position) && $feature->updatePosition($way, $position))
+ echo "ok position $position for feature $pos[1]\r\n";
+ else
+ echo '{"hasError" : true, "errors" : "Can not update feature '. $id_attribute_group . ' to position '.$position.' "}';
+ else
+ echo '{"hasError" : true, "errors" : "This feature ('.$id_attribute_group.') can t be loaded"}';
+
+ break;
+ }
+ }
+}
diff --git a/admin-dev/tabs/AdminFeatures.php b/admin-dev/tabs/AdminFeatures.php
index 9d6259542..b7bdd213a 100644
--- a/admin-dev/tabs/AdminFeatures.php
+++ b/admin-dev/tabs/AdminFeatures.php
@@ -40,7 +40,8 @@ class AdminFeatures extends AdminTab
$this->fieldsDisplay = array(
'name' => array('title' => $this->l('Name'), 'width' => 128, 'filter_key' => 'b!name'),
- 'value' => array('title' => $this->l('Values'), 'width' => 255, 'orderby' => false, 'search' => false));
+ 'value' => array('title' => $this->l('Values'), 'width' => 255, 'orderby' => false, 'search' => false),
+ 'position' => array('title' => $this->l('Position'), 'width' => 40,'filter_key' => 'cp!position', 'align' => 'center', 'position' => 'position'));
parent::__construct();
}
@@ -76,12 +77,28 @@ class AdminFeatures extends AdminTab
if (!sizeof($this->_list))
echo '
| '.$this->l('No features found.').' |
';
- $irow = 0;
+
+ echo '
+
+
+
+ ';
+
+ $irow = 0;
+ if ($this->_list AND isset($this->fieldsDisplay['position']))
+ {
+ $positions = array_map(create_function('$elem', 'return (int)$elem[\'position\'];'), $this->_list);
+ sort($positions);
+ }
foreach ($this->_list AS $tr)
{
$id = (int)($tr['id_'.$this->table]);
echo '
-
+
|
'.$tr['name'].' |
@@ -118,6 +135,27 @@ class AdminFeatures extends AdminTab
| ';
+ echo '
+ ';
+
+ if ($this->_orderBy == 'position' AND $this->_orderWay != 'DESC')
+ {
+ echo '
+ ';
+
+ echo '
+ ';
+ }
+ else
+ echo (int)($tr['position'] + 1);
+
+
echo '
|
@@ -194,7 +232,9 @@ class AdminFeatures extends AdminTab
return ;
$this->adminFeaturesValues->tabAccess = Profile::getProfileAccess($this->context->employee->id_profile, $this->id);
- $this->adminFeaturesValues->postProcess($this->token);
+
+ if (Tools::isSubmit('submitAddfeature_value') || Tools::isSubmit('submitDelfeature_value'))
+ $this->adminFeaturesValues->postProcess($this->token);
Module::hookExec('postProcessFeature',
array('errors' => &$this->_errors)); // send _errors as reference to allow postProcessFeature to stop saving process
@@ -216,6 +256,28 @@ class AdminFeatures extends AdminTab
else
$this->_errors[] = Tools::displayError('You do not have permission to delete here.');
}
+ else if (Tools::isSubmit('submitAdd'.$this->table))
+ {
+ if ($this->tabAccess['add'] === '1')
+ {
+ $id_feature = (int)Tools::getValue('id_feature');
+ // Adding last position to the feature if not exist
+ if ($id_feature <= 0)
+ {
+ $sql = 'SELECT `position`+1
+ FROM `'._DB_PREFIX_.'feature`
+ ORDER BY position DESC';
+ // set the position of the new feature in $_POST for postProcess() method
+ $_POST['position'] = DB::getInstance()->getValue($sql);
+ }
+ // clean \n\r characters
+ foreach ($_POST as $key => $value)
+ if (preg_match('/^name_/Ui', $key))
+ $_POST[$key] = str_replace ('\n', '', str_replace('\r', '', $value));
+ parent::postProcess();
+ }
+
+ }
else
parent::postProcess();
}
diff --git a/admin-dev/tabs/AdminImport.php b/admin-dev/tabs/AdminImport.php
index 51e11b0a7..a5237a28d 100644
--- a/admin-dev/tabs/AdminImport.php
+++ b/admin-dev/tabs/AdminImport.php
@@ -179,7 +179,8 @@ class AdminImport extends AdminTab
'label' => $this->l('Delete existing images (0 = no, 1 = yes)'),
'help' => $this->l('If you do not specify this column and you specify the column images, all images of the product will be replaced by those specified in the import file')
),
- 'feature' => array('label' => $this->l('Feature')),
+ 'feature' => array('label' => $this->l('Feature(Name:Position)'),
+ 'help' => $this->l('Position of the feature.')),
'online_only' => array('label' => $this->l('Only available online')),
'condition' => array('label' => $this->l('Condition')),
'shop' => array(
diff --git a/classes/AdminTab.php b/classes/AdminTab.php
index e45ce74c8..1ce618ec9 100644
--- a/classes/AdminTab.php
+++ b/classes/AdminTab.php
@@ -149,7 +149,7 @@ abstract class AdminTabCore
public $smarty;
- protected $identifiersDnd = array('id_product' => 'id_product', 'id_category' => 'id_category_to_move','id_cms_category' => 'id_cms_category_to_move', 'id_cms' => 'id_cms', 'id_attribute' => 'id_attribute', 'id_attribute_group' => 'id_attribute_group');
+ protected $identifiersDnd = array('id_product' => 'id_product', 'id_category' => 'id_category_to_move','id_cms_category' => 'id_cms_category_to_move', 'id_cms' => 'id_cms', 'id_attribute' => 'id_attribute', 'id_attribute_group' => 'id_attribute_group', 'id_feature' => 'id_feature');
/** @var bool Redirect or not ater a creation */
protected $_redirect = true;
@@ -756,6 +756,7 @@ abstract class AdminTabCore
{
$object = new $this->className();
$this->copyFromPost($object, $this->table);
+// d($object);
if (!$object->add())
$this->_errors[] = Tools::displayError('An error occurred while creating object.').' '.$this->table.' ('.Db::getInstance()->getMsgError().')';
elseif (($_POST[$this->identifier] = $object->id /* voluntary */) AND $this->postImage($object->id) AND !sizeof($this->_errors) AND $this->_redirect)
diff --git a/classes/Feature.php b/classes/Feature.php
index cec22af96..cb3ae2d38 100644
--- a/classes/Feature.php
+++ b/classes/Feature.php
@@ -29,6 +29,7 @@ class FeatureCore extends ObjectModel
{
/** @var string Name */
public $name;
+ public $position;
protected $fieldsRequiredLang = array('name');
protected $fieldsSizeLang = array('name' => 128);
@@ -45,7 +46,7 @@ class FeatureCore extends ObjectModel
public function getFields()
{
- return array('id_feature' => NULL);
+ return array('id_feature' => NULL, 'position' => (int)$this->position);
}
/**
@@ -89,7 +90,7 @@ class FeatureCore extends ObjectModel
SELECT *
FROM `'._DB_PREFIX_.'feature` f
LEFT JOIN `'._DB_PREFIX_.'feature_lang` fl ON (f.`id_feature` = fl.`id_feature` AND fl.`id_lang` = '.(int)($id_lang).')
- ORDER BY fl.`name` ASC');
+ ORDER BY f.`position` ASC');
}
/**
@@ -123,9 +124,14 @@ class FeatureCore extends ObjectModel
Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'feature_value` WHERE `id_feature` = '.(int)($this->id));
/* Also delete related products */
Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'feature_product` WHERE `id_feature` = '.(int)($this->id));
+
$return = parent::delete();
if($return)
Module::hookExec('afterDeleteFeature', array('id_feature' => $this->id));
+
+ /* Reinitializing position */
+ $this->cleanPositions();
+
return $return;
}
@@ -225,5 +231,83 @@ class FeatureCore extends ObjectModel
{
return Configuration::get('PS_FEATURE_FEATURE_ACTIVE');
}
+
+ /**
+ * Move a feature
+ * @param boolean $way Up (1) or Down (0)
+ * @param integer $position
+ * @return boolean Update result
+ */
+ public function updatePosition($way, $position)
+ {
+ if (!$res = Db::getInstance()->ExecuteS('
+ SELECT `position`, `id_feature`
+ FROM `'._DB_PREFIX_.'feature`
+ WHERE `id_feature` = '.(int)Tools::getValue('id_feature', 1).'
+ ORDER BY `position` ASC'
+ ))
+ return false;
+
+ foreach ($res AS $feature)
+ if ((int)$feature['id_feature'] == (int)$this->id)
+ $movedFeature = $feature;
+
+ if (!isset($movedFeature) || !isset($position))
+ return false;
+
+ // < and > statements rather than BETWEEN operator
+ // since BETWEEN is treated differently according to databases
+ return (Db::getInstance()->Execute('
+ UPDATE `'._DB_PREFIX_.'feature`
+ SET `position`= `position` '.($way ? '- 1' : '+ 1').'
+ WHERE `position`
+ '.($way
+ ? '> '.(int)$movedFeature['position'].' AND `position` <= '.(int)$position
+ : '< '.(int)$movedFeature['position'].' AND `position` >= '.(int)$position))
+ AND Db::getInstance()->Execute('
+ UPDATE `'._DB_PREFIX_.'feature`
+ SET `position` = '.(int)$position.'
+ WHERE `id_feature`='.(int)$movedFeature['id_feature']));
+ }
+
+ /**
+ * Reorder feature position
+ * Call it after deleting a feature.
+ *
+ * @return bool $return
+ */
+ public static function cleanPositions()
+ {
+ $return = true;
+
+ $sql = '
+ SELECT *
+ FROM `'._DB_PREFIX_.'feature`
+ ORDER BY `position`';
+ $result = Db::getInstance()->ExecuteS($sql);
+ $sizeof = sizeof($result);
+
+ for ($i = 0; $i < $sizeof; $i++)
+ $return = Db::getInstance()->Execute('
+ UPDATE `'._DB_PREFIX_.'feature`
+ SET `position` = '.(int)$i.'
+ WHERE `id_feature` = '.(int)$result[$i]['id_feature']);
+ return $return;
+ }
+
+ /**
+ * getHigherPosition
+ *
+ * Get the higher feature position
+ *
+ * @return integer $position
+ */
+ public static function getHigherPosition()
+ {
+ $sql = 'SELECT `position`
+ FROM `'._DB_PREFIX_.'feature`
+ ORDER BY position DESC';
+ return ((DB::getInstance()->getValue($sql)!==false)) ? DB::getInstance()->getValue($sql) : -1;
+ }
}
diff --git a/classes/Product.php b/classes/Product.php
index 28da3c03a..c311aef49 100644
--- a/classes/Product.php
+++ b/classes/Product.php
@@ -2904,7 +2904,9 @@ class ProductCore extends ObjectModel
FROM '._DB_PREFIX_.'feature_product pf
LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = pf.id_feature AND fl.id_lang = '.(int)$id_lang.')
LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = pf.id_feature_value AND fvl.id_lang = '.(int)$id_lang.')
- WHERE pf.id_product = '.(int)$id_product);
+ LEFT JOIN '._DB_PREFIX_.'feature f ON (f.id_feature = pf.id_feature AND fl.id_lang = '.(int)$id_lang.')
+ WHERE pf.id_product = '.(int)$id_product.'
+ ORDER BY f.position ASC');
}
return self::$_frontFeaturesCache[$id_product.'-'.$id_lang];
}
diff --git a/install-dev/php/add_feature_position.php b/install-dev/php/add_feature_position.php
new file mode 100644
index 000000000..824185943
--- /dev/null
+++ b/install-dev/php/add_feature_position.php
@@ -0,0 +1,42 @@
+
+* @copyright 2007-2011 PrestaShop SA
+* @version Release: $Revision: 6844 $
+* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
+* International Registered Trademark & Property of PrestaShop SA
+*/
+
+function add_feature_position()
+{
+ $features = Db::getInstance()->ExecuteS('
+ SELECT `id_feature`
+ FROM `'._DB_PREFIX_.'feature`');
+ $i = 0;
+ if (sizeof($features) && is_array($features))
+ foreach ($features as $feature)
+ {
+ Db::getInstance()->Execute('
+ UPDATE `'._DB_PREFIX_.'feature`
+ SET `position` = '.$i++.'
+ WHERE `id_feature` = '.(int)$feature['id_feature']);
+ }
+}
\ No newline at end of file
diff --git a/install-dev/sql/db.sql b/install-dev/sql/db.sql
index d67ec85c9..4840df4cd 100644
--- a/install-dev/sql/db.sql
+++ b/install-dev/sql/db.sql
@@ -641,6 +641,7 @@ CREATE TABLE `PREFIX_employee` (
CREATE TABLE `PREFIX_feature` (
`id_feature` int(10) unsigned NOT NULL auto_increment,
+ `position` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`id_feature`)
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
diff --git a/install-dev/sql/db_settings_extends.sql b/install-dev/sql/db_settings_extends.sql
index 2e8de2a5a..8d25424df 100644
--- a/install-dev/sql/db_settings_extends.sql
+++ b/install-dev/sql/db_settings_extends.sql
@@ -371,7 +371,7 @@ INSERT INTO `PREFIX_product_attribute_combination` (`id_attribute`, `id_product_
(4, 26),(5, 10),(5, 35),(5, 36),(6, 8),(6, 39),(6, 40),(7, 33),(7, 34),(8, 13),(8, 15),(9, 12),(9, 14),(10, 12),(10, 13),(11, 14),(11, 15),(14, 31),(14, 32),(15, 19),
(15, 26),(15, 28),(15, 30),(15, 32),(15, 34),(15, 36),(15, 40),(15, 42),(16, 22),(16, 25),(16, 27),(16, 29),(16, 31),(16, 33),(16, 35),(16, 39),(16, 41),(17, 23),(18, 41),(18, 42),(19, 27),(19, 28);
-INSERT INTO `PREFIX_feature` (`id_feature`) VALUES (1), (2), (3), (4), (5);
+INSERT INTO `PREFIX_feature` (`id_feature`, `position`) VALUES (1, 0), (2, 1), (3, 2), (4, 3), (5, 4);
INSERT INTO `PREFIX_feature_group_shop` (`id_feature`, `id_group_shop`) (SELECT `id_feature`, 1 FROM PREFIX_feature);
diff --git a/install-dev/sql/upgrade/1.5.0.1.sql b/install-dev/sql/upgrade/1.5.0.1.sql
index b13a1afb6..3074f795f 100644
--- a/install-dev/sql/upgrade/1.5.0.1.sql
+++ b/install-dev/sql/upgrade/1.5.0.1.sql
@@ -151,3 +151,7 @@ ALTER TABLE `PREFIX_product_download` ADD `is_shareable` TINYINT( 1 ) UNSIGNED N
ALTER TABLE `PREFIX_attribute_group` ADD `position` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0';
/* PHP:add_group_attribute_position(); */;
+
+ALTER TABLE `PREFIX_feature` ADD `position` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0';
+
+/* PHP:add_feature_position(); */;
diff --git a/js/admin-dnd.js b/js/admin-dnd.js
index db967d577..314ea79ac 100644
--- a/js/admin-dnd.js
+++ b/js/admin-dnd.js
@@ -110,6 +110,15 @@ $(document).ready(function() {
}
}
+ if (table.id == 'feature') {
+ params = {
+ ajaxFeaturesPositions: true,
+ id_feature : ids[1],
+ way: way,
+ token: token
+ }
+ }
+
$.ajax({
type: 'POST',
async: false,
@@ -147,7 +156,7 @@ $(document).ready(function() {
}
else
{
- if (table.id == 'product' || table.id.indexOf('attribute') != -1 || table.id == 'attribute_group')
+ if (table.id == 'product' || table.id.indexOf('attribute') != -1 || table.id == 'attribute_group' || table.id == 'feature')
{
var reg = /_[0-9][0-9]*$/g;
}
diff --git a/themes/prestashop/order-opc-new-account.tpl b/themes/prestashop/order-opc-new-account.tpl
index 2170c75ff..5c77c9753 100644
--- a/themes/prestashop/order-opc-new-account.tpl
+++ b/themes/prestashop/order-opc-new-account.tpl
@@ -44,7 +44,7 @@
- |