Javascript.RU

Скрипт для показа уведомлений в углу экрана

Возникла идея, написать скрипт, показывающий разные ненавязчивые уведомления в углу экрана, а не как alert, который, на мой взгляд, только для отладки и годен. И я подумал, что аргументом этой функции должно быть не только само сообщение, но и какой нибудь идентификатор, задающий уведомлению "настроение". Но ближе к делу, вот что получилось.
alerter.js

function alerter(code, content){
	var thisElem = undefined;
	var lim = 4;
	var class = {
		0:"code_0",
		1:"code_1",
		2:"code_2",
		num: function(val){return this[val] || "other_code";}
	};
	
	function getTop(elem){
		var top=0;
		var i=0;
		while(elem.parentNode.childNodes[i]!=elem) {
			var child = elem.parentNode.childNodes[i];
			var cS = window.getComputedStyle(child,null) || child.currentStyle;
			top+=(	parseInt(cS.marginTop,10)+
					parseInt(cS.borderTopWidth,10)+
					parseInt(cS.paddingTop,10)+
					parseInt(cS.height,10)+
					parseInt(cS.paddingBottom,10)+
					parseInt(cS.borderBottomWidth,10)+
					parseInt(cS.marginBottom,10));
			i++;
		}
		return top;
	}
	
	function getWid(elem){
		var cS = window.getComputedStyle(elem,null) || elem.currentStyle;
		return parseInt(cS.width,10);
	}
	
	function giveChildsStatic(parent){
		for(var i=0;i<parent.childNodes.length;i++)
			parent.childNodes[i].style.position ="static";
	}
	
	function giveChildsTop(parent, from){
		for(var i=from;i<parent.childNodes.length;i++){
			var child = parent.childNodes[i];
			child.style.position = "absolute";
			child.style.top = getTop(child)+"px";
			child.style.width = child.wid+"px";
		}
	}
	
	function getNumber(elem){
		var n=0;	while(elem.parentNode.childNodes[n]!=elem) n++;
		return n;
	}
	
	var message = document.createElement("div");
		message.className = class.num(code);
		message.style.position = "static";
		message.innerHTML = content;
		
		message.onmouseover = function(){			
			giveChildsTop(this.parentNode, getNumber(this));
			thisElem = this;
		}
		
		message.onmouseout = function(){
			giveChildsStatic(this.parentNode);
			thisElem = undefined;	
		}
		
		message.onclick = function(){
			giveChildsStatic(this.parentNode);
			thisElem = undefined;
			this.parentNode.removeChild(this);
		}
	
	if (!document.getElementById("mesBlock")){
		var mesBlock = document.createElement("div");
			mesBlock.id = "mesBlock";
			mesBlock.style.position = "fixed";
			mesBlock.style.border = "none";
			mesBlock.style.padding = "0px";
	} else var mesBlock = document.getElementById("mesBlock");
	
	if(mesBlock.childNodes[lim-1]) mesBlock.removeChild(mesBlock.lastChild);
	
	mesBlock.childNodes[0] ? mesBlock.insertBefore(message, mesBlock.childNodes[0]) : mesBlock.appendChild(message);

	
	if(!document.getElementById("mesBlock"))document.body.appendChild(mesBlock);////
	
	message.wid = getWid(message);
	
	function delta(t, p){return t>=0&t<=1?(p>=0?1-Math.pow(t,p+1):1-Math.pow(t,1/(-p+t))):t<0?1:0;}
	
	var duration = 3000;				
	var start = new Date().getTime();		
	setTimeout(function(){
		if(thisElem) start = new Date().getTime();
		var now = (new Date().getTime()) - start;	
		var progress = now / duration;				
		message.style.opacity = delta(progress, 2); 
		if(progress<1) setTimeout(arguments.callee, 10);	
			else {											
				mesBlock.removeChild(message);				
				if(!mesBlock.childNodes[0]) mesBlock.parentNode.removeChild(mesBlock);
			}
	},10);		
}

Я решил, что лучше стайлинг разных типов сообщений делать не непосредственно в js коде, а в CSS, так легко можно дополнить список разных типов сообщений. Тут, конечно, все от фантазии зависит.
alerter.css

