Greasy Fork

Greasy Fork is available in English.

Weibo Huati Check-in

超级话题集中签到

当前为 2017-10-26 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name		Weibo Huati Check-in
// @description	超级话题集中签到
// @namespace	http://greasyfork.icu/users/10290
// @version		0.2.2017102618
// @author		xyau
// @match		http*://*.weibo.com/*
// @match		http*://weibo.com/*
// @icon		https://n.sinaimg.cn/photo/5b5e52aa/20160628/supertopic_top_area_big_icon_default.png
// @grant		GM_getValue
// @grant		GM_setValue
// @grant		GM_deleteValue
// @grant		GM_xmlhttpRequest
// @connect		m.weibo.cn
// @connect		login.sina.com.cn
// @connect		passport.weibo.cn
// @connect		weibo.com
// ==/UserScript==

if (+$CONFIG.islogin)
(() => {
/**
 * see config
 * @const	{object}	DEFAULT_CONFIG	默认设置
 */
const DEFAULT_CONFIG = Object.freeze({
	autoCheckin: true,
	checkNormal: true,
	openDetail: true,
	maxHeight: 360,
	timeout: 5000,
	retry: 5,
	delay: 0,
}),

	/**
	 * @const	{object}	USER			当前用户
	 * @const	{string}	USER.UID		用户ID
	 * @const	{string}	USER.NICK	用户昵称
	 */
	USER = Object.freeze({
		UID: $CONFIG.uid,
		NICK: $CONFIG.nick,
	});

/**
 * @global	{object}	config				脚本设置
 * @global	{boolean}	config.autoCheckin	自动签到
 * @global	{boolean}	config.checkNormal	普话签到
 * @global	{boolean}	config.openDetail	展开详情
 * @global	{int}		config.maxHeight	详情限高(px)
 * @global	{int}		config.timeout		操作超时(ms)
 * @global	{int}		config.retry		重试次数
 * @global	{int}		config.delay		操作延时(ms)
 */
let config = Object.assign(Object.assign({},DEFAULT_CONFIG), JSON.parse(GM_getValue(`config${USER.UID}`, '{}'))),

	/** @global	{object}	lastCheckin	上次签到记录 */
	lastCheckin = JSON.parse(GM_getValue(`lastCheckin${USER.UID}`, '{}'));

/** 清理旧版数据 */
['autoSignbox', 'todaySigned'].forEach((key) => GM_deleteValue(key));

/**  隐藏游戏按钮,替换为超话签到 */
var logname,
	checkinBtn = document.createElement("li");
checkinBtn.id = 'checkinBtn';
checkinBtn.innerHTML = `<a href="javascript: void(0);"><em class="W_ficon ficon_checkin S_ficon">s</em><em class="S_txt1 signBtn">超话签到</em></a>`;
checkinBtn.addEventListener('contextmenu', () => setupConfig(), true);
checkinBtn.addEventListener('click', () => huatiCheckin(false),	true);

function initCheckinBtn() {
	checkinBtn.style['pointer-events'] = 'auto';
	Array.from(checkinBtn.querySelectorAll('em')).forEach((em) => {em.removeAttribute('style');});
	checkinBtn.querySelector('.signBtn').innerText = '超话签到';
	checkinBtn.title = '左击开始签到/右击配置脚本';
	console.groupEnd(logname);
}

function alterCheckinBtn(text) {
	checkinBtn.style['pointer-events'] = 'none';
	Array.from(checkinBtn.querySelectorAll('em')).forEach((em) => {em.style.color = '#fa7d3c';});
	checkinBtn.querySelector('.signBtn').innerText = `${text}中…`;
}

let addBtn = setInterval(() => {
	if (document.querySelector('.gn_nav_list li:last-child')) {
		clearInterval(addBtn);
		document.querySelector('.gn_nav_list li:last-child').before(checkinBtn);
		document.querySelector('a[nm="game"]').parentNode.style.display = 'none';
	}

	/** 自动签到 */
	if (config.autoCheckin)
		huatiCheckin();
}, 100);

/** @param	{boolean}	auto	自动开始*/
function huatiCheckin(auto=true) {
	console.group(logname='微博超话签到');
	/**
	 * 任务构造,初始化通用 xhr 参数
	 * @constructor
	 * @param	{string}	name			任务名称
	 * @param	{object}	options			附加 xhr 参数
	 * @param	{function}	load			成功加载函数
	 * @param	{function}	retry			重试函数
	 * @param	{function}	[retryButton=]	重试按钮函数
	 */
	var	Task = window.Task || function (name, options, load, retry, retryButton) {
		this.name = name;
		this.onerror = function(errorType='timeout') {
			initLog(name, 0);
			log[name] += 1;

			if (errorType != 'timeout')
				console.error(`${name}异常,最终网址为${this.xhr.finalUrl},返回值为${this.xhr.response}`);

			if (log[name] < config.retry + 1) {
				setStatus(name + (errorType === 'timeout' ? `超过${config.timeout / 1e3}秒` : '异常') + `,第${log[name]}次重试…`);
				retry();
			} else {
				setStatus(`${name}超时/异常${log[name]}次,停止自动重试`);

				if (retryButton)
					retryButton();
				else
					clearTask();
			}
		};
		this.xhrConfig = {
			synchoronous: false,
			timeout: config.timeout,
			onloadstart: () => {
				currentTask = this;

				if (!log.hasOwnProperty(name))
					setStatus(`${name}…`);
				if (retryButton) {
					/** 跳过按钮 */
					let skipHuati = document.createElement('a');
					skipHuati.classList.add('S_ficon');
					skipHuati.style = 'cusor: pointer';
					skipHuati.onclick = () => {
						this.xhr.abort();
						retryButton();
						skipHuati.remove();
					};
					skipHuati.innerText = '[跳过]';
					checkinStatus.appendChild(skipHuati);
				}
			},
			onload: (xhr) => {
				if (xhr.finalUrl.includes('login')) {
					xhr.timeout = 0;
					/** 登录跳转 */
					let loginJump = GM_xmlhttpRequest({
						method: 'GET',
						synchronous: false,
						timeout: config.timeout,
						url: /url=&#39;([^']+)&#39;/.exec(xhr.responseText)[1],
						onloadstart: () => this.xhr = loginJump,
						onload: (xhr) => this.load(xhr),
						ontimeout: xhr.ontimeout,
					});
				}
				else
					this.load(xhr);
			},
			ontimeout: () => this.onerror(),
		};

		Object.assign(this.xhrConfig, options);

		this.load = (xhr) => setTimeout(load(xhr), config.delay);
		this.xhr = GM_xmlhttpRequest(this.xhrConfig);
	};

	/**
	 * 获取话题列表
	 * @param	{object[]}	[huatiList=[]]		话题列表
	 * @param	{string}	huatiList[].name	名称
	 * @param	{string}	huatiList[].hash	编号
	 * @param	{int|null}	huatiList[].level	超话等级
	 * @param	{boolean}	huatiList[].checked	超话已签
	 * @param	{string}	[type='super']		超话或普话, 'super'/'normal'
	 * @param   {int}		[total=0]			关注话题数量
	 * @param	{int}		[page=1]			列表页码
	 */
	function getHuatiList(huatiList=[], type='super', total=0, page=1) {

		let getPage = new Task(
			`获取${type === 'super' ? '超' : '普'}话列表第${page}页`,
			{
				method: 'GET',
				url: `https://m.weibo.cn/api/container/getIndex?containerid=100803_-_page_my_follow_${type}&page=${page}`,
			},
			(xhr) => parsePage(xhr),
			() => getHuatiList(huatiList, type, total, page)
		);

		function parsePage(xhr) {
			let data = JSON.parse(xhr.responseText);

			if (!data.cardlistInfo) {
				getPage.onerror('error');
			} else {
				if (page === 1)
					total += data.cardlistInfo.total;

				data.cards[0].card_group.forEach(function(card) {
					if (card.card_type === 4) {
						let name = card.desc.slice(1, -1),
							level = type === 'super' ?
							+/level(\d+)\./.exec(card.icon)[1] : null,
							checked = !!card.avatar_url,
							hash = null,
							element = null;

						if (lastHuatiList && lastHuatiList.includes(name)) {
							if (lastCheckinDate != date) {
								let huati = log['待签'].find((huati) => name === huati.name);
								if (checked)
									huati = log['待签'].splice(log['待签'].findIndex((huati) => name === huati.name), 1).pop();
								hash = huati.hash;
								element = huati.element;
							} else {
								hash = log['已签'][name];
								element = document.getElementById(`${hash}`);
							}
						} else {
							hash = /100808([\w\d]+)&/.exec(card.scheme)[1];
							element = initElement(name, hash);
						}
						huatiList.push({name, checked, hash, level});

						if (checked) {
							if (!lastHuatiList || (lastHuatiList.includes(name) ? lastCheckinDate != date : true)) {
								checkinDone.appendChild(element);
								initLog('已签', {});
								log['已签'][name] = hash;
							}
						} else if (!lastHuatiList || (lastHuatiList.includes(name) ? lastCheckinDate === date && type === "super" : true)){
							checkinToDo.appendChild(element);
							initLog('待签', []);
							log['待签'].push({name, hash, element});
						}
						if (level)
							setStatus(`Lv.${level}`, element, true);
					}
				});

				if (huatiList.length < total)
					getHuatiList(huatiList, type, total, page + 1);
				else if (config.checkNormal && type != 'normal')
					getHuatiList(huatiList, 'normal', total);
				else {
					setStatus(`关注列表获取完毕,共${total}个${config.checkNormal ? '话题' : '超话'},` + (log.hasOwnProperty('待签') ? `${log['待签'].length}个待签` : '全部已签'));
					console.table(huatiList);
					console.info(log);

					if (log.hasOwnProperty('待签')) {
						if (config.autoCheckin)
							checkin(log['待签'].shift());
						else {
							clearTask();
							/** 开始签到按钮 */
							let startCheckin = document.createElement('a');
							startCheckin.classList.add('S_ficon');
							startCheckin.style = 'cusor: pointer';
							startCheckin.onclick = () => checkin(log['待签'].shift());
							startCheckin.innerText = '[开始签到]';
							checkinStatus.appendChild(startCheckin);
						}
					} else {
						clearTask();
						initCheckinBtn();
					}
				}
			}
		}
	}

	/**
	 * 话题签到
	 * @param	{object}	huati		话题,参见 {@link getHuatiList#huatiList}
	 * @param	{boolean}	checkinAll	签到全部话题
	 */
	function checkin(huati, checkinAll=true) {
		let huatiCheckin = new Task(
			`${huati.name}话题签到`,
			{
				method: 'GET',
				url: `https://weibo.com/p/aj/general/button?ajwvr=6&api=http://i.huati.weibo.com/aj/super/checkin&texta=签到&textb=已签到&status=0&id=100808${huati.hash}`,
			},
			(xhr) => {
				let data = JSON.parse(xhr.responseText),
					code = +data.code;

				if (code === 100000 || code === 382004) {
					checkinDone.appendChild(huati.element);
					initLog('已签', {});
					log['已签'][huati.name] = huati.hash;
					Object.assign(lastCheckin, {date, nick: USER.NICK});
					Object.assign(lastCheckin, log['已签']);
					GM_setValue(`lastCheckin${USER.UID}`, JSON.stringify(lastCheckin));
				} else {
					initLog('异常', {});
					log['异常'][huati.name] = {huati: huati, code: data.code, msg: data.msg};
					huatiCheckin.onerror('error');
				}
				if (code === 100000)
					setStatus(`签到第${/\d+/g.exec(data.data.alert_title)[0]}名,经验+${/\d+/g.exec(data.data.alert_subtitle)[0]}`, huati.element);
				else
					setStatus(data.msg, huati.element);
				if (checkinAll) {
					if (log['待签'].length > 0)
						checkin(log['待签'].shift());
					else {
						clearTask();
						setStatus(`${date} 签到完成`);
						checkinToDo.parentNode.style.display = 'none';
						checkinDone.parentNode.setAttribute('open', '');
						Object.assign(lastCheckin, {allChecked: true});
						GM_setValue(`lastCheckin${USER.UID}`, JSON.stringify(lastCheckin));
						console.info(log);
						initCheckinBtn();
					}
				}
			},
			() => checkin(huati, false),
			() => {
				log['待签'].push(huati);
				if (log['待签'].length > 0)
					checkin(log['待签'].shift());
				else
					clearTask();

				let retryHuati =document.createElement('a');
				retryHuati.classList.add('S_ficon');
				retryHuati.style = 'cusor: pointer';
				retryHuati.onclick = () => checkin(Object.assign({}, huati), false);
				retryHuati.innerText = '[重试]';
				setStatus(retryHuati, huati.element, true);
			}
		);
	}

	function clearTask() {
		currentTask = null;
		checkinClose.title = '关闭';
	}

	function initLog(key, initialValue) {
		if (!log.hasOwnProperty(key))
			log[key] = initialValue;
	}

	function initElement(name, hash) {
		let element = document.createElement('li');
		element.id = hash;
		element.innerHTML = `<span class="order"></span>.<a href="https://weibo.com/p/100808${hash}" target="_blank">${name}</a><span class="info"></span>`;
		return element;
	}

	/**
	 * @global	{object}	log			操作日志
	 * @global	{object[]}	log['已签']	已签话题列表
	 * @global	{object[]}	log['待签']	待签话题列表
	 * @global	{object}	log['异常']	签到异常列表
	 */
	let log = {},

		/** @global	{string}	date		当前东八区日期 */
		date = new Date(new Date().getTime() + 288e5).toJSON().substr(0, 10).replace(/-0?/g, '/'),

		/** @global	{Task|null}	currentTask 当前 xhr 任务 */
		currentTask = null;

	alterCheckinBtn('签到');

	if (!lastCheckin.date || lastCheckin.date != date || !lastCheckin.allChecked || !auto) {

		/** 设置信息展示界面 */
		let checkinCSS = document.getElementById('checkinCSS') || document.createElement('style');
		checkinCSS.id = 'checkinCSS';
		checkinCSS.type = 'text/css';
		checkinCSS.innerHTML = `#checkinInfo {z-index:10000;position:fixed;left: 0px;bottom: 0px;min-width:320px;max-width: 640px;opacity: 0.9}#checkinInfo .W_layer_title {border-top: solid 1px #fa7f40}#checkinStatus {float: right;padding: 0 60px 0 10px}#checkinMore {right: 36px}#checkinClose {right: 12px}#checkinDetail {display: ${config.openDetail ? '' : 'none'};margin: 6px 12px;padding: 2px;max-height: ${config.maxHeight}px;overflow-y:auto;}${scrollbarStyle('#checkinDetail')}#checkinDetail summary {margin: 2px}#checkinDetail ol {column-count: 3}#checkinDetail li {line-height: 1.5}#checkinDetail a {cusor: pointer}#checkinDetail .info {float: right}#checkinStatus ~ .W_ficon {position: absolute;bottom: 0px;font-size: 18px;}`;
		document.head.appendChild(checkinCSS);

		let	checkinInfo = document.getElementById('checkinInfo') || document.createElement('div');
		checkinInfo.id = 'checkinInfo';
		checkinInfo.classList.add('W_layer');
		checkinInfo.innerHTML = `<div class="content"><div><div id="checkinDetail"><details id="checkinToDo" open style="display: none"><summary class="W_f14 W_fb">待签</summary><ol></ol></details><details id="checkinDone" style="display: none"><summary class="W_f14 W_fb">已签</summary><ol></ol></details></div></div><div class="W_layer_title">${USER.NICK}<span id="checkinStatus"></span><a id="checkinMore" title="${config.openDetail ? '收起' :'详情'}" class="W_ficon S_ficon">${config.openDetail ? 'c' : 'd'}</a><a id="checkinClose" title="${currentTask ? '中止' : '关闭'}" class="W_ficon S_ficon">X</a></div></div>`;
		document.body.appendChild(checkinInfo);

		var checkinStatus = document.getElementById('checkinStatus'),
			checkinMore = document.getElementById('checkinMore'),
			checkinClose = document.getElementById('checkinClose'),
			checkinDetail = document.getElementById('checkinDetail'),
			checkinDone = document.querySelector('#checkinDone ol'),
			checkinToDo = document.querySelector('#checkinToDo ol');
		checkinMore.onclick = function() {
			if (this.innerText === 'd') {
				this.innerText = 'c';
				this.title = '收起';
				checkinDetail.style.display = '';
			} else {
				this.innerText = 'd';
				this.title = '详情';
				checkinDetail.style.display = 'none';
			}
		};

		checkinClose.onclick = function() {
			if (currentTask) {
				currentTask.xhr.abort();
				setStatus(`${currentTask.name}中止`);
				clearTask();
				initCheckinBtn();
			} else {
				checkinInfo.remove();
				checkinCSS.remove();
				initCheckinBtn();
			}
		};

		[checkinToDo, checkinDone].forEach((ol, i) =>
			['DOMNodeInserted', 'DOMNodeRemoved'].forEach((event) =>
				ol.addEventListener(event, function() {
					let isRemoval = event != 'DOMNodeInserted';
					if (this.parentNode.style.display === 'none')
						this.parentNode.removeAttribute('style');
					this.previousSibling.innerText = `${i ? '已' : '待'}签${ol.childElementCount - (isRemoval ? 1 : 0)}个话题`;
					Array.from(this.querySelectorAll('li .order')).forEach((span) =>
						span.innerText = Array.from(span.parentNode.parentNode.querySelectorAll('li')).findIndex((li) =>
							li === span.parentNode) + (isRemoval ? 0 : 1));
				})));

		/** 开始获取话题列表 */
		checkinClose.title = '中止';

		if (lastCheckin.date) {
			setStatus(`从${lastCheckin.date}签到记录读取话题列表`);
			var lastHuatiList = [],
				lastCheckinDate = lastCheckin.date;
			for (let key in lastCheckin) {
				if (!['date', 'nick', 'allChecked'].includes(key)) {
					lastHuatiList.push(key);
					let hash = lastCheckin[key],
						element = initElement(key, hash);
					if (lastCheckinDate != date) {
						checkinToDo.appendChild(element);
						initLog('待签', []);
						log['待签'].push({name:key, hash, element});
					} else {
						checkinDone.appendChild(element);
						initLog('已签', {});
						log['已签'][key] = hash;
					}
				}
			}
			if (lastCheckinDate != date)
				lastCheckin = {};
			if (log.hasOwnProperty('待签')) {
				setStatus(`关注列表读取完毕,共${log['待签'].length}个话题待签`);
				if (config.autoCheckin)
					checkin(log['待签'].shift());
				else {
					/** 开始签到按钮 */
					let startCheckin = document.createElement('a');
					startCheckin.classList.add('S_ficon');
					startCheckin.style = 'cusor: pointer';
					startCheckin.onclick = () => checkin(log['待签'].shift());
					startCheckin.innerText = '[开始签到]';
					checkinStatus.appendChild(startCheckin);
				}
			}
		}
		getHuatiList();
	} else
		initCheckinBtn();
}

function setupConfig() {
	console.group(logname='微博超话签到设置');
	alterCheckinBtn('设置');

	let configCSS = document.createElement('style');
	configCSS.id = 'configCSS';
	configCSS.type = 'text/css';
	configCSS.innerHTML = `#configForm {z-index:6666;position:fixed;right: 0px;top: 50px;width:540px;opacity: 0.9}#configForm form {height: 288px}#configForm header {text-align: center}#configClose {position: absolute;z-index: 2;left: 12px;top: 2px;font-size: 18px;}#configForm header img {position: relative;top: 3px;padding-right: 6px}#configForm footer {position: absolute;bottom: 0px;padding: 12px;width: 492px;border-top: solid 1px #ccc}#configForm footer input {margin: 0 12px}#configForm main {margin: 6px 12px;}#configForm fieldset:first-child {width: 240px;float:left;margin-right: 12px}#configForm fieldset {padding: 1px 12px}#configForm fieldset > fieldset > legend {text-align: right}#configForm input[type=number] {width: 48px}#configForm input[type=button] {padding: 0 12px}#configForm th {font-weight: bold;padding-top: 6px}#configForm table {float: left;margin: 0 6px}#configForm pre {padding: 6px;height: 160px;overflow-y: scroll;background-color: whitesmoke;line-height: 1.5}${scrollbarStyle('#configForm pre')}#configForm span {float: right}`;
	document.head.appendChild(configCSS);

	let configForm = document.createElement('div');
	configForm.id = 'configForm';
	configForm.classList.add('W_layer');
	configForm.innerHTML = `<form class="content"><header class="W_layer_title"><img src="https://img.t.sinajs.cn/t6/style/images/pagecard/icon.png">签到脚本设置<a title="关闭" class="W_ficon S_ficon" id="configClose">X</a></header><main><fieldset><legend>参数设定</legend><fieldset><legend>签到偏好</legend><input type="checkbox" name="autoCheckin" ${config.autoCheckin ? 'checked' : ''}>自动签到<br><input type="checkbox" name="checkNormal" ${config.checkNormal ? 'checked' : ''}>普话签到</fieldset><fieldset><legend>视觉偏好</legend><input type="checkbox" name="openDetail" ${config.openDetail ? 'checked' : ''}>自动展开签到详情<br>详情最大高度 <input type="number" name="maxHeight" value=${config.maxHeight} min=60 max=1080 step=60> 像素</fieldset><fieldset><legend>运行参数</legend>请求延时 <input type="number" name="delay" value=${config.delay} min=0 step=100> 毫秒<br>请求超时 <input type="number" name="timeout" value=${config.timeout} min=0 step=100> 毫秒<br>超时及异常自动重试 <input type="number" name="retry" value=${config.retry} min=0> 次</fieldset></fieldset><fieldset><legend>账户信息</legend><table><tbody><tr><th>昵称</th></tr><tr><td>${USER.NICK}</td></tr><tr><th>ID</th></tr><tr><td>${USER.UID}</td></tr><tr><th>上次签到</th></tr><tr><td>${lastCheckin.date || '尚无记录'}</td></tr><tr><th><input type="button" value="清空记录" id="configClear" ${Object.keys(lastCheckin).length != 0 ? '' : 'disabled'}></th></tr></tbody></table><pre>${Object.keys(lastCheckin).filter((key) => !['date', 'nick', 'allChecked'].includes(key)).join('\n')}</pre></fieldset><footer><input type="button" value="保存" id="configSave"><input type="button" value="还原" id="configRestore" disabled><span title="请 F12 打开控制台查看错误记录,与出错情况一并反馈"><input type="button" value="重置" id="configDefault" ${isEqual(config, DEFAULT_CONFIG) ? 'disabled' : ''}>Bug反馈请到<a href=http://greasyfork.icu/zh-CN/scripts/32143-weibo-huati-check-in/feedback target=_blank>GreasyFork</a>/ <a href=https://gist.github.com/xyauhideto/b9397058ca3166b87e706cbb7249bd54 target=_blank>Gist</a> / 微博@<a href=https://weibo.com/678896489 target=_blank>作者</a></span></footer> </form>`;
	document.body.appendChild(configForm);
	let inputs = Array.from(document.querySelectorAll('#configForm fieldset > input')),
		getInputs = () => inputs.reduce((conf, input) => {
			conf[input.name] = input.type != 'checkbox' ? +input.value : input.checked;
			return conf;
		}, {}),
		configRestore = document.getElementById('configRestore'),
		configDefault = document.getElementById('configDefault');

	document.getElementById('configSave').onclick = function() {
		config = getInputs();
		GM_setValue(`config${USER.UID}`, JSON.stringify(config));
		initForm();
	};
	configRestore.onclick = () => initForm();
	configDefault.onclick = function() {
		console.warn('重置原设置');
		console.table(config);
		GM_deleteValue(`config${USER.UID}`);
		initForm(DEFAULT_CONFIG);
	};
	document.getElementById('configClear').onclick = function() {
		console.warn('清空上次签到');
		console.table(lastCheckin);
		GM_deleteValue(`lastCheckin${USER.UID}`);
		lastCheckin = {};
		document.querySelector('#configForm tr:nth-of-type(6)>td').innerText = '尚无记录';
		document.querySelector('#configForm pre').innerText = '';
		this.disabled = true;
	};
	document.getElementById('configClose').onclick = function() {
		configCSS.remove();
		configForm.remove();
		initCheckinBtn();
	};

	inputs.forEach(function(input) {
		input.onchange = () => {
			configRestore.disabled = isEqual(getInputs(), config) ? true : false;
			configDefault.disabled = isEqual(getInputs(), DEFAULT_CONFIG) ? true : false;
		};
	});

	function initForm(conf=config) {
		config = conf;
		for (let key in conf) {
			if (typeof conf[key] === 'boolean')
				document.getElementsByName(key)[0].checked = conf[key];
			else
				document.getElementsByName(key)[0].value = conf[key];
		}
		inputs.forEach((input) => input.onchange());
	}

	/** 简单对象比较
	 * @param	{object}	x	比较对象x
	 * @param	{object}	y	比较对象y
	 * @return	{boolean}	比较结果
	 */
	function isEqual(x, y) {
		if (Object.values(x).length != Object.values(y).length)
			return false;
		for (let key in x) {
			if (typeof y[key] === 'undefined' || x[key] != y[key])
				return false;
		}
		return true;
	}
}

/**
 * 提示签到状态
 * @param	{string|node}	text					当前状态
 * @param	{node}			[element=checkinStatus]	显示提示的节点
 * @param	{boolean}		[append=false]			追加节点
 */
function setStatus(text, element=checkinStatus, append=false) {
	if (element != checkinStatus)
		element = element.querySelector('.info');
	else if (!append)
		console.info(text);

	if (append) {
		if (typeof text != 'string')
			element.appendChild(text);
		else
			element.innerHTML += text;
	} else
		element.innerHTML = text;
}


function scrollbarStyle(elementSelector) {
	return `${elementSelector}::-webkit-scrollbar {width: 4px;background-color: #f2f2f5;border-radius: 2px;}${elementSelector}::-webkit-scrollbar-thumb {width: 4px;background-color: #808080;border-radius: 2px;}`;
}
})();