MRAS Mobile Reactor advanced script

Представься, мразь! (с)

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name        MRAS Mobile Reactor advanced script
// @description Представься, мразь! (с)
// @author      Rus-Ivan
// @namespace   m.joyreactor.cc
// @version     1.3.1
// @include     *://m.joyreactor.cc/*
// @include     *://m.reactor.cc/*
// @require     https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM.xmlHttpRequest
// @grant       GM.getValue
// @grant       GM.setValue
// @grant       unsafeWindow
// @connect     m.joyreactor.cc
// @connect     joyreactor.cc
// @connect     reactor.cc
// @icon        http://joyreactor.cc/favicon.ico
// @run-at      document-end
// @license     MIT
// @copyright   2018, Rus-Ivan (https://github.com/Rus-Ivan)
// ==/UserScript==

/*
========================
 Для чего?
 Облегчает просмотр постов на m.joyreactor.cc
 Часто сижу на m.joyreactor.cc и приходится
 1. открывать пост, чтобы
	+ посмотреть гифку
	+ почитать комментарии
 2. открывать пост на основном хосте, чтобы
	+ добавить в избранное
	+ оценить комментарий
========================
 Что делает этот скрипт?
 1. при нажатии на кнопку/ссылку "Комментарии":
	+ открывает комментарии
	+ делает картинки/гифки/гиф-видео кликабельными (прим., чтобы загрузить гифки/гиф-видео, кликните на постер)
	+ показывает панель управления гиф-видео
 2. есть кнопка "Добавить в избранное"
 3. возможность оценивать комментарии
 ========================
 Дополнительные плюшки:
 1. убирает редиректы с ссылок
 2. сохраняет избранные посты в базе данных
 ========================
 P.S. Этот скрипт я писал чисто для личного пользования,
 если людям он покажется полезным, то могу добавить в него
 какие-нибудь дополнительные плюшки
*/
function consoleLog(){window['console']['log'].apply(this, arguments);}
consoleLog("====== start " + GM.info.script.name + " v" + GM.info.script.version + "\n" + GM.info.script.description);
var DEBUG = false;
var FAVKEY = 'favorite-key';
(async function(){
	'use strict';
	try{
	var uWindow = unsafeWindow;
	consoleLog("window: ", uWindow);
	var userFavorite = await GM.getValue( FAVKEY, "[]" );
	userFavorite = JSON.parse(userFavorite);
	var syncInProgress = false;
	startSync();
	removeRedirect();
	makeVotableComments();
	activateComments();
	activateFavorite();
	addNewStyle();
	consoleLog("======== end " + GM.info.script.name + " v" + GM.info.script.version);
	function startSync()
	{
		var html = '<div class="user-info-content" style="margin: 5px;">' +
		'<div id="user_id">user_id := ' + uWindow.user_id + '</div>' + 
		'<div id="token">token := ' + uWindow.token + '</div>' +
		'<div id="sync_fav">favorite sync</div></div>';
		makePopup({
			html: html,
			attr: {
				id: 'user-info',
				'class': 'popup-window',
			},
			'next': {
				html: '<div><span style="padding: 0 2px;"><<</span></div>',
				attr: {
					id: 'user-info-button',
					'class': 'popup-window',
				},
				'event': {
					type: 'click',
					handler: function(event){
						this.style.display = 'none';
					},
				},
				'next': {
					attr: {
						id: 'user-info',
					},
				},
			},
			'event': {
				type: 'click',
				handler: function(event){
					var t = event.target,
						that = this;
					that.style.zIndex = 15;
					setTimeout(function(){that.style.display = 'none';}, 200);
					if(t.id == 'sync_fav' )
						syncFavorite();
				},
			},
		});
		syncFavorite();
	}
	async function syncFavorite()
	{
		try{
		if( syncInProgress )
			return;
		var user_name = uWindow.user_name || getUserName();
		consoleLog("user_name: ", user_name);
		if( !user_name )
			return;
		var url = 'http://joyreactor.cc/user/' + user_name + '/favorite',
			el = $('#sync_fav');
		var lastPage = await GM.getValue('sync-favorite', -1);
		lastPage = parseInt(lastPage, 10);
		if( lastPage > 0 )
			url += '/' + lastPage;
		el.setAttribute('data-last-page', lastPage);
		el.setAttribute('title', url);
		el.setAttribute('data-user-favorite', url);
		el.setAttribute('data-user-name', user_name);
		el.innerHTML = 'favorite sync: ' + user_name + ' [' + lastPage + ']';
		uWindow.user_name = user_name;
		var syncComplete = await GM.getValue('sync-complete', false);
		el.addEventListener('click', function(event){
			if( event.ctrlKey )
				window.open(this.getAttribute('data-user-favorite'));
		}, false);
		if( syncComplete )
		{
			el.parentNode.click();
			return;
		}
		syncInProgress = true;
		GM.xmlHttpRequest({
			url: url,
			method: 'GET',
			Referer: 'http://joyreactor.cc',
			context: {'url': url, count: 1, maxCount: 20},
			onload: ajaxFavorite,
		});
		}catch(e){console.error(e);}
	}
	async function ajaxFavorite(xhr)
	{
		try{
		if( xhr.status != 200 )
		{
			console.error("Error: xhr.status = ", xhr.status, xhr.statusText);
			console.error("xhr: ", xhr);
			return;
		}
		var doc = document.implementation.createHTMLDocument(""),
			cntx = xhr.context, res;
		doc.documentElement.innerHTML = xhr.response;
		res = addPostsToFavorite(doc);
		saveFavoriteStorage();
		var page = getLocation(cntx.url, 'pathname').match(/\/[^\/]*$/)[0],
			next_url = null;
		page = /\d+/.test(page) ? parseInt(page.match(/\d+/)[0], 10) : -1;
		consoleLog("--------------");
		consoleLog("favorite page: ", page);
		consoleLog("iter: ", cntx.count, "/", cntx.maxCount);
		consoleLog("added: ", res);
		var sync_fav = $('#sync_fav'),
			usr_name = sync_fav.getAttribute('data-user-name');
		sync_fav.innerHTML = 'favorite sync: ' + usr_name + ' [' + page + ']';
		if( page > 0 )
			await GM.setValue('sync-favorite', page);
		next_url = $('.next', doc);
		if( (res == 0 && page == 1) || cntx.count >= cntx.maxCount || !next_url )
		{
			if( page == 1 && res == 0 )
			{
				sync_fav.click();
				GM.setValue('sync-complete', true);
			}
			syncInProgress = false;
			return;
		}
		next_url = 'http://joyreactor.cc' + next_url.pathname;
		setTimeout(function(){
			GM.xmlHttpRequest({
				url: next_url,
				method: 'GET',
				Referer: 'http://joyreactor.cc',
				context: {url: next_url, count: cntx.count + 1, maxCount: cntx.maxCount},
				onload: ajaxFavorite,
			});
		}, 2000 + getRandom(500, 1000) + getRandom(500, 900));
		}catch(e){console.error(e);}
	}
	function getRandom( min, max )
	{
		return Math.floor(Math.random() * (max - min) + min);
	}
	function addPostsToFavorite(doc)
	{
		doc = doc || document;
		var posts = $$('.postContainer', doc), count = 0;
		for( var i = 0, post_id; i < posts.length; ++i )
		{
			post_id = posts[i].id.slice(13);
			if( !isFavorite(post_id) )
			{
				++count;
				addToFavoriteStorage(post_id);
			}
		}
		return count;
	}
	function getUserName()
	{
		var spans = $$('span');
		for( var i = 0, len = spans.length, span; i < len; ++i )
		{
			span = spans[i];
			if( span.innerHTML.toString().indexOf('Привет') != -1 )
				return span.innerHTML.replace(/Привет\,/i, '').trim().replace(/\s/g, '+');
		}
		return null;
	}
	function removeRedirect( doc )
	{
		var links = $$('a', doc), link;
		consoleLog("links.length := ", links.length);
		for( var i = 0, len = links.length; i < len; ++i )
		{
			link = links[i];
			if( link['hostname'].indexOf('reactor') != -1 && link['pathname'].indexOf('redirect') != -1 )
				link.href = decodeURIComponent(link.search.slice(5));
		}
	}
	function makeVotableComments( doc )
	{
		var commentList = $$('.comment_rating'),
			voteHTML = '<div class="vote-plus" title="голосовать за"></div><div class="vote-minus" title="голосовать против"></div>';
		consoleLog("commentList.length := ", commentList.length);
		for( var i = 0, len = commentList.length, commentRating; i < len; ++i )
		{
			commentRating = commentList[i];
			if( !commentRating.querySelector('.vote-plus') )
				commentRating.innerHTML += voteHTML;
			if( !commentRating.classList.contains('comment-vote-active') )
			{
				commentRating.addEventListener('click', handleCommentVoteEvent, false);
				commentRating.classList.add('comment-vote-active');
			}
		}
	}
	function handleCommentVoteEvent(event)
	{
		var t = event.target, act;
		if( t.classList.contains('vote-plus') )
			act = 'plus';
		else if( t.classList.contains('vote-minus') )
			act = 'minus';
		if( !act )
			return;
		var commentId = t.parentNode.getAttribute('comment_id'),
			data = 'token=' + uWindow.token;
		GM.xmlHttpRequest({
			url: 'http://joyreactor.cc/comment_vote/add/' + commentId + '/' + act + '?' + data,
			method: 'GET',
			context: {'commentId': commentId, 'act': act},
			headers: {
				'X-Requested-With': 'XMLHttpRequest',
				'Referer': 'http://joyreactor.cc' + window.location.pathname,
			},
			onload: function(xhr){
				try{
				var cntx = xhr.context,
					regEx =	/\-?\d+(\.\d+)?/,
					commentR = $('[comment_id="' + cntx.commentId + '"]'),
					html = commentR.innerHTML,
					voteChangeAct = (cntx.act == 'plus' ? 'minus': 'plus');
				commentR.innerHTML = html.replace( regEx, xhr.responseText.match(regEx)[0] );
				if( !$('.vote-change', commentR) )
					$('.vote-' + voteChangeAct, commentR).classList.add('vote-change');
				if( DEBUG )
				{
					consoleLog("comment vote [" + act + "]");
					consoleLog("xhr.status: ", xhr.status, xhr.statusText);
					consoleLog("xhr.response: ", xhr.response);
				}
				}catch(e){console.error(e);}
			},
		});
	}
	function activateFavorite()
	{
		// начало создания кнопки "Добавить в избранное"
		var postList = $$('.postContainer');
		consoleLog("postList.length := ", postList.length);
		for( var i = 0, len = postList.length; i < len; ++i )
			makeFavorite( postList[i] );
	}
	function makeFavorite( postContainer )
	{
		var postId, postRating, fav;
		postRating = $('.post_rating', postContainer);
		if( !postRating )
			return;
		postId = postContainer.id.match(/\d+/)[0];
		fav = document.createElement('div');
		fav.setAttribute('class', 'favorite_link');
		fav.setAttribute('data-post-id', postId);
		fav.setAttribute('title', 'Добавить в избранное');
		postRating.parentNode.insertBefore( fav, postRating );
		fav.addEventListener('click', handleFavoriteEvent, false);
		//consoleLog("post_rating: ", postRating, postRating.innerHTML.toString().trim());
		if( isFavorite(postId) )
			fav.classList.add('favorite');
	}
	function handleFavoriteEvent(event)
	{
		var t = this,
			token = uWindow.token,
			data = 'token=' + token + '&rand=' + Math.floor(1e4*Math.random()),
			postId = t.getAttribute('data-post-id'),
			act = 'create', url;
		if( t.classList.contains('favorite') )
			act = 'delete';
		url = 'http://joyreactor.cc/favorite/' + act + '/' + postId + '?' + data;
		// отправка xml-http запроса на создание/удаление [из] избранного
		GM.xmlHttpRequest({
			url: url,
			method: 'GET',
			context: {'t': t, 'token': token, 'data': data, 'act': act, 'postId': postId, 'url': url},
			headers: {
				'X-Requested-With': 'XMLHttpRequest',
				'Referer': 'http://joyreactor.cc/post/' + postId,
			},
			onload: function(xhr){
				var cntx = xhr.context;
				if( cntx.t.classList.contains('favorite') )
				{
					cntx.t.classList.remove('favorite');
					cntx.t.setAttribute('title', 'Добавить в избранное');
					removeFromFavoriteStorage(cntx.postId);
				}else{
					cntx.t.classList.add('favorite');
					cntx.t.setAttribute('title', 'Удалить из избранного');
					addToFavoriteStorage(cntx.postId);
				}
				saveFavoriteStorage();
				if( DEBUG )
				{
					consoleLog("-------------");
					consoleLog("favorite[" + cntx.act + "] post-id: ", cntx.postId);
					consoleLog("xhr.status  : ", xhr.status, xhr.statusText);
					consoleLog("xhr.response: ", xhr.response);
					consoleLog("token: ", cntx.token);
					consoleLog("data : ", cntx.data);
					consoleLog("url  : ", cntx.url);
				}
			},
		});
	}
	function activateComments()
	{
		// начало создания кнопки "Комментарии"
		var links = $$('.article .comments > a');
		for( var i = 0, len = links.length; i < len; ++i )
			links[i].addEventListener('click', handleCommentListEvent, false);
	}
	function handleCommentListEvent(event)
	{
		try{
		// если зажать Ctrl, то ссылка откроется как обычно (в новом окне)
		if( event.ctrlKey )
			return;
		// простой click на ссылку
		event.preventDefault();
		var t = event.target, ufoot, commentList;
		if( t.tagName !== 'A' )
		{
			console.error("[handleCommentListEvent] invalid link: ", t);
			return;
		}
		ufoot = t.parentNode.parentNode;
		commentList = $('.comment_list_post', ufoot);
		if( commentList && t.classList.contains('comment-list-opened') )
		{
			// если комментарии были открыты - то скрыть их
			t.classList.remove('comment-list-opened');
			commentList.style.display = 'none';
			return;
		}
		else if( commentList )
		{
			// если комментарии были скрыты (см. выше), то показать их
			commentList.style.display = 'block';
			t.classList.add('comment-list-opened');
		}
		// загружает комментарии, делает картинки кликабельными
		openCommentList( t );
		}catch(e){console.error(e);}
	}
	function openCommentList( link )
	{
		if( !link || link.tagName !== 'A' )
		{
			console.error("[openCommentList] invalid link: ", link);
			return;
		}
		GM.xmlHttpRequest({
			url: link.href,
			method: 'GET',
			context: {
				'link': link, 
			},
			onload: setCommentList,
		});
	}
	function setCommentList( xhr )
	{
		try{
		if( xhr.status != 200 )
		{
			console.error("[setComments] xhr.status: ", xhr.status, xhr.statusText );
			return;
		}
		var doc = document.implementation.createHTMLDocument("");
		doc.documentElement.innerHTML = xhr.response;
		removeRedirect(doc);
		var xhrCommentList = $('.comment_list_post', doc),
			ufoot = xhr.context.link.parentNode.parentNode,
			commentList = $('.comment_list_post', ufoot);
		var xhrImageList = $$('.image', doc),
			imageList = $$('.image', ufoot.parentNode);
		// создает комментарии
		if( commentList )
			commentList.innerHTML = xhrCommentList.innerHTML;
		else
			ufoot.appendChild(xhrCommentList);
		makeVotableComments();
		xhr.context.link.classList.add('comment-list-opened');
		// создает кликабельную картинку в ленте на m.joyreactor.cc
		// если это гифка/гиф-видео, то для ее загрузки нужно кликнуть на постер
		for( var i = 0, xhrImg, img; i < imageList.length && i < xhrImageList.length; ++i )
		{
			xhrImg = xhrImageList[i];
			img = imageList[i];
			if( $('iframe', xhrImg) )
				continue;
			else if( $('.video_gif_holder', xhrImg) )
			{
				// код для гифок/видео-гифок
				$('a.attribute_preview', img).addEventListener('click',
					makeGifImageHandler(xhrImg, img), false);
			}else
				img.innerHTML = xhrImg.innerHTML;
		}
		}catch(err){console.error(err);}
	}
	function makeGifImageHandler( elm, img )
	{
		var video = $('video', elm);
		if( video )
			$('img', img).src = decodeURIComponent(video.getAttribute('poster'));
		function handler(event)
		{
			try{
			if( event.ctrlKey )
				return;
			event.preventDefault();
			if( video )
				video.setAttribute('controls', '');
			this.parentNode.innerHTML = elm.innerHTML;
			}catch(e){console.error(e);}
		}
		return handler;
	}
	async function saveFavoriteStorage()
	{
		GM.setValue( FAVKEY, JSON.stringify(userFavorite) );
	}
	function addToFavoriteStorage( postId )
	{
		if( userFavorite.indexOf(postId) == -1 )
			userFavorite.push(postId);
	}
	function removeFromFavoriteStorage( postId )
	{
		var idx = userFavorite.indexOf(postId);
		if( idx != -1 )
			userFavorite.splice(idx, 1);
	}
	function isFavorite( postId )
	{
		return userFavorite.indexOf(postId) != -1;
	}
	function addStyle( cssClass, id )
	{
		var style = document.createElement('style');
		style.type = 'text/css';
		style.innerHTML = cssClass;
		if( id !== undefined )
			style.setAttribute('id', id);
		var head = document.head || $('head');
		return head.appendChild(style);
	}
	function addNewStyle()
	{
		addGifStyle('video-gif-css');
		addFavoriteStyle('favorite-css');
		addCommentVoteStyle('comment-css');
		//addDarkStyle();
		//addDarkPopupStyle();
		addLightPopupStyle();
	}
	function addGifStyle( id )
	{
		addStyle(`
			.video_gif_source:hover {
				opacity: 1;
			}
			.video_gif_source[href*=".gif"] {
				display: none !important;
			}
			.video_gif_source {
				display: inline-block !important;
				opacity: 0.6;
				background: rgba(204, 204, 204, 0.6);
			}
		`, id );
	}
	function addFavoriteStyle( id )
	{
		var starN = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfiAR0CNzizynofAAACcklEQVRIx52V30tTcRTAP3e7UKKGb5L0IOZssoEKI3oouUoZaT+g/gFfeglECiJoazub+AOKehCCkGTiW2APgS8heEsRqaA9bDS8KobJ3oS08kHd7WG67Y7uzXnezq/POd9z7v1+wVGkSqqcI1RnN2+AbqcAxbH+eXRAk0/H7SDMGBDm+rE6kABzaiPsLXNJvthFuRzrj4c2QhuME7YPsgXE2uhSRwDUEbpibWUDsmEmQusAoXUmsuEyAbEWuhnOq8N0x1rKAmTDTMpafpxrTNr1ULJGqaKRJnzcwGtxDJGWKCmWWJZfxQ5FTro8WY/iMT148HCaHVYweCfxEnQvN/FwlgoyGBiKYRouI2soksTL0qFJNYI/FNN+aaYyeGavUK6JtCJdvFXuR8YoW6J3zRfcdusr2iJx7af+ubx0ucczbslMTmmXrWh/WdX7ZUvaAdwA+nftA6879vWFI6Y/NCNck/k8APT1zlnzVYeqzx0hPWg+cl2NLOY096F5dqNzxnypVer6f84epd91JZyfmLvgms1o7xnVTugfHdJD9HE58rVgsXzKkiBKj2MDPUQlUWwo/RcaSDkCUjRYDaUAn+IIUFL4nAF+ko4dJPE7AKSGOtURoCapkxr7DvxsBjNFwIBMy7QECpZghk1rDxaA4iscYKBZpphnlVXmZWqguXAIxWcLMA8AUi/x/QTbeKVP+vCyvZ+QuNTnAKY9AL+SHKyVUdJUu1ulN3epyZr0ulupJi2jg7VKyRitV5rP/LP7lAUulj4kT75xRwIM7a6gWxdZ9DI9r9j6zSKPRbffgmgMceFU5YOdf7oHznEEOZjFgfwFS4LW7qbwLDkAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDEtMjlUMDI6NTU6NTYrMDE6MDB5Men4AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTAxLTI5VDAyOjU1OjU2KzAxOjAwCGxRRAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=";
		var starF = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAulBMVEUAAAD//wD54Ab//wD54AX54Qb//wD54AX54Ab54AX44gf54AX44AP24wn54QX14AD74gT64AX54Qb54AT54AX54AX54AT54AX/5AD54AX/3wD53wX/2wD54AX/6gD43wX/5gD64AX/4wD54Qb/2wD54Ab63wX64AX64QX63wX54Ab/4wD54AX44AP53wX53wb63wX54AT64QX//wD44AX44AX44AT/3wD64AX53wT54QT/2AD54AUAAAAv4GzOAAAAPHRSTlMAA1oC1lYB01LPTsxKG8kZPWKHrNH1fPMTzhDKDsYMwgq9CbkHtDdjj7rmEtBL2lhp42UEletyCJSyfw1tcXAwAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+IBHBc1JtmiIwAAAAD/SURBVDjLfZLnFoIwDEbrQnGiguJgiFtQcK+8/3PJ8kgi7feryb3ntMkpYziFAhOnWBTzUrlcEgoVgIqIS1WAqiQQahCmJhDkSJD5vA5x6lyhkQgNHm9Cmmb+BK32V2i38CQdpdvrqxpkoqn9XlfpRHQgD4GboTxg+ggEGemMjSd8PhlHl0wNHjemySNNK59b5ncMe5bHZ/ZvUGf+z+dOdhWLJeXLBd6jTgWdLHpFhRUR1lRYE2FDhQ0RtlTYEmFHhR3mbtr29nsvPbpIUOLewQ8/iuQf4kJBQhB2jqdzUpxPx7AMkHCB6+3+K++3KzyQ8Hy98aPeryeqbfaXtPUB5yBig3vwmkMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDEtMjhUMjM6NTM6MzgrMDE6MDBw72fcAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTAxLTI4VDIzOjUzOjM4KzAxOjAwAbLfYAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=";
		addStyle(`
			.favorite_link {
				background: url(${starN});
				cursor: pointer;
				display: inline-block;
				width: 32px;
				height: 32px;
				vertical-align: middle;
				margin: 12px 16px 0 0;
				float: right;
			}
			.post_rating {
				margin-right: 16px;
			}
			.favorite_link:hover {
				background: url(${starF});
				transform: scale(1.4);
			}
			div.favorite {
				background: url(${starF});
			}
			div.favorite:hover {
				background: url(${starN});
				transform: scale(1.4);
			}
		`, id );
	}
	function addCommentVoteStyle( id )
	{
		addStyle(`
			span.comment_rating div.vote-plus {
				background-position: 0 -120px;
			}
			span.comment_rating div.vote-minus {
				background-position: -40px -120px;
			}
			.comment_rating div.vote-plus,
			.comment_rating div.vote-minus {
				width: 30px;
				height: 30px;
				line-height: 30px;
				margin: 0 0 0 3px;
				background: url(http://img0.joyreactor.cc/images/icon_smiles.png) no-repeat 0 -120px;
				cursor: pointer;
				display: inline-block;
				vertical-align: middle;
				/*transform: scale(0.75);*/
			}
			div.vote-change {
				opacity: 0.5;
			}
		`, id);
	}
	function addDarkStyle( id )
	{
		addStyle(`
		a ,
		div.uhead_nick a {
			color: #b1cbf7 !important;
		}
		a:hover ,
		div.uhead_nick a:hover {
			color: #d1ebf7 !important;
		}
		.post_content span {
			color: #d2d2d2 !important;*/
			/*background-color: #626f61 !important;*/
			/*color: #f6f7b9 !important;*/
		}
		.submenuitem a, .article .comments a {
			color: #FAF68C !important;
			/*text-shadow: 0 1px 1px #c04e03 !important;*/
		}
		.taglist a {
			color: #d2d2d2 !important;
		}
		.m_pagination a {
			color: #f8c010 !important;
		}
		.m_pagination a:hover {
			color: #F44336 !important;
		}
		`, id);
	}
	function addDarkPopupStyle( id )
	{
		addStyle(`
		.popup-window {
			position: fixed;
			top: 10px;
			right: 20px;
			background-color: #272727;
			color: #d0d0d0;
			text-align: center;
			z-index: 10;
			font-size: 14px;
			cursor: pointer;
			border-radius: 5px;
			border-color: #d0d0d0;
			border-style: solid;
			border-width: thin;
		}
		`, id);
	}
	function addLightPopupStyle( id )
	{
		addStyle(`
		.popup-window {
			position: fixed;
			top: 10px;
			right: 20px;
			background-color: #d78917;
			color: #faf68c;
			text-shadow: 0 1px 1px #c04e03;
			text-align: center;
			font-size: 14px;
			z-index: 10;
			/*cursor: pointer;*/
			border-radius: 5px;
			border-color: #c04e03;
			border-style: solid;
			border-width: thin;
		}
		.user-info-content {
			margin: 5px;
		}
		#sync_fav ,
		#user-info-button {
			cursor: pointer;
		}
		#sync_fav:hover {
			color: #ffffd6;
		}
		`, id);
	}
	function $( str, doc )
	{
		doc = doc || document;
		return doc.querySelector(str);
	}
	function $$( str, doc )
	{
		doc = doc || document;
		return doc.querySelectorAll(str);
	}
	function makePopup( prop )
	{
		if( !prop )
			return null;
		var wnd = $('#' + prop.attr.id);
		if( wnd )
		{
			wnd.style.display = 'block';
			return wnd;
		}
		wnd = document.createElement('div');
		for( var key in prop.attr )
			wnd.setAttribute( key, prop.attr[key] );
		wnd.innerHTML = prop.html || '';
		$('body').appendChild(wnd);
		var f = prop.event,
			n = prop.next,
			callback = function(event){
				f.handler.call(this, event);
				makePopup(n);
			};
		if( f )
			wnd.addEventListener(f.type, callback, false);
		return wnd;
	}
	function hide( str, doc )
	{
		var el = $(str, doc);
		if( el )
			el.style.display = 'none';
	}
	function show( str, doc )
	{
		var el = $(str, doc);
		if( el )
			el.style.display = 'block';
	}
	function getLocation( href, prop )
	{
		if( !href )
			return null;
		var a = document.createElement('a');
		a.href = href;
		return a[prop];
	}
	}catch(e){console.error(e);}
})();