2009-10-19 5 views
20

Мне нужно установить кнопку с абсолютным расположением рядом с выбранным пользователем текстом. точно так же, как IE8 делает внутренне.Как я могу поместить элемент рядом с выбором текста пользователя?

Я связывание события JQuery MouseUp к документу, и получить выделенный текст, но я в настоящее время из идей о том, как знать, где фактический выбор позиционируются, без упаковки его в каком-то элементе, потому что выбор текста может быть через несколько элементов, и это испортит структуру, если я ее оберну.

+0

HTTP-: //www.nytimes.com делает это в своих статьях – vsync

ответ

23

Вы можете расположить пролет маркера в конце отбора, получить его координату используя jQuery, поместите вашу кнопку в эти координаты и удалите маркер.

Следующие должны вы начали:

var markSelection = (function() { 
    var markerTextChar = "\ufeff"; 
    var markerTextCharEntity = ""; 

    var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2); 

    var selectionEl; 

    return function() { 
     var sel, range; 

     if (document.selection && document.selection.createRange) { 
      // Clone the TextRange and collapse 
      range = document.selection.createRange().duplicate(); 
      range.collapse(false); 

      // Create the marker element containing a single invisible character by creating literal HTML and insert it 
      range.pasteHTML('<span id="' + markerId + '" style="position: relative;">' + markerTextCharEntity + '</span>'); 
      markerEl = document.getElementById(markerId); 
     } else if (window.getSelection) { 
      sel = window.getSelection(); 

      if (sel.getRangeAt) { 
       range = sel.getRangeAt(0).cloneRange(); 
      } else { 
       // Older WebKit doesn't have getRangeAt 
       range = document.createRange(); 
       range.setStart(sel.anchorNode, sel.anchorOffset); 
       range.setEnd(sel.focusNode, sel.focusOffset); 

       // Handle the case when the selection was selected backwards (from the end to the start in the 
       // document) 
       if (range.collapsed !== sel.isCollapsed) { 
        range.setStart(sel.focusNode, sel.focusOffset); 
        range.setEnd(sel.anchorNode, sel.anchorOffset); 
       } 
      } 

      range.collapse(false); 

      // Create the marker element containing a single invisible character using DOM methods and insert it 
      markerEl = document.createElement("span"); 
      markerEl.id = markerId; 
      markerEl.appendChild(document.createTextNode(markerTextChar)); 
      range.insertNode(markerEl); 
     } 

     if (markerEl) { 
      // Lazily create element to be placed next to the selection 
      if (!selectionEl) { 
       selectionEl = document.createElement("div"); 
       selectionEl.style.border = "solid darkblue 1px"; 
       selectionEl.style.backgroundColor = "lightgoldenrodyellow"; 
       selectionEl.innerHTML = "&lt;- selection"; 
       selectionEl.style.position = "absolute"; 

       document.body.appendChild(selectionEl); 
      } 

      // Find markerEl position http://www.quirksmode.org/js/findpos.html 
     var obj = markerEl; 
     var left = 0, top = 0; 
     do { 
      left += obj.offsetLeft; 
      top += obj.offsetTop; 
     } while (obj = obj.offsetParent); 

      // Move the button into place. 
      // Substitute your jQuery stuff in here 
      selectionEl.style.left = left + "px"; 
      selectionEl.style.top = top + "px"; 

      markerEl.parentNode.removeChild(markerEl); 
     } 
    }; 
})(); 
+0

Когда я выполнил этот код, верхняя переменная была объектом. Вероятно, была глобальная переменная, называемая вершиной. Лучше написать var left = 0; var top = 0; вместо var left = top = 0; –

+0

@ Z-CORE: Вы абсолютно правы: 'top' - это ссылка на внешнее окно, содержащее текущий документ. Для меня очень необычно копировать и вставлять чужой код (в данном случае из quirksmode.org), но по крайней мере ясно, что ошибка не изначально моя :) –

+0

Хотя маловероятно, могут существовать правила CSS, которые зависят от определенных например, '#example> span + span'. вставка разметки маркера в содержимое нарушит эти правила, потенциально изменяющие/нарушающие макет. Диапазон.getBoundingClientRect() может быть более надежным решением. – Rick

2

Возможно, вы должны вставить абсолютно элемент позиции в конце диапазона. Это работает по-разному в разных браузерах, поэтому лучше всего понюхать.

И так как вы спросили: это как раз новый йорк делает его в своем файле «altClickToSearch.js»:

function insertButton() { 

selectionButton = new Element(
     'span', { 
      'className':'nytd_selection_button', 
      'id':'nytd_selection_button', 
      'title':'Lookup Word', 
      'style': 'margin:-20px 0 0 -20px; position:absolute; background:url(http://graphics8.nytimes.com/images/global/word_reference/ref_bubble.png);width:25px;height:29px;cursor:pointer;_background-image: none;filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://graphics8.nytimes.com/images/global/word_reference/ref_bubble.png", sizingMethod="image");' 
     } 
    ) 

if (Prototype.Browser.IE) { 
    var tmp = new Element('div'); 
    tmp.appendChild(selectionButton); 
    newRange = selection.duplicate(); 
    newRange.setEndPoint("StartToEnd", selection); 
    newRange.pasteHTML(tmp.innerHTML); 
    selectionButton = $('nytd_selection_button'); 
} 
else { 
    var range = selection.getRangeAt(0); 
    newRange = document.createRange(); 
    newRange.setStart(selection.focusNode, range.endOffset); 
    newRange.insertNode(selectionButton); 
} 
} 
+0

Спасибо, да, похоже, они просто вставляют его в эту конкретную точку в выборе вместо абсолютного самому документу. благодаря! – vsync

+3

Там есть ненужный браузер. Вы можете просто проверить объекты или методы, которые вам нужны. Кроме того, объект выбора в старых WebKits (Safari 2, может быть, 3, я немного туман на этом, и у меня нет всех подходящих браузеров, которые можно легко передать) не имеют метода getRangeAt. –

+0

Я не предлагал код выше, как лучшее решение, особенно с браузером. Он спросил о nytimes в своем комментарии. Это всего лишь код с этого сайта. –

8

Я использую getBoundingClientRect(), когда мне нужно содержание, чтобы оставаться в покое, при размещении дополнительного контента рядом с ним.

var r=window.getSelection().getRangeAt(0).getBoundingClientRect(); 
    var relative=document.body.parentNode.getBoundingClientRect(); 
    ele.style.top =(r.bottom -relative.top)+'px';//this will place ele below the selection 
    ele.style.right=-(r.right-relative.right)+'px';//this will align the right edges together 

это работает в Chrome, но IE любит давать странные вещи, так вот решение кросс-браузер: (Испытано в Chrome и IE, вероятно, работает в другом месте)

https://jsfiddle.net/joktrpkz/7/

+0

Привет, вы можете объяснить, почему вы используете cal1/cal2 в своей скрипке? Благодарю. –

+0

@Guy Это было связано с тем, как IE обрабатывает пиксели при увеличении. Я не помню, было ли это необходимо или нет в других сценариях. – Rick

+0

Мои требования предназначены только для моего расширения для работы под хром, поэтому это решение отлично работает для меня. – SKYnine