Выделение в браузерах
Ребят это баг или у меня руки кривые?
Задача: 1) сохранить выделение. 2) изменить значение текстовой ноды(эта процедура заставляет браузер сбросить выделение). 3) восстановить выделение. Вот класс отвечающий за сохранение и восстановление выделения: class Selection constructor: -> @ranges = [] clear: -> @ranges = [] save: -> @clear() selection = window.getSelection() for i in [0...selection.rangeCount] range = selection.getRangeAt(i) @ranges.push 'startContainer': range.startContainer 'startOffset': range.startOffset 'endContainer': range.endContainer 'endOffset': range.endOffset return restore: -> selection = window.getSelection() selection.removeAllRanges() for rangeData in @ranges range = document.createRange() range.setStart(rangeData.startContainer, rangeData.startOffset) range.setEnd(rangeData.endContainer, rangeData.endOffset) selection.addRange(range) return Написал скрипт который меняет значение текстовой ноды каждые 300 миллисекунд, и пытаюсь до изменеиня делать сейв выделения, после изменения ноды делать рестор, в хроме и лисе все работает, в ишаке все работает. А тепрь пытаюсь делать вот что, начинаю делать выделение мышкой и не отпускаю кнопку, дожидаюсь пока значение ноды изменится, иииии... О ЧУДО, после рестора, в хроме и лисе все работает, а в ишаке процесс выделения прерывается, и при дальнейшем движении мышки выделение остается на том же месте где мы рестор сделали. И второй косяк, это когда мы в хроме ведем выделение в обратную сторону, то есть мышкой с конца текста вначало, и делаем сейв и рестор, тооо, выделение сбрасывается. Это вобще што за баги? неужели поведение этого API не описано в стандарте? Так же основной собственно вопрос, существует ли какая-то возможность определить направление выделения? Чтобы хотя бы в хроме и лисе знать в какую сторону рестор делать чтобы он выделение не сбрасывал. Дело в том что при сейве у них стартОффсет и ендОффсет расположены всегда в одинаковом порядке, старт всегда меньше енд, несзависимо оттого в какую сторону мы мышкой ведем. |
Оу, ну в общем как получить выделение в браузерах я нашел, то где кончается выделение показывается не в ренджах, а в селекшене
а именно selection = getSelection() // начало выделения selection.anchorNode // нода selection.anchorOffset // символ // конец выделения selection.focusNode // нода selection.focusOffset // символ |
В итоге я написал работающий класс который сохраняет как обычное так и реверсивное выделение:
class Selection constructor: -> @anchorNode = null @anchorOffset = null @focusNode = null @focusOffset = null clear: -> @anchorNode = null @anchorOffset = null @focusNode = null @focusOffset = null save: -> selection = window.getSelection() @anchorNode = selection.anchorNode @anchorOffset = selection.anchorOffset @focusNode = selection.focusNode @focusOffset = selection.focusOffset return restore: -> selection = window.getSelection() selection.removeAllRanges() unless @anchorNode then return range = document.createRange() range.setStart(@anchorNode, @anchorOffset) selection.addRange(range) selection.extend(@focusNode, @focusOffset) return В итоге мы ренджи не трогаем, мы у селекшена запоминаем стартовую и конечную точки, а потом при ресторе, мы создаем коллапсовый замкнутый рендж задавая ему лишь стартовую точку, и продолжаем (extend) его в нужном направлении до конечной точки, подобное extend заставляет нам сохранить направление выделения. И выделение под курсором не обрывается ^_^ Еще один момент в EDGE такое выделение сбрасывается при любой активности мышкой, по этому щас я добавлю проверку на то нажата ли клафиша мышки или отпущена. И если нажата то буду думать что делать |
Вот готовое решение:
class SelectionSaver isMs = /edge|msie|trident/i.test(navigator.userAgent) isInteractive = off if isMs addEventListener 'mousedown', => isInteractive = on , on addEventListener 'mouseup', => isInteractive = off , on constructor: -> @selection = getSelection() @anchorNode = null @anchorOffset = null @focusNode = null @focusOffset = null return clear: -> @anchorNode = null @anchorOffset = null @focusNode = null @focusOffset = null return save: -> @anchorNode = @selection.anchorNode @anchorOffset = @selection.anchorOffset @focusNode = @selection.focusNode @focusOffset = @selection.focusOffset return restore: -> if isMs and isInteractive then return @selection.removeAllRanges() unless @anchorNode then return range = document.createRange() range.setStart(@anchorNode, Math.min(@anchorOffset, @anchorNode.length)) @selection.addRange(range) @selection.extend(@focusNode, Math.min(@focusOffset, @focusNode.length)) return |
тадаам, ставим звезды https://github.com/Maxmaxmaximus/SelectionSaver
|
Часовой пояс GMT +3, время: 01:18. |