1 (изменено: mozers, 2016-02-06 19:30:16)

Тема: JS: Placeholder

Вы наверняка видели поля ввода в которых подсказка написана прямо внутри их и исчезает при вводе первой буквы.
Удобная вещь! Наглядно, удобно, экономит место. В современных браузерах поддерживается с помощью атрибута placeholder тега <INPUT>.
Как быть с теми браузерами, которые этот атрибут не поддерживают? Мне, например, он позарез понадобился в HTA.
Гугл выдаёт монстроидальные варианты на jQuery + placeholder.js. Нашел лишь несколько простых реализаций, но с весьма урезанным функционалом. Решил написать сам. Работает точь-в-точь как "фирменный".

<!DOCTYPE html>
<html>
<head>
<hta:application />
<style type="text/css">
	.plh {
		position: absolute;
		left: 4px;
		top: 2px;
		color:graytext;
	}
</style>
<script type="text/javascript">
	function setPlaceHolders(){
		var input = document.getElementsByTagName('input');
		if (input) {
			var plh, container;
			for(var i = 0, inp; inp = input[i++];) {
				if ((inp.type == 'text')||(inp.type == 'password')){
					var txt = inp.getAttribute("placeholder");
					if (txt && (txt.length > 0)) {
						plh = document.createElement("DIV");
						plh.className = "plh";
						plh.innerHTML = txt;
						if (inp.value.length>0) plh.style.display = 'none'; // вариант с скрытием подсказки
						// if (inp.value.length>0) plh.style.top = '-18px';    // вариант с подъёмом подсказки
						plh.onfocus = function(){this.previousSibling.focus();};

						container = document.createElement("SPAN");
						container.style.position = 'relative';

						inp.parentElement.insertBefore(container, inp);
						container.appendChild(inp);
						container.appendChild(plh);

						inp.attachEvent('onkeyup', function(elem){
								return function(){elem.nextSibling.style.display = elem.value.length ? 'none' : '';}; // вариант с скрытием подсказки
								// return function(){elem.nextSibling.style.top = elem.value.length ? '-18px' : '2px';}; // вариант с подъёмом подсказки
							}(inp)
						);

						/* Для перетаскивания данных на поля ввода (c) wisgest */
						container.ondragover = function () {
							event.dataTransfer.dropEffect = event.ctrlKey ? 'copy' : 'move';
							return event.srcElement.tagName == "INPUT";
						};
						container.ondrop = function () {
							if (this.ondragover()) return;
							var inp = this.firstChild;
							inp.value = event.dataTransfer.getData('text');
							inp.nextSibling.style.display = 'none'; // вариант с скрытием подсказки
							// inp.nextSibling.style.top = '-18px';    // вариант с подъёмом подсказки
						};
					}
				}
			}
		}
	}
</script>
</head>
<body onload="setPlaceHolders();">
	<br />
	<input type="text" placeholder="Domain" value="Home"><br /><br />
	<input type="text" placeholder="User Name" onkeyup="idLen.innerHTML=this.value.length;"> <span id="idLen">0</span><br /><br />
	<input type="password" placeholder="Password"><br /><br />
</body>
</html>

2

Re: JS: Placeholder

Самому никогда еще никогда не потребовалась, но выглядит здорово.

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


<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">

function setPlaceHolders(){
	var inputs = document.getElementsByTagName('input');
	if ( ! inputs || ! inputs.length ) {
		return;
	}

	for (var i = 0; i < inputs.length; i++) {
		var input = inputs[i];

		var type = input.type.toLowerCase();
		if ( type != 'text' && type != 'password' ) {
			continue;
		}

		var placeholder = input.placeholder;
		if ( ! placeholder || ! placeholder.length ) {
			continue;
		}

		(function(input, placeholder)
		{
			var changed = false;
			var value = input.value;
			input.value = placeholder;
			input.onfocus = function()
			{
				if ( changed ) {
					return;
				}
				input.value = value;
			};
			input.onblur = function()
			{
				if ( changed ) {
					return;
				}
				if ( input.value != value ) {
					changed = true;
				} else {
					input.value = placeholder;
				}
			};
		})(input, placeholder);
	}
}

