Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Как сделать цитирование? (https://javascript.ru/forum/events/4217-kak-sdelat-citirovanie.html)

`p r o x y 02.07.2009 17:44

[Решено 2 из 3] Как сделать цитирование?
 
Доброго времени суток, подскажите, пожалуйста, в двух словах, в каком направление «копать» …

Задача: При выделение любого текста на сайте - необходимо, что бы появлялась ссылка, чуть ниже курсора мыши, с текстом «цитировать». Действие ссылки – скопировать выделенный текст и вставить в textarea в позицию каретки.

1. Подскажите, как «отловить», что был выделен текст.
2. Скопировать выделенный текст.
3. Как узнать позицию каретки в textarea.
cсоответственно, под IE 6-8, Opera, FF

Рабочий вариант на функциях:
Скачать / Пример
// When a generated page (in PHP, Perl or something else)
// need add to each post (DIV, TABLE, TR, TD): onmouseover="qq.Nick='user nick'"
// Exsample for PHP: echo '<tr class="bugnote" id="'.$postId.'" onmouseover="qq.Nick=\''.$userNick.'\'" >';

var qq = {

	// QuickQuote Settings
	LinkShowTime	: 3000,
	LinkId  		: 'quickQuote',
	LinkStyle		: 'z-index:1000; cursor:pointer; position:absolute; visibility:hidden',
	LinkText		: '<b>Цитировать</b>',
	TextAreaId   	: 'bugnote_text', // id or name
	TextBefore		: '[q\nick]', // \nick - will be replaced by qq. Nick
	TextAfter		: '[/q]',
	// <--------------------
	
	Link : '', TextArea : '', Text : '', Nick : 'e', TimerId : '',
	
	Install		: function(){
		document.write(	'<div onmousedown="qq.InsertText()" onmouseout="qq.TimerStart()" onmouseover="qq.TimerStop()" \
						class="button" id="'+qq.LinkId+'" style="'+qq.LinkStyle+'">'+qq.LinkText+'</div>');
		
		qq.Link = document.getElementById(qq.LinkId);
		
		if (navigator.appName == 'Opera') qq.TextAfter += '\r\n';
		else qq.TextAfter += '\n';
		
		document.onclick   = qq.GetSelText;
		document.onmouseup = qq.LinkShow;
	},
	
	TimerStart	: function(){ qq.TimerStop(); qq.TimerId = setTimeout(qq.LinkHide, qq.LinkShowTime); },
	TimerStop	: function(){ clearTimeout(qq.TimerId); },
	LinkHide	: function(){ qq.Link.style.visibility = 'hidden'; },

	LinkShow 	: function(event){
		qq.GetSelText(event);
		if (qq.Text == '') return;
		
		var mc = event || window.event;
		if (mc.pageX || mc.pageY){
			mc.X = mc.pageX;
			mc.Y = mc.pageY;
		}else if (mc.clientX || mc.clientY){
			mc.X = mc.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			mc.Y = mc.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
		}
		qq.Link.style.left = (mc.X-35)+'px';
		qq.Link.style.top  = (mc.Y+11)+'px';
		qq.Link.style.visibility = 'visible';
		
		qq.TimerStart();
	},
	
	GetSelText	: function(event){
		event = event || window.event;
		var targ = event.target || event.srcElement;
		if (	targ && targ.tagName == 'TEXTAREA' || targ.tagName == 'A' || targ.tagName == 'IMG' ||
				(targ.tagName == 'INPUT' || targ.type == 'TEXT' || targ.type == 'PASSWORD')) return qq.LinkHide();
		
		qq.Text = getSelText();
		qq.Text = qq.Text.replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
		if (qq.Text == '') return qq.LinkHide();
	},
	
	InsertText	: function(){
		qq.LinkHide();
		if (qq.TextArea == '' || qq.TextArea == null){
			qq.TextArea = document.getElementById(qq.TextAreaId);
			if (qq.TextArea == null) qq.TextArea = document.getElementsByName(qq.TextAreaId)[0];
		}
		if (qq.TextArea == null) return;
		
		insertText(	qq.TextArea, qq.TextBefore.replace(/\nick/gi, (qq.Nick ? '='+qq.Nick : '')) 
					+ qq.Text + qq.TextAfter.replace( /\nick/gi, (qq.Nick ? '='+qq.Nick : '')));
		
		qq.Nick = '';
	}
};

// Common functions
function saveCaretPos(event){
    event = event || window.event;
    var obj = event.target || event.srcElement;
    if (typeof(document.selection) != 'undefined' && typeof(document.selection.createRange) != 'undefined')
    obj.caretPos = document.selection.createRange().duplicate();
}
function getSelText(){
	if (window.getSelection && !window.opera) 	var selText = window.getSelection(); // ff
	else if (document.getSelection) 			var selText = document.getSelection(); // opera
	else if (document.selection) 				var selText = document.selection.createRange().text; // ie
	if (!selText) selText = '';
	return selText.toString();
}
function insertText(obj, text){
	var scrollTop = obj.scrollTop;
	var scrollLeft = obj.scrollLeft;

	if (window.getSelection || document.getSelection) var caretPos = obj.selectionStart + text.length;
	
	if (obj && obj.caretPos) 
		obj.caretPos.text = text;
	else if (obj && obj.selectionStart+1 && obj.selectionEnd+1)
		obj.value = obj.value.substring(0, obj.selectionStart) + text + obj.value.substring(obj.selectionEnd, obj.value.length);
	else if (obj)
		obj.value += text;
	
	if (window.getSelection || document.getSelection) obj.setSelectionRange(caretPos, caretPos);
	
	obj.scrollTop = scrollTop;
	obj.scrollLeft = scrollLeft;
}
// <--------------------

// Install QuickQuote
qq.Install();

document.body.onload = function(){
	qq.TextArea = document.getElementById(qq.TextAreaId);
	if (qq.TextArea == null) qq.TextArea = document.getElementsByName(qq.TextAreaId)[0];
	if (qq.TextArea == null) return;
	
	qq.TextArea.onselect = saveCaretPos;
	qq.TextArea.onclick  = saveCaretPos;
	qq.TextArea.onkeyup  = saveCaretPos;
}
// <--------------------

Octane 02.07.2009 17:51

Большинство ответов на ваши вопросы здесь: Range, TextRange и Selection.

По событию mouseup документа, получаете объект-выделение (selection), проверяет схлопнуто (collapsed) ли оно, если нет, то создаете ссылку для помещения выделенного текст в textarea.

Для получения координат события mouseup прочитайте Свойства объекта событие: Координаты мыши

`p r o x y 02.07.2009 18:03

Octane, благодарю, полезная и понятная информация.

Octane 02.07.2009 18:13

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

`p r o x y 02.07.2009 18:24

Octane,
ни капли - наоборот - ооооочень помогают, форумы где используют: forum.oszone.net / forum.ru-board.com - после выделения, одна единственная ссылка "цитировать", на 2 сек, далее исчезает.
Имхо, очень удобно.
Вот теперь к Мантису хочу прикрутить такое еже ..

`p r o x y 03.07.2009 23:03

Часть решения:

var divQuote = document.write('<div onmousedown="oQuote.past()" class="button" id="quote_div" style="z-index:1000;cursor:pointer;position:absolute;visibility:hidden;"><b>Цитировать</b></div>');
var divQuote = document.getElementById('quote_div');

window.onload = function(){
	//document.onselect	= quickQuote;
	//document.onclick	= quickQuote;
	document.onkeyup	= quickQuote;
	document.onmouseup	= quickQuote;	
	var oQuote = new quickQuote();
}

function quickQuote(e){
	var selText = '';
	if (window.getSelection && !window.opera) selText = window.getSelection();
	else if (document.getSelection) selText = document.getSelection();
	else if (document.selection) selText = document.selection.createRange().text;
	this.selText2 = selText;

	selText.toString().replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
	if(!selText) return
		
	var e = e || window.event;
	if (e.pageX == null && e.clientX != null){ 
		var html = document.documentElement;
		var body = document.body;
		e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0);
		e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0);
	}
	
	divQuote.style.left = (e.pageX-80)+'px';
	divQuote.style.top	= (e.pageY+11)+'px';
	divQuote.style.visibility = 'visible';
	//divQuote.innerText = selText;
	
	this.past = function(){
		alert(selText);
	}
}





