Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Обработчик события действует только на ссылки? (https://javascript.ru/forum/jquery/11039-obrabotchik-sobytiya-dejjstvuet-tolko-na-ssylki.html)

x-yuri 06.08.2010 06:11

как можно делать замечания, если не хочеться вникать в этот код? (смайлик как у 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', ''); 
    } 
});

Octane 06.08.2010 06:47

Цитата:

Сообщение от x-yuri
кстати, Octane, ты как-то абстрактно, имхо, подошел к вынесению функциональности. Т.е. я в первую очередь исхожу из того, как что-то будет использоваться. Selection.get() выглядит симпатичнее по сравнению с $Range.stringify($Selection.getRange()). Может, твой вариант чем-то лучше, но я пока не вижу чем. Он сложнее

Зачем смешивать Selection с Range? Вообще я там поудалял методы, их было больше.

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);

рони 06.08.2010 09:12

....
<!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>

Cuprum 06.08.2010 09:49

Цитата:

Сообщение от x-yuri
так совсем же просто

Спасибо, буду вникать.
Цитата:

Сообщение от x-yuri
вот только зачем ее автоматически убирать? Пользователь ее и так убрать сможет, кликнув на пустом месте.

Может человек выделил тест не для того чтобы вставить цитату, я для других целей (исключать такую возможность нельзя) - тогда в данном случае панель будет мозолить глаз и надо лишне где-то кликнуть, чтобы ее убрать. Пусть лучше исчезает.
Цитата:

Сообщение от x-yuri
Главное, чтобы она не перекрывала выделение

А что не так с перекрытием? Если фрагмент выделен большой, то панель в любом случае будет перекрывать выделение (всплывать над ним). Правда если внешний клик после этого будет на области выделения, то выходит чудно - в Fx и Chrome выделение снимается после события click, а в Opera - уже после события mousedown.
Цитата:

Сообщение от x-yuri
А вы еще говорите, что все должно быть максимально просто

Простота при тщательном изучении всегда усложняется :yes:

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

x-yuri 06.08.2010 20:53

Цитата:

Сообщение от Cuprum
Может человек выделил тест не для того чтобы вставить цитату, я для других целей (исключать такую возможность нельзя) - тогда в данном случае панель будет мозолить глаз и надо лишне где-то кликнуть, чтобы ее убрать. Пусть лучше исчезает.

а если человек отвлекся/задумался, а оно уже исчезло. Опять выделять?

Octane, да, я c Range, Selection не особо много работал. Просто подумал, что $Selection.get могло бы сразу текст возвращать. Или как вариант можно было бы метод getText написать. Но в общем-то мне сложно судить...

рони, хватит one-liner'ами досить ;)

Octane 06.08.2010 23:37

Цитата:

Сообщение от x-yuri
Просто подумал, что $Selection.get могло бы сразу текст возвращать.

Насколько я знаю, из document.selection не вытащить выделенный текст, надо сначала TextRange создать. В остальных браузерах Selection хоть и преобразуется в строку, но по спецификации выделение может содержать несколько Range-объектов, поэтому:
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();

Cuprum 10.08.2010 00:09

<!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:

Octane 10.08.2010 01:38

<!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>

Cuprum 10.08.2010 14:46

Octane, Спасибо бо!

Octane 10.08.2010 16:19

В 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, время: 06:46.