</script>
</head>
<body onload="setPlaceHolders();">

<input type="text" placeholder="Domain" value="Home"><br />
<input type="text" placeholder="User Name"><br />
<input type="password" placeholder="Password">

</body>
</html>
( 2 * b ) || ! ( 2 * b )

3 (изменено: mozers, 2016-02-02 01:06:37)

Re: JS: Placeholder

Rumata пишет:

Работает не совсем точь-в-точь

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

4 (изменено: wisgest, 2016-02-02 08:08:30)

Re: JS: Placeholder

mozers пишет:

Наглядно, удобно, экономит место.

Экономит. Остальное спорно. Например, получая посылку, я имею привычку в извещениях путать поля: когда и кем выдан паспорт. А тут при полностью заполненной форме и не скажешь, всё ли на своих местах. Для мнительного человека очень неудобно. По меньшей мере надо обязательно дублировать через title, но тот, кто по несколько раз возвращается проверить, закрыт ли холодильник и выключен ли газ, всё-равно будет задумчиво-раздражённо переводить указатель с одного поля на  другое. Подходит только для форм с одним (запрос) или двумя (имя, пароль) полями.

mozers пишет:

Да и с password-ом без динамической подмены никак не обойтись...

Как правило, пароль только один (а если не один, то см. выше) и кружочки-звёздочки на порядок понятней всякой надписи.

mozers пишет:

Работает точь-в-точь как "фирменный".

Подсказка исчезает не при получении фокуса, а только если что-нибудь ввести. Если так и задумано, то, соответствено, и наоборот появлятся должна при полной очистке поля даже без потери фокуса.

Обычно формы входа заполняю перетаскиванием паролей из просмотрщика WinRAR.
Почему-то почти все разработчики забывают о таком способе ввода. К удивлению здесь он хоть и криво, но работает. Но этого сразу и не заметишь, т.к. надо очень тщательно прицелиться в узкий зазор перед первой буквой.

Rumata пишет:

избежать динамического создания новых элементов страницы и их скрытия/показа.

Скорее согласен, но как быть при отправке формы?..

mozers пишет:

Посетители этого форума ХР давно уже не пользуют...

Проверено на WinXP в IE8 (iexplore.exe), IE7 (mshta.exe, hh.exe):

<style>
.input-placeholder {color: silver;}
</style>

<hta:application navigable />


<form action="javascript:alert(&quot;Hello, world!&quot;);">
<input value="Home">
<input>
<input type="submit">
</form>


<script>
document.attachEvent('onreadystatechange', function () {
	if (document.readyState != 'complete') return;
	/*
		При обновлении страницы поля ввода уже восстановили значения
	*/
	AttachPlaceholder(document.forms[0].elements[0], "Domain");
	AttachPlaceholder(document.forms[0].elements[1], "User name");
});

function AttachPlaceholder(element, text) {
	var empty = Boolean();
	onleave();

	element.attachEvent('onfocus', function () {
		onenter();
		if (empty) element.select(); /*
			Иначе при переходе по Tab исчезает каретка до начала ввода
		*/
	});
	element.attachEvent('onblur', onleave);
	element.attachEvent('ondragenter', onenter);
	element.attachEvent('ondragleave', onleave);
	element.attachEvent('ondrop', function () {
		empty = false;
	});
	window.attachEvent('onbeforeunload', function () {
		onenter(); /* Для случая обновления страницы */
		window.setTimeout(onleave, 1); /*
			Для случая открытия JavaScript-URL
			(при timeout = 0 срабатывает преждевременно)
		*/
	});
	
	function onenter() {
		if (empty) {
			element.value = "";
			element.className = element.className
				.replace(/(?:^|\s+)input-placeholder(?!\S)/, "");
		}
	}

	function onleave() {
		if (empty = element.value == "") {
			element.className += " input-placeholder";
			element.value = text;
		}
	}
}
</script>

5

Re: JS: Placeholder

wisgest, полагаю что если placeholder внесли в спецификацию html, то значит он кому то нужен. Каждый выбирает для себя... Кстати, мой вариант достаточно просто переделать чтобы подсказка не исчезала, а перемещалась выше поля ввода.

