Пытаюсь сделать для одного из своих проектов «иерархическое дерево» (по сути аналог
jQuery Treeview,
jsTree и тому подобных плагинов), в котором также задействован функционал drag & drop. Для задействования возможности drag & drop использую
jQuery UI. Всё вроде получается, но застопорился на одном моменте.
Лирическое отступление: да, я знаю что это по сути написание велосипеда, и что можно не париться и взять один из распространённых плагинов, но для меня важно научиться делать разные фишки на jQuery с drag & drop, потому что он ещё много где нужен будет в моём проекте.
Значит что имеем. Есть ненумерованный список <ul></ul> элементы которого представляют собой категории. У категорий могут быть подкатегории, а у тех, в свою очередь, свои подкатегории и т.д. Если у категории есть подкатегории, то слева от неё отображается иконка «плюсик», нажав на который, произойдёт запрос на сервер и в ответ мы получим необходимый список подкатегорий, который автоматически вставится в виде подсписка, т.е. вот так:
<ul><br>
<li class="categories close" id="cat1" rel="1">category A</li><br>
<li class="categories open" id="cat2" rel="2">category B</li><br>
<ul id="p2"><br>
<li class="categories" id="cat4" rel="4">subcategory D</li><br>
<li class="categories" id="cat5" rel="5">subcategory E</li><br>
<li class="categories" id="cat6" rel="6">subcategory F</li><br>
</ul><br>
<li class="categories close" id="cat3" rel="3">category C</li><br>
</ul><br>
Лирическое отступление: да, я знаю что по правилам синтаксиса HTML подсписок <ul id=«p2»></ul> должен находится внутри родительского элемента <li></li>, но в таком случае вместе с категорией «category B» будет таскаться за курсором и весь подсписок подкатегорий, чего мы никак не хотим.
С помощью jQuery UI я делаю каждый элемент <li></li> «перетаскиваемым» (draggable), и одновременно «принимающим» (droppable).
Дальше я по задумке хочу сделать следующим образом: пользователь захватывает и начинает «таскать» категорию над списком других категорий; как только таскаемый им элемент оказывается над одной из категорий, происходит запрос на сервер, мы получаем и вставляем список подкатегорий. Делается это для того, чтобы облегчить жизнь пользователю: если пользователь хочет сделать категорию «category C» подразделом «subcategory F», то ему будет достаточно захватить «category C», задержать её над «category B» чтобы открылся список подкатегорий, после чего перетащить и отпустить над «subcategory F».
Всё вроде получается отлично, но есть одно
НО, на котором я и застопорился: пользователь захватывает «category C» и держит её над «category B», тем самым заставляя открытся список подкатегорий; в момент появления списка подкатегорий, удерживаемый элемент «category C» уезжает вниз относительно курсора ровно на высоту всего подсписка категорий. Именно эту проблему мне не удаётся пока побороть.
Как я пытался решить эту проблему:
1) в момент вызова функции
over (вызывается когда draggable-элемент находится над droppable-элементом и находится в состоянии готовности) пробовал запоминать позицию перетаскиваемого элемента в глобальных переменных вот так:
...<br>
over:function(event,ui) {<br>
_cury = ui.position.top;<br>
_curx = ui.position.left;<br>
...<br>
}<br>
...<br>
после этого запрашивать список подкатегорий и уже после их вставки заново присваивать перетаскиваемому элементу координаты:
...<br>
ui.position.top = _cury;<br>
ui.position.left = _curx;<br>
...<br>
В итоге не сработало.
2) я подумал, что возможно в момент появления подсписка и соответственно «отпрыгивания» перетаскиваемого элемента, он уходит из состояния готовности и вызывается функция
out. Тогда я просто перенёс задание запомненных координат в функцию
out:
...<br>
out:function(event,ui) {<br>
ui.position.top = _cury;<br>
ui.position.left = _curx;<br>
...<br>
}<br>
...<br>
Это тоже не сработало. Также пробовал использовать
ui.offset вместо
ui.position — тоже не помогло. Т.е. получение координат перетаскиваемого элемента происходит нормально, корректно. А вот попытка задать их обратно не приводит ни к каким результатам. Может кто подскажет решение?
Скачать полный код примера со всеми файлами и подробными комментариями.
Смотреть
пример онлайн.