Есть вопрос: Как работать с объектами Javascript?
вот это прочитал, не осилил.

В данном случае у меня происходит:

1. Появляется ссылка, после выделения любого текста на старнице.
2. При нажатие на ссылку - необходимо вызвать функцию, которая продеманстрирует выделенный текст, который содержится в переменной selText.

Как это сделать с помощью объектов, а не банальной передачей выделенного текста в функцию?

А такой вриант:
if(!selText) return

не вызовет ошибку? Т.е. всегда будет выполняться верно?
Этим хотел проверить, есть ли текст в этой переменной, и нет ли ошибок получения выделенного текст (undefined).

`p r o x y 04.07.2009 01:21

нарыл более подробный материал с примерами, изучаю...

x-yuri 04.07.2009 02:21

объекты хочешь использовать потому что модно?
Цитата:

Сообщение от `p r o x y
А такой вриант:
if(!selText) return
не вызовет ошибку? Т.е. всегда будет выполняться верно?

а какие значения может принимать эта переменная?

`p r o x y 04.07.2009 02:30

x-yuri,
1. потому, что не умею ))
2. потому что, скрипт цитирования, который выковырял с форума на объектах работает, и работает он хорошо - вот и стараюсь равняться на лучшее. Но, мало что понимаю в том скрипте, вот и пишу сам, почти все с нуля.


Не пойму, почему тут ошибка:
function quickQuote(){
	document.write('<div onmousedown="quickQuote.showSelText()" class="button" id="divQuickQuote" style="z-index:1000;cursor:pointer;position:absolute;visibility:hidden"><b>Цитировать</b></div>');
	var selText = '';
	
	this.getSelText = function(){
		selText = '';
		if (window.getSelection && !window.opera) 	selText = window.getSelection();
		else if (document.getSelection) 			selText = document.getSelection();
		else if (document.selection) 				selText = document.selection.createRange().text;
		
		selText.toString().replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
		if(!selText) return;
		
		this.showSelText();
	};
	
	/*this.getMouseCord = function(e){
		var e = e || window.event;
		if (e.pageX == null && e.clientX != null){ 
			var html = document.documentElement;
			var body = document.body;
			e.X = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0);
			e.Y = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0);
		}
		return e;
	};
	
	this.showLink = function(e){
		var divQuote = document.getElementById('divQuickQuote');
		divQuote.style.left = (e.X-35)+'px';
		divQuote.style.top	= (e.Y+11)+'px';
		divQuote.style.visibility = 'visible';
		//divQuote.innerText = selText;
	};*/
	
	this.showSelText = function(){
		alert('= '+selText);
	};
}

var oQuote = new quickQuote();
window.onload = function(){
	//document.onselect	= quickQuote;
	//document.onclick	= quickQuote;
	document.onkeyup	= oQuote.getSelText();
	document.onmouseup	= oQuote.getSelText();
}


это решил, правильно использовать вот так:
document.onkeyup    = oQuote.getSelText;
document.onmouseup    = oQuote.getSelText;

`p r o x y 04.07.2009 02:35