wisgest пишет:

Подсказка исчезает не при получении фокуса, а только если что-нибудь ввести. Если так и задумано, то, соответствено, и наоборот появлятся должна при полной очистке поля даже без потери фокуса.

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

wisgest пишет:

перетаскиванием паролей из просмотрщика WinRAR.
Почему-то почти все разработчики забывают о таком способе ввода.

Насчет перетаскивания я не подумал. Вероятно если сделать исчезновение подсказки не при вводе первой буквы, а при получении фокуса, то срабатывать будет 100%.

wisgest пишет:

кружочки-звёздочки на порядок понятней всякой надписи

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

6

Re: JS: Placeholder

mozers пишет:

Кстати, в предложенном тобой варианте это тоже не выполняется.

Что именно не выполняется:
исчезновение подсказки при получении полем фокуса
или
появление подсказки при очистки поля имеющего фокус?

7 (изменено: mozers, 2016-02-02 15:34:26)

Re: JS: Placeholder

wisgest
У тебя не работает появление подсказки при очистке поля имеющего фокус. А исчезновение подсказки при получении полем фокуса это, имхо, не комильфо. (Во всяком случае оригинальный placeholder так не поступает).
Свой вариант поправил. Теперь подсказка появляется при очистке поля имеющего фокус. И перетаскивать на поле ввода данные можно как и прежде, только не обязательно "очень тщательно прицелиться в узкий зазор перед первой буквой". Можно перетаскивать в свободное пространство после подсказки.
Вот только подсказка при таком перетаскивании не исчезает и я не думаю что этого можно избежать, т.к. тут нет никакого события.

8 (изменено: wisgest, 2016-02-03 03:55:09)

Re: JS: Placeholder

Спасибо, значит у меня всё как задумано.

mozers пишет:

Во всяком случае оригинальный placeholder так не поступает.

Смотря где: в Firefox и Chromium - нет, а в Opera 12 - именно так.
(Да и, надо полагать, «оригинальный» placeholder возник в ответ на моду на самодельные.)
По крайней мере, можно принять любой вариант, если он реализован последовательно.

Известный и, похоже, неустранмый недостаток моего (т.е. через value) решения: очистили поле, ушли с него, вернулись — восстановить прежнее содержимое (Ctrl-Z, пункт контекстного меню «Отменить») нельзя.

У твоего текущего решения недостатков больше, но они, вероятно, все устранимые…

mozers пишет:

…не обязательно "очень тщательно прицелиться в узкий зазор перед первой буквой". Можно перетаскивать в свободное пространство после подсказки.

А хотелось бы в любую точку. С вызовом контекстного меню в пустом поле щелчком мыши — та же трудность.

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

mozers пишет:

…и я не думаю что этого можно избежать, т.к. тут нет никакого события.

ondrop, ondragleave, onmouseup, onfocus?

Можно попробовать:

  • поместить подсказку под <INPUT> с прозрачным фоном;

  • при наступлении события ondragenter в подсказке:

    • передавать фокус <INPUT>,

    • разрешить бросать прямо на подсказку…

9

Re: JS: Placeholder

wisgest пишет:

Можно попробовать:

  • поместить подсказку под <INPUT> с прозрачным фоном;

  • при наступлении события ondragenter в подсказке:

    • передавать фокус <INPUT>,

Попробовал, не очень то помогает.

10

Re: JS: Placeholder

Я говорил про то, пока мышь "держит в клюве" перетаскиваемый текст ни onfocus, ни onmouseover
, ни любое другое событие, с помощью которого можно было бы убрать подсказку, не срабатывает. Браузер в момент перетаскивания вообще х.з. чем занят. Даже подсветка у кнопок (при MSThemeCompatible) не работает. В HTA, во всяком случае, все именно так.

11

Re: JS: Placeholder

