Обработчик события действует только на ссылки?
Есть незамысловатый код ((document).ready подразумевается):
var textSelection = ''; function getSel() { //функция пишет в переменную выделение мышкой if (textSelection = window.getSelection) // !IE textSelection = window.getSelection().toString(); else // IE textSelection = document.selection.createRange().text; return textSelection; } $('body').mouseup(function(){ getSel(); }); $('#link').click(function () { alert (textSelection); }); Проблема вот в чем: почему то обработчик работает как-то не так (а может я чего-то не знаю:-? ). Если элемент это ссылка с id="link", то все в порядке, в модальном окне виден выделенный текст. Но если элемент не является ссылкой (например <div id="link">, <span id="link"> и т.д.) то появляется просто пустое модальное окно. Вопросы просты: как заставить обрабочик выводить выделенный фрагмент по клику на блоке (нужно именно это) и где ошибка в приведенном коде? |
1.
if (textSelection = window.getSelection)должна быть if (window.getSelection) 2. так как click состоит из mousedown, mouseup $('#link').click стирает предыдущее выделение, если выделение было на другом элементе кроме #link' надо менять логику скрипта или как вариант сделать так: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body><div id="link">Выдели текст и кликни тут!!!</div><div id="link0">всякий разный текст</div><div id="link1">всякий разный текст</div><div id="link2">всякий разный текст</div> <script language="JavaScript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script> <script language="JavaScript" type="text/javascript"> var textSelection = ''; function getSel() { //функция пишет в переменную выделение мышкой if (window.getSelection) // !IE textSelection = window.getSelection().toString(); else // IE textSelection = document.selection.createRange().text; return textSelection; } $('body').mouseup(function () { getSel(); }); $('#link').mouseup(function () { if (textSelection) alert(textSelection); }); </script> </body> </html> |
Спасибо за код и инфу, по поводу затирания не знал. А если как-то в моем выражении
$('body').mouseup(function(){ getSel(); }); докапаться до того элемента где непосредственно происходит событие и работать уже с ним? Это спасет? Те "слушать" весь body, но при отпускании мыши работать с тем элементом, над которым произошел mouseup. |
Цитата:
Я бы сделал как-то так: $Selection = { standardsCompliant: typeof getSelection != "undefined", get: function () { return this.standardsCompliant ? getSelection() : document.selection; }, getRange: function () { return this.get()[this.standardsCompliant ? "getRangeAt" : "createRange"](0); } }; $Range = { standardsCompliant: $Selection.standardsCompliant, stringify: function (range) { return this.standardsCompliant ? range.toString() : range.text; } }; var text; $("body").mouseup(function () { text = $Range.stringify($Selection.getRange()); }); $("#link").click(function () { alert(text); }); |
Octane,
Цитата:
А в чем преимущество вашего способа определения выделения (сложновато будет;)) перед функцией? ЗЫ. $Selection - это объект, не так ли? |
ну если продолжать, то я бы избавился от глобальной переменной и подготовил пути к развитию
Function.prototype.bind = function(scope) { var that = this, args = [].slice.call(arguments, 1); return function() { return that.apply(scope || this, args.concat([].slice.call(arguments, 0))); }; }; function QuoteLink( el ){ this._el = $(el); $("body").mouseup( this._onMouseUp_body.bind(this) ); this._el.click( this._onClick.bind(this) ); } QuoteLink.prototype._onMouseUp_body = function(){ this._text = $Range.stringify($Selection.getRange()); } QuoteLink.prototype._onClick = function(){ alert(this._text); } |
Цитата:
|
Цитата:
|
Ой самое главное забыл дописать. Чтобы ваш вариант работал, нужно preventDefault выполнить по mousedown на #link.
<!DOCTYPE html> <meta charset="utf-8"> <div> <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p> <span id="test">test</span> </div> <script> $Selection = { standardsCompliant: typeof getSelection != "undefined", get: function () { return this.standardsCompliant ? getSelection() : document.selection; }, getRange: function () { return this.get()[this.standardsCompliant ? "getRangeAt" : "createRange"](0); } }; $Range = { standardsCompliant: $Selection.standardsCompliant, stringify: function (range) { return this.standardsCompliant ? range.toString() : range.text; } }; //~~~~~~~~~~~~~~~~~~~~~~~ var text; document.body.onmouseup = function () { text = $Range.stringify($Selection.getRange()); }; var btn = document.getElementById("test"); btn.onmousedown = function (event) { if (event && event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }; btn.onclick = function () { alert(text); }; </script> Цитата:
Цитата:
Короче не всегда лучше. |
проще понятие неоднозначное и уж точно не то же самое, что и "меньше строк". Меньше строк получилось? Отлично. А строки от этого проще стали? Пихать все в одну строку - усложнение кода (понимания кода). В частности, использование выражений с побочными эффектами. Разве не проще рассчитывать, что все выражения будут без побочных эффектов? Для меня же проще в первую очередь, когда я вижу что происходит, а не как это реализовано (это в целом про "что такое просто для меня"). Да и Эйнштейн, ведь, говорил про "настолько просто, насколько это возможно", а не про "максимально просто"
Вариант Octane - это выделение библиотечного кода, который будет повторно использоваться. Мой вариант - выделение компонентов, которые тоже будут повторно использоваться. Для кода в первом сообщении это, в общем-то, не актуально, но ведь это не окончательный вариант? |
x-yuri,
Да, я в первом сообщении не упомянул (и хорошо), что вряд ли код (функция выделения фрагмента) будет где-то еще использоваться. Функция будет является частью небольшого скрипта и действовать только в его рамках. Цитата:
Цитата:
И "простоту" я упомянул зря - она не только не однозначна, но как оказалось, ситуативна :yes: . |
Цитата:
Цитата:
function getSel(){ if( window.getSelection ) return window.getSelection(); else return document.selection.createRange().text; } Цитата:
<a id="quote-link" href="#">Цитировать</a> <script type="text/javascript">new QuoteLink('#quote-link')</script> и вижу, что при щелчке по этой ссылке происходит копирование выделенного текста (так как не было указано куда, соответственно компонент не доделан). Т.е. я вижу, что происходит, но не вижу как это реализовано. Если мне нужно узнать, как это реализовано я смотрю исходник компонента function QuoteLink( el ){ this._el = $(el); $("body").mouseup( this._onMouseUp_body.bind(this) ); this._el.click( this._onClick.bind(this) ); } QuoteLink.prototype._onMouseUp_body = function(){ this._text = $Range.stringify($Selection.getRange()); } QuoteLink.prototype._onClick = function(){ alert(this._text); } и вижу, что назначаются два обработчика, что происходит в обработчиках, но не вижу реализацию назначения обработчиков, как находится выделение. Т.е. на каждом уровне у меня есть минимум необходимых деталей. В общем-то я не знаю вашей задачи, поэтому какие-то действия могут быть лишними или может быть лучший вариант организации кода, но вынесение библиотечного кода в любом случае не помешает Кроме того, в моем случае нету никаких необоснованно глобальных переменных. Вообще можно было еще всякие детали поубирать, вот только jQuery не предоставляет такие возможности. Хотя по задумке и не должна. Все должно быть максимально просто. Просто пишем код и пишем, и никаких дополнительных движений не делаем. Зачем разбивать код на вменяемые части? Ведь это дополнительные движения, сложно. Зачем повторное использование? Лучше мы в каждом плагине напишем то же самое. Зачем нам компоненты, если можно общаться с объектами через одну функцию ($(foo).dialog('open'))? Цитата:
|
Цитата:
, но пока работает не совсем так, и делает еще не все, что я задумал. Цитата:
Цитата:
Цитата:
Цитата:
Сам скрипт (условно назвал "просто вставить цитату" - видел на некоторых форумах, вот пытаюсь сделать что-то подобное) // Задаем необходимые переменные var qPanel = $('<div id="past" style="position:absolute; display:none;"><a href="" id="link">Вставить цитату в поле<a></div>'); var textarea = $('textarea'); function getSel() { // Функция возвращает текстовое выделение if (window.getSelection) // !IE, используем метод getSelection return window.getSelection().toString(); else // IE, используем объект selection return document.selection.createRange().text; } qPanel.click(function () { // Обработчик события textarea.val(textarea.val() + '<blockquote>' + getSel() + '</blockquote>\r\n').focus(); $(this).hide(); return false; }); qPanel.appendTo('body'); $('body').mouseup(function(event){ var widthqPanel = qPanel.outerWidth(); if (getSel()) { qPanel .css({ top: event.pageY - 40, left: event.pageX - widthqPanel/3, display: 'block', opacity: 0 }) .animate({ top: '-=' + 10 + 'px', opacity: 1 }, 250); } }); $('body').click(function () { if (!getSel()) qPanel.hide(); }); |
Цитата:
Цитата:
я бы сделал как-то так (ошибки не исправлял, может даже новые добавил) var QuotePanel = new Class({ initialize: function( textarea ){ this._el = textarea; this._panel = new Element('div', {'html': '<a href="#">Вставить цитату в поле</a>'}); document.body.addEvents({ 'mouseup': this._onMouseUp_body.of(this), 'click': this._onClick_body.of(this) }); this._panel.addEvent( 'click', this._onClick_panel.of(this) ); this._panel.inject( document.body ); }, _onMouseUp_body: function( e ){ if( ! Selection.get() ) return; var panelWidth = this._panel.getStyle('width').parseInt(); var top = e.page.y - 40; var left = e.page.x - panelWidth/3; this._panel .setStyles({ 'top': top, 'left': left, 'display': 'block', 'opacity': 0 }) .morph({ 'opacity': 1, 'top': top-10 }); }, _onClick_body: function( e ){ if( ! Selection.get() ) this._panel.setStyle('display', ''); }, _onClick_panel: function( e ){ this._el.value += this._el.value+'<blockquote>'+Selection.get()+'</blockquote>\r\n'; this._el.focus(); this._panel.setStyle('display', ''); e.preventDefault(); } }); |
x-yuri,
Ловко вы перешли на MooTools! :) Там, где скрипт будет использоваться есть только jQuery, так что придется остаться на нем. Возник вопрос - (e) это сокращенная форма записи (event)? И еще один - долго ломал над ним голову и так и не придумал ничего путного. Хочу на панельку, всплывающую после выделения мышкой, повесить таймер - если, допустим, 3 секунды ничего не происходит (нет клика на ней и вне ее), панель исчезает. Если до истечения этих 3 секунд был клик вне панели, панель тут же исчезает (если был клик на панели, цитата вставляется в поле ответа). Может подскажите как это реализовать? |
Цитата:
Цитата:
|
Цитата:
|
Цитата:
function Class( methods ){ var r = function(){ if( this.initialize ) this.initialize(); }; $.extend( r.prototype, methods ); return r; } String.prototype.parseInt = function(){ return parseInt(this); }; Function.prototype.of = function( o ){ var self = this; return function(){ return self.apply(o, arguments); } }; var QuotePanel = new Class({ initialize: function( textarea ){ this._el = $(textarea); this._panel = $('<div><a href="#">Вставить цитату в поле</a></div>'); document.body.mouseup( this._onMouseUp_body.of(this) ); document.body.click( this._onClick_body.of(this) ); this._panel.click( this._onClick_panel.of(this) ); this._panel.appendTo( $('body') ); }, _onMouseUp_body: function( e ){ if( ! Selection.get() ) return; var panelWidth = this._panel.css('width').parseInt(); this._panel .css({ 'top': e.pageY - 40, 'left': e.pageX - panelWidth/3, 'display': 'block', 'opacity': 0 }) .animate({ 'opacity': 1, 'top': '-='+10+'px' }); }, _onClick_body: function( e ){ if( ! Selection.get() ) this._panel.css('display', ''); }, _onClick_panel: function( e ){ this._el.value += this._el.value+'<blockquote>'+Selection.get()+'</blockquote>\r\n'; this._el.focus(); this._panel.css('display', ''); e.preventDefault(); } }); да, я, кстати, подразумевал, что лишний css, который не изменяется я бы поместил в отдельный файл. Это несколько усложняет использование, но упрощает код Цитата:
var QuotePanel = new Class({ _onMouseUp_body: function( e ){ ... this._panel ... .animate( { ... }, { 'complete': function(){ setTimeout( function(){ this._hidePanel(); }.of(this), 3000 ); }.of(this) }); }, _onClick_body: function( e ){ ... this._hidePanel(); }, _hidePanel: function(){ this._panel.css('display', ''); } }); вот только зачем ее автоматически убирать? Пользователь ее и так убрать сможет, кликнув на пустом месте. Главное, чтобы она не перекрывала выделение. А вы еще говорите, что все должно быть максимально просто ;) |
замена алерта ... как раз висит 3 секунды и удаляется по клику ...
замечания принимаются ))) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script language="JavaScript" type="text/javascript"> function position(b) { b = typeof b == "string" ? document.getElementById(b) : b; var a = document.documentElement, c = document.body, e = self.pageXOffset || a && a.scrollLeft || c && c.scrollLeft || 0; t = self.pageYOffset || a && a.scrollTop || c && c.scrollTop || 0; var f = b.offsetHeight, g = b.offsetWidth, d = document.compatMode == "CSS1Compat" && !window.opera ? a.clientWidth : c.clientWidth; a = document.compatMode == "CSS1Compat" && !window.opera ? a.clientHeight : c.clientHeight; if (document.compatMode == "CSS1Compat" && window.opera) { d = window.innerWidth; a = window.innerHeight } b.style.left = Math.floor(e + (d - g) / 2) + "px"; b.style.top = Math.floor(t + (a - f) / 2) + "px" }; window.alert = function (b) { b = b.replace(/\n/gim, "<br />"); var a = document.createElement("div"); a.style.position = "absolute"; a.style.color = "#0000FF"; a.style.backgroundColor = "#FFFACD"; a.style.border = "1px solid #000"; a.style.padding = "0px 4px"; a.innerHTML = b; document.onmousedown = function () { a && document.body.removeChild(a); c && window.clearTimeout(c); document.onmousedown = null }; document.body.appendChild(a); position(a); var c = window.setTimeout(function () {a && document.body.removeChild(a);document.onmousedown = null}, 3E3) }; </script> </head> <body> <a href="#" onclick="alert('замена алерта'); return 0">кликни</a> </body> </html> |
Однобуквенные переменные
![]() |
как можно делать замечания, если не хочеться вникать в этот код? (смайлик как у Octane) И при чем тут замена alert'а?
кстати, Octane, ты как-то абстрактно, имхо, подошел к вынесению функциональности. Т.е. я в первую очередь исхожу из того, как что-то будет использоваться. Selection.get() выглядит симпатичнее по сравнению с $Range.stringify($Selection.getRange()). Может, твой вариант чем-то лучше, но я пока не вижу чем. Он сложнее и все-таки лучше отменять скрытие панели, а то оно может скрыть панель для нового выделения Function.prototype.makeCancelable = function(){ var self = this; var r = function(){ if( r.canceled ) return; return self.apply(this, arguments); }; r.cancel = function(){ this.canceled = true; } return r; } var QuotePanel = new Class({ _onMouseUp_body: function( e ){ ... this._panel ... .animate( { ... }, { 'complete': function(){ this._hidePanelCancelable = this._hidePanel().of(this).makeCancelable(); setTimeout( this._hidePanelCancelable, 3000 ); }.of(this) }); }, _onClick_body: function( e ){ ... if( this._hidePanelCancelable ) this._hidePanelCancelable.cancel(); this._hidePanel(); }, _hidePanel: function(){ this._panel.css('display', ''); } }); |
Цитата:
Selection используется редко из-за того, что динамически меняется, как NodeList, а еще в IE почти ничего не умеет, но иногда бывает нужно, поэтому для $Selection оставляем простой интерфейс: $Selection.get(); $Selection.clear(); $Selection.getRange(); $Selection.selectRange(range); А большинство работы выполняется с Range: $Range.create(); $Range.isCollapsed(range); $Range.stringify(range); $Range.getRootContainer(range); $Range.clone(range); … Создавать конструктор в этом конкретном случае неудобно, потому что полностью кросс-браузерный интерфейс написать не получится и постоянно обращаться к Range/TextRange-объекту через obj.range бессмысленно, удобнее: var range = $Selection.getRange(), text = $Range.stringify(range); if ($Range.standardsCompliant) { range… } else { range… } $Selection.selectRange(range); |
....
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <div id="link">Выделите ниже текст и кликни тут!!!</div> <div id="link0">всякий разный текст</div> <div id="link1">всякий разный текст</div> <div id="link2">всякий разный текст</div> <script language="JavaScript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script> <script language="JavaScript" type="text/javascript"> $('div').not('#link').mouseup(function () { var txt=document.selection? document.selection.createRange().text:window.getSelection().toString(); $('#link').one("click",function () {alert(txt)}) }); </script> </body> </html> |
Цитата:
Цитата:
Цитата:
Цитата:
Приведенные примеры посмотрю попозже, убегаю сейчас. |
Цитата:
Octane, да, я c Range, Selection не особо много работал. Просто подумал, что $Selection.get могло бы сразу текст возвращать. Или как вариант можно было бы метод getText написать. Но в общем-то мне сложно судить... рони, хватит one-liner'ами досить ;) |
Цитата:
var range = $Selection.getRange(), // получаем TextRange или *!*первый*/!* Range text = $Range.stringify(range); // получаем выделенный текст Хотя ничего страшного, наверное, не будет, если $Selection добавить метод getText: $Selection = { … getText: function () { return $Range.stringify(this.getRange()); } };Кому как нравится :) Просто не хотел, чтобы $Selection знал, как работать с Range/TextRange, но этого избежать не совсем получилось, метод для восстановления выделения, все же знает, что надо выполнить textrange.select(); |
<!DOCTYPE html> <html><head> <title>Работа с выделениями</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <style type="text/css"> #past {height:30px; padding:5px; border:1px solid #000; text-align:center; line-height:30px; color:#000; font:12px Arial, sans-serif; background:#fff; cursor:pointer;} </style> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() { var qPanel = $('<div id="past" style="position:absolute; display:none;"><a href="" id="link">Вставить цитату в поле<a></div>'); var textarea = $('textarea'); var text; $Selection = { standardsCompliant: typeof getSelection != "undefined", get: function () { return this.standardsCompliant ? getSelection() : document.selection; }, getRange: function () { return this.get()[this.standardsCompliant ? "getRangeAt" : "createRange"](0); } }; $Range = { standardsCompliant: $Selection.standardsCompliant, stringify: function (range) { return this.standardsCompliant ? range.toString() : range.text; } }; qPanel.click(function () { textarea.val(textarea.val() + '<blockquote>' + text + '</blockquote>\r\n').focus(); $(this).hide(); return false; }); qPanel.appendTo('body'); $('#paragraph').mouseup(function(e){ text = $Range.stringify($Selection.getRange()); var widthqPanel = qPanel.outerWidth(); if (text) { qPanel .css({ top: e.pageY - 40, left: e.pageX - widthqPanel/3, display: 'block', opacity: 0 }) .animate({ top: '-=' + 10 + 'px', opacity: 1 }, 250); } e.stopPropagation(); }); $('body').click(function() { if (!text) qPanel.hide(); }); }); </script> </head><body> <p id="paragraph">Proin gravida auctor velit vitae facilisis. Vestibulum ac lacus vitae nunc vulputate sodales a eget augue. Quisque ornare enim a nibh ullamcorper volutpat. Nulla imperdiet gravida pulvinar. Proin consequat nisi sit amet augue convallis nec viverra nisl mollis. Nulla in orci metus? Morbi interdum ligula vitae tortor elementum sodales. Curabitur ut ante vitae lectus egestas commodo congue non tortor. Cras mi massa, vulputate id rhoncus ac, facilisis sed leo! Mauris purus urna; ultrices non sodales sed, molestie in neque. Vestibulum ullamcorper orci ac dolor commodo ac aliquam nunc ultrices. Aliquam dapibus congue massa, eleifend vestibulum ligula viverra vitae.</p> <form action="" name=""> <textarea cols="50" rows="10"></textarea> </form> </body></html> Итак, воспользовался способом Octane (в данном случае он мне больше подходит), отказался от setTimeout (согласен с x-yuri) Возникли вопросы: 1. Не совсем понятно почему панель не скрывается после выделения если сделать клик не на параграфе на котором произошло выделение. (по логике в <body> входит не только #paragraph, но и, например, textarea) 2. Если выделение текста велико, внешний клик (чтобы скрыть панель) вполне может быть на самой области выделения. Однако панель всплывает повторно. Только Opera ведет себя адекватно (а может и неадекватно, как посмотреть) скрывая панель по клику на самом выделении. Прошу разъяснить :help: |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Работа с выделениями</title> <style type="text/css"> body { color: #000; position: relative; } .paragraph { border: 1px solid #000; } .quote-popup-menu { position: absolute; padding: 10px; background: #ffc; border: 1px solid #000; } .quote-popup-menu .btn:hover { color: #fff; background: #33c; cursor: pointer; } .hidden { display: none; } </style> </head> <body> <div> <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p> <p class="paragraph">Proin gravida auctor velit vitae facilisis. Vestibulum ac lacus vitae nunc vulputate sodales a eget augue. Quisque ornare enim a nibh ullamcorper volutpat. Nulla imperdiet gravida pulvinar. Proin consequat nisi sit amet augue convallis nec viverra nisl mollis. Nulla in orci metus? Morbi interdum ligula vitae tortor elementum sodales. Curabitur ut ante vitae lectus egestas commodo congue non tortor. Cras mi massa, vulputate id rhoncus ac, facilisis sed leo! Mauris purus urna; ultrices non sodales sed, molestie in neque. Vestibulum ullamcorper orci ac dolor commodo ac aliquam nunc ultrices. Aliquam dapibus congue massa, eleifend vestibulum ligula viverra vitae.</p> <p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old.</p> <form action=""> <fieldset> <textarea id="editor-text" name="editor-text" cols="50" rows="10"></textarea> </fieldset> </form> </div> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"> jQuery.bindContext = function (func, thisObj) { return function (event) { return func.call(thisObj, event); }; }; var $Selection = { standardsCompliant: typeof getSelection != "undefined", get: function () { return this.standardsCompliant ? getSelection() : document.selection; }, getRange: function () { return this.get()[this.standardsCompliant ? "getRangeAt" : "createRange"](0); } }; var $Range = { standardsCompliant: $Selection.standardsCompliant, stringify: function (range) { return this.standardsCompliant ? range.toString() : range.text; }, isCollapsed: function (range) { return this.standardsCompliant ? range.collapsed : !range.htmlText.length; }, getRootContainer: function (range) { if (this.standardsCompliant) { var root = range.commonAncestorContainer; return root.nodeType == this.TEXT_NODE ? root.parentNode : root; } return range.parentElement(); } }; var quote = function ($) { return { template: [ '<blockquote>', '<p>', '{QUOTE}', '</p>', '</blockquote>', '\r\n' ].join(""), templateRegExp: /{QUOTE}/, menuTemplate: [ '<div class="quote-popup-menu hidden">', '<span class="btn">Вставить цитату</span>', '</div>' ].join(""), root: "body", text: ".paragraph", menu: ".quote-popup-menu", btn: ".btn", textarea: "#editor-text", done: false, range: null, $menu: null, $btn: null, $textarea: null, init: function (cfg) { if (this.done) { return; } this.done = true; $.extend(this, cfg) this.$textarea = $(this.textarea); this.createMenu(); this.initEvents(); }, initEvents: function () { $(document).click($.bindContext(this.toggleMenu, this)); this.$btn.click($.bindContext(this.paste, this)); }, createMenu: function () { this.$menu = $(this.menuTemplate); this.$btn = this.$menu.find(this.btn); this.$menu.appendTo(this.root); }, paste: function (event) { this.$textarea.val(this.$textarea.val() + this.template.replace(this.templateRegExp, $Range.stringify(this.range))); }, saveSelection: function () { this.range = $Selection.getRange(); }, needShowMenu: function () { this.saveSelection(); var $root = $($Range.getRootContainer(this.range)); return this.$menu.is(":hidden") && !$Range.isCollapsed(this.range) && ($root.is(this.text) || $root.parent(this.text).length); }, toggleMenu: function (event) { if (this.needShowMenu()) { this.showMenu(event.pageX, event.pageY) } else { this.hideMenu(); } }, showMenu: function (x, y) { this.$menu.css({ top: y + "px", left: x + "px" }).show(); }, hideMenu: function () { this.$menu.hide(); } }; }(jQuery); $(function () { quote.init(); }); </script> </body> </html> |
Octane, Спасибо бо!
|
В Opera не генерируется событие click при выделении текста.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Работа с выделениями</title> <style type="text/css"> body { color: #000; position: relative; } .paragraph { border: 1px solid #000; } .quote-popup-menu { position: absolute; padding: 10px; background: #ffc; border: 1px solid #000; } .quote-popup-menu .btn:hover { color: #fff; background: #33c; cursor: pointer; } .hidden { display: none; } </style> </head> <body> <div> <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p> <p class="paragraph">Proin gravida auctor velit vitae facilisis. Vestibulum ac lacus vitae nunc vulputate sodales a eget augue. Quisque ornare enim a nibh ullamcorper volutpat. Nulla imperdiet gravida pulvinar. Proin consequat nisi sit amet augue convallis nec viverra nisl mollis. Nulla in orci metus? Morbi interdum ligula vitae tortor elementum sodales. Curabitur ut ante vitae lectus egestas commodo congue non tortor. Cras mi massa, vulputate id rhoncus ac, facilisis sed leo! Mauris purus urna; ultrices non sodales sed, molestie in neque. Vestibulum ullamcorper orci ac dolor commodo ac aliquam nunc ultrices. Aliquam dapibus congue massa, eleifend vestibulum ligula viverra vitae.</p> <p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old.</p> <form action=""> <fieldset> <textarea id="editor-text" name="editor-text" cols="50" rows="10"></textarea> </fieldset> </form> </div> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"> var $Selection = { standardsCompliant: typeof getSelection != "undefined", get: function () { return this.standardsCompliant ? getSelection() : document.selection; }, getRange: function () { return this.get()[this.standardsCompliant ? "getRangeAt" : "createRange"](0); } }; var $Range = { standardsCompliant: $Selection.standardsCompliant, stringify: function (range) { return this.standardsCompliant ? range.toString() : range.text; }, isCollapsed: function (range) { return this.standardsCompliant ? range.collapsed : !range.htmlText.length; }, getRootContainer: function (range) { if (this.standardsCompliant) { var root = range.commonAncestorContainer; return root.nodeType == this.TEXT_NODE ? root.parentNode : root; } return range.parentElement(); } }; var quote = function ($) { return { template: [ '<blockquote>', '<p>', '{QUOTE}', '</p>', '</blockquote>', '\r\n' ].join(""), templateRegExp: /{QUOTE}/, menuTemplate: [ '<div class="quote-popup-menu hidden">', '<span class="btn">Вставить цитату</span>', '</div>' ].join(""), root: "body", text: ".paragraph", btn: ".btn", textarea: "#editor-text", done: false, range: null, $menu: null, $btn: null, $textarea: null, init: function (cfg) { if (this.done) { return; } this.done = true; $.extend(this, cfg) this.$textarea = $(this.textarea); this.createMenu(); this.initEvents(); }, initEvents: function () { var quote = this; $(document).mousedown(function () { quote.hideMenu(); }).mouseup(function (event) { quote.showMenu(event); }); this.$btn.bind("click mousedown mouseup", function (event) { if (event.type == "click") { quote.paste(); } event.stopPropagation(); }); }, createMenu: function () { this.$menu = $(this.menuTemplate); this.$btn = this.$menu.find(this.btn); this.$menu.appendTo(this.root); }, paste: function (event) { this.hideMenu(); this.$textarea.val(this.$textarea.val() + this.template.replace(this.templateRegExp, $Range.stringify(this.range))); }, saveSelection: function () { this.range = $Selection.getRange(); }, needShowMenu: function () { this.saveSelection(); var $root = $($Range.getRootContainer(this.range)); return !$Range.isCollapsed(this.range) && ($root.is(this.text) || $root.parent(this.text).length); }, showMenu: function (event) { if (!this.needShowMenu()) { return; } this.$menu.css({ top: event.pageY + "px", left: event.pageX + "px" }).show(); }, hideMenu: function () { this.$menu.hide(); } }; }(jQuery); $(function () { quote.init(); }); </script> </body> </html> |
Часовой пояс GMT +3, время: 16:45. |