Цитата:

а какие значения может принимать эта переменная?
ну по коду должно быть видно, эта переменная принимает:
- либо выделенный текст
- либо ошибки, при попытки определить выделенный текст

Сначала написал так:
if (selText == '' || selText == 'undefined') return;

но потом сократил на то, что выше.

x-yuri 04.07.2009 03:08

Цитата:

Сообщение от `p r o x y
- либо выделенный текст

для строк: пустая будет считаться как false

Цитата:

Сообщение от `p r o x y
- либо ошибки, при попытки определить выделенный текст

что за ошибки и какой тип данных? undefined и null тоже будут считаться как false

`p r o x y 04.07.2009 03:11

x-yuri,
понял, значит моя конструкция:
if(!selText) return;

будет работать правильно.

`p r o x y 04.07.2009 03:54

А как из метода одного объекта, вызвать другой метод этого же объекта?

function QuickQuote(){
	document.write('<div onmousedown="quickQuote.showSelText()" class="button" id="divQuickQuote" style="z-index:1000;cursor:pointer;position:absolute;visibility:hidden"><b>Цитировать</b></div>');
	var selText = '';
	
	this.GetSelText = function(){
		selText = '';
		if (window.getSelection && !window.opera) 	selText = window.getSelection();
		else if (document.getSelection) 			selText = document.getSelection();
		else if (document.selection) 				selText = document.selection.createRange().text;
		
		selText.toString().replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
		if (!selText) selText = '<error>';
		
		this.ShowSelText;
	};
	
	this.ShowSelText = function(){
		alert(selText);
	};

}

var oQQ = new QuickQuote();
window.onload = function(){
	document.onkeyup	= oQQ.GetSelText;
	document.onmouseup	= oQQ.GetSelText;
}


почему не срабатывает и как сделать, что бы работало?
this.ShowSelText;

x-yuri 04.07.2009 04:15

если ты пишешь
function o() {
    this.method = function() {}
}

