Drag-n-drop группировка элементов по нескольким параметрам одновременно — sortable, а так же «Ленивый градиент»
Ожидает приглашения
Пару дней назад задумался о том, чтобы облегчить задачу сортировки по группам (параметрам), как только можно проще.
И как не странно решение было реализовано на стороне клиента.
Прочитав статью, мне сразу стало понятно в каком русле мне требуется двигаться.
Набравшись терпением я сел писать код. вот результат: демо.
Вот исходный код который у меня получился:
В результате получится многомерный массив, типа такого:
Где: idX — номер группы (у меня первая группа начинается с 1),
el6ments — массив с элементами в группе,
id — уникальный кодификатор в БД,
idY — позиция в группе (у меня первая группа начинается с 0).
На серверной же стороне это будет выглядеть примерно так:
Для визуализации я использовал обычный
Как оказалось, мене сложно подбирать градиент, тк я не дизайнер. Поэтому я написал свою функцию, которую я назвал "Ленивый градиент", все что только нужно — это заменить RGB цвета на свои.
Прототипом данной функции являлся простой php скрипт:
Успехов вам!
И как не странно решение было реализовано на стороне клиента.
Прочитав статью, мне сразу стало понятно в каком русле мне требуется двигаться.
Набравшись терпением я сел писать код. вот результат: демо.
Вот исходный код который у меня получился:
index.html
Немного пояснений: <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Sortable - Default functionality</title>
<script src="//code.jquery.com/jquery-1.9.1.js"></script>
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<style id="mainStyle">
#TableSortable ul {
top:0px;
min-height:50px;
list-style-type: none;
margin: 0 0 auto 0;
padding: 0;
width: 100%;
border:0px solid #000;
cursor: move;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}
#TableSortable tr td:last-child ul:before{
content:'+ Новая группа';margin:20px 10px;
text-shadow: 1px 1px 1px black;
}
#TableSortable tr td:last-child ul {
border:1px dashed #597BA5;
background-color:#A3B6C9;
color: #EFF1F3;
text-decoration: none;
font-size: 40px;
font-family: helvetica, arial;
font-weight: bold;
display: block;
text-align: left;
/* BOX SHADOW */
-moz-box-shadow: 0 1px 3px black;
-webkit-box-shadow: 0 1px 3px black;
box-shadow: 0 1px 3px black;
}
#TableSortable ul li {
border:1px solid #666;
border-radius:5px;
margin: 0 3px 3px 3px;
padding: 0.4em;
padding-left: 1.5em;
font-size: 1.4em;
min-height: 18px;
z-index:0;
}
#TableSortable ul li span {
position: absolute; margin-left: -1.3em;
z-index:1;
}
#TableSortable ul li div#noTextSelect {
position: absolute;
z-index:2;
width:100%;
height:100%;
border:none;
margin:-0.4em -0.4em -0.4em -1.5em;
}
#TableSortable .element {
line-height: 70%;
color: white;
text-decoration: none;
font-size: 25px;
font-family: helvetica, arial;
font-weight: bold;
display: block;
text-align: left;
position: relative;
border: 1px solid rgb(255,255,255);
/* BORDER RADIUS */
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
/* TEXT SHADOW */
text-shadow: 1px 1px 1px black;
/* BOX SHADOW */
-moz-box-shadow: 0 1px 3px black;
-webkit-box-shadow: 0 1px 3px black;
box-shadow: 0 1px 3px black;
}
/* WHILE BEING CLICKED */
#TableSortable .element:active {
-moz-box-shadow: 0 2px 6px black;
-webkit-box-shadow: 0 2px 6px black;
}
</style>
<script type = "text/javascript">
var blockTable = 'TableSortable';
var idElement = 'sortable';
var QGroup = 0;
function scanGroup(id){
var arr = [],
i = 0;
$('#'+idElement+id).children().each(function() {
arr.push( { 'id' : this.id, 'idY': i++ } ); //и заносим в массив id текущего элемента
});
arr = { 'idX' : id, 'elements': arr };
return arr;
}
//добавляет новую свободную группу
function addNewGroup(){
var id = QGroup+1;
var appendTr = '<td valign="top" id="td'+id+'"><ul id="'+idElement+id+'"></ul></td>';
$('#'+blockTable+' tr').html($('#'+blockTable+' tr').html() + appendTr);
sartSelector();
elementGradient(id);
}
//функция пробегает по всем группам начиная с указанной
//смещает группу на денницу влево и сканирует ее
function bustGroup(idStart){
var arr = [];
var result = '';
for(var id = idStart; id <= QGroup; id++){
$('#'+idElement+id).attr('id',idElement+(id-1));
$('#'+blockTable+' #td'+id).attr('id','td'+(id-1));
if(id != QGroup){
result = scanGroup(id-1);
arr.push( result );
}
}
return arr;
}
//удаляем элемент
function delEmptyGroup(id){
var arr = [];
var result = '';
//если это предпоследняя группа
if(id != QGroup-1){
$('#'+blockTable+' #td'+id).remove();
result = bustGroup(id + 1);
arr.push( result );
}else{
$('#'+blockTable+' #td'+QGroup).remove();
}
sartSelector();
return arr;
}
//запоминаем все измененные группы
var bufferTableSortable = [];
function setBuffer(element){
bufferTableSortable[bufferTableSortable.length]=element;
if(element == QGroup){
addNewGroup();
}
}
function submitAjax(){
var bufferLangth = bufferTableSortable.length;
if(bufferLangth > 0){
var arr = [],
arr1 = [],
arr2 = [],
result = null,
groupe = 0;
//перебираем массив затронутых групп
for(var i=0; i < bufferLangth; i++){
groupe = bufferTableSortable[i];
if($('#'+idElement+groupe).children().length == 0){
arr1 = delEmptyGroup(groupe);
if(bufferLangth > 1){
if( groupe < bufferTableSortable[(i+1)]){
break;
}
}
}else{
result = scanGroup(groupe);
arr2.push( result );
}
}
arr = arr1.concat(arr2);
//alert(JSON.stringify(arr[0]));
alert(JSON.stringify(arr));
bufferTableSortable =[];
}
}
//Функция для супер ленивых верстальщиков
//генерирует цвета градиента относительно основного цвета
function elementGradient(id){
//массив расцветки элементов
var rgb=[
"72,116,203",
"201,160,75",
"111,201,111",
"222,33,222"
];
//длина массива расцветок
var rgbLength=rgb.length;
var idRgb = id-1;
if(idRgb >= rgbLength){
idRgb = idRgb % rgbLength;
}else{
idRgb = idRgb;
}
var sep = ',';
rgb=rgb[idRgb].split(sep);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
//Вычисляем градиент
var rgb1 = Math.abs(r) + sep + Math.abs(g) + sep + Math.abs(b);
var rgb2 = Math.abs(r-33) + sep + Math.abs(g-36) + sep + Math.abs(b-38);
var rgb3 = Math.abs(r-26) + sep + Math.abs(g-31) + sep + Math.abs(b-51);
var rgb4 = Math.abs(r-44) + sep + Math.abs(g-44) + sep + Math.abs(b-59);
var rgb1_2 = Math.abs(r-20) + sep + Math.abs(g-20) + sep + Math.abs(b-20);
var rgb2_2 = Math.abs(r-33-20) + sep + Math.abs(g-36-20) + sep + Math.abs(b-38-20);
var rgb3_2 = Math.abs(r-26-20) + sep + Math.abs(g-31-20) + sep + Math.abs(b-51-20);
var rgb4_2 = Math.abs(r-44-20) + sep + Math.abs(g-44-20) + sep + Math.abs(b-59-20);
if(true){//css - чтоб можно было свернуть этот большой блок в редакторе
var css = '\
#'+blockTable+' #'+idElement+id+' .element {\
/* BACKGROUND GRADIENTS */\
background: rgb('+rgb1+');\
background: -moz-linear-gradient(top,\
rgb('+rgb1+'),\
rgb('+rgb2+') 50%,\
rgb('+rgb3+') 51%,\
rgb('+rgb4+'));\
background: -webkit-gradient(linear, left top, left bottom,\
color-stop(0, rgb('+rgb1+')),\
color-stop(.5, rgb('+rgb2+')),\
color-stop(.5, rgb('+rgb3+')),\
to( rgb('+rgb4+')));\
border: 1px solid rgb(255,255,255);\
border-top: 1px solid rgb(255,255,255);\
}\
/* WHILE HOVERED */\
#'+blockTable+' #'+idElement+id+' .element:hover {\
background: rgb('+rgb1_2+');\
background: -moz-linear-gradient(top,\
rgb('+rgb1_2+'),\
rgb('+rgb2_2+') 50%,\
rgb('+rgb3_2+') 51%,\
rgb('+rgb4_2+'));\
background: -webkit-gradient(linear, left top, left bottom,\
color-stop(0, rgb('+rgb1_2+')),\
color-stop(.5, rgb('+rgb2_2+')),\
color-stop(.5, rgb('+rgb3_2+')),\
to( rgb('+rgb4_2+')));\
}';
}
var head = document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
function sartSelector(){
//Выбираем все сортируемые группы
var qElement = document.querySelectorAll('#'+blockTable+' ul');
var qElementLength =qElement.length;
//проходим по каждой группе
for(var i=0; i < qElementLength; i++) {
//Запускаем все группы
$(function() {
$( '#'+qElement[i].id ).sortable({
connectWith: qElement,
update: function(event, ui) {setBuffer(parseInt(this.id.replace(/[^\d]*/,'')));},
stop: function(event, ui) {submitAjax();}
});
});
}
//равномерная ширина столбцов таблицы
$('#'+blockTable+' td').width(''+(100 / qElementLength) +'%');
QGroup = qElementLength;
}
window.onload=function(){
sartSelector();
//проходим по каждой группе
for(var i=1; i <= QGroup; i++) {
//применяем стили
elementGradient(i);
}
}
//http://habrahabr.ru/post/124013/
//http://jqueryui.com/demos/sortable/
//http://slyweb.ru/jquerydoc/sortable-options.php - русская документация
</script>
</head>
<body>
<table width="100%" height="100%" border="0" cellspacing="0" cellpadding="0" id="TableSortable">
<tr id='1235'>
<td valign="top" id="td1">
<ul id="sortable1">
<li class="ui-state-default element" id='1'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Техника</li>
<li class="ui-state-default element" id='2'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Телефон</li>
<li class="ui-state-default element" id='3'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Планшет</li>
<li class="ui-state-default element" id='4'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Ноутбук</li>
<li class="ui-state-default element" id='5'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>ВебКамера</li>
<li class="ui-state-default element" id='6'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Фотоаппарат</li>
<li class="ui-state-default element" id='7'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Плеер</li>
</ul>
</td>
<td valign="top" id="td2">
<ul id="sortable2">
<li class="ui-state-default element" id='19'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Быт.Приборы</li>
<li class="ui-state-default element" id='25'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Стиральная машина</li>
<li class="ui-state-default element" id='34'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Посудомойка</li>
<li class="ui-state-default element" id='15'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Пылесос</li>
<li class="ui-state-default element" id='12'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Обогреватель</li>
<li class="ui-state-default element" id='18'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Фен</li>
</ul>
</td>
<td valign="top" id="td3">
<ul id="sortable3">
<li class="ui-state-default element" id='31'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Кухня</li>
<li class="ui-state-default element" id='81'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Кофеварка</li>
<li class="ui-state-default element" id='27'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Блендер</li>
<li class="ui-state-default element" id='29'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Печка</li>
<li class="ui-state-default element" id='35'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Микроволновка</li>
<li class="ui-state-default element" id='36'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Чайник</li>
<li class="ui-state-default element" id='47'><div id="noTextSelect"></div><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Холодильник</li>
</ul>
</td>
<td valign="top" id="td4">
<ul id="sortable4">
</ul>
</td>
</tr>
</table>
<div id="info"></div>
</body>
</html>
В результате получится многомерный массив, типа такого:
[{"idX":1,"el6ments":[{"id":"19","idY":0},{"id":"25","idY":l}, {"id":"15","idY":2},{"id":"12","idY":3},{"id":"18","idY":4}]}]
Где: idX — номер группы (у меня первая группа начинается с 1),
el6ments — массив с элементами в группе,
id — уникальный кодификатор в БД,
idY — позиция в группе (у меня первая группа начинается с 0).
На серверной же стороне это будет выглядеть примерно так:
mysql_query("UPDATE `table` SET `idX`=1,`idY`=0 WHERE `id`=19");
Для визуализации я использовал обычный
alert();
, который нужно заменить на обычный ajax и с этой задачей я думаю вы справитесь.Как оказалось, мене сложно подбирать градиент, тк я не дизайнер. Поэтому я написал свою функцию, которую я назвал "Ленивый градиент", все что только нужно — это заменить RGB цвета на свои.
Ленивый градиент
//Функция для супер ленивых верстальщиков
//генерирует цвета градиента относительно основного цвета
function elementGradient(id){
//массив расцветки элементов
var rgb=[
"72,116,203",
"201,160,75",
"111,201,111",
"222,33,222"
];
//длина массива расцветок
var rgbLength=rgb.length;
var idRgb = id-1;
if(idRgb >= rgbLength){
idRgb = idRgb % rgbLength;
}else{
idRgb = idRgb;
}
var sep = ',';
rgb=rgb[idRgb].split(sep);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
//Вычисляем градиент
var rgb1 = Math.abs(r) + sep + Math.abs(g) + sep + Math.abs(b);
var rgb2 = Math.abs(r-33) + sep + Math.abs(g-36) + sep + Math.abs(b-38);
var rgb3 = Math.abs(r-26) + sep + Math.abs(g-31) + sep + Math.abs(b-51);
var rgb4 = Math.abs(r-44) + sep + Math.abs(g-44) + sep + Math.abs(b-59);
var rgb1_2 = Math.abs(r-20) + sep + Math.abs(g-20) + sep + Math.abs(b-20);
var rgb2_2 = Math.abs(r-33-20) + sep + Math.abs(g-36-20) + sep + Math.abs(b-38-20);
var rgb3_2 = Math.abs(r-26-20) + sep + Math.abs(g-31-20) + sep + Math.abs(b-51-20);
var rgb4_2 = Math.abs(r-44-20) + sep + Math.abs(g-44-20) + sep + Math.abs(b-59-20);
if(true){//css - чтоб можно было свернуть этот большой блок в редакторе
var css = '\
#'+blockTable+' #'+idElement+id+' .element {\
/* BACKGROUND GRADIENTS */\
background: rgb('+rgb1+');\
background: -moz-linear-gradient(top,\
rgb('+rgb1+'),\
rgb('+rgb2+') 50%,\
rgb('+rgb3+') 51%,\
rgb('+rgb4+'));\
background: -webkit-gradient(linear, left top, left bottom,\
color-stop(0, rgb('+rgb1+')),\
color-stop(.5, rgb('+rgb2+')),\
color-stop(.5, rgb('+rgb3+')),\
to( rgb('+rgb4+')));\
border: 1px solid rgb(255,255,255);\
border-top: 1px solid rgb(255,255,255);\
}\
/* WHILE HOVERED */\
#'+blockTable+' #'+idElement+id+' .element:hover {\
background: rgb('+rgb1_2+');\
background: -moz-linear-gradient(top,\
rgb('+rgb1_2+'),\
rgb('+rgb2_2+') 50%,\
rgb('+rgb3_2+') 51%,\
rgb('+rgb4_2+'));\
background: -webkit-gradient(linear, left top, left bottom,\
color-stop(0, rgb('+rgb1_2+')),\
color-stop(.5, rgb('+rgb2_2+')),\
color-stop(.5, rgb('+rgb3_2+')),\
to( rgb('+rgb4_2+')));\
}';
}
var head = document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
Прототипом данной функции являлся простой php скрипт:
Скрипт
<?php
$rgb="222,33,33";
$sep=',';
$rgb=explode($sep, $rgb);
$r=$rgb[0];
$g=$rgb[1];
$b=$rgb[0];
$rgb1=abs($r).$sep.abs($g).$sep.abs($b);
$rgb2=abs($r-33).$sep.abs($g-36).$sep.abs($b-38);
$rgb3=abs($r-26).$sep.abs($g-31).$sep.abs($b-51);
$rgb4=abs($r-44).$sep.abs($g-44).$sep.abs($b-59);
$rgb1_2=abs($r-20).$sep.abs($g-20).$sep.abs($b-20);
$rgb2_2=abs($r-33-20).$sep.abs($g-36-20).$sep.abs($b-38-20);
$rgb3_2=abs($r-26-20).$sep.abs($g-31-20).$sep.abs($b-51-20);
$rgb4_2=abs($r-44-20).$sep.abs($g-44-20).$sep.abs($b-59-20);
echo " #TableSortable #sortable1 .element {
/* BACKGROUND GRADIENTS */
background: rgb($rgb1);
background: -moz-linear-gradient(top,
rgb($rgb1),
rgb($rgb2) 50%,
rgb($rgb3) 51%,
rgb($rgb4));
background: -webkit-gradient(linear, left top, left bottom,
color-stop(0, rgb($rgb1)),
color-stop(.5, rgb($rgb2)),
color-stop(.5, rgb($rgb3)),
to( rgb($rgb4)));
border: 1px solid rgb(255,255,255);
border-top: 1px solid rgb(255,255,255);
/**/
}
/* WHILE HOVERED */
#TableSortable #sortable1 .element:hover {
background: rgb($rgb1_2);
background: -moz-linear-gradient(top,
rgb($rgb1_2),
rgb($rgb2_2) 50%,
rgb($rgb3_2) 51%,
rgb($rgb4_2));
background: -webkit-gradient(linear, left top, left bottom,
color-stop(0, rgb($rgb1_2)),
color-stop(.5, rgb($rgb2_2)),
color-stop(.5, rgb($rgb3_2)),
to( rgb($rgb4_2)));
}";
?>
Успехов вам!