mozers, прошу прощение за вмешательство. А чем так "монструозен" вариант с jquery? Сам jquery весит немного в minify варианте, зато имеет шикарный набор кроссбраузерных функций, а плагинов эмулирующих placeholder довольно много. Можно выбрать с оптимальным кодом. Да и возможно на странице потребуется ещё какой-то функционал, тогда jquery опять же пригодится ? К тому же он (jquery) признан мировым сообществом как полезный инструмент и сейчас трудится чуть ли не на каждом сайте, да и просто в проектах, где есть веб страницы. Я его задействовал в нашей БС в формах ввода. Вся прелесть в минимуме управлящего кода и универсальности. Размер файлов в пару сотен кил, ПМСМ не сильно портит картину, двигло браузеров давно уже заточено под работу с объемными скриптами. Да и компьютеры уже позволяют выполнять такой код за доли секунды. Мы же ведь не переживаем, когда грузим ActiveX-ы: Scripting.FileSystemObject, shell.Application, adodb.stream только ради какой-нибудь одной функции: проверить существование файла, получить количество окон эксплорера, изменить кодировку текста, хотя эти объекты внутри с собой тянут гораздо больший функционал?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

12 (изменено: wisgest, 2016-02-05 20:50:45)

Re: JS: Placeholder

mozers пишет:

Вот только подсказка при таком перетаскивании не исчезает…

inp.ondrop = function () {
	var inp = this;
	setTimeout(function () {inp.onkeyup();}, 0);
};

Тот же обработчик можно назначить inp.oncontextmenu во избежание:

wisgest пишет:

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

-----

wisgest пишет:

Можно попробовать:

    • разрешить бросать прямо на подсказку…

Например, так:

plh.ondragover = function () {
	event.dataTransfer.dropEffect = event.ctrlKey ? 'copy' : 'move';
	return false;
};
plh.ondrop = function () {
	var inp = this.previousSibling;
	inp.value = event.dataTransfer.getData('text');
	inp.focus();
	inp.onkeyup();
	return this.ondragover();
}

Правда, непосредственно на левой и правой границах подсказки указатель всё-равно принимает запрещающий вид. Этого можно избежать, например, назначив обработчик не plh.ondragover, а одновременно container.ondragenter и container.ondragover, но тогда нужно колдовать, чтобы не переопределить или идентично переопределить поведение самого INPUT.

Кажется, получилось:


container.ondragenter = 
container.ondragover = function () {
	event.dataTransfer.dropEffect = event.ctrlKey ? 'copy' : 'move';
	return event.srcElement.tagName.toUpperCase() == "INPUT";
};
container.ondrop = function () {
	if (this.ondragover()) return;
	var inp = this.firstChild;
	inp.value = event.dataTransfer.getData('text');
	inp.focus();
	inp.onkeyup();
	return false;
}

----
Осталось только разобраться с

wisgest пишет:

С вызовом контекстного меню в пустом поле щелчком мыши — та же трудность.

====

Xameleon пишет:

Мы же ведь не переживаем, когда грузим ActiveX-ы: Scripting.FileSystemObject, shell.Application, adodb.stream только ради какой-нибудь одной функции…

В большинстве случаев без них просто не обойтись.

13

Re: JS: Placeholder

Добавил в код обработку перетаскивания (c) wisgest.
Убил обработку onblur, т.к. она стала ненужной.
Сейчас onkeyup рулит всем процессом, причем эвент остается свободным для пользовательских задач (для примера навесил на один инпутов подсчет кол-ва символов).
В общем, получилось достаточно симпатично и функционально (исправил код в первом сообщении).

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

14

Re: JS: Placeholder

Попробовал сохранить код в hta, но никаких подсказок не увидел.

15

Re: JS: Placeholder

Flasher
Подсказка отображается в самом InputBox при отсутствии текста в нем. От вводимого текста она отличается серым цветом. Цвет подсказки берется из стандартной виндусёвой палитры [HKEY_CURRENT_USER\Control Panel\Colors]. Вот этот тест должен выводится двумя разными цветами.

<font color="windowtext">WindowText</font> <font color="graytext">GrayText</font>

Если это не так, то необходима настройка палитры. Иначе неизбежны проблемы с отображением не только в HTA, но и во множестве других программ.

16

Re: JS: Placeholder

mozers
А, ясно, я про другую фичу подумал - временное отображение последнего символа при наборе до появления звёздочки.