для каждого объекта будет создан свой "экземпляр" метода. Лучше
function o() {}
o.prototype.method = function() {}


this.ShowSelText - ссылка на метод, чтобы его вызвать нужно добавить ()

`p r o x y 04.07.2009 04:21

Цитата:

Сообщение от x-yuri (Сообщение 23629)
если ты пишешь
function o() {
    this.method = function() {}
}

для каждого объекта будет создан свой "экземпляр" метода. Лучше
function o() {}
o.prototype.method = function() {}


this.ShowSelText - ссылка на метод, чтобы его вызвать нужно добавить ()

вот это, как раз, не укладывается у меня в сознании - с prototype-ами ....посмотри, пожалуйста, по коду. Все ли нормально? Можешь именно на примере моего кода ткунть, как и что лучше - так думаю пойму .....

Цитата:

this.ShowSelText - ссылка на метод, чтобы его вызвать нужно добавить ()
пробовал и так, конечно:
this.ShowSelText();

все равно "ошибка на странице" и никакого alert-а ...


У меня происходит вызов: document.onmouseup = oQQ.GetSelText;
выделенный текст записывается в selText для объекта oQQ.
Вот только низ метода document.onmouseup = oQQ.GetSelText;
не получается вызвать метод this.ShowSelText ...

x-yuri 04.07.2009 04:29

Цитата:

Можешь именно на примере моего кода ткунть, как и что лучше - так думаю пойму .....
прийдется понимать на моих примерах. Если в объекте не найден метод, он ищется в прототипе. Есть еще вопросы?

Цитата:

все равно "ошибка на странице" и никакого alert-а ...
поставь ff и посмотри в консоль ошибок или поставь/включи отладчик для ie

`p r o x y 04.07.2009 05:16

Цитата:

Есть еще вопросы?
есть, что это значит:
Цитата:

Если в объекте не найден метод, он ищется в прототипе.
Цитата:

прийдется понимать на моих примерах.
да лана, тебе умничать, я же НЕ прошу за меня решить мою задачу. Наоборот - разобраться желаю ) Просто реально не могу ухватиь суть, в этом, пока. ......)

я же не стал бы писать, если б все понимал ))

если использовать:
this.ShowSelText();

ошибка: this.ShowSelText is not a function

ну а если так:
this.ShowSelText

то и ошибок нет и alert-а нет ...


тогда так:
function QuickQuote(){
	document.write('<div onmousedown="quickQuote.showSelText()" class="button" id="divQuickQuote" style="z-index:1000;cursor:pointer;position:absolute;visibility:hidden"><b>Цитировать</b></div>');
	var selText = '';
}
QuickQuote.prototype.GetSelText = function(){
	selText = '';
	if (window.getSelection && !window.opera) 	selText = window.getSelection();
	else if (document.getSelection) 			selText = document.getSelection();
	else if (document.selection) 				selText = document.selection.createRange().text;
	
	selText.toString().replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
	if (!selText) return;
	
	this.ShowSelText();
}
QuickQuote.prototype.ShowSelText = function(){
	alert('sdf');
}

var oQQ = new QuickQuote();
window.onload = function(){
	document.onkeyup	= oQQ.GetSelText;
	document.onmouseup	= oQQ.GetSelText;
}

все равно ошибка:
Цитата:

this.ShowSelText is not a function

`p r o x y 04.07.2009 06:15

в общем, без prototype-ов, так и не понял как добиться вызова одного метода из другого метода, одного и того же объекта. А с prototype-ом, вариант такой:

function QuickQuote(e){
	document.write('<div onmousedown="QuickQuote.showSelText()" class="button" id="divQuickQuote" style="z-index:1000;cursor:pointer;position:absolute;visibility:hidden"><b>Цитировать</b></div>');
	this.SelText = '1';
}
QuickQuote.prototype.GetSelText = function(){
	SelText = '';
	if (window.getSelection && !window.opera) 	SelText = window.getSelection();
	else if (document.getSelection) 			SelText = document.getSelection();
	else if (document.selection) 				SelText = document.selection.createRange().text;
	
	SelText.toString().replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
	if (!SelText || SelText == '') return;

	QuickQuote.prototype.ShowSelText();
}
QuickQuote.prototype.ShowSelText = function(){
	alert(SelText);
}

var oQQ = new QuickQuote();
window.onload = function(){
	document.onkeyup	= oQQ.ShowSelText;
	document.onmouseup	= oQQ.GetSelText;
}

x-yuri 04.07.2009 22:15

Цитата:

Сообщение от `p r o x y
да лана, тебе умничать