#mesBlock{width:200px; top:0px;}

	.code_0, .code_1, .code_2, .other_code{
		cursor:pointer;
		padding:10px;
		margin-top:5px;
		font-family:calibri;
		border-radius:5px;
		-moz-border-radius:5px;
	}

	.code_0{background-color:#fed; border:1px solid #fc9; }
	.code_0:before{content:"Ошибка!\A "; color:red; white-space:pre;}

	.code_1{background-color:#def;  border:1px solid #9cf;}
	.code_1:before{content:"Оповещение\A "; color:blue; white-space:pre;}

	.code_2{background-color:#dfe;  border:1px solid #9fc;}
	.code_2:before{content:"Поздравляем!\A "; color:green; white-space:pre;}

	.other_code{background-color:#eee;  border:1px solid #bbb;}
	.other_code:before{content:"Без категории\A "; color:gray; white-space:pre;}

Ну и "быстрая страничка" для демонстрации

alerter.html

<!DOCTYPE html>
	
<title>alerter</title>
<meta charset="utf-8">
<link rel="stylesheet" href="alerter.css"><!--Почему "автоматом" добавилось /forum/ в начале?-->
	
<div style="height:5000px;"><div id="monitor" style="text-align:center;"></div>
	
<div style="position:fixed; right:0px; top:0px;">
			
	<input type="button" onclick="alerter(0, 'Оповещение об ошибке, например: &quot;Неправильная пара логин/пароль!&quot;. Оформление см. CSS');" value="code=0"><br>
				
	<input type="button" onclick="alerter(1, 'Обычное оповещение. Например, Пользователь #123 вошел в сеть. Оформление см. CSS');" value="code=1"><br>
				
	<input type="button" onclick="alerter(2, 'Радостное оповещение! Например: Спасибо, что пожертвовали нашему проекту 500WMZ! :DDD. Оформление см. CSS');" value="code=2"><br>
				
	<input type="button" onclick="alerter(3, 'Например, просто, какое-нибудь сообщение. Оформление см. CSS');" value="code=3"><br>
		
</div>	

<script src="alerter.js" ></script><!--Почему "автоматом" добавилось /forum/ в начале?-->

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

В IE не знаю как сделать, потому что, например,

<div id="test" style="margin:10px; top:10px; padding:10px;border:20px solid red;" onclick="alert(s.height);">		
	Lorem ipsum<br />dolor sit<br />amet blah blah
</div>
<script>
	var obj=document.getElementById("test");
		
	var s=obj.currentStyle || window.getComputedStyle(obj,null); 
</script>

нормальные браузеры вычислят высоту в пикселах, а IE говорит auto, если она не была задана в стилях.

0

Автор: chipp (не зарегистрирован), дата: 6 декабря, 2010 - 08:10
#permalink

Все так хорошо начиналось


Автор: poorking, дата: 6 декабря, 2010 - 17:13
#permalink

Да я пробовал доделать, кое-что уже переделал, да что то пока не получалось и я отложил. Во первых появилась функция getAbsTop(elem) которая измеряет положение выбранного сообщение от верхнего края родителя до сообщения. При создании сообщения к нему прикручивается свойство, в котором хранится это значение на момент создания. В том месте анимации, где проверяется не выбрано ли сообщение, при сбрасывании начала анимации вызывается функция позиционирования, которая постоянно позиционирует выбранный блок. В данном случае, все блоки имеют position static по умалчанию. поэтому единственный способ задать положение блока - задать ему marginTop, и это не проблема, в функции позиционирования мы задаем marginTop = высота элемента на момент создания - настоящая высота элемента, она меняется так как сообщения, которые были над выбранным, могут уже раствориться. Но дело в том, что получается так, сначала сообщение перед выбранным удаляется, и выбранное сообщение перескавивает вверх, когда сообщение выпрыгивает из под курсора, оно становится не выбранным, и только затем функция задает ему маргинТоп, сообщение обратно подпрыгивает и становится выбранным, так как залетает под курсор и получается мерзкое дерганье.. вобщем думаю надо все переделать так, чтобы все сообщения позиционировались абсолютно, относительно родительского блока, а не относительно друг друга, маргином. Думал еще как нибудь действовать относительно координат мыши, да че-то пока нет идей. Вообще я был бы рад услышать подсказку от опытных людей, а пока получаю только "минусы", а это новичка не очень то стимулирует =(


Автор: poorking, дата: 6 декабря, 2010 - 13:28
#permalink

Вроде придумал. Каждый раз при создании нового сообщения, абсолютно позиционировать все сообщения, top каждого следующего сообщения будет равен высоте всех предыдущих сообщений, учитывая все маргины, паддинги, бордеры. При ручном удалении сообщения кликом, снова позиционировать. При автоудалении сообщения позиционировать только если не выбрано ни одно сообщение. Приду домой, доделаю...


Автор: poorking, дата: 6 декабря, 2010 - 17:12
#permalink

Все оказалось даже проще, никакого постоянного позиционирования во время анимации, не понимаю вообще почему сразу не догадался. Просто при наведении мышки все сообщения позиционируются absolute и им задается top несложными вычислениями. Когда мышку убираем, обратно position - static. обновлю главный пост


Автор: Гость (не зарегистрирован), дата: 13 января, 2011 - 02:57
#permalink

Чем вам не угодил position: fixed для позиционирования + количество блоков * высоту блоков для смещения от верха? Это избавит вас от лишних телодвижений с поиском смещения.
Добавили диалог, некая переменная += innerHeight в итоге некая переменная будет иметь координаты нижней точки последнего диалога.


Автор: poorking, дата: 23 января, 2011 - 17:21
#permalink

Чем вам не угодил position: fixed для позиционирования + количество блоков * высоту блоков для смещения от верха? Это избавит вас от лишних телодвижений с поиском смещения

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


Автор: Jason Bourne, дата: 19 января, 2011 - 12:05
#permalink

Могу еще такой способ прижимания сообщение к самому краю вместо блока большой высоты.

mesBlock.style.bottom = 0 + "px";
mesBlock.style.left = 0 + "px";

Автор: poorking, дата: 23 января, 2011 - 17:23
#permalink

высоту 5000 я сделал просто чтобы скроллинг появился, а mesBlock в коде вообще не позиционируется, можно в любое место его поставить в стилях


Автор: Ewicon (не зарегистрирован), дата: 25 июля, 2017 - 17:06
#permalink

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


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
13 + 5 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Другие записи этого автора
poorking
Реклама
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Популярные таги
Последние комментарии
Последние темы на форуме
Forum