diff --git a/admin-dev/ajax.php b/admin-dev/ajax.php index 1b779c78f..bd380c7f4 100644 --- a/admin-dev/ajax.php +++ b/admin-dev/ajax.php @@ -794,3 +794,32 @@ if (Tools::isSubmit('syncImapMail')) imap_close($mbox); die('{"hasError" : false, "errors" : '.$str_errors.'}'); } + +/* Modify attribute position */ +if (array_key_exists('ajaxAttributesPositions', $_POST)) +{ + $way = (int)(Tools::getValue('way')); + $id_attribute = (int)(Tools::getValue('id_attribute')); + $id_attribute_group = (int)(Tools::getValue('id_attribute_group')); + $positions = Tools::getValue('attribute_'.(int)(Tools::getValue('id_attribute_group'))); + + if (is_array($positions)) + foreach ($positions AS $position => $value) + { + // pos[1] = id_attribute_group, pos[2] = id_attribute, pos[3]=old position + $pos = explode('_', $value); + + if ((isset($pos[1]) AND isset($pos[2])) AND ($pos[1] == $id_attribute_group AND (int)$pos[2] === $id_attribute)) + { + if ($attribute = new Attribute((int)$pos[2])) + if (isset($position) && $attribute->updatePosition($way, $position)) + echo "ok position $position for attribute $pos[2]\r\n"; + else + echo '{"hasError" : true, "errors" : "Can not update attribute '. $id_attribute . ' to position '.$position.' "}'; + else + echo '{"hasError" : true, "errors" : "This attribute ('.$id_attribute.') can t be loaded"}'; + + break; + } + } +} diff --git a/admin-dev/tabs/AdminAttributeGenerator.php b/admin-dev/tabs/AdminAttributeGenerator.php index 0b7040ad1..c76c61a45 100644 --- a/admin-dev/tabs/AdminAttributeGenerator.php +++ b/admin-dev/tabs/AdminAttributeGenerator.php @@ -101,7 +101,7 @@ class AdminAttributeGenerator extends AdminTab private static function displayAndReturnAttributeJs() { - $attributes = Attribute::getAttributes($this->context->language->id, true); + $attributes = Attribute::getAttributes(Context::getContext()->language->id, true); $attributeJs = array(); foreach ($attributes AS $k => $attribute) $attributeJs[$attribute['id_attribute_group']][$attribute['id_attribute']] = $attribute['name']; diff --git a/admin-dev/tabs/AdminAttributes.php b/admin-dev/tabs/AdminAttributes.php index d2bd77d73..0547b7c8a 100644 --- a/admin-dev/tabs/AdminAttributes.php +++ b/admin-dev/tabs/AdminAttributes.php @@ -155,8 +155,19 @@ class AdminAttributes extends AdminTab } elseif (Tools::isSubmit('submitAddattribute')) { + $id_attribute = (int)Tools::getValue('id_attribute'); + // Adding last position to the attribute if not exist + if ($id_attribute <= 0) + { + $sql = 'SELECT `position`+1 + FROM `'._DB_PREFIX_.'attribute` + WHERE id_attribute_group = '.(int)Tools::getValue('id_attribute_group').' + ORDER BY position DESC'; + // set the position of the new attribute in $_POST for postProcess() method + $_POST['position'] = DB::getInstance()->getValue($sql); + } // clean \n\r characters - foreach($_POST as $key => $value) + foreach ($_POST as $key => $value) if (preg_match('/^name_/Ui', $key)) $_POST[$key] = str_replace ('\n', '', str_replace('\r', '', $value)); parent::postProcess(); diff --git a/admin-dev/tabs/AdminAttributesGroups.php b/admin-dev/tabs/AdminAttributesGroups.php index 611a4b493..5022a97e4 100644 --- a/admin-dev/tabs/AdminAttributesGroups.php +++ b/admin-dev/tabs/AdminAttributesGroups.php @@ -109,11 +109,24 @@ class AdminAttributesGroups extends AdminTab if ($this->_list === false) Tools::displayError('No elements found'); - $this->displayListHeader(); + $this->displayListHeader($this->token); echo ''; if (!sizeof($this->_list)) echo '
'.$this->l('The available date when this product is out of stock').'
'; }
+ alt="'.$this->l('Up').'" title="'.$this->l('Up').'" />';
+ }
else
echo (int)($tr[$key] + 1);
}
diff --git a/classes/Attribute.php b/classes/Attribute.php
index 978a74eb5..0f8a6fff3 100644
--- a/classes/Attribute.php
+++ b/classes/Attribute.php
@@ -33,11 +33,12 @@ class AttributeCore extends ObjectModel
/** @var string Name */
public $name;
public $color;
+ public $position;
public $default;
protected $fieldsRequired = array('id_attribute_group');
- protected $fieldsValidate = array('id_attribute_group' => 'isUnsignedId', 'color' => 'isColor');
+ protected $fieldsValidate = array('id_attribute_group' => 'isUnsignedId', 'color' => 'isColor', 'position' => 'isInt');
protected $fieldsRequiredLang = array('name');
protected $fieldsSizeLang = array('name' => 64);
protected $fieldsValidateLang = array('name' => 'isGenericName');
@@ -59,6 +60,7 @@ class AttributeCore extends ObjectModel
$fields['id_attribute_group'] = (int)($this->id_attribute_group);
$fields['color'] = pSQL($this->color);
+ $fields['position'] = (int)($this->position);
return $fields;
}
@@ -88,6 +90,9 @@ class AttributeCore extends ObjectModel
if (Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'product_attribute` WHERE `id_product_attribute` IN ('.implode(', ', $combinationIds).')') === false)
return false;
}
+ /* Reinitializing position */
+ $this->cleanPositions((int)($this->id_attribute_group));
+
return parent::delete();
}
@@ -109,7 +114,7 @@ class AttributeCore extends ObjectModel
LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute_group` = ag.`id_attribute_group`
LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = '.(int)($id_lang).')
'.($notNull ? 'WHERE a.`id_attribute` IS NOT NULL AND al.`name` IS NOT NULL' : '').'
- ORDER BY agl.`name` ASC, al.`name` ASC');
+ ORDER BY agl.`name` ASC, a.`position` ASC');
}
/**
@@ -181,7 +186,7 @@ class AttributeCore extends ObjectModel
{
if (!Db::getInstance()->getRow('
SELECT `is_color_group` FROM `'._DB_PREFIX_.'attribute_group` WHERE `id_attribute_group` = (
- SELECT `id_attribute_group` FROM `'._DB_PREFIX_.'attribute` WHERE `id_attribute` = '.(int)($this->id).')
+ SELECT `id_attribute_group` FROM `'._DB_PREFIX_.'attribute` WHERE `id_attribute` = '.(int)$this->id.')
AND is_color_group = 1'))
return false;
return Db::getInstance()->NumRows();
@@ -199,12 +204,80 @@ class AttributeCore extends ObjectModel
$minimal_quantity = Db::getInstance()->getValue('
SELECT `minimal_quantity`
FROM `'._DB_PREFIX_.'product_attribute`
- WHERE `id_product_attribute` = '.(int)($id_product_attribute));
+ WHERE `id_product_attribute` = '.(int)$id_product_attribute);
if ($minimal_quantity > 1)
return (int)$minimal_quantity;
return false;
}
+
+ /**
+ * Move an attribute inside its group
+ * @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 a.`id_attribute`, a.`position`, a.`id_attribute_group`
+ FROM `'._DB_PREFIX_.'attribute` a
+ WHERE a.`id_attribute_group` = '.(int)Tools::getValue('id_attribute_group', 1).'
+ ORDER BY a.`position` ASC'
+ ))
+ return false;
+
+ foreach ($res AS $attribute)
+ if ((int)$attribute['id_attribute'] == (int)$this->id)
+ $movedAttribute = $attribute;
+
+ if (!isset($movedAttribute) || !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_.'attribute`
+ SET `position`= `position` '.($way ? '- 1' : '+ 1').'
+ WHERE `position`
+ '.($way
+ ? '> '.(int)$movedAttribute['position'].' AND `position` <= '.(int)$position
+ : '< '.(int)$movedAttribute['position'].' AND `position` >= '.(int)$position).'
+ AND `id_attribute_group`='.(int)$movedAttribute['id_attribute_group'])
+ AND Db::getInstance()->Execute('
+ UPDATE `'._DB_PREFIX_.'attribute`
+ SET `position` = '.(int)$position.'
+ WHERE `id_attribute` = '.(int)$movedAttribute['id_attribute'].'
+ AND `id_attribute_group`='.(int)$movedAttribute['id_attribute_group']));
+ }
+ /**
+ * Reorder attribute position in group $id_attribute_group.
+ * Call it after deleting an attribute from a group.
+ *
+ * @param int $id_attribute_group
+ * @return bool $return
+ */
+ public function cleanPositions($id_attribute_group)
+ {
+ $return = true;
+
+ $result = Db::getInstance()->ExecuteS('
+ SELECT `id_attribute`
+ FROM `'._DB_PREFIX_.'attribute`
+ WHERE `id_attribute_group` = '.(int)$id_attribute_group.'
+ AND `id_attribute` != '.(int)$this->id.'
+ ORDER BY `position`');
+ $sizeof = sizeof($result);
+
+ for ($i = 0; $i < $sizeof; $i++)
+ $return &= Db::getInstance()->Execute('
+ UPDATE `'._DB_PREFIX_.'attribute`
+ SET `position` = '.(int)$i.'
+ WHERE `id_attribute_group` = '.(int)$id_attribute_group.'
+ AND `id_attribute` = '.(int)$result[$i]['id_attribute']);
+ return $return;
+ }
+
}
diff --git a/classes/AttributeGroup.php b/classes/AttributeGroup.php
index e990b0205..cc8769cda 100644
--- a/classes/AttributeGroup.php
+++ b/classes/AttributeGroup.php
@@ -142,7 +142,7 @@ class AttributeGroupCore extends ObjectModel
FROM `'._DB_PREFIX_.'attribute` a
LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = '.(int)($id_lang).')
WHERE a.`id_attribute_group` = '.(int)($id_attribute_group).'
- ORDER BY `name`');
+ ORDER BY `position` ASC');
}
/**
diff --git a/classes/Product.php b/classes/Product.php
index 5df83b6ab..829ce7cd8 100644
--- a/classes/Product.php
+++ b/classes/Product.php
@@ -2309,7 +2309,7 @@ class ProductCore extends ObjectModel
WHERE pa.`id_product` = '.(int)($this->id).'
AND al.`id_lang` = '.(int)($id_lang).'
AND agl.`id_lang` = '.(int)($id_lang).'
- ORDER BY agl.`public_name`, al.`name`';
+ ORDER BY agl.`public_name`, a.`position` ASC';
return Db::getInstance()->ExecuteS($sql);
}
diff --git a/controllers/ProductController.php b/controllers/ProductController.php
index 9c3c96a46..892cef7e3 100644
--- a/controllers/ProductController.php
+++ b/controllers/ProductController.php
@@ -318,8 +318,8 @@ class ProductControllerCore extends FrontController
unset($colors[$key]);
}
- foreach ($groups AS &$group)
- natcasesort($group['attributes']);
+ /*foreach ($groups AS &$group) // attributes are now sortable in BO
+ natcasesort($group['attributes']);*/
foreach ($combinations AS $id_product_attribute => $comb)
{
diff --git a/install-dev/sql/db.sql b/install-dev/sql/db.sql
index 9cc807163..7924e752d 100644
--- a/install-dev/sql/db.sql
+++ b/install-dev/sql/db.sql
@@ -83,6 +83,7 @@ CREATE TABLE `PREFIX_attribute` (
`id_attribute` int(10) unsigned NOT NULL auto_increment,
`id_attribute_group` int(10) unsigned NOT NULL,
`color` varchar(32) default NULL,
+ `position` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`id_attribute`),
KEY `attribute_group` (`id_attribute_group`)
) 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 516fa0bdb..a75a28365 100644
--- a/install-dev/sql/db_settings_extends.sql
+++ b/install-dev/sql/db_settings_extends.sql
@@ -309,9 +309,9 @@ INSERT INTO `PREFIX_scene_products` (`id_scene`, `id_product`, `x_axis`, `y_axis
(3, 5, 198, 47, 137, 92),(1, 1, 394, 14, 73, 168),(1, 1, 318, 14, 69, 168),(1, 1, 244, 14, 66, 169),(1, 1, 180, 13, 59, 168),(1, 1, 6, 12, 30, 175),
(1, 1, 38, 12, 30, 170),(1, 1, 76, 14, 41, 169),(1, 1, 123, 13, 49, 169);
-INSERT INTO `PREFIX_attribute` (`id_attribute`, `id_attribute_group`) VALUES (1, 1),(2, 1),(8, 1),(9, 1),(10, 3),(11, 3),(12, 1),(13, 1);
-INSERT INTO `PREFIX_attribute` (`id_attribute`, `id_attribute_group`, `color`) VALUES (3, 2, '#D2D6D5'),(4, 2, '#008CB7'),(5, 2, '#F3349E'),(6, 2, '#93D52D'),
-(7, 2, '#FD9812'),(15, 1, ''),(16, 1, ''),(17, 1, ''),(18, 2, '#7800F0'),(19, 2, '#F6EF04'),(20, 2, '#F60409'),(14, 2, '#000000');
+INSERT INTO `PREFIX_attribute` (`id_attribute`, `id_attribute_group`, `position`) VALUES (1, 1, 0),(2, 1, 1),(8, 1, 2),(9, 1, 3),(10, 3, 0),(11, 3, 1),(12, 1, 4),(13, 1, 5);
+INSERT INTO `PREFIX_attribute` (`id_attribute`, `id_attribute_group`, `color`, `position`) VALUES (3, 2, '#D2D6D5', 0),(4, 2, '#008CB7', 1),(5, 2, '#F3349E', 3),(6, 2, '#93D52D', 4),
+(7, 2, '#FD9812', 5),(15, 1, '', 6),(16, 1, '', 7),(17, 1, '', 8),(18, 2, '#7800F0', 6),(19, 2, '#F6EF04', 7),(20, 2, '#F60409', 8),(14, 2, '#000000', 9);
INSERT INTO `PREFIX_attribute_group_shop` (`id_attribute`, `id_group_shop`) (SELECT `id_attribute`, 1 FROM `PREFIX_attribute`);
diff --git a/install-dev/sql/upgrade/1.5.0.1.sql b/install-dev/sql/upgrade/1.5.0.1.sql
index a1c6db552..08379588c 100644
--- a/install-dev/sql/upgrade/1.5.0.1.sql
+++ b/install-dev/sql/upgrade/1.5.0.1.sql
@@ -137,4 +137,8 @@ CREATE TABLE `PREFIX_customer_message_sync_imap` (
ALTER TABLE `PREFIX_customer_message` ADD `private` TINYINT NOT NULL DEFAULT '0' AFTER `user_agent`;
-/* PHP:add_new_tab(AdminGenders, fr:Genres|es:Genders|en:Genders|de:Genders|it:Genders, 2); */;
\ No newline at end of file
+/* PHP:add_new_tab(AdminGenders, fr:Genres|es:Genders|en:Genders|de:Genders|it:Genders, 2); */;
+
+ALTER TABLE `PREFIX_attribute` ADD `position` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0';
+
+/* PHP:add_attribute_position(); */;
diff --git a/js/admin-dnd.js b/js/admin-dnd.js
index 959f13d06..6d21b7454 100644
--- a/js/admin-dnd.js
+++ b/js/admin-dnd.js
@@ -38,7 +38,6 @@ $(document).ready(function() {
onDragClass: 'myDragClass',
onDrop: function(table, row) {
if (originalOrder != $.tableDnD.serialize()) {
-
var way = (originalOrder.indexOf(row.id) < $.tableDnD.serialize().indexOf(row.id))? 1 : 0;
var ids = row.id.split('_');
var tableDrag = $('#' + table.id);
@@ -92,6 +91,16 @@ $(document).ready(function() {
token: token
};
}
+ if (table.id.indexOf('attribute') != -1) {
+ params = {
+ ajaxAttributesPositions: true,
+ id_attribute_group: ids[1],
+ id_attribute: ids[2],
+ way: way,
+ token: token
+ };
+ }
+
$.ajax({
type: 'POST',
@@ -130,7 +139,7 @@ $(document).ready(function() {
}
else
{
- if (table.id == 'product')
+ if (table.id == 'product' || table.id.indexOf('attribute') != -1)
{
var reg = /_[0-9][0-9]*$/g;
}
@@ -152,8 +161,9 @@ $(document).ready(function() {
$(this).find('td.dragHandle a:even').attr('href', $(this).find('td.dragHandle a:even').attr('href').replace(up_reg, 'position='+ (i + 1) +'&'));
});
- tableDrag.find('tr').not('.nodrag').removeClass('alt_row');
+ tableDrag.find('tr').not('.nodrag').removeClass('alt_row').removeClass('not_alt_row');
tableDrag.find('tr:not(".nodrag"):odd').addClass('alt_row');
+ tableDrag.find('tr:not(".nodrag"):even').addClass('not_alt_row');
tableDrag.find('tr td.dragHandle a:hidden').show();
if (alternate) {