сам ты умничаешь ;)

Цитата:

Сообщение от `p r o x y
Если в объекте не найден метод, он ищется в прототипе.

function c() {}
c.prototype.m1 = function() { alert(1); }
var o = new c();
o.m2 = function() { alert(2); }
o.m1();
o.m2();


Цитата:

в общем, без prototype-ов, так и не понял как добиться вызова одного метода из другого метода, одного и того же объекта
потом разберешься, если понадобится

Цитата:

Сообщение от `p r o x y
А с prototype-ом, вариант такой

лучше по-другому
function c() {}
c.prototype.m1 = function() { 
    alert(this instanceof c);
    if( this.m2 )
        this.m2();
}
c.prototype.m2 = function() { alert(2); }
var o = new c(); // здесь содержимое c.prototype
    // копируется в прототип объекта o
var o2 = {
    m3: o.m1, // эта ссылка указывает на o.prototype.m1
        // (в объекте o нету метода m1
        // но он есть в прототипе)
    m4: function() {
        // вызываем функцию o.m1 так,
        // чтобы this указывал на o
        o.m1.call( o );
    }};
o2.m3(); // при вызове this будет указывать на o2
    // а в объекте o2 нету метода m2
o2.m4();

`p r o x y 05.07.2009 00:34

x-yuri,
...блин......пойду рисовать схемы.
Понимать то понимаю, но вот как обычно, в сознании, структура так и не прояснилась. Че то не хватает....)

Благодарю.

БЛИн )) но его доканаяю.....на функциях то просто все...

x-yuri 05.07.2009 02:01

Цитата:

Сообщение от `p r o x y
Понимать то понимаю, но вот как обычно, в сознании, структура так и не прояснилась. Че то не хватает....)

значит чего-то не понимаешь. Для начала нужно выяснить, чего именно, а потом начать задавать вопросы
Цитата:

Сообщение от `p r o x y
БЛИн )) но его доканаяю.....на функциях то просто все...

а на чем не просто?

`p r o x y 06.07.2009 22:19

Цитата:

а на чем не просто?
да все просто и понятно. НО, есть но, когда начинаю разбираться в коде с объектами, в сознании, теряется понимание структуры, какие методы наследуют у каких, что с чем связанно, т.е. ясного представления цепочки объектов/методов.

Пишу то на php и под win на скриптах - там большенство без объектов/классов (т.е. подобия ооп), вот и не привычно. На js первый раз начал разбираться с объектами.

Благодарю за терпение. Сейчас привел в готовый вид вариант на функциях, и скланяюсь к варианту, что это реализация лучше для данной задачи.

Хотя, все таки доделаю и на объектах - для сравнения и понимания.

А пока, рабочий вариант на функциях. Провернно: IE 6, Opera 9, FF 3, (Chrome, Safari 3 немного криво вставляются \r\n).

// When a generated page (in PHP, Perl or something else)
// need add to each post (DIV, TABLE, TR, TD): onmouseover="qqNick='user nick'"
// Exsample: <tr class="bugnote" id="c59" onmouseover="qqNick='TikTak'">

// QuickQuote Settings:
var qqLinkShowTime 	= 3000;
var qqLinkId  		= 'quickQuote';
var qqLinkStyle		= 'z-index:1000; cursor:pointer; position:absolute; visibility:hidden';
var qqLinkText		= '<b>Цитировать</b>';
var qqTextAreaId   	= 'bugnote_text'; // id or name
//_____________________

document.write(	'<div 	onmousedown="qqInsertText()" onmouseout="qqTimerStart()" onmouseover="qqTimerStop()" \
						class="button" id="'+qqLinkId+'" style="'+qqLinkStyle+'">'+qqLinkText+'</div>');

var qqText, qqNick, qqTimerId, qqLink = document.getElementById(qqLinkId);
document.onclick   = qqGetSelText;
document.onmouseup = qqLinkShow;

document.body.onload = function(){
	var oTextArea = document.getElementById(qqTextAreaId);
	if (oTextArea == null) oTextArea = document.getElementsByName(qqTextAreaId)[0];
	if (oTextArea == null) return;
	
	oTextArea.onselect = saveCaretPos;
	oTextArea.onclick  = saveCaretPos;
	oTextArea.onkeyup  = saveCaretPos;
}

