Настройка
Итак, у меня есть contenteditable div - я создаю WYSIWYG-редактор: полужирный, курсив, форматирование, что угодно и последнее: вставка фантазийных изображений (в причудливой коробке с надписью).
<a class="fancy" href="i.jpg" target="_blank">
<img alt="" src="i.jpg" />
Optional Caption goes Here!
</a>
Пользователь добавляет эти причудливые изображения с помощью диалогового окна, в котором я им представляю: они заполняют детали, загружают изображение, а затем, как и другие функции редактора, я использую document.execCommand('insertHTML',false,fancy_image_html);
, чтобы вскрыть его при выборе пользователя.
Желаемая функциональность
Итак, теперь, когда мой пользователь может заглянуть в причудливый образ - им нужно уметь перемещать его. Пользователь должен иметь возможность щелкнуть и перетащить изображение (причудливое поле и все), чтобы разместить его в любом месте, где они захотят, в пределах контента. Они должны иметь возможность перемещать его между абзацами или даже внутри абзацев - между двумя словами, если они хотят.
Что дает мне надежду
Имейте в виду - в контентных, простых старых тегах <img>
уже благословляются пользовательским агентом с этой прекрасной возможностью перетаскивания. По умолчанию вы можете перетаскивать теги <img>
, где бы вы ни находились; операция перетаскивания по умолчанию ведет себя так, как можно было бы мечтать.
Итак, учитывая, как это поведение по умолчанию уже работает так беспорядочно на наших <img>
приятелях - и я только хочу немного расширить это поведение, чтобы включить немного больше HTML - это похоже на то, что должно быть легко возможным.
Мои усилия до сих пор
Во-первых, я настроил свой причудливый тег <a>
с помощью перетаскиваемого атрибута и отключил contenteditable (не уверен, что это необходимо, но похоже, что он также может быть отключен):
<a class="fancy" [...] draggable="true" contenteditable="false">
Затем, поскольку пользователь все еще мог вытащить изображение из фэнтезийного <a>
, мне пришлось сделать некоторый CSS. Я работаю в Chrome, поэтому я показываю вам только префиксы -webkit-prefixes, хотя я тоже использовал других.
.fancy {
-webkit-user-select:none;
-webkit-user-drag:element; }
.fancy>img {
-webkit-user-drag:none; }
Теперь пользователь может перетащить весь причудливый бокс, и небольшое частично выцветшее изображение представления перетаскивания мышью отражает это - я вижу, что я собираю всю коробку сейчас:)
Я пробовал несколько комбинаций различных свойств CSS, приведенная выше комбо, кажется, имеет смысл для меня и, кажется, работает лучше всего.
Я надеялся, что только этого CSS будет достаточно, чтобы браузер использовал весь элемент в качестве перетаскиваемого элемента, автоматически предоставляя пользователю функциональность, о которой я мечтал... Однако она выглядит сложнее чем это.
HTML5 API перетаскивания JavaScript JavaScript
Этот материал перетаскивания кажется более сложным, чем нужно.
Итак, я начал углубляться в api docs, и теперь я застрял. Итак, вот что я подстроил (да, jQuery):
$('.fancy')
.bind('dragstart',function(event){
//console.log('dragstart');
var dt=event.originalEvent.dataTransfer;
dt.effectAllowed = 'all';
dt.setData('text/html',event.target.outerHTML);
});
$('.myContentEditable')
.bind('dragenter',function(event){
//console.log('dragenter');
event.preventDefault();
})
.bind('dragleave',function(event){
//console.log('dragleave');
})
.bind('dragover',function(event){
//console.log('dragover');
event.preventDefault();
})
.bind('drop',function(event){
//console.log('drop');
var dt = event.originalEvent.dataTransfer;
var content = dt.getData('text/html');
document.execCommand('insertHTML',false,content);
event.preventDefault();
})
.bind('dragend',function(event){
//console.log('dragend');
});
Итак, здесь, где я застрял: Это почти полностью работает. Почти полностью. У меня все работает, вплоть до самого конца. В событии drop теперь у меня есть доступ к содержимому HTML-контента, которое я пытаюсь вставить в папку. Все, что мне нужно сделать сейчас, вставляет его в нужное место!
Проблема Я не могу найти правильное место для удаления или любой способ вставить в нее. Я надеялся найти какой-то объект dropLocation для сброса моего причудливого окна в, что-то вроде dropEvent.dropLocation.content=myFancyBoxHTML;
, или, по крайней мере, по крайней мере, какие-то значения местоположения перетаскивания, с помощью которых можно найти свой собственный способ разместить там контент?
Я что-то даю?
Я делаю это совершенно неправильно? Я что-то не хватает?
Я попытался использовать document.execCommand('insertHTML',false,content);
, как я ожидал, я должен быть в состоянии, но, к сожалению, меня здесь не сработало, поскольку каретка выбора не находится в точном месте падения, так как я надеюсь.
Я обнаружил, что если я прокомментирую все event.preventDefault();
, каретка выбора станет видимой, и, как можно было бы надеяться, когда пользователь будет готовиться к отбрасыванию, contenteditable, можно видеть, что небольшая каретка выбора просматривается между символами, следующими за курсором пользователя и операцией drop - указывая пользователю, что каретка выбора представляет точное местоположение перетаскивания. Мне нужно расположение этой каретки выбора.
В некоторых экспериментах я попробовал execCommand-insertHTML'ing во время события drop, а событие dragend - не вставлял HTML, где был drop-selection-caret, вместо этого он использовал любое местоположение, выбранное до операции перетаскивания.
Поскольку каретка выбора видна во время перетаскивания, я запустил план.
В течение некоторого времени я пытался в событии dragover вставить временный маркер, например <span class="selection-marker">|</span>
, сразу после $('.selection-marker').remove();
, при попытке браузера постоянно (во время перетаскивания) удалять все маркеры выделения и затем добавление одного в точку вставки - по существу, оставляя один маркер, где бы ни находилась эта точка вставки, в любой момент. Конечно, план заключался в том, чтобы затем заменить этот временный маркер перетаскиваемым контентом, который у меня есть.
Ничего из этого не получилось, конечно: я не мог заставить маркер выбора вставлять в видимую видимую каретку выбора, как и планировалось, - снова, вставленный execCommandHTML, где бы он ни находился, до перетаскивания операции.
Хафф. Так что я пропустил? Как это делается?
Как получить или вставить точное местоположение операции перетаскивания? Я чувствую, что это, очевидно, общая операция среди перетаскиваний - наверняка я, должно быть, не обратил внимания на важную и вопиющую деталь какого-то рода? Мне даже нужно углубиться в JavaScript, или, может быть, есть способ сделать это только с такими атрибутами, как draggable, droppable, contenteditable и некоторый fancydancy CSS3?
Я все еще нахожусь на охоте - по-прежнему возиться - я отправлю сообщение, как только узнаю, что я провалил:)
Hunt Continues (редактирование после оригинального сообщения)
Фаррух добавил хорошее предложение - используйте:
console.log( window.getSelection().getRangeAt(0) );
Чтобы увидеть, где находится каттинг выбора. Я вложил это в событие dragover, которое, когда я полагаю, что каретка выбора видимо перемещается между моим редактируемым контентом в contenteditable.
Увы, объект Range, который возвращается, сообщает об индексах смещения, относящихся к каретке выбора, перед операцией перетаскивания.
Это было отважное усилие. Спасибо Фарруху.
Итак, что здесь происходит? Я получаю ощущение, что маленькая каретка выбора, которую я вижу, прыгает вокруг, не является кареткой выбора вообще! Я считаю это самозванцем!
При дальнейшем осмотре!
Оказывается, это самозванец! Каретка выбора реального остается на месте во время всей операции перетаскивания! Вы можете увидеть маленького педераста!
Я читал MDN Drag and Drop Docs и нашел это:
Естественно, вам может понадобиться переместить маркер вставки вокруг события перетаскивания. Вы можете использовать свойства client client client и clientY как другие события мыши для определения местоположения указателя мыши.
Yikes, значит ли это, что я должен сам это понять, на основе clientX и clientY? Использовать координаты мыши для определения местоположения каретки выбора? Страшно!!
Я буду смотреть на это завтра - если только я или кто-то еще здесь не читает это, можно найти разумное решение:)