Выделение в браузерах
Ребят это баг или у меня руки кривые?
Задача: 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, время: 02:51. |