function qqTimerStart(){ qqTimerStop(); qqTimerId = setTimeout(qqLinkHide, qqLinkShowTime); }
function qqTimerStop(){  clearTimeout(qqTimerId); }
function qqLinkHide(){ 	 qqLink.style.visibility = 'hidden'; }

function qqLinkShow(event){
	qqGetSelText();
	if (qqText == '') return;
	
	var mc = event || window.event;
	if (mc.pageX || mc.pageY){
		mc.X = mc.pageX;
		mc.Y = mc.pageY;
	}else if (mc.clientX || mc.clientY){
		mc.X = mc.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		mc.Y = mc.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
	}
	qqLink.style.left = (mc.X-35)+'px';
	qqLink.style.top  = (mc.Y+11)+'px';
	qqLink.style.visibility = 'visible';
	
	qqTimerStart();
}
function qqGetSelText(){
	qqText = getSelText();
	qqText.replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
	if (qqText == '') qqLinkHide();
}
function qqInsertText(){
	qqLinkHide();
	var oTextArea = document.getElementById(qqTextAreaId);
	if (oTextArea == null) oTextArea = document.getElementsByName(qqTextAreaId)[0];
	if (oTextArea == null) return;
	insertText(oTextArea, '[q]'+qqNick+': ' + qqText + '[/q]\r\n');
}

function insertText(obj, text){
	if (window.getSelection && !window.opera) var caretPos = obj.selectionStart + text.length;
	
	if (obj && obj.caretPos) 
		   obj.caretPos.text = text; 
	else if (obj && obj.selectionStart+1 && obj.selectionEnd+1)
		   obj.value = obj.value.substring(0, obj.selectionStart) + text + obj.value.substring(obj.selectionEnd, obj.value.length);
	else if (obj)
		   obj.value += text;
	
	if (window.getSelection && !window.opera) obj.setSelectionRange(caretPos, caretPos);
}
function getSelText(){
	if (window.getSelection && !window.opera) 	var selText = window.getSelection(); // ff
	else if (document.getSelection) 			var selText = document.getSelection(); // opera
	else if (document.selection) 				var selText = document.selection.createRange().text; // ie
	if (!selText) selText = '';
	return selText.toString();
}
function saveCaretPos(event){
	event = event || window.event;
	var obj = event.target || event.srcElement;
	if (typeof(document.selection) != 'undefined' && typeof(document.selection.createRange) != 'undefined')
	obj.caretPos = document.selection.createRange().duplicate();
}

x-yuri 06.07.2009 23:24

1) тебе "классы" тут не особо то и нужны. У тебя же скрипт рассчитан на один экземпляр (на странице одна textarea, с которой работаем)
2) функции, используемые только в одной (другой) функции можно туда же и запихнуть (чтобы не создавать лишних глобальных имен)
function a() {
   ...
   b();
   ...
   function b() { ... }
}

3) можно использовать DOM-элементы для хранения информации вместо глобальных переменных
4) можно использовать namespace'ы
(function() {
    // идентификаторы объявленные здесь
    // не будут видны снаружи
})();

`p r o x y 06.07.2009 23:37

Цитата:

x-yuri
п. 1, ну опять же, делал с другого скрипта, вот и решил делать на "классах", тперь мне уже ясней, что тут то это и не нужно.
п. 2-3 очень интересны, поработаю.
п. 4 хм..а зачем? ...ну наверно полезное...

Благодарю, за комментарий.

x-yuri 07.07.2009 00:44

Цитата:

Сообщение от `p r o x y
п. 4 хм..а зачем?

чтобы не было много глобальных переменных: если два скрипта используют глобальную переменную (функцию, "класс") с одним и тем же именем, то у них будут проблемы

`p r o x y 07.07.2009 08:15

Цитата:

если два скрипта используют глобальную переменную (функцию, "класс") с одним и тем же именем, то у них будут проблемы
это само собой понятно.
для этого имена переменных и функций выбрал с префиксом...
хотя конечно раааазное бывает )

x-yuri 07.07.2009 08:21

для полноты, префикс можно и точкой отделять:
var Ajax = {
    get: function() { ... }
}
// или так
// var Ajax = {};
// Ajax.get = function() { ... };
...
Ajax.get(...);

т.е. наличие точки не означает наличие "класса" (использование оператора new)

`p r o x y 07.07.2009 09:31

Цитата:

т.е. наличие точки не означает наличие "класса" (использование оператора new)
умм, уже интересней. такие подробности синтаксиса очень интересны, еще не встречал!

Kolyaj 07.07.2009 10:36

Цитата:

