В свое время приходилось реализовывать кучу drag and drop'ов под самым разным соусом.
Эта статья представляет собой учебник-выжимку о том, как организовать drag'n'drop в javascript, начиная от основ и заканчивая готовым фреймворком.
Кроме того, почти все javascript-библиотеки реализуют drag and drop так, как написано (в статье дано несколько разных вариантов, не факт что ваш фреймворк использует лучший). Зная, что и как, вы сможете поправить и адаптировать существующую библиотеку под себя.
Drag'n'drop в свое время был замечательным открытием в области интерфейсов, которое позволило упростить большое количество операций.
Одно из самых очевидных применений drag'n'drop - переупорядочение данных. Это могут быть блоки, элементы списка, и вообще - любые DOM-элементы и их наборы.
Перенос мышкой может заменить целую последовательность кликов. И, самое главное, он упрощает внешний вид интерфейса: функции, реализуемые через drag'n'drop, в ином случае потребовали бы дополнительных полей, виджетов и т.п.
Организовать перенос элементов по странице - довольно просто. Для этого нужно:
При помощи события mouseDown отследить клик на переносимом элементе
При каждом движении мыши в обработчике события mouseMove передвигать переносимый элемент по странице.
При отпускании кнопки мыши, то есть наступлении события mouseUp - остановить перенос элемента и произвести все действия, связанные с окончанием drag and drop.
При обработке событий, связанных с мышью, нужен кроссбраузерный способ получения координат курсора из события в обработчике. Кроме того, необходимо знать нажатую кнопку мыши.
Для этого будем использовать свойства which и pageX/pageY, полное описание и механизмы кросс-браузерной реализации которых есть в статье по свойствам объекта событие.
which
кнопка мыши - 1: левая, 2: средняя, 3: правая
pageX/pageY
координаты курсора относительно верхнего-левого угла документа (с учетом прокрутки)
Кроссбраузерно ставить эти свойства на объект будет функция fixEvent (по статье свойства объекта событие):
function fixEvent(e) {
// получить объект событие для IE
e = e || window.event
// добавить pageX/pageY для IE
if ( e.pageX == null && e.clientX != null ) {
var html = document.documentElement
var body = document.body
e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0)
e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0)
}
// добавить which для IE
if (!e.which && e.button) {
e.which = e.button & 1 ? 1 : ( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) )
}
return e
}
В этом коде e.which проходит кросс-браузерную обработку, чтобы корректно отражать нажатую кнопку мыши. Вы можете подробно прочитать об этом в статье Свойства объекта событие.
На демке ниже обработчик mouseMove отслеживает координаты курсора мыши относительно левого-верхнего угла страницы, используя кроссбраузерную обертку fixEvent.
Чтобы начать перенос элемента, мы должны отловить нажатие кнопки мыши на объекте.
Для этого нам пригодится событие mousedown. Повесим обработчик на те элементы, которые хотим сделать доступными для переноса.
Пока этот обработчик будет запоминать объект в глобальной переменной dragObject
element.onmousedown = function(e){
// запомнить переносимый объект
// в переменной dragObject
dragObject = this
// остановить обработку события
return false
}
Остановить обработку события return false очень важно - иначе браузер может запустить свои механизмы перетаскивания элементов и все нам поломать.
В случае с отпусканием кнопки мыши все проще - объект мы уже знаем, так что можно повесить один обработчик onmouseup на document.
При нажатии на элемент он запоминается и выделяется.
Выделение(запоминание) действует на все время, когда нажата кнопка мыши, в том числе при перемещении курсора.
Остается добавить визуальное перемещение элемента - и drag and drop заработает.
Оптимизация onmousedown
Иногда бывает, что объектов, которые могут быть перенесены, много. Например, это ячейка таблицы или длинный список, или дерево статей с массой узлов.
Тогда время инициализации можно сильно сократить, если назначать обработчик onmousedown не на каждый объект переноса, а на контейнер. И уже в самом обработчике по event.target определять, где произошел клик.
Перед дальнейшим развитием проведем реорганизацию кода.
Используем способ описания объекта без new (описан здесь как фабрика объектов), чтобы объявить объект dragMaster, предоставляющий необходимый функционал и отслеживающий перенос.
var dragMaster = (function() {
// private методы и свойства
var dragObject
function mouseDown(e) {
клик на переносимом элементе: начать перенос
}
function mouseMove(e){
if (dragObject) {
отобразить перенос объекта
}
}
function mouseUp(e){
if (dragObject) {
конец переноса
}
}
// public методы и свойства
return {
init: function() {
// инициализовать контроллер
document.onmousemove = mouseMove
document.onmouseup = mouseUp
},
makeDraggable: function(element){
// сделать элемент переносимым
element.onmousedown = mouseDown
}
}
}())
При таком способе задания объекта dragMaster получает публичные свойства (например, makeDraggable), которые имеют доступ к приватным переменным и методам mouse*, dragObject, так как являются вложенными функциями.
Полученный код:
Не загрязняет глобальную область видимости переменными типа dragObject.
Дает единый объект-синглтон dragMaster, управляющий переносом.
Приватные переменные хорошо сжимаются javascript-компрессором, что убыстряет и уменьшает код.
Последний пункт очень важен, так как обработчики mouseMove, mouseUp вызываются при каждом передвижении мыши и поднятии кнопки соответственно. Если mouseMove будет работать медленно, то передвижение курсора станет рваным, заметно тормозным.
На это натыкались многие писатели drag'n'drop приложений. Мы же будем изначально закладывать производительность во все критические участки кода.
Для того, чтобы перенести элемент, ему нужно поставить значение CSS-свойства position в absolute. Тогда он будет позиционироваться относительно верхнего-левого угла документа (точнее говоря, относительно ближайшего родителя, у которого position - relative/absolute, но у нас таких нет), и установка CSS-свойств left и top в координаты курсора мыши поместит левый-верхний угол элемента непосредственно под указатель.
Для перемещения элемента нам достаточно всего-лишь обновлять значения left/top при каждом движении мыши mousemove!
Посетитель обычно кликает не в левый-верхний угол, а куда угодно на элементе.
Поэтому чтобы элемент не прилипал к курсору верхним-левым углом, к позиции элемента необходимо добавить смещение мыши на момент клика.
На рисунке ниже mouseX/mouseY - координаты курсора мыши, а positionX/positionY - координаты верхнего-левого угла элемента, которые легко получить из DOM:
Это изначальное смещение мы запоминаем при клике, прибавляем его при начале движения и сохраняем в дальнейшем.
Тогда позиция элемента относительно курсора мыши будет все время одной и той же.
var dragMaster = (function() {
var dragObject
var mouseOffset
// получить сдвиг target относительно курсора мыши
function getMouseOffset(target, e) {
var docPos = getPosition(target)
return {x:e.pageX - docPos.x, y:e.pageY - docPos.y}
}
function mouseUp(){
dragObject = null
// очистить обработчики, т.к перенос закончен
document.onmousemove = null
document.onmouseup = null
document.ondragstart = null
document.body.onselectstart = null
}
function mouseMove(e){
e = fixEvent(e)
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
return false
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
dragObject = this
// получить сдвиг элемента относительно курсора мыши
mouseOffset = getMouseOffset(this, e)
// эти обработчики отслеживают процесс и окончание переноса
document.onmousemove = mouseMove
document.onmouseup = mouseUp
// отменить перенос и выделение текста при клике на тексте
document.ondragstart = function() { return false }
document.body.onselectstart = function() { return false }
return false
}
return {
makeDraggable: function(element){
element.onmousedown = mouseDown
}
}
}())
function getPosition(e){
var left = 0
var top = 0
while (e.offsetParent){
left += e.offsetLeft
top += e.offsetTop
e = e.offsetParent
}
left += e.offsetLeft
top += e.offsetTop
return {x:left, y:top}
}
В коде появилась новая функция getPosition(элемент) - она получает абсолютные координаты верхнего-правого угла элемента. Функция это стандартная и много где используемая.
Кроме того, при начале переноса останавливается выделение и перенос текста браузером:
Если этого не сделать, то движение курсора мыши при нажатой кнопке будет не только перемещать элемент, но и, например, выделять текст под собой (стандартная функция выделения текста на странице).
Иногда красивее и удобнее - визуально перемещать не сам элемент, а его клон или макет.
Например, переносимый объект очень сложен, и его передвижение целиком тормозит браузер и выглядит громоздко/неэстетично.
Сам элемент при этом скрывается display/visibility='none' или просто остается на месте, в зависимости от логики интерфейса.
Переносимый клон инициализуется в начале переноса и уничтожается в конце.
Когда иконка опущена, нам необходимо определить, куда.
В другое хранилище - переместить. В корзину - удалить, и т.п.
Существенная техническая проблема заключается в том, что событие mouseup сработает не на корзине, а на переносимом элементе, т.к. курсор мыши находится именно над ним.
Поэтому в событии будет информация об элементе непосредственно под курсором. На картинке выше event.target = сердечко, а корзина в объекте события event не присутствует.
Определить, что иконка опущена на корзину, можно, сравнив координаты корзины с коорданатами мыши на момент события.
В момент опускания на корзину выводится сообщение, перемещаемая иконка - в переменной dragObject, цель переноса (корзина, объект-акцептор) - в переменной currentDropTarget.
В коде контроллера: функции, тело которых заменено на "...", остались без изменения с прошлого примера.
var dragMaster = (function() {
var dragObject
var mouseOffset
var dropTargets = []
function mouseUp(e){
e = fixEvent(e)
for(var i=0; i<dropTargets.length; i++){
var targ = dropTargets[i]
var targPos = getPosition(targ)
var targWidth = parseInt(targ.offsetWidth)
var targHeight = parseInt(targ.offsetHeight)
if(
(e.pageX > targPos.x) &&
(e.pageX < (targPos.x + targWidth)) &&
(e.pageY > targPos.y) &&
(e.pageY < (targPos.y + targHeight))){
alert("перенесен объект dragObject на акцептор currentDropTarget")
}
}
dragObject = null
removeDocumentEventHandlers()
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
dragObject = this
mouseOffset = getMouseOffset(this, e)
addDocumentEventHandlers()
return false
}
function removeDocumentEventHandlers() {
document.onmousemove = null
document.onmouseup = null
document.ondragstart = null
document.body.onselectstart = null
}
function addDocumentEventHandlers() {
document.onmousemove = mouseMove
document.onmouseup = mouseUp
document.ondragstart = function() { return false }
document.body.onselectstart = function() { return false }
}
function getMouseOffset(target, e) {...}
function mouseMove(e) {...}
return {
makeDraggable: function(element){...},
addDropTarget: function(dropTarget){
dropTargets.push(dropTarget)
}
}
}())
var dragMaster2 = (function() {
var dragObject
var mouseOffset
var dropTargets = []
function mouseUp(e){
e = fixEvent(e)
for(var i=0; i<dropTargets.length; i++){
var targ = dropTargets[i]
var targPos = getPosition(targ)
var targWidth = parseInt(targ.offsetWidth)
var targHeight = parseInt(targ.offsetHeight)
if(
(e.pageX > targPos.x) &&
(e.pageX < (targPos.x + targWidth)) &&
(e.pageY > targPos.y) &&
(e.pageY < (targPos.y + targHeight))){
alert("dragObject was dropped onto currentDropTarget!")
}
}
dragObject = null
removeDocumentEventHandlers()
}
function removeDocumentEventHandlers() {
document.onmousemove = null
document.onmouseup = null
document.ondragstart = null
document.body.onselectstart = null
}
function getMouseOffset(target, e) {
var docPos = getPosition(target)
return {x:e.pageX - docPos.x, y:e.pageY - docPos.y}
}
function mouseMove(e){
e = fixEvent(e)
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
return false
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
dragObject = this
mouseOffset = getMouseOffset(this, e)
addDocumentEventHandlers()
return false
}
function addDocumentEventHandlers() {
document.onmousemove = mouseMove
document.onmouseup = mouseUp
// отменить перенос и выделение текста при клике на тексте
document.ondragstart = function() { return false }
document.body.onselectstart = function() { return false }
}
return {
makeDraggable: function(element){
element.onmousedown = mouseDown
},
addDropTarget: function(dropTarget){
dropTargets.push(dropTarget)
}
}
}())
function getPosition(e){
var left = 0;
var top = 0;
while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
Основных изменений всего три.
Добавлен массив dropTargets и функция addDropTarget, которая добавляет в него элементы, на которые можно дропать.
Измененный обработчик mouseUp теперь проходит в цикле по возможным таким объектам и проверяет, не находится ли курсор внутри ограничивающего объект прямоугольника.
Если да, то демка всего лишь выводит сообщение. Реально приложение, конечно, может сделать более сложные действия.
Кроме того, установка и удаление обработчиков событий для document выделены в отдельные функции - просто в целях лучшей читаемости.
В удобном интерфейсе мы, скорее всего, захотим как-то показывать посетителю, над каким объектом он сейчас находится.
Единственно место, где это можно сделать - обработчик mouseMove. Сама проверка, над чем курсор сейчас находится, полностью аналогична mouseUp.
Однако, так как mouseMove выполняется при каждом передвижении мыши, его надо максимально оптимизировать.
Функция getPosition - довольно медленная: она работает с DOM, и ей надо пройти по всей цепочке offsetParent. Выполнять ее каждый раз при движении мыши для поиска текущего акцептора - все равно что нажать на большой-большой тормоз.
Стандартным выходом в такой ситуации является кеширование координат акцепторов, а точнее - их ограничивающих прямоугольников, так чтобы код mouseMove был максимально прост.
Код уже стал довольно длинным, поэтому в листинге ниже повторяющиеся фрагменты заменены на троеточие "..."
var dragMaster = (function() {
var dragObject
var mouseOffset
var dropTargets = []
/* кеш прямоугольников границ акцепторов */
var dropTargetRectangles
/* текущий акцептор, над которым объект в данный момент */
var currentDropTarget
function cacheDropTargetRectangles() {
dropTargetRectangles = /* сделать кеш прямоугольников */
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
/* начать перенос */
dragObject = this
mouseOffset = getMouseOffset(this, e)
/* закешировать прямоугольники при начале переноса */
cacheDropTargetRectangles()
addDocumentEventHandlers()
return false
}
function getCurrentTarget(e) {
var dropTarget = /* взять из кеша прямоугольник, в котором мышь */
return dropTarget /* null, если мы не над акцепторами */
}
function mouseMove(e){
/* визуально показать перенос объекта */
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
/* newTarget = над каким акцептором сейчас объект */
var newTarget = getCurrentTarget(e)
/* если ушли со старого акцептора */
if (currentDropTarget && currentDropTarget != newTarget) {
/* убрать выделение currentDropTarget */
}
/* пришли на новый акцептор (возможно null) */
currentDropTarget = newTarget
/* если новый акцептор существует (не null) */
if (newTarget) {
/* выделить newTarget */
}
return false;
}
function mouseUp(ev){
if (currentDropTarget) {
alert("перенесен объект dragObject на акцептор currentDropTarget")
/* убрать выделение с currentDropTarget */
}
/* конец операции переноса */
dragObject = null
removeDocumentEventHandlers()
}
function getMouseOffset(target, e) {...}
function addDocumentEventHandlers() {...}
function removeDocumentEventHandlers() {...}
return {
...
}
}())
Полностью рабочий вариант с кешем и т.п. - здесь:
var dragMaster = (function() {
var dragObject
var mouseOffset
var dropTargets = []
var dropTargetRectangles
var currentDropTarget
function cacheDropTargetRectangles() {
dropTargetRectangles = []
for(var i=0; i<dropTargets.length; i++){
var targ = dropTargets[i];
var targPos = getPosition(targ);
var targWidth = parseInt(targ.offsetWidth);
var targHeight = parseInt(targ.offsetHeight);
dropTargetRectangles.push({
xmin: targPos.x,
xmax: targPos.x + targWidth,
ymin: targPos.y,
ymax: targPos.y + targHeight,
dropTarget: targ
})
}
}
function mouseUp(ev){
if (currentDropTarget) {
alert("перенесен объект dragObject на акцептор currentDropTarget")
showRollOff(currentDropTarget)
}
dragObject = null
removeDocumentEventHandlers()
}
function getCurrentTarget(e) {
for(var i=0; i<dropTargetRectangles.length; i++){
var rect = dropTargetRectangles[i];
if(
(e.pageX > rect.xmin) &&
(e.pageX < rect.xmax) &&
(e.pageY > rect.ymin) &&
(e.pageY < rect.ymax)){
return rect.dropTarget
}
}
return null
}
function mouseMove(e){
e = fixEvent(e)
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
var newTarget = getCurrentTarget(e)
if (currentDropTarget && currentDropTarget != newTarget) {
showRollOff(currentDropTarget)
}
currentDropTarget = newTarget
if (newTarget) {
showRollOn(newTarget)
}
return false;
}
function showRollOn(elem) {
elem.className = 'uponMe'
}
function showRollOff(elem) {
elem.className = ''
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
dragObject = this
mouseOffset = getMouseOffset(this, e)
cacheDropTargetRectangles()
addDocumentEventHandlers()
return false
}
function getMouseOffset(target, e) {...}
function addDocumentEventHandlers() {...}
function removeDocumentEventHandlers() {...}
return {
...
}
}())
var dragMaster3 = (function() {
var dragObject
var mouseOffset
var dropTargets = []
var dropTargetRectangles
var currentDropTarget
function cacheDropTargetRectangles() {
dropTargetRectangles = []
for(var i=0; i<dropTargets.length; i++){
var targ = dropTargets[i];
var targPos = getPosition(targ);
var targWidth = parseInt(targ.offsetWidth);
var targHeight = parseInt(targ.offsetHeight);
dropTargetRectangles.push({
xmin: targPos.x,
xmax: targPos.x + targWidth,
ymin: targPos.y,
ymax: targPos.y + targHeight,
dropTarget: targ
})
}
}
function mouseUp(ev){
if (currentDropTarget) {
alert("droped dragObject into curTarget")
showRollOff(currentDropTarget)
}
dragObject = null
removeDocumentEventHandlers()
}
function removeDocumentEventHandlers() {
document.onmousemove = null
document.onmouseup = null
document.ondragstart = null
document.body.onselectstart = null
}
function getMouseOffset(target, e) {
var docPos = getPosition(target)
return {x:e.pageX - docPos.x, y:e.pageY - docPos.y}
}
function getCurrentTarget(e) {
for(var i=0; i<dropTargetRectangles.length; i++){
var rect = dropTargetRectangles[i];
if(
(e.pageX > rect.xmin) &&
(e.pageX < rect.xmax) &&
(e.pageY > rect.ymin) &&
(e.pageY < rect.ymax)){
return rect.dropTarget
}
}
return null
}
function mouseMove(e){
e = fixEvent(e)
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
var newTarget = getCurrentTarget(e)
if (currentDropTarget && currentDropTarget != newTarget) {
showRollOff(currentDropTarget)
}
currentDropTarget = newTarget
if (newTarget) {
showRollOn(newTarget)
}
return false;
}
function showRollOn(elem) {
elem.className = 'uponMe'
}
function showRollOff(elem) {
elem.className = ''
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
dragObject = this
mouseOffset = getMouseOffset(this, e)
cacheDropTargetRectangles()
addDocumentEventHandlers()
return false
}
function addDocumentEventHandlers() {
document.onmousemove = mouseMove
document.onmouseup = mouseUp
// отменить перенос и выделение текста при клике на тексте
document.ondragstart = function() { return false }
document.body.onselectstart = function() { return false }
}
return {
makeDraggable: function(element){
element.onmousedown = mouseDown
},
addDropTarget: function(dropTarget){
dropTargets.push(dropTarget)
}
}
}())
function getPosition(e){
var left = 0;
var top = 0;
while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
Следуя общему принципу отделения мух от котлет - лучше отделить простой клик на объекте от начала drag and drop.
Еще одна причина - дорогая инициализация drag & drop: нужно прокешировать все возможные акцепторы. Совершенно не обязательно это делать на mousedown, если имеем простой клик.
Как отделить? Очень просто:
При mousedown запомнить координаты и объект, но пока не начинать перенос
Если произошло событие mouseup - это был всего лишь клик, сбросить координаты
В mousemove проверить: если есть запомненные координаты и курсор отошел от них хотя бы на 2 пикселя - начать перенос
В коде этой демки стоит расстояние не 2, а 25 пикселей, в целях наглядности происходящего.
До перемещения курсора на 25 пикселей вверх или вниз перенос не начнется.
Код демо:
var dragMaster = (function() {
...
var mouseDownAt
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
mouseDownAt = { x: e.pageX, y: e.pageY, dragObject: this }
addDocumentEventHandlers()
return false
}
function mouseMove(e){
e = fixEvent(e)
if (mouseDownAt) {
if (Math.abs(mouseDownAt.x-e.pageX)<25 && Math.abs(mouseDownAt.y-e.pageY)<25) {
// слишком близко, возможно это клик
return
}
// курсор нажатой мыши отвели далеко - начинаем перенос
dragObject = mouseDownAt.dragObject
mouseOffset = getMouseOffset(dragObject, mouseDownAt.x, mouseDownAt.y)
cacheDropTargetRectangles()
// запомненные координаты нам больше не нужны
mouseDownAt = null
}
showDrag(e) // показать перенос
return false;
}
function mouseUp(ev){
if (!dragObject) {
// ничего не начали нести, был просто клик
mouseDownAt = null
} else {
// чего-то несем - обрабатываем конец переноса
if (currentDropTarget) {
alert("перенесен объект dragObject на акцептор currentDropTarget")
showRollOff(currentDropTarget)
}
dragObject = null
}
// (возможный) drag and drop завершен
removeDocumentEventHandlers()
}
function showDrag(e) {
// перенести объект
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
// подсветить акцептор
var newTarget = getCurrentTarget(e)
if (currentDropTarget && currentDropTarget != newTarget) {
showRollOff(currentDropTarget)
}
currentDropTarget = newTarget
if (newTarget) {
showRollOn(newTarget)
}
}
function getMouseOffset(target, x, y) {
// для удобства поменяли синтаксис: x/y вместо event
var docPos = getPosition(target)
return {x:x - docPos.x, y:y - docPos.y}
}
function cacheDropTargetRectangles() {...}
function removeDocumentEventHandlers() {...}
function getCurrentTarget(e) {...}
function showRollOn(elem) {...}
function showRollOff(elem) {...}
function addDocumentEventHandlers() {...}
return {
...
}
}())
var dropMove2 = (function() {
var dragObject
var mouseOffset
var mouseDownAt
var dropTargets = []
var dropTargetRectangles
var currentDropTarget
function cacheDropTargetRectangles() {
dropTargetRectangles = []
for(var i=0; i<dropTargets.length; i++){
var targ = dropTargets[i];
var targPos = getPosition(targ);
var targWidth = parseInt(targ.offsetWidth);
var targHeight = parseInt(targ.offsetHeight);
dropTargetRectangles.push({
xmin: targPos.x,
xmax: targPos.x + targWidth,
ymin: targPos.y,
ymax: targPos.y + targHeight,
dropTarget: targ
})
}
}
function mouseUp(ev){
if (!dragObject) {
mouseDownAt = null
} else {
if (currentDropTarget) {
alert("перенесен объект dragObject на акцептор currentDropTarget")
showRollOff(currentDropTarget)
}
dragObject = null
}
removeDocumentEventHandlers()
}
function removeDocumentEventHandlers() {
document.onmousemove = null
document.onmouseup = null
document.ondragstart = null
document.body.onselectstart = null
}
function getMouseOffset(target, x, y) {
var docPos = getPosition(target)
return {x:x - docPos.x, y:y - docPos.y}
}
function getCurrentTarget(e) {
for(var i=0; i<dropTargetRectangles.length; i++){
var rect = dropTargetRectangles[i];
if(
(e.pageX > rect.xmin) &&
(e.pageX < rect.xmax) &&
(e.pageY > rect.ymin) &&
(e.pageY < rect.ymax)){
return rect.dropTarget
}
}
return null
}
function mouseMove(e){
e = fixEvent(e)
if (mouseDownAt) {
if (Math.abs(mouseDownAt.x-e.pageX)<25 && Math.abs(mouseDownAt.y-e.pageY)<25) {
return
}
dragObject = mouseDownAt.dragObject
mouseOffset = getMouseOffset(dragObject, mouseDownAt.x, mouseDownAt.y)
cacheDropTargetRectangles()
mouseDownAt = null
}
showDrag(e)
return false;
}
function showDrag(e) {
with(dragObject.style) {
position = 'absolute'
top = e.pageY - mouseOffset.y + 'px'
left = e.pageX - mouseOffset.x + 'px'
}
var newTarget = getCurrentTarget(e)
if (currentDropTarget && currentDropTarget != newTarget) {
showRollOff(currentDropTarget)
}
currentDropTarget = newTarget
if (newTarget) {
showRollOn(newTarget)
}
}
function showRollOn(elem) {
elem.className = 'uponMe'
}
function showRollOff(elem) {
elem.className = ''
}
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
mouseDownAt = { x: e.pageX, y: e.pageY, dragObject: this }
addDocumentEventHandlers()
return false
}
function addDocumentEventHandlers() {
document.onmousemove = mouseMove
document.onmouseup = mouseUp
// отменить перенос и выделение текста при клике на тексте
document.ondragstart = function() { return false }
document.body.onselectstart = function() { return false }
}
return {
makeDraggable: function(element){
element.onmousedown = mouseDown
},
addDropTarget: function(dropTarget){
dropTargets.push(dropTarget)
}
}
}())
function getPosition(e){
var left = 0;
var top = 0;
while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
Бывает, что возможных акцепторов очень много. Тогда код, кеширующий прямоугольники при начале переноса, будет тормозить.
Визуально это проявляется как задержка от клика на объекте до его фактического переноса - потому что долго, с 100% поеданием одного ядра CPU обрабатывается mousedown.
Речь тут идет о 100 акцепторах или больше - например, при переносе между длинными списками или деревьями. Хотя какие-то тормоза могут быть заметны и от 50.
Этот малоизвестный метод работает во всех браузерах и возвращает элемент по координатам на странице.
Firefox/IE используют для этого clientX/Y, а Opera, Chrome и Safari - pageX/Y.
Возвращенный элемент является самым глубоко вложенным на точке с координатами (x,y). Это может быть текстовый узел в том числе.
Следуя по цепочке родителей, легко найти нужного акцептора.
На время вызова elementFromPoint необходимо спрятать переносимый элемент, чтобы он не закрывал акцептора.
Псевдокод будет выглядеть так:
function getCurrentTarget(e) {
dragObject.style.display = 'none' // спрятать
if (navigator.userAgent.match('MSIE') || navigator.userAgent.match('Gecko')) {
// IE || FF
var elem = document.elementFromPoint(e.clientX,e.clientY)
} else {
var elem = document.elementFromPoint(e.pageX,e.pageY)
}
dragObject.style.display = '' // показать побыстрее
while (elem!= null) {
if (elem является акцептором) {
return elem
}
elem = elem.parentNode
}
// не нашли
return null
}
И мы знаем, что каждый элемент имеет фиксированную высоту и отступы:
.articles-list li {
height: 20px;
margin: 0px;
padding: 0px;
}
В таком случае, можно вычислить номер LI, разделив общую высоту контейнера на высоту акцептора.
function getCurrentTarget(e) {
var rect = /* ограничивающий прямоугольник для UL */
// (ulX, ulY) - координаты относительно верхнего-левого угла контейнера
var ulX= e.pageX - rect.xmin
var ulY = e.pageY - rect.ymin
if ( ulX < 0 || ulX > rect.xmax-rect.xmin || ulY < 0 || ulY > rect.ymax-rect.ymin) {
/* событие за границами списка */
return null
}
/* по 20px на каждого ребенка-акцептора */
var childNum = ulY / 20
return rect.dropTarget.childNodes[childNum]
}
Конечно, такая оптимизация возможна не всегда и зависит от конкретной задачи.
В ряде задач допустимо не сохранять переносимый элемент под курсором, а передвинуть его на несколько пикселей в сторону, то mouseUp и mouseMove будут срабатывать уже на акцепторе, который станет возможным получить из event.target.
Да, получится не так красиво, но это может быть единственным выходом.
Объект DragObject - обобщенный переносимый объект, который привязывается к DOM-элементу. Он представлен на следующем листинге.
function DragObject(element) {
element.dragObject = this
dragMaster.makeDraggable(element)
var rememberPosition
var mouseOffset
this.onDragStart = function(offset) {
var s = element.style
rememberPosition = {top: s.top, left: s.left, position: s.position}
s.position = 'absolute'
mouseOffset = offset
}
this.hide = function() {
element.style.display = 'none'
}
this.show = function() {
element.style.display = ''
}
this.onDragMove = function(x, y) {
element.style.top = y - mouseOffset.y +'px'
element.style.left = x - mouseOffset.x +'px'
}
this.onDragSuccess = function(dropTarget) { }
this.onDragFail = function() {
var s = element.style
s.top = rememberPosition.top
s.left = rememberPosition.left
s.position = rememberPosition.position
}
this.toString = function() {
return element.id
}
}
Использование:
new DragObject(element)
Достаточно одного вызова new, т.к функция DragObject добавляет конструируемый объект к element в свойство element.dragObject:
...
element.dragObject = this
...
Методы:
onDragStart(offset)
Вызывается при начале переноса. В текущей реализации отрывает объект "от земли" и запоминает текущую позицию в rememberPosition и сдвиг курсора мыши от левого-верхнего угла объекта в mouseOffset.
В другой реализации может показывать перенос как-то по-другому, например создавать "переносимый клон" объекта.
onDragMove(x, y)
Вызывается при переносе объекта в координаты (x,y). Отображает перенос.
onDragFail()
Обрабатывает неудачный перенос. В текущей реализации возвращает объект на старые координаты.
Вообще говоря, можно делать это с анимацией, показывая как объект "перелетает" на старое место.
onDragSuccess(dropTarget)
Обрабатывает успешный перенос. В текущей реализации обработка успешного переноса целиком сосредоточена у принимающего объекта DropTaget, поэтому эта функция пустая.
show/hide()
Показать/спрятать переносимый объект - вспомогательные методы
Методов у DropTarget поменьше, чем у DragObject. Еще бы, акцептору ведь не нужно анимировать собственный перенос.
canAccept(dragObject)
При проносе объекта над DropTarget, dragMaster спросит у акцептора, может ли он принять dragObject. Если нет - dragMaster проигнорирует этот акцептор.
В текущей реализации всегда возвращает true, то есть положить можно. Вообще говоря, может проверять класс переносимого объекта:
this.canAccept = function(dragObject) {
// могу принять только объекты типа TreeNodeDragObject
return dragObject instanceof TreeNodeDragObject
}
accept(dragObject)
Принимает переносимый объект. Объект может быть перемещен(в другой каталог) или уничтожен(корзина) - зависит от вашей логики обработки переноса.
В конкретном приложении стоит посмотреть особо, какую часть логики конца переноса стоит поместить DragObject#onDragSuccess, а какую - в DropTarget#accept. Как правило, основную логику переноса удобно сосредоточить у DropTarget.
onLeave/onEnter
Анимация возможности положить объект на акцептор. Как правило, акцептор при этом подсвечивается. Эти методы будут вызваны только если акцептор может принять (canAccept) переносимый объект.
Ну и, наконец, похудевший и лишенный большинства обязанностей dragMaster.
var dragMaster = (function() {
var dragObject
var mouseDownAt
var currentDropTarget
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
mouseDownAt = { x: e.pageX, y: e.pageY, element: this }
addDocumentEventHandlers()
return false
}
function mouseMove(e){
e = fixEvent(e)
// (1)
if (mouseDownAt) {
if (Math.abs(mouseDownAt.x-e.pageX)<5 && Math.abs(mouseDownAt.y-e.pageY)<5) {
return false
}
// Начать перенос
var elem = mouseDownAt.element
// текущий объект для переноса
dragObject = elem.dragObject
// запомнить, с каких относительных координат начался перенос
var mouseOffset = getMouseOffset(elem, mouseDownAt.x, mouseDownAt.y)
mouseDownAt = null // запомненное значение больше не нужно, сдвиг уже вычислен
dragObject.onDragStart(mouseOffset) // начали
}
// (2)
dragObject.onDragMove(e.pageX, e.pageY)
// (3)
var newTarget = getCurrentTarget(e)
// (4)
if (currentDropTarget != newTarget) {
if (currentDropTarget) {
currentDropTarget.onLeave()
}
if (newTarget) {
newTarget.onEnter()
}
currentDropTarget = newTarget
}
// (5)
return false
}
function mouseUp(){
if (!dragObject) { // (1)
mouseDownAt = null
} else {
// (2)
if (currentDropTarget) {
currentDropTarget.accept(dragObject)
dragObject.onDragSuccess(currentDropTarget)
} else {
dragObject.onDragFail()
}
dragObject = null
}
// (3)
removeDocumentEventHandlers()
}
function getMouseOffset(target, x, y) {
var docPos = getOffset(target)
return {x:x - docPos.left, y:y - docPos.top}
}
function getCurrentTarget(e) {
// спрятать объект, получить элемент под ним - и тут же показать опять
if (navigator.userAgent.match('MSIE') || navigator.userAgent.match('Gecko')) {
var x=e.clientX, y=e.clientY
} else {
var x=e.pageX, y=e.pageY
}
// чтобы не было заметно мигание - максимально снизим время от hide до show
dragObject.hide()
var elem = document.elementFromPoint(x,y)
dragObject.show()
// найти самую вложенную dropTarget
while (elem) {
// которая может принять dragObject
if (elem.dropTarget && elem.dropTarget.canAccept(dragObject)) {
return elem.dropTarget
}
elem = elem.parentNode
}
// dropTarget не нашли
return null
}
function addDocumentEventHandlers() {
document.onmousemove = mouseMove
document.onmouseup = mouseUp
document.ondragstart = document.body.onselectstart = function() {return false}
}
function removeDocumentEventHandlers() {
document.onmousemove = document.onmouseup = document.ondragstart = document.body.onselectstart = null
}
return {
makeDraggable: function(element){
element.onmousedown = mouseDown
}
}
}())
mouseDown(e)
Метод не изменился. Он запоминает позицию, на которой произошло нажатие кнопки мыши mouseDownAt и добавляет остальные обработчики слежения за переносом addDocumentEventHandlers().
mouseMove(e)
Этот обработчик присоединяется к document в момент mouseDown.
Если в момент его срабатывания есть запомненное нажатие и курсор отошел больше чем на 5 пикселей - значит начался перенос. DragObject'у это сообщается вызовом onDragStart с передачей текущего сдвига курсора относительно левого-верхнего угла mouseOffset.
Объект информируется о текущих координатах переноса.
Вычисляем текущий акцептор при помощи модифицированного метода getCurrentTarget (см. выше в разделе "Оптимизация").
Обработать нового акцептора и уход со старого акцептора.
Вернуть false для блокирования действий браузера и всплывания события mouseMove
mouseUp()
Этот обработчик завершает (возможный) перенос. Обратите внимание - само событие в данном случае не нужно. Весь процесс переноса отслеживается событием mouseMove.
Если объект переноса не установлен, значит перед этим было простое нажатие mouseDown, элемент не отнесли на 5 пикселей в сторону - это не drag'n'drop.
При наличии акцептора - перенос успешно завершается, если акцептора нет - отменяется.
В любом случае в конце все обработчики с документа снимаются
Функция определения позиции элемента getPosition заменена на более точный вариант getOffset, описанный в статье про определение координат.
В процессе переноса акцепторы объекты могут сдвигаться, освобождая место.
Если вы используете кеш координат акцепторов, то при этом производится соответствующее обновление кеша, но вместо полного перевычисления обновляются только координаты сдвинувшихся объектов.
Например, при раздвижении списка вниз - увеличиваются Y-координаты всех сдвинувшихся LI.
При этом для удобного обновления кеш делается не массивом, а объектом с доступом по ID элемента, так чтобы можно было легко обновить именно нужные координаты.
Иногда, например, при смене позиции элемента в списке, объект переносится не на акцептор, а между акцепторами. Как правило, "между" - имеется в виду по высоте.
Для этого логику определения currentDropTarget нужно поменять. Возможно два варианта:
Допустим перенос как между, так и над
В этом случае акцептор делится на 3 части по высоте clientHeight: 25% - 50% - 25%, и определяется попадание координаты события на нужную часть.
Перенос только между
Акцептор делится на две части: 50% - 50%
Кроме того, в дополнение к текущему акцептору currentDropTarget добавляется флаг, обозначающий, куда относительно акцептора происходит перенос.
Индикацию "переноса между" удобнее всего делать либо раздвижением элементов, либо показом полосы-индикатора border-top/border-bottom, как показано на рисунке ниже:
Обычно при переносе объекта куда-либо посетитель может просто отпустить его в любом месте.
При этом drag and drop фреймворк анимирует отмену переноса. Один из частых вариантов - скольжение объекта обратно к исходному месту, откуда его взяли.
Конечно, для этого исходное место необходимо запомнить.
Если перетаскивается аватарка(клон), то можно его и просто уничтожить.
Совершенно не факт, что любой объект можно перенести на любой аксептор.
Как правило, все с точностью наоборот.
Акцептор может быть недоступен по двум причинам:
либо это несовпадение типов, для этого drag and drop должен предусматривать различные типы объектов/акцепторов и проверку их соответствия
либо у посетителя недостаточно для этого прав, в рамках наложенных CMS ограничений
При переносе над недоступным акцептором - getCurrentTarget просто возвращает null.
Иногда проверку прав и результата переноса необходимо делать на сервере. Как правило, такую проверку выполняют только при mouseUp, чтобы не нагружать сервер излишними запросами во время mouseMove.
Здесь используется два подхода
Синхронный XmlHttpRequest
Запрос отправляется синхронно, чтобы не нарушать общий поток выполнения. Все хорошо, вот только браузер видимо подвисает при отпускании кнопки мыши. Да и другие недостатки у синхронного запроса есть.
Отложенная отмена переноса
Более продвинутый и удобный вариант. Основан на "оптимистичном" сценарии, по которому перенос, как правило, проходит успешно.
Посетитель кладет объект туда, куда он хочет.
Фреймворк перемещает объект, и затем "в фоне" делает асинхронный запрос к серверу. На запрос вешается callback, содержащий информацию, откуда был перенесен объект.
Сервер обрабатывает перенос и возвращает ответ, все ли в порядке.
Если нет - callback выводит ошибку и объект возвращается туда, откуда был перенесен.
Использование jQuery.ui.sortable, а также Dojo draggable, а также других существующих библиотек есть гуд. Другое дело, что они не всегда соответствуют решаемой задаче, занимают больше места, да и вообще полезно понимать, что происходит.
Эх, много бы время мне сэкономила эта статья выйдя на пол года раньше=) Облазил я тогда всё но кроме простых примеров ни чего не нашёл. Раньше я использовал script.aculo и прототип, для проекта где было много перетаскиваемых объектов, что сказать мне не хватило ее функциональности. Не было в ней событий которые вызывались в тот момент когда перетаскиваемый объект начинал заходить и уходить в область drop объекта=) пришлось добавит только предварительно поняв как там всё это устроенно. Вот живой пример. Для простых целей он конечно же подходят.
События которые отображающие весь процесс это:
onStartDrag()
onStopDrag()
onDrag()
onStartHover()
onHover()
onStopHover()
onDrop()
И если их сделать тогда вам больше не чего не придётся дописывать
Больше всего в это статье мне нравится не сама описываемая в ней тема, хотя и она интересна сама по себе, а то, как автор оперирует ОО подходом применительно к JS. Использует много интересных приемов и главное не отдельно, а непосредственно решая задачу.
Т.е. если он использует обработчик событий, то это не статья об обработчиках, а статья где показано практическое его применение.
И вообще, автор талантлив. Я считаю, что это идеальный обучающий материал. Хотя некоторые моменты не совсем раскрыты, но это вполне верно, так как статья не о них.
Большое спасибо за качественный материал.
отмечаю что статья не доведена до логического конца в зугрузку необходимо добавить не только JS, но и маленький html где используется данный скирпт. тогда вопросов
"Может кто подскажет как использовать???Ну есть у меня этот котроллер.и есть объект, допустим div id="im".Как применить к нему это все???"
возникать не будет. к сожаленю этим страдает не только эта статья здесь.
У меня есть мнение, что изучать программирование и его основы нужно не с этой статьи. Поэтому такие моменты как банальное не знание HTML или не понимание общих принципов программирования как такого (не говоря об ООП), это, в конечном счете, не проблема автора. Цель данной статьи объяснить и принципы, а не дать рабочий пример. Если нужен механизм, то нужно читать не статьи, а документацию библиотек, а лучше базовый курс.
А от вопросов: - "Где в javascript C++?" и - "Как добавить на страницу этот форум?", никуда не деться.
Отличная статья. Все хорошо расписано и понятно. Для определенных сайтов драг-энд-дроп сильно повысит интерактивность управления (к примеру кидать товары в магазине в тележку).
Неплохо было было добавить реакцию на скролл. А то если во время перетаскивания прокрутить колесо мыши, то объект замирает в первоначальной позиции и потом при малейшем движении рывком прыгает в новое место. Не очень красиво, правда? Также часто делают автоскролл при поднесении объекта к краю экрана.
Все это очень замечательно, но для действительно полноценного drag'n'drop'а следует рассмотреть еще много-много интересного. Итак:
1. Вы совершенно не учитываете возможность наличия других обработчиков mousemove/mouseup, которые могут сделать stopPropagation/cancelBubble, и Ваш drag'n'drop никогда не кончится. Во избежание этой ситуации обработчики mousemove/mouseup следует навешивать С КАПЧУРИНГОМ на document: document.addEventListener('mousemove', callback, true). В IE для тех же целей необходимо установить setCapture на таскаемый элемент.
2. Вы не учитываете возможность прерывания таскания, например, по alt+tab, одновременному нажатию нескольких кнопок мыши или выходу курсора за пределы документа.
3. Есть очень скользкий момент с тем, что после mouseup приходит событие click, которое, вообще говоря, логически вовсе не click - если по клику выполняется какое-то другое действие, то оно после драггинга очевидно выполняться не должно. Поэтому надо в определенных ситуациях слушать приходящий следом click и отменять его.
Это только верхушка айсберга на самом деле. Там еще море всевозможных тонкостей, особенно с разными странными браузерами типа Оперы 9.2 и Сафари под Мак.
FF2 использует примерно 2% пользователей - не так уж и мало. Больше чем Сафари под Мак, например. То же касается Оперы 9.27. А эти два браузера не отслеживают выход мыши за пределы документа (т.е. в строку меню браузера, например).
Выход мыши за пределы документа особенно резкий - вообще нельзя отследить, как и отпускание кнопки там. Можно только
1) Попробовать предусмотреть такой нестандарт и не глюкануть сильно
2) Иметь в виду, что пользователь, который так делает, обычно морально готов к глюкам.
В приципе FF3 событие onmouseup ловит за пределами окна (если конечно мышь туда перемещается в нажатом состоянии. Ну и может дело в том что в своей реализации D&D я вешаю обработчики через addEventListener/attachEvent, чтобы не мешать другим).
А вот у IE с этим проблема (использую 6ую версию). Событие onmouseup ловится за пределами окна только в том случае если нет обработчиков в стиле document.body.onselectstart = funtion(e) {return false;}. Т.е. если работает выделение и мы его не трогаем.
Поэтому для того чтобы, D&D корректно прекращался, а не продолжался после того как кнопка была отпущена "за пределами", необходимо ловить document.[body.]onmouseover и прекращать его если не нажать левая кнопка мыши. Кстати у вас в примерах такой эффект присутствует. D&D продолжается если отжать мышь за пределами ограничивающего контейнера.
В FF2 вполне можно отследить выход курсора за пределы окна, через relatedTarget. В IE надо делать setCapture на нужный элемент и слушать событие onlosecapture.
в статье ещё не рассмотрен случай, когда элемент перетаскивается за его часть (например окно за заголовок) и не написано про обработку вытаскивания элемента за пределы окна
Хорошая статья. Наткнулся на нее когда писал свой drag'n'drop, уже почти все написал, осталось только определить над каким элементом находится курсор при onMouseUp и ответ как это сделать был найден именно тут.
На счет выхода курсора за пределы окна, контроля последующего клика, реакции на alt+tab.. Это уже похоже на попытку контроля хаоса. Ну в крайнем случае можно сделать отмену перетаскивания, если курсор мыши долго не меняет свои координаты. Впрочем даже это кажется мне излишним.
Чтобы я мог полностью использовать все преимущества этого скрипта - подскажите, как перетаскивать не картинку, а ее копию?
Хочу на базе вашей реализации сделать драг н дроп товаров в корзину.
Надо:
1. Взять мышей картинку.
2. Перетянуть ее на корзину.
При этом изображение товара - должно статично, а перетягиваться копия изображения
Нужно отметить, что можно столкнуться с ситуацией, когда перетаскиваемый элемент находится в контейнере с абсолютной или относительной позицией.
Поскольку в скрипте отсчет позиции идет от x: 0, y: 0 для body, то такой элемент, при перетаскивании, будет появляться не в месте, где мы его "схватили", а с соответствующим смещением (между "нулями" body и родительского позиционированного элемента). Поскольку "правильное" определение элемента с позиционированием может стоить ресурсов, лучше при перетаскивании делать клон элемента, подсоединяя его к контейнеру body, таким образом обходя вышеуказанную проблему и возможную проблему с вложенностью.
Уважаемый Илья Кантор! Огромное спасибо Вам за этот ресурс, по-моему, это лучшее, что есть по javascript. Все информация излагается доступно, с логикой развития, полно, с наглядными работающими красивыми примерами!!! Потрясающе!
Может, сделать отдельный тип комментариев "спасибо" ? Конечно, я рад, что мой труд кому-то пригодился, но такие комментарии не добавляют полезности статье..
Спасибо автору, фреймворк очень компактный.
Правда процессор грузит в среднем также как jQuery.ui Drag&Drop. Использовать не так удобно как jQuery.ui
Для повышения удобства и универсальности достаточно вынести функцию обработки дропа из фреймворка на пользовательскую страницу, как это сделано в jQuery.ui
Статья совсем не ставит целью заменить jquery ui, dojo dijit и прочие фреймворки. Конечно, вы можете адаптировать код под свои нужды или адаптировать поправить тот же jquery ui, используя информацию из статьи.
1. Добавил комментарий об этом в статью. & - это логическое И.
2. Да, опечатка, поправил.
3. Таким образом мы объявляем и тут же создаем объект-синглтон.
4. Что непонятного? IE выводит что-то другое? Вы берете элемент, у которого нет offsetParent (родительского по offset элемента). Естественно, выходит null...
Не указан один важный момент. Для Драг&Дропа необходимо заставлять браузер перерисовывать страницу при mouseover. Это в библиотеке просисходит, но для других целей. Заставить перерисовать страницу можно простым обращением к свойству DOM-элемента, которое заставит браузер что-то вычислить:
ele.offsetTop
Не все свойства DOM-элемента подходят для этого, например style.top, т.к. это по-сути всего лишь получение уже установленного значения. В сложный интерфейсах этот момент может сыграть чуть ли не самую важную роль.
Да уж, перетаскивание клона картинки - полезная штука,
а можно ли выложить полный код? А то изменения применил,
но не работает ...
то картинку вообще сдвинуть нельзя, то днд отключается,
и картинка тянется браузером, а не скриптом.
Здравствуйте!
Спасибо полезно, применяю.
Есть вопрос:
У меня перетаскиваемый объект содержит html код (текст картинки и т.д.) он в контейнере table td. (таблицей нарисовано обрамление содержания)
В js новичОк, не могу сделать так чтобы таскать только за область границы вокруг.
При этом по mousedown на контенте контейнера не таскать но выделять текст.
вот пример http://webpokaz.ru/media/test/testgallery.html
И еще одно, после нескольких внесенных исправлений повесил ИЕ...
В этой версии, при том что локально все работает, выложил в нет и ИЕ повис.
Рассмотрите пожалуйста мой пример. Очень надеюсь на вашу помощь
Я только что столкнулся с данной проблемой - мне необходимо было иметь возможность перетаскивать всплывающее окошко:
<div id="popup" style="border: solid 1px #000000;">
<div class="dTitle" id="dTitle">Popup</div>
<div class="dBody">
<p class="dText">
The relevant FIX connections are setup in the FIX Gateway b/w the FIX 5.0 VeriFIX receiver (outbound) and RTNS GID.logs (inbound)
The relevant FIX connections are setup in the FIX Gateway b/w the FIX 5.0 VeriFIX receiver (outbound) and RTNS GID.logs (inbound)
</p>
<button style="clear:both;" type="button" onClick="layerClose();">
Close
</button>
</div>
</div><script>
dragMaster.makeDraggable(document.getElementById('dTitle'))
</script>
Так вот, для того, чтобы беспроблемно таскать это всплывающее окошко, я просто подставил в вызове не его само, а его хэдер, т.е. в данном случае dTitle, а в самом скрипте сделал так:
...
function mouseDown(e) {
e = fixEvent(e)
if (e.which!=1) return
dragObject = this.parentNode; // изначально было dragObject = this
...
Здесь возвращается позиция элемента относительно документа
function getPosition(e){
62 var left = 0
63 var top = 0
64
65 while (e.offsetParent){
66 left += e.offsetLeft
67 top += e.offsetTop
68 e = e.offsetParent
69 }
70
71 left += e.offsetLeft
72 top += e.offsetTop
73
74 return {x:left, y:top}
75 }
а тут элементу назначаются координаты относительно родительского элемента
with(dragObject.style) {
26 position = 'absolute'
27 top = e.pageY - mouseOffset.y + 'px'
28 left = e.pageX - mouseOffset.x + 'px'
29 }
и если задать родительскому элементу position, перетаскиваемый прыгает
в исходном файле demo.html я приписал позицию для дива
Статья действительно супер, но добавлю пару замечаний.
Во-первых, по поводу pageX/Y и clientX/Y: Chrome и Opera 10.5 уже тоже использует clientX/Y, по крайней мере с ним всё работает корректно. Для Opera < 10.5 действительно требуется pageX/Y, но это, по-видимому, единственное исключением из правила, т.к. Opera 10.5 с pageX/Y уже работает некорректно при прокрутке страницы. Как себя ведёт Safari - не смотрел, но учитывая, что это тоже WebKit, подозреваю, что тоже может работать с clientX/Y.
А в Konqueror'е, например, вообще нет метода elementFromPoint. Чем бы его заменить?
Во-вторых, по поводу объектной модели DragObject: те методы, которые у вас "onXXX", я бы назвал просто "xXX", и добавил бы в них if (this.onXXX) onXXX(...), чтобы легче было добавлять в объект обработчики событий. И кроме того, по умолчанию сделал бы восстановление позиции элемента при успешном drag&drop'е, если пользователь захочет - нехай переопределяет.
В-третьих, по поводу используемых локальных переменных - мне кажется логичнее их засунуть в объект (не var element, а this.element = ...), чтобы потом их легко было достать из тех же обработчиков событий, например.
С этими доработками получается уже вполне приличная, но в то же время лёгкая библиотека для drag&drop'а) DragHelpers.js DragObject.js DragMaster.js DropTarget.js
P.S: тут в редакторе во "вставке ссылки" не работает текст, вставляется ссылка без текста внутри.
Илья, спасибо за умную статью. На основе Вашего материала построил свой сайт.
Но вот столкнулся с проблемой: если перетаскиваемый объект (в примере картинка img/piki.gif) заключены в html-ссылку, например:
[a target=_blank href=http://mysite.com][img src="img/piki.gif" id="piki"/][/a]
то после перетаскивания такой картинки броузеры ведут себя по-разному.
В частности, Google Hrome после перетаскивания открывает новую вкладку, т.е. отрабатывает тег [a]. Как бы предотвратить это? То есть, клик по картинке должен отправлять пользователя по адресу, указанному в href... Но если пользователь только переместил картинку, то перехода быть НЕ должно.
Илья, спасибо за умную статью. На основе Вашего материала построил свой сайт.
Но вот столкнулся с проблемой: если перетаскиваемый объект (в примере картинка img/piki.gif) заключены в html-ссылку, например:
(a target=_blank href=http://mysite.com)(img src="img/piki.gif" id="piki"/)(/a)
то после перетаскивания такой картинки броузеры ведут себя по-разному.
В частности, Google Hrome после перетаскивания открывает новую вкладку, т.е. отрабатывает тег (a).
Как бы предотвратить это? То есть, клик по картинке должен отправлять пользователя по адресу, указанному в href... но если пользователь только переместил картинку, то перехода быть НЕ должно.
Использую эти скрипты для DnD. Очень сильно грузять процессор. Под FF и Chrome еще как-то шевелятся(95%), а под IE вначале перетаскивания проц загружается на 100% и по этой причине объект не визуализируется, ему просто некогда. Это происходит даже если после начала движения просто остановить мышку но не отпускать левую клавишу. Постоянно срабатывает событие mousemove, хотя движения мышкой нет. В чем может быть причина? Если не победю придется на другой фреймоворк переходить, а это месяц отладки.
Мне кажется, что к проверке прав второго типа (асинхронный запрос) надо добавить предварительную проверку прав на всех объектах, которые могут быть перетаскиваемыми, на этапе формирования страницы (PHP).
Например, если у нас есть сотня объектов трех типов, мы можем выделить эти типы. И у нас есть авторизованный (или неавторизованный, гость) пользователь, у которого есть права. Для каждого типа объектов проверяются права на перенос - да, нет. Всего лишь булевая переменная, которая добавляется в свое свойство объекту. Таким образом мы отсекаем бОльшую часть "отбракованных" переносов еще до их совершения. Кстати абсолютное большинство "отбракованных" переносов будет говорить о попытках изменить что то в коде страницы и получить доступ к запрещенным элементам: если проект - онлайн-игра, такому пользователю можно выносить предупреждение, и знать, что от него можно ждать попыток эксплоитов и багоюзерства =)
Спасибо за статью!
Но вот глюк...
Взял за основу пример с 2-мя вложенными дивами.
если на странице с примером появляется полоса прокрутки вниз
То в Opera прокрутив чуть чуть и попробовав перенести, меняется позиция droptarget, а именно становится выше реального((( Подскажите?
есть одна проблема с получением координат мыши отномительно документа: при нахождении мыши над обьектом со свойством position:fixed; в интернет эксплорере значение координат остается не определенным.. как можно это исправить?
Мне вот интересно насчет дропа между элементами. Чтобы делить акцепторы на 2 части, для определения выше или ниже будет дропаться элемент, нужно знать его высоту, которую можно снять c помощью getComputedStyle, но подобный метод для IE (currentStyle) вернет "auto" если высота нигде не задана, и как же тогда быть, если все элементы "списка" (подразумевается некий набор блочных элементов) разной высоты, которая нигде не задана, а зависит от количества контента блока.
Интересно, конечно, но вот практическая применимость сего на сегодня мне кажется сомнительной. Точнее, в некоторых браузерах работать будет, в некоторых (пусть это считаные проценты пользователей) будут одни глюки.
Мне самому хотелось бы кой-чего замутить (не без драг-н-дропа), но как прикину, сколько на это времени уйдёт, чтобы хотя бы в паре основных браузеров работало без нареканий, так руки и опускаются. Тут уже перечислили выход мышки за пределы окна и т.д. с комментариями "если пользователь это делает, то он морально готов к глюкам".
Даже не знаю, как это комментировать. Если вы наворачиваете на сайт свистулек и чего там ещё, нужно добиваться того, чтобы с ними результат был лучше, чем без них. Зачем нужны свистульки, если из-за них у пользователя заглючит интерфейс? При чём не просто какая-нибудь картинка на полсантиметра в сторону съедет, а вообще страницу заклинит.
Если же вы не можете обеспечить безглючную работу задуманного - не беритесь.
"Надо там ещё додумать, надо там ещё доделать, ещё пользователь может вот так, ну это всё равно, а может ещё и так, ну и плевать, пусть развалится."
"Вот вечно у нас так всё, на авось, авось не всплывёт, небось и так сойдёт, везде халтура. А я хочу, чтобы наша липовая печать была лучшей печатью во всей прокуратуре!"
Если бы автомат калашникова клинило в тот момент, когда пользователь "должен быть морально готов к глюкам" - был бы он брендом номер один в своей области?
Уважаемый Илья. Очень прошу уточнить как вместо alert произвести асинхронный запрос. И самое главное как после того как, dragObject будет отпушен на акцепторе
запретить ему Drag and drop?????
ведем его до верхней границе окна
неотпуская мыши уводим ее за границу окна и там отжимаем клавишу мыши. Сердечко при этом осталось около границы. Далее возвращаем курсор в область окна и сердечко продолжает двигаться за курсосром....
Ребят, сколько ни ковыряю, что-то не могу разобрать. Можно ли устанавливать значения ClientX/ClientY (pageX/pageY), а не просто получать их? Подскажите, для примера, функцию, автоматизирующую некоторое перетаскивание:
1. Устанавливаются заданные координаты Х,Y (150, 250)
2. Происходит нажатие левой кнопки мыши
3. Устанавливаются другие координаты (200,300)
4. Происходит отпускание кнопки
Это бы всё расставило на свои места, заранее благодарю.
статейка понравилась, переделал данный фреймворк под touch-событийную модель, проверил на ipad-е и андроиде, без тормозов пашет, пальцем перемещаются элементы
Заметил баг - если быстро перемещать элемент и отпустить кнопку мыши не над элементом, который сейчас перемещается, то dragObject у элемента становится равным null. Не могу понять из-за чего это может быть, подскажите плиз куда копать.
А как закрепить место за объектом после перемещения?
Чтоб при последующей загрузке страницы объекты были на тех позициях, куда их переместил пользователь?
backgr.png - прозрачный фон, типа щелкаешь на див и на весь экран растягивается другой див с прозрачным фоном на котором работают онмоусмув применительно к первому элементу, двигаешь в большом а двигается маленький Х)
Одни минусы, но круто ведь )
ОГРОМНОЕ спасибо , статья тяжелая после ее прочтение 90% не понял , НО это помогло мне взглянуть с другой стороны на JS , благодаря ей поменя стиль написания кода.
А вот я работаю с формами в проекте и web-технологии плохо знаю. Можно сделать так чтобы из опшыны перетаскивались в другие поля ввода по вашей методике?.. т.е. заполнять поля ввода перетаскивая элементы из списка или таблицы?
Добрый вечер. А я вот заметил, что метод document.elementFromPoint(x,y) во всех браузерах сейчас ведет себя одинаково. В смысле везде принимает clientX/Y.
Пример
var x = e.clientX,//e.pageX - window.pageXOffset,
y = e.clientY//e.pageY - window.pageYOffset,
element = document.elementFromPoint(x, y);
проверял в Ie9, ff 17, chrome 23, opera 12, стандартный браузер android (версия браузера 4.0.4) , dolphin browser 9.0.1 ... кто-нибудь может проверить на ios ? скорей всего там все хорошо, но хотелось бы точно знать
Илья, спасибо огромное за отличную разжёванную до мелочей статью!
Я у себя в проекте использую твой код (финал). У меня также используется для вывода тултипов маленькая библиотека qtip. Так вот после того как я перемещаю с помощью твоего решения объект, все тултипы начинают показываться с каким-то диким смещением.
Пробовал вникнуть почему может происходить, не смог. Можешь помочь куда копнуть чтобы починить это?
Ребят, помогите, не могу понять, где нужно значение поменять или что-то подправить. Вопрос в след. Если у элементов сразу абсолютное позиционирование то при нажатие элемент от курсора очень далеко, но всё остальное работает. Где исправить это?
Добрый день.
Не могу разобраться с переносом "между". Смысл задачи в том, что у меня в одном divе рандомно генерируются какое то количество html элементов и их нужно уметь перетаскивать в другой div. C самим переносом и обычным дропом разобрался, добавляю во второй div с помощью appendChild, соответственно элементы добавляются просто в конец. Проблема в том как добавить не в конец, а в любое другое место. Может кто-нибудь помочь разобраться?
Спасибо, большое Илья за статью, но у меня никак не получается при перетаскивании объекта на принимающем заставить исчезать тект или блок с текстом. К примеру: в примере с nested.html есть блок drop - как сделать так, чтобы при перетягивании на него объекта в момент отпускания кнопки мыши он исчезал?
<style type="text/css">
div.dragElement {font-size: large; border: thin solid black; padding:16px;
width: 8em; text-align: center; background-color: lightgray; margin: 4px }
#container { border: medium double black; width: 700px; height: 450px}
</style>
<script type="text/javascript">
$(function() {
$('.dragElement').draggable({
containment: "parent"
}).mousemove(function(){
var coord = $(this).position();
$("p:last").text( "left: " + coord.left + ",id: " + coord.id + ", top: " + coord.top );
alert('Квадрат с ID "' + draggable.attr('id') + '" был доставлен к месту назначения!');
}).mouseup(function(){
var coords=[];
var coord = $(this).position();
var item={ coordTop: coord.left, coordLeft: coord.top };
coords.push(item);
var order = { coords: coords };
$.post('updatecoords.php', 'data='+$.toJSON(order), function(response){
if(response == "success")
$("#respond").html('<div class="success">X and Y Coordinates Saved!</div>').hide().fadeIn(1000);
setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);
})
});
});
</script>
</head>
<body>
<div id="container">
<?=
$req = mysql_query("SELECT * FROM `table` WHERE `ref` = '1' ORDER BY `reallid` LIMIT 3;");
while ($res = mysql_fetch_array($req)) {
$i++;
echo ' <div id="dragH_'.$res['uid'].'" uid="dragH" class="dragElement ui-widget ui-corner-all ui-state-error">
<img src="images/zdaneya/'.$res['uid'].'_1.png" width="" height="" alt="" border="0">
</div>';
}
?>
</div>
</body>
</html>
Подскажите как получить содержимое id="dragH_'.$res['uid'].'" после окончания перемешения элемента, хочу организовать запись этих данных в BD но не могу получить индефикатор перетаскиваемой записи для дальнейшева сохранения с новыми координатами:(
Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with more information? It is extremely helpful for me...thanks
It is work and also a way to relax. There are topics you think are boring, but there are topics that you find interesting. Thank you for sharing so much
Awesome blog. I enjoyed reading your articles. This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work t rex game
I’m not sure exactly how I discovered your blog because I had been researching information on Real Estate inWinter Springs, FL, but anyway, I have had a pleasant time reading it, keep it up! ut9winth.com
Oh my goodness! a fantastic write-up dude. Thanks a lot However We’re experiencing issue with ur rss . Do not know why Struggling to register for it. Could there be any person getting identical rss dilemma? Anyone who knows kindly respond. Thnkx glo cart
Oh my goodness! a fantastic write-up dude. Thanks a lot However We’re experiencing issue with ur rss . Do not know why Struggling to register for it. Could there be any person getting identical rss dilemma? Anyone who knows kindly respond. Thnkx glo cart
Most of us commit a great deal of time frame looking released most of these options along with producing jacksonville divorce attorney these folks for individuals just like you, genuine, hard-working people who are sick and tired of working independantly unwell without previously appearing qualified to obtain forward. All of us wish to assist most people obtain additional. Consequently work with all of us in addition to we will retain everyone apprised involving fantastic strategies for making money on-line. Become one of the primary to educate yourself concerning the very best prospects for making massive funds. We live content with talk about by using other folks who sadly are keen to learn, nevertheless , you, in conversation with have the information when you are not within the variety. LtoLto prom dress for sale
Trans Der Hauptgrund, warum viele Menschen das Internet für Sex nutzen, ist also die Anonymität, die es bietet. Hier finden Sie Frauen aus dem ganzen Land, so dass die Wahrscheinlichkeit gering ist, dass Sie jemanden treffen, den Sie kennen. Auf diese Weise können Sie nach geilen Frauen suchen, ohne dass Ihre Freunde und Familie etwas davon wissen. Das macht den Sex-Chat beliebt bei Frauen, die bereits verheiratet sind, aber seit Jahren mit einem erschöpften Sexualleben zu kämpfen haben.
Fantastic blog! Do you have any suggestions for aspiring writers? I’m hoping to start my own blog soon but I’m a little lost on everything. Would you suggest starting with a free platform like Wordpress or go for a paid option? There are so many choices out there that I’m totally overwhelmed .. Any ideas? Appreciate it! iboga for sale
Thank you for sharing such a great with us. I appreciate your sharing this great post. If you forget your password to the Roblox account then you can get back your lost password using the Roblox Password Finder tool.
Thanks for your handy post. Over time, I have come to be able to understand that the particular symptoms of mesothelioma are caused by the actual build up associated fluid between the lining of your lung and the chest muscles cavity. The ailment may start inside chest region and pass on to other parts of the body. Other symptoms of pleural mesothelioma cancer include weight-loss, severe inhaling and exhaling trouble, temperature, difficulty swallowing, and bloating of the face and neck areas. It really should be noted that some people with the disease will not experience just about any serious indications at all. gloextracts
Iskuri Deze site is een beetje onconventioneel in dat het oudere singles koppelt aan jongere partners. Deze site gelooft dat leeftijdsverschillen in relaties minder belangrijk zijn dan het vinden van een gemeenschappelijke basis met een potentiële liefdespartner. Op de site kunt u een profiel aanmaken, tot 10 foto's toevoegen, zoeken op land, staat of stad, een lijst van uw favoriete mensen samenstellen en een vriendelijke "flirt" sturen naar mensen die u graag zou willen ontmoeten. Als je iemand vindt die je interesseert, kun je je gratis aanmelden!
Sex Dortmund ist der beste Ort, um einheimische Frauen kennenzulernen. Wenn Sie Probleme haben, lokale Kontakte mit geeigneten Partnern zu finden, ist unsere Online-Dating-Website für Sie da.
Wonderful post. This post is one of the best posts according to my point of view. Your work is so good and impressive. Thanks for it play poppy playtime free
Я многому научился на этом сайте. Это, безусловно, стоит добавить в закладки для дальнейшего использования. Я поражен тем, сколько времени и труда вы вложили в создание такой интересной веб-страницы. Посетите мою веб-страницу penalty shooters 2 fútbol для получения дополнительной информации.
Thank you for sharing this great post, I am very impressed with your post, the information given is detailed and easy to understand. I will follow your next post often. poppy playtime
Black satta king Easily, the article is actually the best topic on this registry related issue. I fit in with your conclusions and will eagerly look forward to your next updates. Just saying thanks will not just be sufficient, for the fantasti c lucidity in your writing. I will instantly grab your rss feed to stay informed of any updates.
AO Huren ist der beste Ort, um einheimische Frauen kennenzulernen. Wenn Sie Probleme haben, lokale Kontakte mit geeigneten Partnern zu finden, ist unsere Online-Dating-Website für Sie da.
А где код HTML? К чему всё это прекручивать. Я вот новичёк и у меня ничего не работает. А если бы шарил, то относился бы к сайту как к помойке. Я из кода не понимаю к какому id или class всё это прикрутить. Статья бесполезна.
King Size Waterproof Mattress Protector This is my first opportunity to visit this website. I found some interesting things and I will apply to the development of my blog. Thanks for sharing useful information.
Thank you for producing such a fascinating essay on this subject. This has sparked a lot of thought in me, and I'm looking forward to reading more. usps tracking
I wish to show thanks to you just for bailing me out of this particular trouble.As a result of checking through the the net and meeting techniques that were not productive, I was thinking my life was done.
I was very impressed by this post, this site has always been pleasant news Thank you very much for such an interesting post, and I meet them more often then I visited this site.
Of course, your article is good enough, 카지노사이트 but I thought it would be much better to see professional photos and videos together. There are articles and photos on these topics on my homepage, so please visit and share your opinions.
login
I was very impressed by this post, this site has always been pleasant news Thank you very much for such an interesting post, and I meet them more often then I visited this site.
Kik sex is ideaal voor eenmalige verbindingen. Het mooie van losse relaties is dat je er niets voor terug verwacht. Je bent niet verplicht je te binden aan iemand die je niet leuk vindt, en je kunt het gewoon vergeten en verder gaan met iemand anders. Maar als u er een vaste gewoonte van wilt maken, kunt u de persoon in uw contact houden en het opnieuw proberen.
I'm so happy to find you. I also wrote several articles similar to the theme of your writing. I read your article more interesting because there are similar opinions to mine and some parts that are not. I want to use your writing on my blog. Of course, I will leave you my blog address as well. : D. Good job, cheers 먹튀검증사이트
I'm so happy to find you. I also wrote several articles similar to the theme of your writing. I read your article more interesting because there are similar opinions to mine and some parts that are not. I want to use your writing on my blog. Of course, I will leave you my blog address as well. : D. Good job, cheers 먹튀검증사이트
I'm so happy to find you. I also wrote several articles similar to the theme of your writing. I read your article more interesting because there are similar opinions to mine and some parts that are not. I want to use your writing on my blog. Of course, I will leave you my blog address as well. : D. Good job, cheers.
Webcammen.nl is een prachtige landingspagina van schoonheidssalon scheduling software. Het is een intelligent online boekingsplatform dat schoonheidssalon bedrijven helpt een geweldige klantervaring te creëren. Super schoon en netjes ontwerp
Dupcia ist der Ort, an dem man nach Sex sucht. Menschen suchen Sex an verschiedenen Orten. Manche gehen in Bars und Clubs, andere nehmen den ersten Kontakt bei anderen gesellschaftlichen Anlässen auf. Aber der beste Ort, um nach Fickfreunden zu suchen, ist online.
Yo Desi - Watch It Your Way, <a href="https://yodesiserial.org/">Yo Desi Serial</a> Presents All Indian <a href="https://yodesiserial.org/">Hindi Drama</a> Serial regularly. Watch Online Video Episode on Yo Desi Tv in HD.
If the human brain were so simple that we could understand it, we would be so simple that we couldn’t
Looking but not seeing is the hearing but not understanding of the eye
I accidentally searched and visited your site. I still saw several posts during my visit, but the text was neat and readable. I will quote this post and post it on my blog. Would you like to visit my blog later? 온라인카지노사이트
This site is a very great site.
And if you are interested in dramas then I am working on an Indian dramas website.If you want to watch Indian dramas and movies on our site.
We provide you with dramas and movies with high quality graphics.
The article on drag and drop in javascript is a great resource for anyone looking to simplify their interface operations. The drag and drop feature has become a common and convenient way to reorder data and can replace a sequence of clicks. It's interesting to know that almost all javascript libraries implement drag and drop in the same way as described in the article, making it easy to tweak and adapt the existing library to suit individual needs.
Moreover, the article highlights the significance of drag and drop as a remarkable discovery in the field of interfaces, which simplifies a large number of operations. It is indeed a great tool to have for simplifying the appearance of the interface and reducing the need for additional fields and widgets.
Speaking of simplification, I have found a great way to unwind and relax after a long day of coding - playing mahjong gratis. It's a great way to take a break and recharge while enjoying the benefits of a game that can improve cognitive abilities and reduce stress levels. Just like drag and drop simplifies interface operations, mahjong gratis simplifies relaxation and rejuvenation.
What a post I've been looking for! I'm very happy to finally read this post. 카지노사이트 Thank you very much. Can I refer to your post on my website? Your post touched me a lot and helped me a lot. If you have any questions, please visit my site and read what kind of posts I am posting. I am sure it will be interesting.
I’m extremely inspired along with your writing talents and also with the layout for your weblog. Is that this a paid theme or did you customize it your self? Either way stay up the excellent high quality writing, it is rare to peer a nice weblog like this one today. เว็บ ufabet
What a post I've been looking for! I'm very happy to finally read this post. 토토사이트 Thank you very much. Can I refer to your post on my website? Your post touched me a lot and helped me a lot. If you have any questions, please visit my site and read what kind of posts I am posting. I am sure it will be interesting.
Someone necessarily help to make severely articles I might state. That is the first time I frequented your web page and up to now? I surprised with the analysis you made to create this actual publish extraordinary. Fantastic process 하하포커
Great post! I really appreciate the in-depth analysis and thoughtful insights you provided. Your writing style is engaging and easy to follow, making Sativa Juicy Melon Dew accessible for readers of all backgrounds. I also appreciate the fact that you included additional resources for readers who want to learn more about the topic. Keep up the excellent work!"
That's a really impressive new idea! 바카라사이트추천 It touched me a lot. I would love to hear your opinion on my site. Please come to the site I run once and leave a comment. Thank you.
What a post I've been looking for! I'm very happy to finally read this post. 토토사이트 Thank you very much. Can I refer to your post on my website? Your post touched me a lot and helped me a lot. If you have any questions, please visit my site and read what kind of posts I am posting. I am sure it will be interesting.
Tertarik untuk mengetahui lebih lanjut mengenai Nagabet88? Dalam postingan blog kali ini, kami akan bercerita mengenai pengalaman judi yang kami miliki bersama Nagabet88, mulai dari Slot88 Online, Poker88 Online, hingga Live Casino88 Online. Ayo bergabung dan mainkan game-game seru di Nagabet88 bersama kami! Login Nagabet88 Slot Gacor Naga Slot Gacor Naga Akun Slot Pro Link Nagabet88 Nagabet88
Nice post! Acadecraft, one of the most skilled typesetting companies, comprises a team of designers who efficiently format creative engaging books for primary, secondary, and senior secondary levels to deliver professional typesetting services. 사설토토사이트
Ada banyak sekali permainan menarik penghasil uang yang bisa kamu mainkan di situs slot deposit pulsa tanpa potongan dengan minimal deposit 10000 ribu rupiah.
Memainkan game judi online di situs kpop4d memang menyenangkan, selain itu banyak game slot online yang benar-benar gacor, sehingga kita bisa bersenang senang sekaligus menghasilkan uang banyak.
Thankyou for the nice and sharing for the comments great blog!! I have found here lots of important information for my knowledge I need. Fairfax Traffic Lawyer
Excellent article plus its information and I positively bookmark to this site because here I always get an amazing knowledge as I expect. Thanks for this to share with us. outdoor wood furnace
Check out our list of the best methods to get started! From using a third-party service like Gmail or Outlook, to using an email client like Gmail or Outlook on your desktop, we’ve got you covered. 먹튀검증
Nevertheless imagine if you added some great graphics or video clips to give your posts more, “pop”! Your content is excellent but with images and clips, this site could definitely be one of the most beneficial in its niche. https://laoal.com/
Nice post! Acadecraft, one of the most skilled typesetting companies, comprises a team of designers who efficiently format creative engaging books for primary, secondary, and senior secondary levels to deliver professional typesetting services.
Amazing post, it is very impressive and informative content. Would you like want to view private Instagram accounts without human verification? If yes, then you can use Imglookup. Imglookup is safe. This tool is currently one of the best Instagram private account viewer tools without human verification on the market. With complete anonymity, visit the article for more information.
You can certainly see your enthusiasm within the article
you write. The arena hopes for more passionate writers such as you
who are not afraid to mention how they believe. All the time follow your heart. 스포츠토토
Dengan kegembiraan musim sepak bola di atas kita, para penggemar kumpulan situs mpo yang bersemangat bersiap untuk menyemangati tim dan pemain favorit mereka. Seiring dengan keseruan permainan, banyak peminat juga menikmati keseruan tambahan dalam memasang taruhan pada judi bola resmi dengan prediksi mereka. Dalam hal situs taruhan sepak bola, SBOBET telah memantapkan dirinya sebagai platform terdepan dan terpercaya untuk tahun 2023-2024. Mari jelajahi apa yang membedakan SBOBET dari yang lain.
Drag & drop (drag and drop) is a very useful and popular feature in today's websites. This feature allows users to move connections objects from one location to another on the web.
Drag and drop (drag and drop) is a common and useful feature on today's websites. Users can use this connections functionality to move objects from one area to another on the web.
При обработке событий, связанных с мышью, нужен кроссбраузерный способ получения координат курсора из события в обработчике. Кроме того, необходимо знать нажатую кнопку мыши.
Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены. Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
А просто использование jQuery.ui.sortable не нравится?
Или статья именно в обучающих цельях? Тогда, конечно, классно - полезно будет.
Использование jQuery.ui.sortable, а также Dojo draggable, а также других существующих библиотек есть гуд. Другое дело, что они не всегда соответствуют решаемой задаче, занимают больше места, да и вообще полезно понимать, что происходит.
Эх, много бы время мне сэкономила эта статья выйдя на пол года раньше=) Облазил я тогда всё но кроме простых примеров ни чего не нашёл. Раньше я использовал script.aculo и прототип, для проекта где было много перетаскиваемых объектов, что сказать мне не хватило ее функциональности. Не было в ней событий которые вызывались в тот момент когда перетаскиваемый объект начинал заходить и уходить в область drop объекта=) пришлось добавит только предварительно поняв как там всё это устроенно. Вот живой пример. Для простых целей он конечно же подходят.
События которые отображающие весь процесс это:
onStartDrag()
onStopDrag()
onDrag()
onStartHover()
onHover()
onStopHover()
onDrop()
И если их сделать тогда вам больше не чего не придётся дописывать
Все это легко делается..
Можно даже добавить это в нужную библиотеку, если понимать, что и как там работает.
А статья как раз это и описывает.
UPDATED: добавил в статью раздел про рефакторинг с событиями.
Да без условно это хорошая и нужная статья.
Хорошая статья.
Пустую false-функцию для document.ondragstart и document.body.onselectstart тоже можно сделать одну, а не создавать каждый раз при mouseup'e:
Третий день изучаю js, для того что бы заменить формы html на "Drag and Drop" , дабы изменять переменные не перегружая страницу.
Какой метод лучше использовать для этой цели (для FF2) ваш первый или http://elouai.com/javascript-drag-and-drop.php ?
("Демо улучшенного метода" в FF2 под Linux не работает).
Если я "перетащил" div с определенным ID в определенную область - как мне лучше запустить произвольную функцию, передав ей этот ID ?
Спасибо.
В Firefox 2 вполне может не работать. Используйте Firefox 3, а то Firefox 4 пропустите
UPDATE: используйте Firefox 3.5
Статья очень крутая.
Больше всего в это статье мне нравится не сама описываемая в ней тема, хотя и она интересна сама по себе, а то, как автор оперирует ОО подходом применительно к JS. Использует много интересных приемов и главное не отдельно, а непосредственно решая задачу.
Т.е. если он использует обработчик событий, то это не статья об обработчиках, а статья где показано практическое его применение.
И вообще, автор талантлив. Я считаю, что это идеальный обучающий материал. Хотя некоторые моменты не совсем раскрыты, но это вполне верно, так как статья не о них.
Большое спасибо за качественный материал.
отмечаю что статья не доведена до логического конца в зугрузку необходимо добавить не только JS, но и маленький html где используется данный скирпт. тогда вопросов
"Может кто подскажет как использовать???Ну есть у меня этот котроллер.и есть объект, допустим div id="im".Как применить к нему это все???"
возникать не будет. к сожаленю этим страдает не только эта статья здесь.
Добавлю пример.
Пример, конечно, не помешал бы, но.
У меня есть мнение, что изучать программирование и его основы нужно не с этой статьи. Поэтому такие моменты как банальное не знание HTML или не понимание общих принципов программирования как такого (не говоря об ООП), это, в конечном счете, не проблема автора. Цель данной статьи объяснить и принципы, а не дать рабочий пример. Если нужен механизм, то нужно читать не статьи, а документацию библиотек, а лучше базовый курс.
А от вопросов: - "Где в javascript C++?" и - "Как добавить на страницу этот форум?", никуда не деться.
Расширил статью, добавил итоговый вариант после рефакторинга и демо.
Сделал общий скачиваемый архив.
Кода, как всегда, мало. Все чистенько, понятненько, юзабельно.
Отличная статья. Все хорошо расписано и понятно. Для определенных сайтов драг-энд-дроп сильно повысит интерактивность управления (к примеру кидать товары в магазине в тележку).
Всегда привлекала тема drag and drop - в javascript автору благодарность
Спасибо огромное! Теперь я знаю, как решить свою задачу!
зачот
Автор а почему драг и дропятся? шутка
Отличная статья огромное спасибо
Спасибо, все доступно и понятно даже для человека посредственно знающего javascript.
Статья просто отличная - на 5+.
Хотя в таких случаях стараюсь использовать готовое - тот же jQuery.
Неплохо было было добавить реакцию на скролл. А то если во время перетаскивания прокрутить колесо мыши, то объект замирает в первоначальной позиции и потом при малейшем движении рывком прыгает в новое место. Не очень красиво, правда? Также часто делают автоскролл при поднесении объекта к краю экрана.
Да, реакция на скролл и правда не разобрана. Возможно, со временем допишу.
Автопрокрутку делают отслеживанием координат мыши - если у края окна/контейнера то вызывается прокрутка.
По самому событию скролла, чтобы все обработать ок - нужно определить, на сколько прокрутили - и апдейтнуть позицию..
Сейчас тоже мучаюсь с автоскроллом. У меня сцена больше, чем страница. Было бы хорошо это описать.
Все это очень замечательно, но для действительно полноценного drag'n'drop'а следует рассмотреть еще много-много интересного. Итак:
1. Вы совершенно не учитываете возможность наличия других обработчиков mousemove/mouseup, которые могут сделать stopPropagation/cancelBubble, и Ваш drag'n'drop никогда не кончится. Во избежание этой ситуации обработчики mousemove/mouseup следует навешивать С КАПЧУРИНГОМ на document: document.addEventListener('mousemove', callback, true). В IE для тех же целей необходимо установить setCapture на таскаемый элемент.
2. Вы не учитываете возможность прерывания таскания, например, по alt+tab, одновременному нажатию нескольких кнопок мыши или выходу курсора за пределы документа.
3. Есть очень скользкий момент с тем, что после mouseup приходит событие click, которое, вообще говоря, логически вовсе не click - если по клику выполняется какое-то другое действие, то оно после драггинга очевидно выполняться не должно. Поэтому надо в определенных ситуациях слушать приходящий следом click и отменять его.
Это только верхушка айсберга на самом деле. Там еще море всевозможных тонкостей, особенно с разными странными браузерами типа Оперы 9.2 и Сафари под Мак.
И кстати, если говорить про jQuery, его стандартная таскалка про все это тоже ничего не знает.
И кстати, в FF2 Ваши примеры не работают.
В FF2 мои примеры не работают и не будут. Как и в Opera 7. Динозаврам место в музеях.
P.S. Легко можно сделать, чтоб работали, 2 строки кода поправить. Но может не надо а?
FF2 использует примерно 2% пользователей - не так уж и мало. Больше чем Сафари под Мак, например. То же касается Оперы 9.27. А эти два браузера не отслеживают выход мыши за пределы документа (т.е. в строку меню браузера, например).
Выход мыши за пределы документа особенно резкий - вообще нельзя отследить, как и отпускание кнопки там. Можно только
1) Попробовать предусмотреть такой нестандарт и не глюкануть сильно
2) Иметь в виду, что пользователь, который так делает, обычно морально готов к глюкам.
В приципе FF3 событие onmouseup ловит за пределами окна (если конечно мышь туда перемещается в нажатом состоянии. Ну и может дело в том что в своей реализации D&D я вешаю обработчики через addEventListener/attachEvent, чтобы не мешать другим).
А вот у IE с этим проблема (использую 6ую версию). Событие onmouseup ловится за пределами окна только в том случае если нет обработчиков в стиле document.body.onselectstart = funtion(e) {return false;}. Т.е. если работает выделение и мы его не трогаем.
Поэтому для того чтобы, D&D корректно прекращался, а не продолжался после того как кнопка была отпущена "за пределами", необходимо ловить document.[body.]onmouseover и прекращать его если не нажать левая кнопка мыши. Кстати у вас в примерах такой эффект присутствует. D&D продолжается если отжать мышь за пределами ограничивающего контейнера.
В FF2 вполне можно отследить выход курсора за пределы окна, через relatedTarget. В IE надо делать setCapture на нужный элемент и слушать событие onlosecapture.
Это довольно просто сделать, записываем состояние объекта и если up небыло, а down уже было, то сбрасываем перенос.
в статье ещё не рассмотрен случай, когда элемент перетаскивается за его часть (например окно за заголовок) и не написано про обработку вытаскивания элемента за пределы окна
Да этого очень не хватает в статье.
Хорошая статья. Наткнулся на нее когда писал свой drag'n'drop, уже почти все написал, осталось только определить над каким элементом находится курсор при onMouseUp и ответ как это сделать был найден именно тут.
На счет выхода курсора за пределы окна, контроля последующего клика, реакции на alt+tab.. Это уже похоже на попытку контроля хаоса. Ну в крайнем случае можно сделать отмену перетаскивания, если курсор мыши долго не меняет свои координаты. Впрочем даже это кажется мне излишним.
Автору большое спасибо за проделанный труд. Читал с удовольствием
Спасибо за статью.
Чтобы я мог полностью использовать все преимущества этого скрипта - подскажите, как перетаскивать не картинку, а ее копию?
Хочу на базе вашей реализации сделать драг н дроп товаров в корзину.
Надо:
1. Взять мышей картинку.
2. Перетянуть ее на корзину.
При этом изображение товара - должно статично, а перетягиваться копия изображения
Нужно модифицировать код отображения перетаскивания и код завершения drag and drop.
Об этом неоднократно упоминается в статье.
Если не трудно - подскажите.
У меня есть опыт программирования.
Но в некоторых вещах я несилен.
Нужно отметить, что можно столкнуться с ситуацией, когда перетаскиваемый элемент находится в контейнере с абсолютной или относительной позицией.
Поскольку в скрипте отсчет позиции идет от x: 0, y: 0 для body, то такой элемент, при перетаскивании, будет появляться не в месте, где мы его "схватили", а с соответствующим смещением (между "нулями" body и родительского позиционированного элемента). Поскольку "правильное" определение элемента с позиционированием может стоить ресурсов, лучше при перетаскивании делать клон элемента, подсоединяя его к контейнеру body, таким образом обходя вышеуказанную проблему и возможную проблему с вложенностью.
Можно брать offsetХ и У контейнера и прибавлять к координатам.
Уважаемый Илья Кантор! Огромное спасибо Вам за этот ресурс, по-моему, это лучшее, что есть по javascript. Все информация излагается доступно, с логикой развития, полно, с наглядными работающими красивыми примерами!!! Потрясающе!
Может, сделать отдельный тип комментариев "спасибо" ? Конечно, я рад, что мой труд кому-то пригодился, но такие комментарии не добавляют полезности статье..
Спасибо автору, фреймворк очень компактный.
Правда процессор грузит в среднем также как jQuery.ui Drag&Drop. Использовать не так удобно как jQuery.ui
Для повышения удобства и универсальности достаточно вынести функцию обработки дропа из фреймворка на пользовательскую страницу, как это сделано в jQuery.ui
Как это сделать догадается далеко не каждый.
Добрый день,
Статья совсем не ставит целью заменить jquery ui, dojo dijit и прочие фреймворки. Конечно, вы можете адаптировать код под свои нужды или адаптировать поправить тот же jquery ui, используя информацию из статьи.
Успехов вам.
Здраствуйте, очень много нового для меня в этой статье! Дочитал пока до параграфа "Опускаем элемент" а уже возникло несколько вопросов:
1. не понятен синтаксис
e.which = e.button & 1 ? 1 : ( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) )
это же одно и то же что и выражение ниже?
if (e.button==true & 1)
{
e.which = 1
}
else
{
( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) )
}
как расшифровать ( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) ) ???
2. Это ошибка чи нет? Подпараграф "Начало движения: сохранение позиции курсора в элементе"
document.onmousemove = function(e) {
e = fixEvent(e)
...
element.style.left = e.pageX + mouseOffset.x + 'px'
element.style.top = e.pageY + mouseOffset.y + 'px'
...
}
Должно быть наверное ж
document.onmousemove = function(e) {
e = fixEvent(e)
...
element.style.left = e.pageX - mouseOffset.x + 'px'
element.style.top = e.pageY - mouseOffset.y + 'px'
...
}
3. Подпараграф "Демо"
var dragMaster = (
function() {
...код...
} ()
)
для чего выделенные жирным скобки?
4. Интересна функция getPosition, понятно что все работает и этого должно быть мне достаточно:), но если не сложно можете объяснить некоторые моменты:
while (e.offsetParent){
left += e.offsetLeft
top += e.offsetTop
e = e.offsetParent
}
Допустим есть такая конструкция
<div class="test">
<div id="dragElem">
</div>
</div>
В файрбаге я смотрю по dom модели, что свойство offsetParent для дива dragElem = div.test
делаю так
while (e.offsetParent){
left += e.offsetLeft
top += e.offsetTop
e = e.offsetParent
alert(e.offsetParent)
}
и он мне выводит первый раз [object HTMLBodyElement], а второй раз null
что это за прикол? кроссбраузерные глюки?
Заранее спасибо
1. Добавил комментарий об этом в статью. & - это логическое И.
2. Да, опечатка, поправил.
3. Таким образом мы объявляем и тут же создаем объект-синглтон.
4. Что непонятного? IE выводит что-то другое? Вы берете элемент, у которого нет offsetParent (родительского по offset элемента). Естественно, выходит null...
Насчет поправки к скролингу, можно примерно так:
С виду - ошибочка:
(e) ? e.pageY : event.clientY
--- переменная e всегда задана после fixEvent.Да, упистил там, я имел в виду, что те две строчки эквивалентны fixEvent, такое может быть? Точнее по части контроля за скролами.
Что будет если на эту страницу поместить iframe - как будут себя вести перетаскиваемые элементы при перемещении над ним?
Не указан один важный момент. Для Драг&Дропа необходимо заставлять браузер перерисовывать страницу при mouseover. Это в библиотеке просисходит, но для других целей. Заставить перерисовать страницу можно простым обращением к свойству DOM-элемента, которое заставит браузер что-то вычислить:
Не все свойства DOM-элемента подходят для этого, например style.top, т.к. это по-сути всего лишь получение уже установленного значения. В сложный интерфейсах этот момент может сыграть чуть ли не самую важную роль.
Да уж, перетаскивание клона картинки - полезная штука,
а можно ли выложить полный код? А то изменения применил,
но не работает ...
то картинку вообще сдвинуть нельзя, то днд отключается,
и картинка тянется браузером, а не скриптом.
Здравствуйте!
Спасибо полезно, применяю.
Есть вопрос:
У меня перетаскиваемый объект содержит html код (текст картинки и т.д.) он в контейнере table td. (таблицей нарисовано обрамление содержания)
В js новичОк, не могу сделать так чтобы таскать только за область границы вокруг.
При этом по mousedown на контенте контейнера не таскать но выделять текст.
вот пример
http://webpokaz.ru/media/test/testgallery.html
И еще одно, после нескольких внесенных исправлений повесил ИЕ...
В этой версии, при том что локально все работает, выложил в нет и ИЕ повис.
Рассмотрите пожалуйста мой пример. Очень надеюсь на вашу помощь
Я только что столкнулся с данной проблемой - мне необходимо было иметь возможность перетаскивать всплывающее окошко:
Так вот, для того, чтобы беспроблемно таскать это всплывающее окошко, я просто подставил в вызове не его само, а его хэдер, т.е. в данном случае dTitle, а в самом скрипте сделал так:
В моем случае помогло, надеюсь, поможет и вам
я тут задумался, интересно, как можно сделать так, задать акцептеру например класс объектов, которые он может принимать
например:
типа того, т.е. акцептер object будет принимать в себя только объекты имеющие класс items
точно так же, объектом которым мы говорим драгиться, что им можно располагаться тока в акцептеры
Всего лишь проверять перед тем или иным действием свойство className объекта.
Вот эщто действительно хорошая статья по переносу объектов.! респект!
Здесь возвращается позиция элемента относительно документа
а тут элементу назначаются координаты относительно родительского элемента
и если задать родительскому элементу position, перетаскиваемый прыгает
в исходном файле demo.html я приписал позицию для дива
так и чешутся руки скрипты украсть!
Полный JS решение проблемы с input ами
Статья действительно супер, но добавлю пару замечаний.
Во-первых, по поводу pageX/Y и clientX/Y: Chrome и Opera 10.5 уже тоже использует clientX/Y, по крайней мере с ним всё работает корректно. Для Opera < 10.5 действительно требуется pageX/Y, но это, по-видимому, единственное исключением из правила, т.к. Opera 10.5 с pageX/Y уже работает некорректно при прокрутке страницы. Как себя ведёт Safari - не смотрел, но учитывая, что это тоже WebKit, подозреваю, что тоже может работать с clientX/Y.
А в Konqueror'е, например, вообще нет метода elementFromPoint. Чем бы его заменить?
Во-вторых, по поводу объектной модели DragObject: те методы, которые у вас "onXXX", я бы назвал просто "xXX", и добавил бы в них if (this.onXXX) onXXX(...), чтобы легче было добавлять в объект обработчики событий. И кроме того, по умолчанию сделал бы восстановление позиции элемента при успешном drag&drop'е, если пользователь захочет - нехай переопределяет.
В-третьих, по поводу используемых локальных переменных - мне кажется логичнее их засунуть в объект (не var element, а this.element = ...), чтобы потом их легко было достать из тех же обработчиков событий, например.
С этими доработками получается уже вполне приличная, но в то же время лёгкая библиотека для drag&drop'а)
DragHelpers.js
DragObject.js
DragMaster.js
DropTarget.js
P.S: тут в редакторе во "вставке ссылки" не работает текст, вставляется ссылка без текста внутри.
Илья, спасибо за умную статью. На основе Вашего материала построил свой сайт.
Но вот столкнулся с проблемой: если перетаскиваемый объект (в примере картинка img/piki.gif) заключены в html-ссылку, например:
[a target=_blank href=http://mysite.com][img src="img/piki.gif" id="piki"/][/a]
то после перетаскивания такой картинки броузеры ведут себя по-разному.
В частности, Google Hrome после перетаскивания открывает новую вкладку, т.е. отрабатывает тег [a]. Как бы предотвратить это? То есть, клик по картинке должен отправлять пользователя по адресу, указанному в href... Но если пользователь только переместил картинку, то перехода быть НЕ должно.
Виталию Филиппову:
в Вашем сообщении все ссылки указывают на один и тот же файл DragHelpers.js
как скачать другие?
Илья, спасибо за умную статью. На основе Вашего материала построил свой сайт.
Но вот столкнулся с проблемой: если перетаскиваемый объект (в примере картинка img/piki.gif) заключены в html-ссылку, например:
(a target=_blank href=http://mysite.com)(img src="img/piki.gif" id="piki"/)(/a)
то после перетаскивания такой картинки броузеры ведут себя по-разному.
В частности, Google Hrome после перетаскивания открывает новую вкладку, т.е. отрабатывает тег (a).
Как бы предотвратить это? То есть, клик по картинке должен отправлять пользователя по адресу, указанному в href... но если пользователь только переместил картинку, то перехода быть НЕ должно.
Чтобы перехода не было - нужно отменять реакцию браузера по умолчанию для события на элементе
a
используя preventDefault.А как отменить срабатывание onclick? C атрибутом href проблем нет, а вот onclick никак не могу побороть.
Использую эти скрипты для DnD. Очень сильно грузять процессор. Под FF и Chrome еще как-то шевелятся(95%), а под IE вначале перетаскивания проц загружается на 100% и по этой причине объект не визуализируется, ему просто некогда. Это происходит даже если после начала движения просто остановить мышку но не отпускать левую клавишу. Постоянно срабатывает событие mousemove, хотя движения мышкой нет. В чем может быть причина? Если не победю придется на другой фреймоворк переходить, а это месяц отладки.
Очень странно что событие mousemove срабатывает без движения мышкой. Не бывает такого..
Мне кажется, что к проверке прав второго типа (асинхронный запрос) надо добавить предварительную проверку прав на всех объектах, которые могут быть перетаскиваемыми, на этапе формирования страницы (PHP).
Например, если у нас есть сотня объектов трех типов, мы можем выделить эти типы. И у нас есть авторизованный (или неавторизованный, гость) пользователь, у которого есть права. Для каждого типа объектов проверяются права на перенос - да, нет. Всего лишь булевая переменная, которая добавляется в свое свойство объекту. Таким образом мы отсекаем бОльшую часть "отбракованных" переносов еще до их совершения. Кстати абсолютное большинство "отбракованных" переносов будет говорить о попытках изменить что то в коде страницы и получить доступ к запрещенным элементам: если проект - онлайн-игра, такому пользователю можно выносить предупреждение, и знать, что от него можно ждать попыток эксплоитов и багоюзерства =)
сдается мне что если dran-n-drop элемент будет находится в блоке с position:relative, то не правильное поведение будет при перемещениии
Safari не дропает в примерах итогового фреймворка...
Спасибо за статью!
Но вот глюк...
Взял за основу пример с 2-мя вложенными дивами.
если на странице с примером появляется полоса прокрутки вниз
То в Opera прокрутив чуть чуть и попробовав перенести, меняется позиция droptarget, а именно становится выше реального((( Подскажите?
Вопрос:
А как можно сделать сразу все объекты передвигаемыми? Т.е. сделать это до того как их в первый раз передвинут?
есть одна проблема с получением координат мыши отномительно документа: при нахождении мыши над обьектом со свойством position:fixed; в интернет эксплорере значение координат остается не определенным.. как можно это исправить?
а ни кто не встречал библиотеки драг анд дроб сразу с записью в кукис?
А с записью в кукис таких библиотек ни кто не встречал?
Мне вот интересно насчет дропа между элементами. Чтобы делить акцепторы на 2 части, для определения выше или ниже будет дропаться элемент, нужно знать его высоту, которую можно снять c помощью getComputedStyle, но подобный метод для IE (currentStyle) вернет "auto" если высота нигде не задана, и как же тогда быть, если все элементы "списка" (подразумевается некий набор блочных элементов) разной высоты, которая нигде не задана, а зависит от количества контента блока.
Интересно, конечно, но вот практическая применимость сего на сегодня мне кажется сомнительной. Точнее, в некоторых браузерах работать будет, в некоторых (пусть это считаные проценты пользователей) будут одни глюки.
Мне самому хотелось бы кой-чего замутить (не без драг-н-дропа), но как прикину, сколько на это времени уйдёт, чтобы хотя бы в паре основных браузеров работало без нареканий, так руки и опускаются. Тут уже перечислили выход мышки за пределы окна и т.д. с комментариями "если пользователь это делает, то он морально готов к глюкам".
Даже не знаю, как это комментировать. Если вы наворачиваете на сайт свистулек и чего там ещё, нужно добиваться того, чтобы с ними результат был лучше, чем без них. Зачем нужны свистульки, если из-за них у пользователя заглючит интерфейс? При чём не просто какая-нибудь картинка на полсантиметра в сторону съедет, а вообще страницу заклинит.
Если же вы не можете обеспечить безглючную работу задуманного - не беритесь.
"Надо там ещё додумать, надо там ещё доделать, ещё пользователь может вот так, ну это всё равно, а может ещё и так, ну и плевать, пусть развалится."
"Вот вечно у нас так всё, на авось, авось не всплывёт, небось и так сойдёт, везде халтура. А я хочу, чтобы наша липовая печать была лучшей печатью во всей прокуратуре!"
Если бы автомат калашникова клинило в тот момент, когда пользователь "должен быть морально готов к глюкам" - был бы он брендом номер один в своей области?
Уважаемый Илья. Очень прошу уточнить как вместо alert произвести асинхронный запрос. И самое главное как после того как, dragObject будет отпушен на акцепторе
запретить ему Drag and drop?????
А как быть с глюком в ie...
Последовательность:
хватаем сердечко из примера
http://javascript.ru/ui/draganddrop#demo-4
ведем его до верхней границе окна
неотпуская мыши уводим ее за границу окна и там отжимаем клавишу мыши. Сердечко при этом осталось около границы. Далее возвращаем курсор в область окна и сердечко продолжает двигаться за курсосром....
Ребят, сколько ни ковыряю, что-то не могу разобрать. Можно ли устанавливать значения ClientX/ClientY (pageX/pageY), а не просто получать их? Подскажите, для примера, функцию, автоматизирующую некоторое перетаскивание:
1. Устанавливаются заданные координаты Х,Y (150, 250)
2. Происходит нажатие левой кнопки мыши
3. Устанавливаются другие координаты (200,300)
4. Происходит отпускание кнопки
Это бы всё расставило на свои места, заранее благодарю.
цель драг-дропа можно определять onouseover целей я думаю
статейка понравилась, переделал данный фреймворк под touch-событийную модель, проверил на ipad-е и андроиде, без тормозов пашет, пальцем перемещаются элементы
Подскажите, как вы переделали событие mousemove?
И если не сложно, можно посмотреть код?
onmousemove == ontouchmove
Заметил баг - если быстро перемещать элемент и отпустить кнопку мыши не над элементом, который сейчас перемещается, то dragObject у элемента становится равным null. Не могу понять из-за чего это может быть, подскажите плиз куда копать.
Разобрался, то я затупил)
А как закрепить место за объектом после перемещения?
Чтоб при последующей загрузке страницы объекты были на тех позициях, куда их переместил пользователь?
backgr.png - прозрачный фон, типа щелкаешь на див и на весь экран растягивается другой див с прозрачным фоном на котором работают онмоусмув применительно к первому элементу, двигаешь в большом а двигается маленький Х)
Одни минусы, но круто ведь )
ОГРОМНОЕ спасибо , статья тяжелая после ее прочтение 90% не понял , НО это помогло мне взглянуть с другой стороны на JS , благодаря ей поменя стиль написания кода.
Спасибо!
А вот я работаю с формами в проекте и web-технологии плохо знаю. Можно сделать так чтобы из опшыны перетаскивались в другие поля ввода по вашей методике?.. т.е. заполнять поля ввода перетаскивая элементы из списка или таблицы?
Добрый вечер. А я вот заметил, что метод document.elementFromPoint(x,y) во всех браузерах сейчас ведет себя одинаково. В смысле везде принимает clientX/Y.
Пример
var x = e.clientX,//e.pageX - window.pageXOffset,
y = e.clientY//e.pageY - window.pageYOffset,
element = document.elementFromPoint(x, y);
проверял в Ie9, ff 17, chrome 23, opera 12, стандартный браузер android (версия браузера 4.0.4) , dolphin browser 9.0.1 ... кто-нибудь может проверить на ios ? скорей всего там все хорошо, но хотелось бы точно знать
Илья, спасибо огромное за отличную разжёванную до мелочей статью!
Я у себя в проекте использую твой код (финал). У меня также используется для вывода тултипов маленькая библиотека qtip. Так вот после того как я перемещаю с помощью твоего решения объект, все тултипы начинают показываться с каким-то диким смещением.
Пробовал вникнуть почему может происходить, не смог. Можешь помочь куда копнуть чтобы починить это?
Здравствуйте, подскажите почему у меня в этом коде
elem для ИЕ 8 всегда null ?
За ранее спасибо
Добрый день, воспользовался Вашим скриптом, очень понравилось, большое Вам спасибо.
Но возник вопрос, как вернуть элемент туда откуда взял?
млять автор штмл чо не выложил куда что в самом начале не.... не понятно.Исходники где для начальных примеров.
Учите сперва основы, раз не можете понять элементарные вещи.
Огромное спасибо!
Ребят, помогите, не могу понять, где нужно значение поменять или что-то подправить. Вопрос в след. Если у элементов сразу абсолютное позиционирование то при нажатие элемент от курсора очень далеко, но всё остальное работает. Где исправить это?
Добрый день.
Не могу разобраться с переносом "между". Смысл задачи в том, что у меня в одном divе рандомно генерируются какое то количество html элементов и их нужно уметь перетаскивать в другой div. C самим переносом и обычным дропом разобрался, добавляю во второй div с помощью appendChild, соответственно элементы добавляются просто в конец. Проблема в том как добавить не в конец, а в любое другое место. Может кто-нибудь помочь разобраться?
Спасибо, большое Илья за статью, но у меня никак не получается при перетаскивании объекта на принимающем заставить исчезать тект или блок с текстом. К примеру: в примере с nested.html есть блок drop - как сделать так, чтобы при перетягивании на него объекта в момент отпускания кнопки мыши он исчезал?
Подскажите как получить содержимое id="dragH_'.$res['uid'].'" после окончания перемешения элемента, хочу организовать запись этих данных в BD но не могу получить индефикатор перетаскиваемой записи для дальнейшева сохранения с новыми координатами:(
Внедрено на websash
Very interesting information!Perfect just what I was searching for! candy crush
Огромное спасибо! порно видео
I really like your site and especially this post with lots of good and informative information. Very helpful to me.
boxnovel
Thank you so much for sharing these amazing tips. I must say you are an incredible writer, I love the way that you describe the things. Please keep sharing.
https://dognames225.hatenablog.com/entry/2019/04/01/151733
https://dognamesinfo.blogspot.com/2019/04/big-dog-breeds.html
https://dognamesinfo.blogspot.com/2019/04/dogs-phisical-activity.html
https://dognamesinfo.blogspot.com/2019/04/choose-perfect-family-dog.html
https://bestdognamess.wordpress.com/2019/04/07/toy-dog-breeds/
https://bestdognamess.wordpress.com/2019/04/07/different-types-of-dog-br...
https://bestdognamess.wordpress.com/2019/04/07/mans-best-friend-dogs/
https://riowicks.weebly.com/blog/dog-grooming-tips
https://riowicks.weebly.com/blog/dog-training-tips
https://taylahroach.weebly.com/blog/dental-tips-for-dogs
https://taylahroach.weebly.com/blog/dog-training
Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with more information? It is extremely helpful for me...thanks
It is work and also a way to relax. There are topics you think are boring, but there are topics that you find interesting. Thank you for sharing so much
Awesome blog. I enjoyed reading your articles. This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work t rex game
wow, awesome blog. 먹튀검증커뮤니티
Very informative article.Thanks Again. Really Great. 소액대출
My good friend tell me for web place with hot sexy ladies ready for free chat – sextreffen kärnten so I tell you now
Необычный пост! Я не знал об этих активах, и я пойду их сейчас!
sex klagenfurt is great web platform for casual sex contacts with fine ladies in EU
I am really thankful to you for sharing such useful info. Hope you are sharing the same in future. Thanks 메이저사이트추천
I’m not sure exactly how I discovered your blog because I had been researching information on Real Estate inWinter Springs, FL, but anyway, I have had a pleasant time reading it, keep it up! ut9winth.com
If you don't like the default ringtone on your phone, dzwonek na telefon will provide you with quality ringtones and free download
I tried to publish a comment earlier, yet it has not shown up. I assume your spam filter may possibly be broken? 補習社
Oh my goodness! a fantastic write-up dude. Thanks a lot However We’re experiencing issue with ur rss . Do not know why Struggling to register for it. Could there be any person getting identical rss dilemma? Anyone who knows kindly respond. Thnkx glo cart
Oh my goodness! a fantastic write-up dude. Thanks a lot However We’re experiencing issue with ur rss . Do not know why Struggling to register for it. Could there be any person getting identical rss dilemma? Anyone who knows kindly respond. Thnkx glo cart
Most of us commit a great deal of time frame looking released most of these options along with producing jacksonville divorce attorney these folks for individuals just like you, genuine, hard-working people who are sick and tired of working independantly unwell without previously appearing qualified to obtain forward. All of us wish to assist most people obtain additional. Consequently work with all of us in addition to we will retain everyone apprised involving fantastic strategies for making money on-line. Become one of the primary to educate yourself concerning the very best prospects for making massive funds. We live content with talk about by using other folks who sadly are keen to learn, nevertheless , you, in conversation with have the information when you are not within the variety. LtoLto prom dress for sale
Trans Der Hauptgrund, warum viele Menschen das Internet für Sex nutzen, ist also die Anonymität, die es bietet. Hier finden Sie Frauen aus dem ganzen Land, so dass die Wahrscheinlichkeit gering ist, dass Sie jemanden treffen, den Sie kennen. Auf diese Weise können Sie nach geilen Frauen suchen, ohne dass Ihre Freunde und Familie etwas davon wissen. Das macht den Sex-Chat beliebt bei Frauen, die bereits verheiratet sind, aber seit Jahren mit einem erschöpften Sexualleben zu kämpfen haben.
Fantastic blog! Do you have any suggestions for aspiring writers? I’m hoping to start my own blog soon but I’m a little lost on everything. Would you suggest starting with a free platform like Wordpress or go for a paid option? There are so many choices out there that I’m totally overwhelmed .. Any ideas? Appreciate it! iboga for sale
I gotta favorite this internet site it seems handy invaluable lONG Island Tree service
Thank you for sharing such a great with us. I appreciate your sharing this great post. If you forget your password to the Roblox account then you can get back your lost password using the Roblox Password Finder tool.
wordle online is a great game to have on hand when you're down, tired, or just need a little reminder that life is beautiful
Roksa pl turek
Roksa pl rybnik
Thanks for your handy post. Over time, I have come to be able to understand that the particular symptoms of mesothelioma are caused by the actual build up associated fluid between the lining of your lung and the chest muscles cavity. The ailment may start inside chest region and pass on to other parts of the body. Other symptoms of pleural mesothelioma cancer include weight-loss, severe inhaling and exhaling trouble, temperature, difficulty swallowing, and bloating of the face and neck areas. It really should be noted that some people with the disease will not experience just about any serious indications at all. gloextracts
Thank you for each of your efforts on this web page. friendly farms carts
Sex Schleswig-Holstein
Hi, your blog is full of comments and it is very active” 토토커뮤니티
Well done! I appreciate your contribution to this matter. It has been insightful. my blog: lemonade diet 작업대출
Roksa odolanow
Roksa nuru
Roksa jablonka
Roksa polkowice
Very good points you wrote here..Great stuff...I think you've made some truly interesting points.Keep up the good work. personal financial advisor
We pay attention to every detail and work hard to offer the high quality you expect.
Iskuri Deze site is een beetje onconventioneel in dat het oudere singles koppelt aan jongere partners. Deze site gelooft dat leeftijdsverschillen in relaties minder belangrijk zijn dan het vinden van een gemeenschappelijke basis met een potentiële liefdespartner. Op de site kunt u een profiel aanmaken, tot 10 foto's toevoegen, zoeken op land, staat of stad, een lijst van uw favoriete mensen samenstellen en een vriendelijke "flirt" sturen naar mensen die u graag zou willen ontmoeten. Als je iemand vindt die je interesseert, kun je je gratis aanmelden!
I bring to everyone a great mobile ringtones website available at télécharger musique gratuitement pour portable to listen to it for free
Hola i would really love to subscribe and read your blog posts ! abcslot
You should be a part of a contest for just one of the best blogs on the net. I’ll recommend this website! abcslot
You should be a part of a contest for just one of the best blogs on the net. I’ll recommend this website! abcslot
Sex Dortmund ist der beste Ort, um einheimische Frauen kennenzulernen. Wenn Sie Probleme haben, lokale Kontakte mit geeigneten Partnern zu finden, ist unsere Online-Dating-Website für Sie da.
Poppy playtime is developed by MOB Games. It's one of the most popular horror games right now.
Wonderful post. This post is one of the best posts according to my point of view. Your work is so good and impressive. Thanks for it play poppy playtime free
Я многому научился на этом сайте. Это, безусловно, стоит добавить в закладки для дальнейшего использования. Я поражен тем, сколько времени и труда вы вложили в создание такой интересной веб-страницы. Посетите мою веб-страницу penalty shooters 2 fútbol для получения дополнительной информации.
i always syndicate feeds on my subcribers and of course feedburner is definitely a great help~ desi sex stories
fnf wiki Hola i would really love to subscribe and read your blog posts!!!
Thank you for sharing this great post, I am very impressed with your post, the information given is detailed and easy to understand. I will follow your next post often. poppy playtime
Black satta king
Easily, the article is actually the best topic on this registry related issue. I fit in with your conclusions and will eagerly look forward to your next updates. Just saying thanks will not just be sufficient, for the fantasti c lucidity in your writing. I will instantly grab your rss feed to stay informed of any updates.
AO Huren ist der beste Ort, um einheimische Frauen kennenzulernen. Wenn Sie Probleme haben, lokale Kontakte mit geeigneten Partnern zu finden, ist unsere Online-Dating-Website für Sie da.
Sloescort nabízí nejspolehlivější online seznamování, pokud jde o kontaktování nenasytných místních singlů.
А где код HTML? К чему всё это прекручивать. Я вот новичёк и у меня ничего не работает. А если бы шарил, то относился бы к сайту как к помойке. Я из кода не понимаю к какому id или class всё это прикрутить. Статья бесполезна.
King Size Waterproof Mattress Protector
This is my first opportunity to visit this website. I found some interesting things and I will apply to the development of my blog. Thanks for sharing useful information.
Fantastic article. wonderful reading material Reading such excellent blogs is wonderful. Thanks! If you want to, rock. retro bowl
Fantastic article. wonderful reading material Reading such excellent blogs is wonderful. Thanks! If you want to, rock. retro bowl
Thank you for producing such a fascinating essay on this subject. This has sparked a lot of thought in me, and I'm looking forward to reading more. usps tracking
upadlosc konsumencka gdansk
I wish to show thanks to you just for bailing me out of this particular trouble.As a result of checking through the the net and meeting techniques that were not productive, I was thinking my life was done.
sports betting
I was very impressed by this post, this site has always been pleasant news Thank you very much for such an interesting post, and I meet them more often then I visited this site.
Of course, your article is good enough, 카지노사이트 but I thought it would be much better to see professional photos and videos together. There are articles and photos on these topics on my homepage, so please visit and share your opinions.
Just released at Colors Tv, You can download Bigg Boss 16 Live Episod
메이저놀이터
This blog contains so many interesting stuff that makes me want to visit again and again. Look forward for more interesting updates..
Your article was very impressive to me. It was unexpected information,but after reading it like this 바카라사이트추천, I found it very interesting.
There must have been many difficulties in providing this information. 카지노사이트 Nevertheless, thank you for providing such high-quality information.
meble do biura
Amazing knowledge and I like to share this kind of information with my friends and hope they like it they why I do.
https://londoncardiovascularsociety.com/
https://assitecforum.com/
https://harga-acemaxs.net/
https://inteligenciadigital2013.com/
https://almostawakeband.com/
https://ontaskfamily.com/
https://avadorfmanseniorcenter.com/
https://endlessinside.com/
https://edubooksrent.com/
https://customercontactexchange.com/
https://mixedbytoast.com/
https://thisaintnarnia.com/
https://riseofthelegend-movie.com/
https://smithbizpartners.com/
https://midwayhomesolutions.com/
https://grupoescomic.com/
https://keepmiddletownbeautiful.com/
https://filam18plus.com/
https://kellyhymannews.com/
https://saltybroadpress.com/
https://pipesplumbing24h.com/
https://kixberlin.com/
https://indieplottwist.com/
https://tlimefxter.com/
https://besthookupdatewebsites.net/
https://storytellingorganization.com/
https://reef-center-host.com/
https://pic-il.com/
https://sonsnstitches.com/
https://ihatevanderslice.com/
https://futurecomicsonline.com/
https://please-go-away-333.com/
https://israelifrenchbulldogs.com/
https://emp3skyline.com/
https://natejoaquinphotography.com/
https://atasteofmusic.biz/
https://karatecowboyspirit.com/
https://gilbertshotchicken.com/
https://windstoperofsi.com/link-for-sh/
https://footballjaguarsstores.com/link-for-sh/
https://hvenc.com/link-for-sh/
https://fmp2go.com/link-for-sh/
https://yicaitong178.com/link-for-sh/
https://07mni.com/link-for-sh/
https://gangguan39.com/link-for-sh/
https://msa-al.com/link-for-sh/
https://7llool.com/link-for-sh/
https://mhlyzt.com/link-for-sh/
https://77-b.com/link-for-sh/
https://ttg-lb.com/link-for-sh/
https://duankou888.com/link-for-sh/
https://samochody-z-usa.info/link-for-sh/
https://bigtent.info/link-for-sh/
https://mainstreetmarketing.info/2022/10/13/link-for-sh/
https://artuditu.info/link-for-sh/
https://ya998.com/link-for-sh/
https://cocorokids.info/link-for-sh/
https://buy-let.info/link-for-sh/
https://esignsh.com/link-for-sh/
https://110harborviewlane.com/link-for-sh/
https://bbsiberia.com/link-for-sh/
https://mauritius-weather.info/link-for-sh/
https://philadelphiafestival.info/link-for-sh/
https://teatromania.info/link-for-sh/
https://pandorauksales.com/link-for-sh/
https://jncncrouter.com/link-for-sh/
https://zabine.info/link-for-sh/
https://inseldoerfer.info/link-for-sh/
https://darlinks.info/link-for-sh/
https://vitalcleansecomplete.info/link-for-sh/
https://ec-tech.info/link-for-sh/
https://tamuvip4dp.org/link-for-sh/
https://internetysoftware.info/link-for-sh/
https://webclickdirectory.info/link-for-sh/
https://farrant.info/link-for-sh/
https://jasoncoleman.info/link-for-sh/
https://pasarpokerwd.org/link-for-sh/
https://mbahtogel.info/link-for-sh/
https://windstoperofsi.com/how-you-can-make-your-product-the-ferrari-of-...
https://footballjaguarsstores.com/three-methods-to-master-health-care-wi...
https://hvenc.com/9-secrets-how-to-use-health-insurance-to-create-a-succ...
https://fmp2go.com/five-ideas-for-health-care-success/
https://yicaitong178.com/4-things-twitter-desires-yout-to-neglect-about-...
https://07mni.com/why-you-by-no-means-see-a-health-that-truly-works/
https://gangguan39.com/put-together-to-giggle-health-will-not-be-harmles...
https://msa-al.com/make-your-health-center-a-actuality/
https://7llool.com/3-highly-effective-ideas-that-will-help-you-health-in...
https://mhlyzt.com/beware-the-health-rip-off/
https://77-b.com/health-consulting-%c2%96-what-the-heck-is-that/
https://ttg-lb.com/what-make-health-dont-want-you-to-know/
https://duankou888.com/here-copy-this-idea-on-health/
https://samochody-z-usa.info/the-demise-of-health-insurance/
https://bigtent.info/image-your-health-on-high-learn-this-and-make-it-so...
https://mainstreetmarketing.info/2022/10/03/fears-of-a-professional-heal...
https://artuditu.info/need-more-time-learn-these-tricks-to-eliminate-hea...
https://ya998.com/kids-love-health-record/
https://cocorokids.info/find-out-how-to-earn-398-day-using-health-insura...
https://buy-let.info/indicators-you-made-an-amazing-impact-on-health/
https://esignsh.com/by-no-means-lose-your-health-record-once-more/
https://110harborviewlane.com/the-health-thriller/
https://bbsiberia.com/easy-methods-to-create-your-health-strategy-bluepr...
https://mauritius-weather.info/health-care-and-the-chuck-norris-impact/
https://philadelphiafestival.info/particulars-of-health-record/
https://teatromania.info/how-four-issues-will-change-the-best-way-you-ap...
https://pandorauksales.com/fascinating-health-tactics-that-may-help-your...
https://jncncrouter.com/my-health-defined/
https://zabine.info/the-last-word-deal-on-health/
https://inseldoerfer.info/10-rules-about-health-record-meant-to-be-damag...
https://darlinks.info/why-have-a-health/
https://vitalcleansecomplete.info/the-new-angle-on-my-health-just-releas...
https://ec-tech.info/ten-ridiculously-simple-methods-to-improve-your-hea...
https://tamuvip4dp.org/open-the-gates-for-health-benefits-through-the-us...
https://internetysoftware.info/right-here-is-what-it-is-best-to-do-in-yo...
https://webclickdirectory.info/4-issues-id-do-if-i-would-begin-once-more...
https://farrant.info/three-sexy-ways-to-enhance-your-health-care/
https://jasoncoleman.info/a-new-mannequin-for-health/
https://pasarpokerwd.org/one-surprisingly-efficient-way-to-health/
https://mbahtogel.info/seven-important-skills-to-do-health-and-wellness-...
https://misoftbol.com/never-altering-health-will-eventually-destroy-you/
https://camellacrestwood.com/get-probably-the-most-out-of-health-and-fac...
https://windstoperofsi.com/who-else-desires-to-find-out-about-youtube-se...
https://footballjaguarsstores.com/there%c2%92s-massive-money-in-seo/
https://hvenc.com/five-methods-of-seo-strategy-that-can-drive-you-bankru...
https://fmp2go.com/seo-ideas/
https://yicaitong178.com/don%c2%92t-be-fooled-by-youtube-seo/
https://07mni.com/key-pieces-of-youtube-seo/
https://gangguan39.com/find-out-how-to-win-purchasers-and-affect-markets...
https://msa-al.com/in-10-minutes-ill-present-you-with-the-truth-about-se...
https://7llool.com/the-right-way-to-handle-each-seo-services-challenge-w...
https://mhlyzt.com/8-causes-individuals-giggle-about-your-google-seo/
https://77-b.com/tremendous-helpful-ideas-to-enhance-seo-marketing/
https://ttg-lb.com/the-battle-over-seo-tools-and-how-to-win-it/
https://duankou888.com/indicators-you-made-an-excellent-affect-on-youtub...
https://samochody-z-usa.info/nine-issues-to-do-immediately-about-seo/
https://bigtent.info/the-1-youtube-seo-mistake-plus-7-extra-lessons/
https://mainstreetmarketing.info/2022/10/06/methods-to-make-your-youtube...
https://artuditu.info/the-largest-fantasy-about-youtube-seo-exposed/
https://ya998.com/are-you-making-these-local-seo-mistakes/
https://cocorokids.info/how-you-can-do-youtube-seo-in-24-hours-or-a-lot-...
https://buy-let.info/heard-of-the-nice-youtube-seo-bs-concept-right-here...
https://esignsh.com/master-the-artwork-of-youtube-seo-with-these-eight-t...
https://110harborviewlane.com/9-reasons-why-you-might-be-still-an-newbie...
https://bbsiberia.com/hearken-to-your-prospects-they-are-going-to-inform...
https://mauritius-weather.info/59-of-the-market-is-desirous-about-seo-ex...
https://philadelphiafestival.info/the-ability-of-seo-expert/
https://teatromania.info/questioning-how-you-can-make-your-youtube-seo-r...
https://pandorauksales.com/the-place-to-begin-with-seo-tools/
https://jncncrouter.com/how-to-teach-seo-tools-like-a-professional/
https://zabine.info/utilizing-seo/
https://inseldoerfer.info/beware-10-seo-mistakes/
https://darlinks.info/these-10-hacks-will-make-your-seo-expert-look-like...
https://vitalcleansecomplete.info/3-suggestions-for-seo-success/
https://ec-tech.info/what-everyone-ought-to-know-about-youtube-seo/
https://tamuvip4dp.org/9-errors-in-youtube-seo-that-make-you-look-dumb/
https://internetysoftware.info/local-seo-information-to-communicating-va...
https://webclickdirectory.info/youtube-seo-like-a-professional-with-the-...
https://farrant.info/find-out-how-to-make-your-youtube-seo-look-wonderfu...
https://jasoncoleman.info/they-requested-100-specialists-about-seo-tools...
https://pasarpokerwd.org/in-10-minutes-i-am-going-to-offer-you-the-truth...
https://mbahtogel.info/the-ultimate-technique-to-seo/
https://misoftbol.com/the-perfect-5-examples-of-yoast-seo/
https://camellacrestwood.com/youtube-seo-for-sale-%c2%96-how-a-lot-is-yo...
https://windstoperofsi.com/three-artistic-ways-you-may-improve-your-plex...
https://footballjaguarsstores.com/my-life-my-job-my-profession-how-four-...
https://hvenc.com/five-tips-for-proxy-server/
https://fmp2go.com/what-you-dont-learn-about-server-may-very-well-be-cos...
https://yicaitong178.com/5-suggestions-that-may-make-you-influential-in-...
https://07mni.com/top-eight-humorous-plex-media-server-quotes/
https://gangguan39.com/the-nine-largest-plex-server-mistakes-youll-be-ab...
https://msa-al.com/heard-of-the-great-plex-media-server-bs-principle-her...
https://7llool.com/8-issues-everyone-knows-about-sql-server-that-you-don...
https://mhlyzt.com/three-highly-effective-suggestions-that-will-help-you...
https://77-b.com/grasp-the-artwork-of-sql-server-with-these-3-tips/
https://ttg-lb.com/3-secrets-and-techniques-about-server-rack-theyre-non...
https://duankou888.com/how-do-you-outline-server-because-this-definition...
https://samochody-z-usa.info/buying-server/
https://bigtent.info/look-ma-you-can-actually-construct-a-bussiness-with...
https://mainstreetmarketing.info/2022/10/09/take-advantage-of-server-lea...
https://artuditu.info/the-a-z-information-of-proxy-server/
https://ya998.com/the-philosophy-of-windows-server/
https://cocorokids.info/five-practical-ways-to-turn-server-into-a-sales-...
https://buy-let.info/se7en-worst-plex-media-server-methods/
https://esignsh.com/famous-quotes-on-server/
https://110harborviewlane.com/need-to-have-a-more-appealing-sql-server-r...
https://bbsiberia.com/these-5-simple-plex-server-tricks-will-pump-up-you...
https://mauritius-weather.info/3-shocking-info-about-plex-media-server-i...
https://philadelphiafestival.info/look-ma-you-can-actually-construct-a-b...
https://teatromania.info/when-is-the-appropriate-time-to-start-out-serve...
https://pandorauksales.com/why-have-a-server/
https://jncncrouter.com/6-romantic-server-holidays/
https://zabine.info/welcome-to-a-brand-new-look-of-plex-media-server/
https://inseldoerfer.info/the-basics-of-plex-server-you-could-profit-fro...
https://darlinks.info/keep-away-from-the-highest-10-plex-server-mistakes...
https://vitalcleansecomplete.info/plex-server-what-to-do-when-rejected/
https://ec-tech.info/5-easy-suggestions-for-using-plex-server-to-get-ahe...
https://tamuvip4dp.org/right-here-is-what-you-should-do-to-your-plex-med...
https://internetysoftware.info/check-out-this-genius-server-plan/
https://webclickdirectory.info/most-noticeable-plex-media-server/
https://farrant.info/a-stunning-software-that-can-assist-you-plex-server...
https://jasoncoleman.info/6-explanation-why-facebook-is-the-worst-choice...
https://pasarpokerwd.org/who-else-desires-to-achieve-success-with-plex-m...
https://mbahtogel.info/plex-media-server-in-2022-%c2%96-predictions/
https://misoftbol.com/sql-server-for-business-the-principles-are-made-to...
https://camellacrestwood.com/plex-server-the-six-determine-challenge/
https://windstoperofsi.com/straightforward-methods-youll-be-able-to-flip...
https://footballjaguarsstores.com/the-etiquette-of-tech-gadgets-2022/
https://hvenc.com/concern-not-if-you-utilize-high-tech-gadgets-the-preci...
https://fmp2go.com/most-individuals-will-never-be-great-at-high-tech-gad...
https://yicaitong178.com/amateurs-tech-gadgets-but-overlook-a-number-of-...
https://07mni.com/what-everybody-ought-to-know-about-tech-gadgets/
https://gangguan39.com/methods-to-lose-cash-with-tech-and-gadgets/
https://msa-al.com/this-is-why-1-million-prospects-in-the-us-are-high-te...
https://7llool.com/dreaming-of-health-tech-gadgets/
https://mhlyzt.com/why-tech-gadgets-is-the-only-talent-you-actually-need...
https://77-b.com/eight-easy-ways-to-make-hi-tech-home-gadgets-quicker/
https://ttg-lb.com/congratulations-your-tech-gadgets-is-about-to-cease-b...
https://duankou888.com/wondering-how-you-can-make-your-office-tech-gadge...
https://samochody-z-usa.info/are-you-able-to-spot-the-a-tech-gadgets-pro...
https://bigtent.info/why-tech-gadgets-is-not-any-buddy-to-small-enterpri...
https://mainstreetmarketing.info/2022/10/12/when-back-to-school-tech-gad...
https://artuditu.info/four-trendy-methods-to-enhance-on-hvac-tech-gadget...
https://ya998.com/listed-below-are-4-itouch-playzoom-tech-gadgets-techni...
https://cocorokids.info/does-cool-tech-gadgets-generally-make-you-are-fe...
https://buy-let.info/dont-waste-time-5-details-to-start-out-latest-tech-...
https://esignsh.com/need-extra-out-of-your-life-tech-gadgets-tech-gadget...
https://110harborviewlane.com/the-definitive-guide-to-high-tech-gadgets/
https://bbsiberia.com/the-key-of-tech-gadgets/
https://mauritius-weather.info/top-choices-of-tech-gadgets/
https://philadelphiafestival.info/future-tech-gadgets-useless-or-alive/
https://teatromania.info/five-high-tech-bathroom-gadgets-april-fools/
https://pandorauksales.com/the-next-4-things-it-is-best-to-do-for-unique...
https://jncncrouter.com/should-fixing-back-to-school-tech-gadgets-take-6...
https://zabine.info/all-about-itouch-playzoom-tech-gadgets/
https://inseldoerfer.info/easy-methods-you-may-flip-tech-gadgets-into-su...
https://darlinks.info/top-tech-gadgets-the-simple-way/
https://vitalcleansecomplete.info/weird-tech-gadgets-pay-attentions-to-t...
https://ec-tech.info/back-to-school-tech-gadgets-is-crucial-to-your-busi...
https://tamuvip4dp.org/hottest-tech-gadgets-is-essential-to-your-enterpr...
https://internetysoftware.info/6-ways-to-reinvent-your-high-tech-gadgets...
https://webclickdirectory.info/best-tech-gadgets-suggestions-you-will-le...
https://farrant.info/one-of-the-best-way-to-tech-gadgets/
https://jasoncoleman.info/four-days-to-a-better-back-to-school-tech-gadg...
https://pasarpokerwd.org/little-identified-info-about-tech-gadgets-and-w...
https://mbahtogel.info/tech-gadgets-suggestions/
https://misoftbol.com/10-examples-of-latest-tech-gadgets/
https://camellacrestwood.com/new-step-by-step-roadmap-for-tech-gadgets/
https://windstoperofsi.com/apply-any-of-those-6-secret-strategies-to-imp...
https://footballjaguarsstores.com/eight-methods-twitter-destroyed-my-wor...
https://hvenc.com/most-people-will-never-be-nice-at-world-travel-read-wh...
https://fmp2go.com/top-5-ways-to-purchase-a-used-world-travel/
https://yicaitong178.com/four-strategies-of-how-to-travel-the-world-domi...
https://07mni.com/seven-easy-details-about-top-50-travel-destinations-in...
https://gangguan39.com/to-people-who-want-to-begin-fast-travel-locations...
https://msa-al.com/the-hidden-reality-on-travel-around-the-world-crosswo...
https://7llool.com/whos-your-jobs-that-travel-the-world-customer/
https://mhlyzt.com/the-final-word-information-to-travel-the-world-and-th...
https://77-b.com/how-world-travel-inc-modified-our-lives-in-2022/
https://ttg-lb.com/the-which-means-of-travel-around-the-world/
https://duankou888.com/the-final-word-guide-to-travel-around-the-world/
https://samochody-z-usa.info/how-you-can-do-how-much-does-it-cost-to-tra...
https://bigtent.info/how-does-world-travel-holdings-work/
https://mainstreetmarketing.info/2022/10/02/these-details-just-would-pos...
https://artuditu.info/10-methods-to-keep-away-from-world-travel-burnout/
https://ya998.com/ten-factor-i-like-about-new-world-fast-travel-location...
https://cocorokids.info/is-world-travel-holdings-making-me-wealthy/
https://buy-let.info/apply-any-of-those-three-secret-strategies-to-enhan...
https://esignsh.com/seven-easy-details-about-travel-passport-explained/
https://110harborviewlane.com/why-world-travel-is-a-tactic-not-a-techniq...
https://bbsiberia.com/six-ideas-for-world-travel-success/
https://mauritius-weather.info/top-five-lessons-about-most-beautiful-pla...
https://philadelphiafestival.info/apply-these-5-secret-techniques-to-enh...
https://teatromania.info/unanswered-questions-on-travel-the-world-that-i...
https://pandorauksales.com/here-is-a-fast-cure-for-anthony-bourdain-worl...
https://jncncrouter.com/world-travel-holdings-just-isnt-that-difficult-a...
https://zabine.info/the-facility-of-world-travel/
https://inseldoerfer.info/technique-for-maximizing-vantage-deluxe-world-...
https://darlinks.info/buying-world-travel/
https://vitalcleansecomplete.info/10-awesome-recommendations-on-how-to-t...
https://ec-tech.info/the-tried-and-true-methodology-for-world-travel-in-...
https://tamuvip4dp.org/most-beautiful-places-in-the-world-to-travel-is-i...
https://internetysoftware.info/why-world-travel-inc-succeeds/
https://webclickdirectory.info/ought-to-fixing-world-travel-take-60-step...
https://farrant.info/use-world-travel-holdings-to-make-somebody-fall-in-...
https://jasoncoleman.info/want-a-thriving-enterprise-focus-on-fox-world-...
https://pasarpokerwd.org/world-travel-holdings-does-measurement-matter/
https://mbahtogel.info/world-travel-explained/
https://misoftbol.com/get-the-most-out-of-world-travel-and-fb/
https://camellacrestwood.com/when-world-travel-companies-develop-too-rap...
https://windstoperofsi.com/the-games-mystery-revealed/
https://footballjaguarsstores.com/want-extra-cash-start-ps5-games/
https://hvenc.com/six-tips-for-games/
https://fmp2go.com/why-it-is-easier-to-fail-with-games-than-you-might-th...
https://yicaitong178.com/transient-article-teaches-you-the-ins-and-outs-...
https://07mni.com/games-information/
https://gangguan39.com/if-you-want-to-be-a-winner-change-your-games-phil...
https://msa-al.com/the-insider-secrets-for-video-games-uncovered/
https://7llool.com/fascinating-info-i-guess-you-never-knew-about-games/
https://mhlyzt.com/want-more-inspiration-with-games-read-this/
https://77-b.com/proper-here-is-a-technique-that-is-helping-games/
https://ttg-lb.com/heres-why-1-million-clients-in-the-us-are-games/
https://duankou888.com/believing-any-of-these-10-myths-about-games-keeps...
https://samochody-z-usa.info/when-is-the-precise-time-to-start-games/
https://bigtent.info/something-fascinating-occurred-after-taking-motion-...
https://mainstreetmarketing.info/2022/10/05/time-examined-ways-to-games/
https://artuditu.info/essential-video-games-smartphone-apps/
https://ya998.com/3-superior-recommendations-on-games-from-unlikely-webs...
https://cocorokids.info/8-biggest-epic-games-mistakes-you-can-simply-avo...
https://buy-let.info/board-games-an-in-depth-anaylsis-on-what-works-and-...
https://esignsh.com/the-way-forward-for-games/
https://110harborviewlane.com/take-the-stress-out-of-games/
https://bbsiberia.com/learn-this-to-alter-the-way-you-video-games/
https://mauritius-weather.info/every-part-you-wanted-to-know-about-games...
https://philadelphiafestival.info/cool-little-games-tool/
https://teatromania.info/warning-these-9-mistakes-will-destroy-your-game...
https://pandorauksales.com/six-efficient-ways-to-get-more-out-of-games/
https://jncncrouter.com/if-you-dont-games-now-youll-hate-yourself-later/
https://zabine.info/nine-stable-reasons-to-avoid-ps5-games/
https://inseldoerfer.info/who-else-wants-to-know-the-mystery-behind-onli...
https://darlinks.info/free-recommendation-on-profitable-games/
https://vitalcleansecomplete.info/sick-and-tired-of-doing-games-the-prev...
https://ec-tech.info/the-next-seven-issues-you-must-do-for-games-success...
https://tamuvip4dp.org/nine-diy-games-ideas-you-may-have-missed/
https://internetysoftware.info/crazy-epic-games-lessons-from-the-pros/
https://webclickdirectory.info/the-important-thing-to-successful-games/
https://farrant.info/how-to-begin-games-with-much-less-than-a-hundred/
https://jasoncoleman.info/the-insider-secrets-for-free-games-exposed/
https://pasarpokerwd.org/don%c2%92t-be-fooled-by-board-games/
https://mbahtogel.info/8-factors-that-affect-ps5-games/
https://misoftbol.com/video-games-critiques-guide/
https://camellacrestwood.com/three-kinds-of-games-which-one-will-make-th...
https://nacooodesign.com
https://gomobilehardwaretabletsandmore.com
https://upcoming2017com111.com
https://allbussniess.com
https://americancontractingandroofing.com
https://forexoptcom.com
https://hourstokillcom.com
https://investmentbusinessguidemu.com
https://businessclubcomc.com
https://newyorkstatedepartmentofeducation.net
https://ccatthemovies.com
https://eleccionesparaguay2013.com
https://freedropusa.com
https://sandyhooksomewhereovertherainbow.com
https://billofladingnow.net
https://cmrightnow.com
https://socalbikeforums.com
https://urbanicablog.com
https://chriscashman.net
https://distractobot.com
https://programslikelimewirenow.net
https://votevahedi.com
https://dailydisposition.com
https://hepatitisbvaccinenow.net
https://howtomodawii.com
https://joinbomburger.com
https://nowherebutpop.com
https://presbyterianhymnalproject.com
https://revengeonrevengeporn.com
https://sirotaforschools.com
https://somereassemblyrequired.com
https://thethirdrailbook.com
https://alfa-forwarding.com
https://ballcontroloffense.com
https://cactusfloweronstage.com
https://ferrethjobs.com
https://lesbianslovecats.com
https://markoutmoments.com
https://shardofapathy.com
https://skipperstandup.com
https://theflamingruby.net
https://zumbaintoronto.com
https://agrariancountry.com
https://avacummingsauthor.com
https://bacarolosangeles.com
https://badcredituk.net
https://barbershop-venice.com
https://bariatricsurgerypittsburgh.com
https://batsfurryfliers.com
https://bevkearneypursuitofdreams.com
https://boomnatives.com
https://cataclysmfrontlines.com
https://creativeabilitynetwork.com
https://drinkgolfshots.com
https://edwardbellacullen.net
https://fortresssocialclub.com
https://healthagingcentercom.com
https://ichoosewalgreens.com
https://imsotight.com
https://inforajapoker88.com
https://jameshellmold4sheriff.com
https://juliannabananna.com
https://ldsmassresignation.com
https://makeupmodecamera.com
https://malia4president.com
https://masslymeconference.com
https://moviesmusicmayhem.com
https://mtvmodelmaker.com
https://padstracker.com
https://politicalreformer.com
https://prideatthearmory.com
https://radorbad.net
https://realmccainbook.com
https://ridingfuryhomebook.com
https://sanctuaryluangprabang.com
https://savejojo.net
https://timkennedypaintings.net
https://urbanbearnyc.com
https://workinginthesetimes.com
https://addictedinafghanistan.com
https://arizonafightsback.com
https://bobforlacitycouncil.com
https://brianhalltest.com
https://chanelno5campaign.com
https://donatetoabum.com
https://dxdseminar.com
https://faerycharm.net
https://frankperduebook.com
https://getmewowed.com
https://heartofawomanmovie.com
https://houssemdellai.net
https://iamjaxpanik.com
https://liamforliverpool.com
https://librostonic.com
https://mamafinarestaurant.com
https://mariaforcouncil09.com
https://mygeneprofile.com
https://myloveawaitsmebythesea.com
https://nepartisan.com
https://nuffdownload.com
https://oneworldfutubol.com
https://petsocietyworld.com
https://pulporiginals.com
https://puppiandburma.com
https://raregiants.com
https://remiiunderwear.com
https://savehanaleiriverridge.com
https://srlccharleston2012.com
https://thebrainstimulatormethodpdf.com
https://thehonestbrew.com
https://themightyhannibal.com
https://thenextwordahead.com
https://theprimerosephotography.com
https://thequickeningtheatre.com
https://tijuanaflatshotfoods.com
https://titanostrongman.com
https://tranquilitylaketahoe.com
https://turkeysobserver.com
https://twilajean.com
https://votefredhead.com
https://wearefancy.net
https://wondersoftheanimalkingdom.com
https://bladerunner2movie.net
https://castillo4congress.com
https://cjpacactionparty.com
https://closeupspacetheplay.com
https://detroitdialogues.com
https://dogrodeo.net
https://durhalformayor.com
https://eatingyourcontent.com
https://flippinlyme.com
https://gardenpiranha.com
https://gccinsider.com
https://greengirlguide.com
https://helpingheroesgala.com
https://jessicasglutendairyfreekitchen.com
https://joannagreenhill.com
https://libertadcondicionalblog.com
https://marcsheep.com
https://markdebolt.com
https://maybeimjustabitch.com
https://nomoreramenonline.com
https://ohioansagainstlebron.com
https://ohmycreativesoul.com
https://paulemilecendron.com
https://playasmanager.com
https://razormonkeymagazine.com
https://savesilentsam.com
https://scorpionhollywood.com
https://scottdcooper.com
https://boston2portland.com
https://bilericomedia.com
https://bardiventures.com
https://arcticblastpainreliefreview.com
https://appliedmktresearch.com
https://anewvisionfordetroit.com
https://andreabowenonline.com
https://africayouthfund.com
https://wowcohol.com
https://warcrackwear.com
https://uptonupdates.com
https://themosersmusic.com
https://tedxbethesdawomen.com
https://techmunchatl.com
https://taylorroseformt.com
https://stopyellingatmeplease.com
https://stevenpresbergforlacouncil.com
https://sockpuppetasylum.com
https://siciliaactive.com
https://shitheadery.com
https://selmamarchon.com
https://rethinkcali.com
https://pjpolitics.com
https://quotationvault.com
https://paivatango.com
https://nbafanifesto.com
https://nauticalvows.com
https://namobrain.com
https://mp4users.com
https://mobiholics.net
https://missionscollide.com
https://militaryspousechronicles.com
https://merhealthcom.com
https://meettheharpergang.com
https://manjushaskitchen.com
https://loudisladylike.com
https://lostatthecon.com
https://lomskincare.com
https://lmaostuffeveryday.com
https://lavinaskincare.com
https://landryforlouisianaequality.com
https://koortwah.com
https://kodiakfund.com
https://kissless.net
https://kindlystate.com
https://jumpflintridge.com
https://jessiedevineauthor.com
https://jessedavidbarronforcitycouncil.com
https://ironbellyantiques.com
https://intheloopica.com
https://initiativet.net
https://imaculturalreference.com
https://ihateloveremakes.com
https://hotelvinccilys.com
https://holyfreecomedy.com
https://hasitsavani.com
https://gregorywaygallery.com
https://graveshiftmusic.com
https://gotofem.com
https://gnnight.com
https://friscocarpetcleaningpros.com
https://foxcitieshd.com
https://familygonehealthycom.com
https://exodays.net
https://emergencyadapters.com
https://eattchicago.com
https://eddiehpark.com
https://eatingwithedie.com
https://devread.net
https://digitalfestivalasia.com
https://deepsexythoughts.com
https://conversationsonthego.com
https://consolidatedboardofrealtists.com
https://colt45auction.com
https://collectivedwnm.com
https://celebritymoviequotes.com
https://caribbeancurry.com
https://cakesbyaantafel.com
https://boulderbop.com
https://apprejected.com
https://writewithadora.com
https://uprooteddiaries.com
https://thewestboundband.com
https://theshakedowncombo.com
https://thereelcult.com
https://senateunidad.com
https://snowesaxman.com
https://simplesolutionsbook2.com
https://theegyptreport.com
https://thetylerwilliamsband.com
https://tubodeexplosao.net
https://un4seenproductions.com
https://untililoseinterest.com
https://wardenburnsmexicanflags.com
https://woodcontour.net
https://writinginbed.com
https://yscondonews.com
https://themckittricks.net
https://themanifoldmag.net
https://thatlooksdirty.com
https://swissmobilityproducts.com
https://soturesponse.com
https://shamanonramen.com
https://seattlevis.com
https://salisburydecorators.com
https://robertcoleforcitycouncil2015.com
https://redlipsblueeyes.com
https://pensidaantirednesscream.com
https://penfedpromisecardchallenge.com
https://omberzombie.com
https://obamatospeakinmorocco.com
https://nobodyrememberswhocameinsecond.com
https://naotenhoideia.com
https://mealdiaries.com
https://liftupcawages.com
https://libertysecure.net
https://laurensaysitall.com
https://koruproductions.com
https://jennifergeorgecolorado.com
https://jeananyon.com
https://hungry4equality.com
https://honbrettkavanaugh.com
https://highimpacttour.com
https://gopluglife.com
https://generalnormanjohnson.com
https://gamesbrasilonline.net
https://firstbassthemovie.com
https://elaineturnerblog.com
https://dsliteblog.com
https://communityempowermentseries.com
https://cocoaverification.net
https://bulletproofyourjob.com
https://bubbleteafordinner.com
https://annacronicas.com
https://americanaatbrand.net
https://abramsonforlarep.com
https://udanstraight.com
https://bootycampdvd.com
Watch all asian dramas on our site free of cost
login
I was very impressed by this post, this site has always been pleasant news Thank you very much for such an interesting post, and I meet them more often then I visited this site.
Kik sex is ideaal voor eenmalige verbindingen. Het mooie van losse relaties is dat je er niets voor terug verwacht. Je bent niet verplicht je te binden aan iemand die je niet leuk vindt, en je kunt het gewoon vergeten en verder gaan met iemand anders. Maar als u er een vaste gewoonte van wilt maken, kunt u de persoon in uw contact houden en het opnieuw proberen.
I'm so happy to find you. I also wrote several articles similar to the theme of your writing. I read your article more interesting because there are similar opinions to mine and some parts that are not. I want to use your writing on my blog. Of course, I will leave you my blog address as well. : D. Good job, cheers 먹튀검증사이트
I'm so happy to find you. I also wrote several articles similar to the theme of your writing. I read your article more interesting because there are similar opinions to mine and some parts that are not. I want to use your writing on my blog. Of course, I will leave you my blog address as well. : D. Good job, cheers 먹튀검증사이트
I'm so happy to find you. I also wrote several articles similar to the theme of your writing. I read your article more interesting because there are similar opinions to mine and some parts that are not. I want to use your writing on my blog. Of course, I will leave you my blog address as well. : D. Good job, cheers.
Webcammen.nl is een prachtige landingspagina van schoonheidssalon scheduling software. Het is een intelligent online boekingsplatform dat schoonheidssalon bedrijven helpt een geweldige klantervaring te creëren. Super schoon en netjes ontwerp
Dupcia ist der Ort, an dem man nach Sex sucht. Menschen suchen Sex an verschiedenen Orten. Manche gehen in Bars und Clubs, andere nehmen den ersten Kontakt bei anderen gesellschaftlichen Anlässen auf. Aber der beste Ort, um nach Fickfreunden zu suchen, ist online.
Nice Information thanks for sharing. May you bring this more in future. driving directions mapquest
will be praised anywhere. I am a columnist This post is really the best on this valuable topic 온라인카지노\
Great post very well written custom boxes
recommend your website to everyone. You have a very good gloss. Write more high-quality articles. I support you. 온라인카지노
You have performed a great job on this article custom packaging boxes uk
I didn t know there was such a good place like this. I ll come every day now.검증카지노
article are presented in a clear way so I followed your instructions quickly and successfully. . I'm so glad I read this great guide 먹튀검증
your website to everyone. You have a very good gloss. Write more high-quality articles.
check my web site 안전놀이터
Desi Cinemas
| Watch Bollywood Movies Online Free desicinemas
Found a blog related to Telegram Group in which we can find and join unlimited groups.
If the human brain were so simple that we could understand it, we would be so simple that we couldn’t
Looking but not seeing is the hearing but not understanding of the eye
Usps tracking
I accidentally searched and visited your site. I still saw several posts during my visit, but the text was neat and readable. I will quote this post and post it on my blog. Would you like to visit my blog later? 온라인카지노사이트
This site is a very great site.
And if you are interested in dramas then I am working on an Indian dramas website.If you want to watch Indian dramas and movies on our site.
We provide you with dramas and movies with high quality graphics.
The article on drag and drop in javascript is a great resource for anyone looking to simplify their interface operations. The drag and drop feature has become a common and convenient way to reorder data and can replace a sequence of clicks. It's interesting to know that almost all javascript libraries implement drag and drop in the same way as described in the article, making it easy to tweak and adapt the existing library to suit individual needs.
Moreover, the article highlights the significance of drag and drop as a remarkable discovery in the field of interfaces, which simplifies a large number of operations. It is indeed a great tool to have for simplifying the appearance of the interface and reducing the need for additional fields and widgets.
Speaking of simplification, I have found a great way to unwind and relax after a long day of coding - playing mahjong gratis. It's a great way to take a break and recharge while enjoying the benefits of a game that can improve cognitive abilities and reduce stress levels. Just like drag and drop simplifies interface operations, mahjong gratis simplifies relaxation and rejuvenation.
What a post I've been looking for! I'm very happy to finally read this post. 카지노사이트 Thank you very much. Can I refer to your post on my website? Your post touched me a lot and helped me a lot. If you have any questions, please visit my site and read what kind of posts I am posting. I am sure it will be interesting.
I’m extremely inspired along with your writing talents and also with the layout for your weblog. Is that this a paid theme or did you customize it your self? Either way stay up the excellent high quality writing, it is rare to peer a nice weblog like this one today. เว็บ ufabet
What a post I've been looking for! I'm very happy to finally read this post. 토토사이트 Thank you very much. Can I refer to your post on my website? Your post touched me a lot and helped me a lot. If you have any questions, please visit my site and read what kind of posts I am posting. I am sure it will be interesting.
Someone necessarily help to make severely articles I might state. That is the first time I frequented your web page and up to now? I surprised with the analysis you made to create this actual publish extraordinary. Fantastic process 하하포커
Great post! I really appreciate the in-depth analysis and thoughtful insights you provided. Your writing style is engaging and easy to follow, making Sativa Juicy Melon Dew accessible for readers of all backgrounds. I also appreciate the fact that you included additional resources for readers who want to learn more about the topic. Keep up the excellent work!"
That's a really impressive new idea! 바카라사이트추천 It touched me a lot. I would love to hear your opinion on my site. Please come to the site I run once and leave a comment. Thank you.
123mkv
Watch and Download Movies at 123 mkv
I really like your site and especially this post with lots of good and informative information. Very helpful to me.
What a post I've been looking for! I'm very happy to finally read this post. 토토사이트 Thank you very much. Can I refer to your post on my website? Your post touched me a lot and helped me a lot. If you have any questions, please visit my site and read what kind of posts I am posting. I am sure it will be interesting.
adt
viralslot
tiktok slot
slot depo shopepay
permata 55 login
mantul slot login
ajaib slot
maduslot
slothoki4d
elang 123 slot
dolarslot 508
djarum slot
bigslot88
asia gaming777
4dku slot
akun jp slot
play1628
win99
winslot
raja slot 303
sbobet casino live
idn poker live chat
shio 88 login
shio88 login
situs303 slot login
slot mandiri 24 jam
rumus 24d spin
xlslot88
semar jitu77 login
masterjudibola
rajacuan
rajaslot
ratuslot
slot server filipina
slot server kamboja
sultan slot login
wow hoki
slot via linkaja
slot deposit via bank neo
slot qris
slot sakuku
deposit pakai pulsa smartfren
slot vietnam
slotvip777
slotwin88
slot winrate tertinggi
link slot zeus gacor
slot server thailand
slot server tokyo
slot server turkey
vip gacor login
gacor50000
slot shopeepay
slot singapore
server singapore slot
slot thailand
slot deposit pulsa tri
slot server luar
slot malaysia
slot server myanmar
server nexus engine
slot server nigeria
slot phnom penh
slot server polandia
slot server rusia
slot server singapore
slot server taiwan
slot server belanda
slot server china
slot server dubai
slot server eropa
slot server gacor penghasil uang
slot server idn
slot server ina
slot server infini88
slot server jakarta
slot server kamboja
slot olympus malaysia
slot paypal
deposit slot pakai pulsa telkomsel 10rb
gacorx5000
slot deposit pulsa xl 10 ribu tanpa potongan
eropa slot
slotresmi
slot sakuku
slot server arab
server asia slot
slotjakarta
slot jepang
slot kakek
kakek zeus slot
bo slot kamboja aman terpercaya
slot luar negeri
daftar slot mahjong online
situs slot malaysia
slot mandiri
megawin slot
slotjakarta
slot jepang
slot kakek
kakek zeus slot
bo slot kamboja aman terpercaya
slot luar negeri
daftar slot mahjong online
situs slot malaysia
slot mandiri
megawin slot
slot bank bsi
slot china
dokuslot
slot server philippines
gacor4d login
slot888 gacor
link kakek zeus
slot hoki asia
slot hongkong gacor
slot deposit pulsa indosat
slot deposit bank neo commerce
slot bank dana
slot bank danamon
slot bank jago
permata slot
slot bank bca
big win slot
bnislot
slot server brazil
slot bri
slot hongkong
joker123 slot
raja slot303
slot4dgacor
cair4d
bca slot88
slot88pulsa
alfa slot
alibaba 4d slot
amerika slot
playland 888
slot raja777
sbowin mobile
fafa slot
situs judi roulette
rajabola
bosslot
situs judi sabung ayam online 24 jam
ludo deposit dana
situs microgaming
pro amerika slot
akun vip cambodia
akun pro filipina
akun pro hongkong
akunprolaos
akun pro malaysia
akun pro myanmar
akun vip slot rusia
akun pro taiwan
papua slot online
Nice Post,
Thanks for sharing this useful information with us. and good info for you check my web site 토토사이트
situs slot shopeepay minimal deposit 10rb gacor hari ini bisa mudah menang pasti resmi dan terpercaya 2023
Tertarik untuk mengetahui lebih lanjut mengenai Nagabet88? Dalam postingan blog kali ini, kami akan bercerita mengenai pengalaman judi yang kami miliki bersama Nagabet88, mulai dari Slot88 Online, Poker88 Online, hingga Live Casino88 Online. Ayo bergabung dan mainkan game-game seru di Nagabet88 bersama kami!
Login Nagabet88
Slot Gacor Naga
Slot Gacor Naga
Akun Slot Pro
Link Nagabet88
Nagabet88
Nice post! Acadecraft, one of the most skilled typesetting companies, comprises a team of designers who efficiently format creative engaging books for primary, secondary, and senior secondary levels to deliver professional typesetting services. 사설토토사이트
I will bookmark your weblog and check again here regularly. I’m quite certain I will learn lots of new stuff right here! 토토사이트
This really answered my problem, thank you! 메이저사이트
Ada banyak sekali permainan menarik penghasil uang yang bisa kamu mainkan di situs slot deposit pulsa tanpa potongan dengan minimal deposit 10000 ribu rupiah.
Memainkan game judi online di situs kpop4d memang menyenangkan, selain itu banyak game slot online yang benar-benar gacor, sehingga kita bisa bersenang senang sekaligus menghasilkan uang banyak.
situs slot shopeepay minimal deposit 10rb gacor hari ini bisa mudah menang pasti resmi dan terpercaya 2023 xdewa slot
kamipoker
slot singapore
slot vietnam
slot dana
slot pulsa
Thankyou for the nice and sharing for the comments great blog!! I have found here lots of important information for my knowledge I need.
Fairfax Traffic Lawyer
I can’t really help but admire your blog. your blog is so adorable and nice Pest Control Waco TX
This is due to the fact that our children are now older.fact that our children are now older. best red light therapy devices
Excellent article plus its information and I positively bookmark to this site because here I always get an amazing knowledge as I expect. Thanks for this to share with us. outdoor wood furnace
Check out our list of the best methods to get started! From using a third-party service like Gmail or Outlook, to using an email client like Gmail or Outlook on your desktop, we’ve got you covered. 먹튀검증
Can I get your affiliate link to your host? I wish my web site loaded up as fast as yours lol 메이저사이트
Nevertheless imagine if you added some great graphics or video clips to give your posts more, “pop”! Your content is excellent but with images and clips, this site could definitely be one of the most beneficial in its niche. https://laoal.com/
https://predikisitogel.com https://vietnamsever.com https://jepangserver.com https://mahjongwe.com https://spyramidpp.com https://slotdemobonanza.com https://slotgampangjpe.com https://slotkakekpetir.com https://slothokiasia.com https://orislotsingapore.com https://starlightprincesslot.com https://slotdpdana.com https://serverorihongkong.com https://luckynekoori.com https://kakekjpsloto.com https://demozeuss.com https://kakekzslot.com https://slotolympusz.com https://agenslotonlin.com https://hokislotg4cor.com https://akunjpsloto.com https://sdysloto.com https://agengacorr.com https://slotseringmaxwin.com https://Gacor50000.com https://gacor888.asia https://pasarjakcpot.com https://slotdanagacor.com https://slotpetir.asia https://slotgacormaxwin.asia https://judipusat.com https://slotpusat.asia https://slotluargacor.com https://akunpromyanmar.asia https://maxwinreceh.asia https://situsslotterbaru.asia https://servertaiwan.com https://linkslotzeus.asia https://slotresmigacor.asia https://joker123gacor.xyz https://situsgampangmaxwin.com https://datatogeltaiwan.asia https://slotyanglagigacor.xyz https://slotmudahmenang.asia https://judiresmi.asia https://dewa4d.asia https://daftarakunslot.asia https://situsdepo10k.com https://judilapakpusat.asia https://infogacorslot.asia https://rajaslot44.com https://slotresmiterpercaya.asia https://daftarolympusslot.asia https://slotpetirmerah.xyz https://slotbet200.xyz https://kumpulanslotgacor.asia https://bocoranslotadminriki.xyz https://slotsweetbonanza.xyz https://pagcorslot.xyz https://zeusslotpragmatic.xyz https://linkdemoslot.xyz https://555slot.fun https://linkslotthailand.fun https://boslot.fun https://slot777gacor.fun https://akunproswis.com https://totoslotgacor.fun https://demobonanzaxmas.com https://lapakzeus.fun https://zeusgacor.fun https://pay4dslot.asia https://slotmahjong.asia https://akunprorusia.asia https://demobonanzagold.asia https://slot123online.asia https://ada777slot.fun https://slotmaniaolympus.fun https://pulsa88.fun https://slot508.fun https://slotmodalreceh.asia https://dewaslot888.fun https://juaraolympus.fun https://dewaslot77.fun https://slotpromo.fun https://situsslotterbesar.asia https://agenasia.asia https://ayamslot.asia https://adminagusslot.com https://slotspain.xyz https://slotamerika.fun https://slotfilipina.fun https://pragmatic128.fun Play now, too, online slots where the win rate is very high and above average because they use foreign servers where the win rate is very high.
Nice post! Acadecraft, one of the most skilled typesetting companies, comprises a team of designers who efficiently format creative engaging books for primary, secondary, and senior secondary levels to deliver professional typesetting services.
Valuable info. Lucky me I found your web site by accident, and I’m shocked why this accident didn’t happened earlier! 먹튀검증
I must say you’ve done a amazing job with this. In addition, the blog loads very fast for me on Chrome. Excellent Blog! 토토사이트
I feel rather privileged to have discovered the website page and look forward to some more pleasurable times reading here. 먹튀검증
Amazing post, it is very impressive and informative content. Would you like want to view private Instagram accounts without human verification? If yes, then you can use Imglookup. Imglookup is safe. This tool is currently one of the best Instagram private account viewer tools without human verification on the market. With complete anonymity, visit the article for more information.
You can certainly see your enthusiasm within the article
you write. The arena hopes for more passionate writers such as you
who are not afraid to mention how they believe. All the time follow your heart. 스포츠토토
Dengan kegembiraan musim sepak bola di atas kita, para penggemar kumpulan situs mpo yang bersemangat bersiap untuk menyemangati tim dan pemain favorit mereka. Seiring dengan keseruan permainan, banyak peminat juga menikmati keseruan tambahan dalam memasang taruhan pada judi bola resmi dengan prediksi mereka. Dalam hal situs taruhan sepak bola, SBOBET telah memantapkan dirinya sebagai platform terdepan dan terpercaya untuk tahun 2023-2024. Mari jelajahi apa yang membedakan SBOBET dari yang lain.
Heath Ledger was the best joker ever, top level acting in the movie.
play alchemy game
Drag & drop (drag and drop) is a very useful and popular feature in today's websites. This feature allows users to move connections objects from one location to another on the web.
Drag and drop (drag and drop) is a common and useful feature on today's websites. Users can use this connections functionality to move objects from one area to another on the web.
При обработке событий, связанных с мышью, нужен кроссбраузерный способ получения координат курсора из события в обработчике. Кроме того, необходимо знать нажатую кнопку мыши.
biowin1688 คาสิโนออนไลน์ที่ทำเงินได้แบบไม่จำกัด
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.