Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   LiveTimer - Живой таймер обновлялка времени "Обновлено: около минуты назад". (https://javascript.ru/forum/misc/22312-livetimer-zhivojj-tajjmer-obnovlyalka-vremeni-obnovleno-okolo-minuty-nazad.html)

fiw 14.10.2011 17:25

LiveTimer - Живой таймер обновлялка времени "Обновлено: около минуты назад".
 
Есть необходимость на сайт поставить скрипт который бы автоматом обновлял время добавления комментариев и тп. Как в любимых соц сетях.
Например: Добавлено: около минуты назад, потом по прошествии минуты само обновляется на добавлено 2 мин. назад.

Я взял готовый код из фейсбука ниже он

var LiveTimer = {
	restart: function (a) {
		this.serverTime = a;
		this.localStartTime = new Date().getTime() / 1000;
		this.updateTimeStamps();
	},
	updateTimeStamps: function () {
		LiveTimer.timestamps = DOM.scry(document.body, 'abbr.livetimestamp');
		LiveTimer.startLoop(20000);
	},
	addTimeStamps: function (a) {
		if (!a || !LiveTimer.timestamps) return;
		var c = DOM.scry(a, 'abbr.livetimestamp');
		for (var b = 0; b < c.length; ++b) LiveTimer.timestamps.push(c[b]);
		LiveTimer.startLoop(0);
	},
	startLoop: function (a) {
		this.stop();
		this.timeout = setTimeout(function () {
			LiveTimer.loop();
		}, a);
	},
	stop: function () {
		clearTimeout(this.timeout);
	},
	updateNode: function (a, b) {
		LiveTimer.updateNode = (ua.ie() < 7) ?
		function (c, d) {
			c.nextSibling.nodeValue = d;
		} : function (c, d) {
			c.firstChild.nodeValue = d;
		};
		LiveTimer.updateNode(a, b);
	},
	loop: function (d) {
		if (d) LiveTimer.updateTimeStamps();
		var c = Math.floor(new Date().getTime() / 1000 - LiveTimer.localStartTime);
		var a = -1;
		LiveTimer.timestamps && LiveTimer.timestamps.each(function (g) {
			var f = +new Date(g.getAttribute('data-date')) / 1000;
			var e = LiveTimer.renderRelativeTime(LiveTimer.serverTime + c, f);
			if (e.text) LiveTimer.updateNode(g, e.text);
			if (e.next != -1 && (e.next < a || a == -1)) a = e.next;
		});
		if (a != -1) {
			var b = Math.max(20000, a * 1000);
			LiveTimer.timeout = setTimeout(function () {
				LiveTimer.loop();
			}, b);
		}
	},
	renderRelativeTime: function (c, d) {
		var e = {
			text: "",
			next: -1
		};
		if (c - d > (12 * 3600) || (new Date(c * 1000).getDay() != new Date(d * 1000).getDay())) return e;
		var f = c - d,
			b = Math.floor(f / 60),
			a = Math.floor(b / 60);
		if (b < 1) {
			e.text = _tx("\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u043a\u0443\u043d\u0434 \u043d\u0430\u0437\u0430\u0434");
			e.next = 60 - f % 60;
			return e;
		}
		if (a < 1) {
			if (b == 1) {
				e.text = _tx("\u043e\u043a\u043e\u043b\u043e \u043c\u0438\u043d\u0443\u0442\u044b \u043d\u0430\u0437\u0430\u0434");
			} else e.text = _tx("{number} \u043c\u0438\u043d. \u043d\u0430\u0437\u0430\u0434", {
				number: b
			});
			e.next = 60 - f % 60;
			return e;
		}
		if (a != 11) e.next = 3600 - f % 3600;
		if (a == 1) {
			e.text = _tx("\u043e\u043a\u043e\u043b\u043e \u0447\u0430\u0441\u0430 \u043d\u0430\u0437\u0430\u0434");
			return e;
		}
		e.text = _tx("{number} \u0447. \u043d\u0430\u0437\u0430\u0434", {
			number: a
		});
		return e;
	}
};


К счастью механизм работы тут понятен.
Я поправил код, и получилось следующее
var LiveTimer: {
	startLoop: function(elem, time,start_update){
		this.timestamp = time;
		this.timeout = setTimeout(function(){
		LiveTimer.loop(elem);
		}, start_update);
	},
	loop: function(elem){
		var result = LiveTimer.renderTime(this.timestamp);
		if(result.text){
			DOM.extensions(elem,{innerHTML: result.text}); // тут я обнавляю результат на новую дату
		};
		var next_update = result.next;
		if(next_update != 0){
			next_update = Math.max(5000, next_update * 1000);
			this.timeout = setTimeout(function(){
			LiveTimer.loop(elem);
			}, next_update);
		};
	},
	renderTime: function(time){
		var now, passedTime, minutes, hours, days, item = {};
		this.servertime = new Number(ge('timestamp').innerHTML);
		passedTime = this.servertime - time;
		minutes = Math.floor(passedTime / 60);
		hours = Math.floor(minutes / 60);
		days = Math.floor(hours / 24);
			
		if(passedTime <= 10){
			item.text = 'Только что';
			item.next = 5; // следующее обновление таймера через 5 секунд
			return item;
		}else if(passedTime < 60){
			item.text = 'несколько секунд назад';
			item.next = 60;
			return item;
		}else if(minutes < 60){
			if (minutes < 2){
				item.text = 'около минуты назад';
			}else{
				item.text = minutes + ' мин. назад';
			};
			item.next = 60;
			return item;
		}else if(hours < 24){
			if (hours < 2){
				item.text = 'около часа назад';
			}else{
				item.text = hours+ ' ч. назад';
			};
			item.next = 3600;
			return item;
		}else if(days < 2){
			item.text = "вчера";
			item.next = 0;
			return item;
		}else{
			item.text = DTF(time); // Приводим время к обычному вормату типа: "12 января 2011 г. в 17:06"
			item.next = 0;
			return item;
		};
	}
}


Но мой код имеет один недостаток, он способен работать, следить и обновлять только один элемент с датой.
Если появляется второй, и запускает скрипт, то он как то влияет на первый более ранний элемент.

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

fiw 17.10.2011 10:57

Ну что никто не может помочь?

dmitriymar 17.10.2011 11:21

Цитата:

Сообщение от fiw
наверняка такая штука будет полезна многим читателям форума.

чем?
чтоб обновлять во всех ,нужно по всем им проходить. для этого им нужно дать идентификатор- имя или класс.

cyanidesign 18.10.2011 01:36

Оформите ваш код в функцию-конструктор, и на каждый элемнет даты создавайте по экземпляру класса. Как это сделать можно найти здесь же, в статьях: http://javascript.ru/tutorial/object

fiw 18.10.2011 16:49

Цитата:

Сообщение от cyanidesign (Сообщение 131654)
Как это сделать можно найти здесь же, в статьях: http://javascript.ru/tutorial/object

Спасибо, я уже читал это, однако не доконца понял как это сделать, Хотелось бы увидеть пример по данному решению. Именно с датой.
Можно и упростить код, для наглядности...

fiw 20.10.2011 03:11

Дописал автоматический сбор всех таймштампов, которые надо будет обновлять.

var elemAbbr = geByClass('timestamp', document,'abrr');
for (var i = 0; i < elemAbbr.length; ++i){
	this.timestamps.push(elemAbbr[i].getAttribute('data-date'));
};

К сожалению, до сих пор не понял как всетаки идет назначение отдельных таймеров....
Без использования функции конструктора.

fiw 24.10.2011 05:09

Долго долго думал... и все таки огромное спасибо соц сети Вконтакте, за их красивый код.
Посмотрев внимательнее как это работает у них, сделал по аналогии, и все работает даже без каких либо функций конструкторов.
Ниже готовый рабочий кусок кода Loop.
Функция each довольно простая, думаю её сможете сами написать кому надо будет.
Её задача перебрать массив элементов, и к каждому вызвать колбэк.
loop: function(){
	var serverTime = id(timestamp).innerHTML;
	var next_update = -1;			
	each(geByClass('timestamp', document,'abrr'),
	function(k, elem) {
		if (!elem) return;
		var timestamp = intval(elem.getAttribute('data-date'));
		var result = LiveTimer.renderTime(serverTime, timestamp);
		if(result.text){
			DOM.extensions(elem,{innerHTML: result.text});
		};
		next_update = result.next;
		if(next_update != -1){
			next_update = Math.max(5000, next_update * 1000);
			this.timeout = setTimeout(function(){
				LiveTimer.loop(elem);
			}, next_update);
		};
	});
},

Riim 24.10.2011 17:43

Цитата:

Сообщение от fiw
item.text = 'около минуты назад';
}else{
item.text = minutes + ' мин. назад';

может тебе пригодится: link.

fiw 25.10.2011 01:56

Да спасибо )


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