Сообщение от x-yuri
тебе "классы" тут не особо то и нужны. У тебя же скрипт рассчитан на один экземпляр (на странице одна textarea, с которой работаем)

А потом вдруг понадобится еще один textarea на странице и, вместо того, чтобы просто его добавить, шуруем переписывать скрипты.

`p r o x y 07.07.2009 16:17

Цитата:

Сообщение от Kolyaj (Сообщение 23780)
А потом вдруг понадобится еще один textarea на странице и, вместо того, чтобы просто его добавить, шуруем переписывать скрипты.

вот поэтому, все же, сделаю два варианта - и обучение и вариант для развития )

`p r o x y 09.07.2009 06:03

окей, а как вот такой вариант:

// When a generated page (in PHP, Perl or something else)
// need add to each post (DIV, TABLE, TR, TD): onmouseover="qq.Nick='user nick'"
// Exsample for PHP: echo '<tr class="bugnote" id="'.$postId.'" onmouseover="qq.Nick=\''.$userNick.'\'">';

var qq = {

	// QuickQuote Settings
	LinkShowTime	: 3000,
	LinkId  		: 'quickQuote',
	LinkStyle		: 'z-index:1000; cursor:pointer; position:absolute; visibility:hidden',
	LinkText		: '<b>Цитировать</b>',
	TextAreaId   	: 'bugnote_text', // id or name
	// <--------------------
	
	Link : '', TextArea : '', Text : '', Nick : '', TimerId : '',
	
	Install		: function(){
		document.write(	'<div onmousedown="qq.InsertText()" onmouseout="qq.TimerStart()" onmouseover="qq.TimerStop()" \
						class="button" id="'+qq.LinkId+'" style="'+qq.LinkStyle+'">'+qq.LinkText+'</div>');
		
		qq.Link = document.getElementById(qq.LinkId);
		
		document.onclick   = qq.GetSelText;
		document.onmouseup = qq.LinkShow;
	},
	
	TimerStart	: function(){ qq.TimerStop(); qq.TimerId = setTimeout(qq.LinkHide, qq.LinkShowTime); },
	TimerStop	: function(){ clearTimeout(qq.TimerId); },
	LinkHide	: function(){ qq.Link.style.visibility = 'hidden'; },

	LinkShow 	: function(event){
		qq.GetSelText();
		if (qq.Text == '') return;
		
		var mc = event || window.event;
		if (mc.pageX || mc.pageY){
			mc.X = mc.pageX;
			mc.Y = mc.pageY;
		}else if (mc.clientX || mc.clientY){
			mc.X = mc.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			mc.Y = mc.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
		}
		qq.Link.style.left = (mc.X-35)+'px';
		qq.Link.style.top  = (mc.Y+11)+'px';
		qq.Link.style.visibility = 'visible';
		
		qq.TimerStart();
	},
	
	GetSelText	: function(){
		qq.Text = getSelText();
		qq.Text.replace(/(\r?\n\s*){2,}/gi,'\r\n').replace(/^\s+|\s+$/gi,'').replace(/(\ |\t)+/gi,' ');
		if (qq.Text == '') qq.LinkHide();
	},
	
	InsertText	: function(){
		qq.LinkHide();
		if (qq.TextArea == '' || qq.TextArea == null){
			qq.TextArea = document.getElementById(qq.TextAreaId);
			if (qq.TextArea == null) qq.TextArea = document.getElementsByName(qq.TextAreaId)[0];
		}
		if (qq.TextArea == null) return;
		
		if (navigator.appName == 'Opera') qq.Text = '[q]'+qq.Nick+': ' + qq.Text + '[/q]\r\n';
		else qq.Text = '[q]'+qq.Nick+': ' + qq.Text + '[/q]\n';
		
		insertText(qq.TextArea, qq.Text);
	}
};

// Common functions
function saveCaretPos(event){
    event = event || window.event;
    var obj = event.target || event.srcElement;
    if (typeof(document.selection) != 'undefined' && typeof(document.selection.createRange) != 'undefined')
    obj.caretPos = document.selection.createRange().duplicate();
}
function getSelText(){
	if (window.getSelection && !window.opera) 	var selText = window.getSelection(); // ff
	else if (document.getSelection) 			var selText = document.getSelection(); // opera
	else if (document.selection) 				var selText = document.selection.createRange().text; // ie
	if (!selText) selText = '';
	return selText.toString();
}
function insertText(obj, text){

	var scrollTop, scrollLeft;
	if (obj.type == 'TEXTAREA' && obj.scrollTop){
		scrollTop = obj.scrollTop;
		scrollLeft = obj.scrollLeft;
	}

	if (window.getSelection || document.getSelection) var caretPos = obj.selectionStart + text.length;
	
	if (obj && obj.caretPos) 
		obj.caretPos.text = text;
	else if (obj && obj.selectionStart+1 && obj.selectionEnd+1)
		obj.value = obj.value.substring(0, obj.selectionStart) + text + obj.value.substring(obj.selectionEnd, obj.value.length);
	else if (obj)
		obj.value += text;
	
	if (window.getSelection || document.getSelection) obj.setSelectionRange(caretPos, caretPos);
	
	if (typeof scrollTop != 'undefined'){
		textObj.scrollTop = scrollTop;
		textObj.scrollLeft = scrollLeft;
	}
}
// <--------------------

// Install QuickQuote
qq.Install();

document.body.onload = function(){
	qq.TextArea = document.getElementById(qq.TextAreaId);
	if (qq.TextArea == null) qq.TextArea = document.getElementsByName(qq.TextAreaId)[0];
	if (qq.TextArea == null) return;
	
	qq.TextArea.onselect = saveCaretPos;
	qq.TextArea.onclick  = saveCaretPos;
	qq.TextArea.onkeyup  = saveCaretPos;
}
// <--------------------



Осталось только разобраться с прокруткой в textarea.
Demo страница

x-yuri 09.07.2009 06:25

можно и так. Минус: рассчитано на одну textarea (хотя мне не приходит в голову ситуация, когда нужно больше). Минус является следствием того, что ты по сути спрятал все в один namespace. Если бы это было реализовано в виде "класса"... но можно и так

`p r o x y 09.07.2009 07:12

Цитата:

Минус: рассчитано на одну textarea
эту разницу я понимаю, именно на это и рассчитываю.

А вот следующий вариант будет на "классе"....

Вопрос: а как проверить, назначен ли объекту обработчик событий: onselect / onclick / onkeyup ?

B~Vladi 09.07.2009 10:21

obj.onclick

Возвратит то, что было назначено объекту через свойство:
obj.onclick=function(){
   alert('');
}

или null.

Что добавленно через addEventListener или attachEvent узнать нельзя, разве что только самому сохранять.

`p r o x y 09.07.2009 12:10

ни как не могу победить - установку позиции корректки в textarea для ie.
Пока только через:

qq.TextArea.onselect = saveCaretPos;
qq.TextArea.onclick  = saveCaretPos;
qq.TextArea.onkeyup  = saveCaretPos;

function saveCaretPos(event){
    event = event || window.event;
    var obj = event.target || event.srcElement;
    if (typeof(document.selection) != 'undefined' && typeof(document.selection.createRange) != 'undefined')
    obj.caretPos = document.selection.createRange().duplicate();
}


Хотя для Opera и FF отлично работает:
obj.setSelectionRange(caretPos, caretPos);


Может для ie есть вариант подобный setSelectionRange?

B~Vladi 09.07.2009 14:19

Для ИЕ есть метод window.getSelection().
Возвращает выделенный текст. Пока только знаю метод removeAllRanges(), который снимает выделение. По поводу других пользуемся конструкцией var in и гуглом.

Octane 09.07.2009 14:25

Можно создать новый TextRange и сдвинуть его границы в нужную позицию

`p r o x y 09.07.2009 16:17

B~Vladi,
дело в том, что getSelection() и removeAllRanges() это только в Opera, FF и т.д. - в IE свое направление на эту тему: selection ............(

Octane,
а можешь привести строку кода для примера, не получается сообразить как выполнить...делаю так:

var obj = document.getElementById('textarea_id');
obj.selection.createRange();

а какой метод дальше? move ? ...ни как не разберусь - все в ошибках постоянно (читаю статью, что ты выше постил).
Кстати, если устанавливать позицию корретки, то как для IE определить в какой позиции она уже стоит?

Octane 09.07.2009 16:21

Как-то так:
var obj = document.getElementById('textarea_id');
var range = obj.selection.createRange();
range.moveStart('character', selStart);
range.moveEnd('character', selEnd);
range.select();


Подробнее здесь: Range, TextRange и Selection

B~Vladi 09.07.2009 17:00

Цитата:

Сообщение от `p r o x y
getSelection() и removeAllRanges() это только в Opera, FF и т.д.

Аха, блин, перепутал немного...


Часовой пояс GMT +3, время: 03:00.