// ==UserScript==
// @name		Page Read Mode
// @description	 [ALT+R] Content reader on any page, selecting the text area automatically or manually.
// @author		  Moshel
// @namespace	   https://hzy.pw
// @homepageURL	 https://hzy.pw/
// @supportURL	  https://github.com/h2y/link-fix
// @icon		https://wiki.greasespot.net/images/f/f3/Book.png
// @license		 GPL-3.0
// @include		 *
// @grant		   GM_setClipboard
// *run-at		  context-menu
// @date		12/17/2015
// @modified		01/23/2016
// @version		 1.1.2
// ==/UserScript==


//	 keymaster.js may be freely distributed under the MIT license.
!function(a){function j(a,b){for(var c=a.length;c--;)if(a[c]===b)return c;return-1}function k(a,b){if(a.length!=b.length)return!1;for(var c=0;c<a.length;c++)if(a[c]!==b[c])return!1;return!0}function m(a){for(b in d)d[b]=a[l[b]]}function n(a){var b,e,g,h,k,l;if(b=a.keyCode,-1==j(i,b)&&i.push(b),(93==b||224==b)&&(b=91),b in d){d[b]=!0;for(g in f)f[g]==b&&(q[g]=!0)}else if(m(a),q.filter.call(this,a)&&b in c)for(l=w(),h=0;h<c[b].length;h++)if(e=c[b][h],e.scope==l||"all"==e.scope){k=e.mods.length>0;for(g in d)(!d[g]&&j(e.mods,+g)>-1||d[g]&&-1==j(e.mods,+g))&&(k=!1);(0!=e.mods.length||d[16]||d[18]||d[17]||d[91])&&!k||e.method(a,e)===!1&&(a.preventDefault?a.preventDefault():a.returnValue=!1,a.stopPropagation&&a.stopPropagation(),a.cancelBubble&&(a.cancelBubble=!0))}}function o(a){var c,b=a.keyCode,e=j(i,b);if(e>=0&&i.splice(e,1),(93==b||224==b)&&(b=91),b in d){d[b]=!1;for(c in f)f[c]==b&&(q[c]=!1)}}function p(){for(b in d)d[b]=!1;for(b in f)q[b]=!1}function q(a,b,d){var e,f;e=y(a),void 0===d&&(d=b,b="all");for(var g=0;g<e.length;g++)f=[],a=e[g].split("+"),a.length>1&&(f=z(a),a=[a[a.length-1]]),a=a[0],a=h(a),a in c||(c[a]=[]),c[a].push({shortcut:e[g],scope:b,method:d,key:e[g],mods:f})}function r(a,b){var d,e,g,i,j,f=[];for(d=y(a),i=0;i<d.length;i++){if(e=d[i].split("+"),e.length>1&&(f=z(e),a=e[e.length-1]),a=h(a),void 0===b&&(b=w()),!c[a])return;for(g in c[a])j=c[a][g],j.scope===b&&k(j.mods,f)&&(c[a][g]={})}}function s(a){return"string"==typeof a&&(a=h(a)),-1!=j(i,a)}function t(){return i.slice(0)}function u(a){var b=(a.target||a.srcElement).tagName;return!("INPUT"==b||"SELECT"==b||"TEXTAREA"==b)}function v(a){e=a||"all"}function w(){return e||"all"}function x(a){var b,d,e;for(b in c)for(d=c[b],e=0;e<d.length;)d[e].scope===a?d.splice(e,1):e++}function y(a){var b;return a=a.replace(/\s/g,""),b=a.split(","),""==b[b.length-1]&&(b[b.length-2]+=","),b}function z(a){for(var b=a.slice(0,a.length-1),c=0;c<b.length;c++)b[c]=f[b[c]];return b}function A(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,function(){c(window.event)})}function C(){var b=a.key;return a.key=B,b}var b,c={},d={16:!1,18:!1,17:!1,91:!1},e="all",f={"\u21e7":16,shift:16,"\u2325":18,alt:18,option:18,"\u2303":17,ctrl:17,control:17,"\u2318":91,command:91},g={backspace:8,tab:9,clear:12,enter:13,"return":13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,"delete":46,home:36,end:35,pageup:33,pagedown:34,",":188,".":190,"/":191,"`":192,"-":189,"=":187,";":186,"'":222,"[":219,"]":221,"\\":220},h=function(a){return g[a]||a.toUpperCase().charCodeAt(0)},i=[];for(b=1;20>b;b++)g["f"+b]=111+b;var l={16:"shiftKey",18:"altKey",17:"ctrlKey",91:"metaKey"};for(b in f)q[b]=!1;A(document,"keydown",function(a){n(a)}),A(document,"keyup",o),A(window,"focus",p);var B=a.key;a.key=q,a.key.setScope=v,a.key.getScope=w,a.key.deleteScope=x,a.key.filter=u,a.key.isPressed=s,a.key.getPressedKeyCodes=t,a.key.noConflict=C,a.key.unbind=r,"undefined"!=typeof module&&(module.exports=key)}(this);

/*
	global var
 */
let mode = 0,	//状态标记
	topNode = null,  //顶层节点
	styleNode = null,
	butNodes = null,
	useageNode = null;

/*
	Tool functions
 */
function isNodeShow(node) {
	const styles = window.getComputedStyle(node);

	if(styles.display=='none' || styles.visibility=='hidden')
	return false;

	if(!parseInt(styles.height) || !parseInt(styles.height))
	return false;

	return true;
}

/*
	main functions
 */
function enterCliping(e) {
	mode = 1;
	e.preventDefault();

	//add style
	if(!styleNode) {
	styleNode = document.createElement('style');
	styleNode.innerHTML = `.cliper-top-node {
		box-shadow: 0 0 20px #777 !important;
		border:	 3px solid red !important;
	} .read-mode-reading {
		position:   fixed   !important;
		z-index:	9999970 !important;
		top:	0	   !important;
		left:	   0	   !important;
		height:	 100%	!important;
		width: 		100%	!important;
		background-color: white   !important;
		overflow:	 scroll  !important;
		padding:	  0	   !important;
		border:	   0	   !important;
		margin:	   0	   !important;
	} .read-mode-buts {
		position:   fixed;
		z-index:	9999985;
		top: 2rem;  right: 1rem;
	} .read-mode-button {
		width:	  32px;
		height:	 28px;
		margin:	 0 .1rem;
		padding:	2px 3px;
		color:	  #fff;
		opacity:	.2;
		transition: 500ms;
		border-radius:	  3px;
		background-color:   black;
	} .read-mode-button:hover {
		background-color:   white;
		border-radius:	  0;
		box-shadow:	 0 0 3px #000;
		color:		  #000;
	} img.read-mode-useage {
		position:   fixed;
		right:	  3rem;
		bottom:	 2rem;
		z-index:	9999975;
		opacity:	.7;
	}`;
	//styleNode.id = 'read_mode';
	document.body.appendChild(styleNode);
	}

	// useage image
	if(!useageNode) {
	useageNode = document.createElement('img');
//	 useageNode.src = 'https://github.com/h2y/link-fix/raw/master/read_mode/useage.png';
	useageNode.className = 'read-mode-useage';
//	 document.body.appendChild(useageNode);
	}

	useageNode.style.display = '';

	//choose the init node
	topNode = document.body;
	let preNode = null;

	do {
	preNode = topNode;
	onDown(e);
	}while(preNode!=topNode && preNode.clientHeight*0.9 < topNode.clientHeight);
}

function quitCliping(e) {
	mode = 0;
	e.preventDefault();

	useageNode.style.display = 'none';

	changeTopNode(null);

	if(butNodes)
	butNodes.style.display = 'none';

	topNode.classList.remove('read-mode-reading');
}


function buildButNodes() {
	butNodes = document.createElement('div');
	butNodes.className = 'read-mode-buts';

	let buts = [
	{
		text:	"Exit read mode",
		handler: quitCliping,
		icon:	'✘'
	}, {
		text:	"Save HTML data",
		handler: onSaveHTML,
		icon:	'❖'
	}
	];

	for(let but of buts) {
	let newBut = document.createElement('a');
	newBut.className = 'read-mode-button';
	newBut.innerHTML = but.icon;
	newBut.title	 = but.text;
	newBut.onclick   = but.handler;
	butNodes.appendChild(newBut);
	}

	document.body.appendChild(butNodes);
}


function changeTopNode(newNode) {
	if(topNode)
	topNode.classList.remove('cliper-top-node');

	if(newNode)
	newNode.classList.add('cliper-top-node');
	else
	return;

	topNode = newNode;

	//scroll
	var winH = window.screen.availHeight,
	winY = window.scrollY,
	domH = topNode.clientHeight,
	domY = topNode.getBoundingClientRect().top + winY;
	//console.log(winH,winY,domH,domY);

	if(domH>winH)
	window.scrollTo(0, domY - 50 );
	else
	window.scrollTo(0, domY - (winH-domH)/2 );
}


/*
	Event handler
 */
function onSaveHTML(e) {
	let htmlStr = '';

	htmlStr += topNode.outerHTML.split('\n').join('')
			.replace(/(id|class)=(\'.*?\'|\".*?\")/ig, '')
			.replace(/<!--.*?-->/g, '')
			.replace(/>[\t ]+?</g, '><')
			.replace(/<(link|meta).*?>/ig, '')
			.replace(/<style.*?>.*?<\/style>/ig, '')
			.replace(/<script.*?>.*?<\/script>/ig, '');

	GM_setClipboard(htmlStr);

	alert('Copied into clipboard.');
}

function onUp(e) {
	if(!mode) return;
	e.preventDefault();

	if(topNode.parentElement)
	changeTopNode(topNode.parentNode);
}

function onDown(e) {
	if(!mode) return;
	e.preventDefault();

	if(!topNode.childElementCount)
	return;

	var scanNodes = topNode.children,
	maxNode = null;
	var maxHeight = -1;

	for(let node of scanNodes)
	if(isNodeShow(node) && node.clientHeight > maxHeight) {
		maxHeight = node.clientHeight;
		maxNode = node;
	}

	if(maxNode)
	changeTopNode(maxNode);
}

function onLeft(e) {
	if(!mode) return;
	e.preventDefault();

	let nowNode = topNode;
	for(let node=nowNode; node.previousElementSibling;) {
	node = node.previousElementSibling;
	if(isNodeShow(node)) {
		nowNode = node;
		break;
	}
	}

	if(nowNode!=topNode)
	changeTopNode(nowNode);
	//else: up
	else if (topNode.parentNode) {
	let bakNode = nowNode = topNode;

	onUp(e);
	nowNode = topNode;

	onLeft(e);
	if(nowNode==topNode)
		changeTopNode(bakNode);
	else
		onDown(e);
	}
}

function onRight(e) {
	if(!mode) return;
	e.preventDefault();

	let nowNode = topNode;
	for(let node=nowNode; node.nextElementSibling;) {
	node = node.nextElementSibling;
	if(isNodeShow(node)) {
		nowNode = node;
		break;
	}
	}

	if(nowNode!=topNode)
	changeTopNode(nowNode);
	//else: up
	else if (topNode.parentNode) {
	let bakNode = nowNode = topNode;

	onUp(e);
	nowNode = topNode;

	onRight(e);
	if(nowNode==topNode)
		changeTopNode(bakNode);
	else
		onDown(e);
	}
}


function onEnter(e) {
	if(!mode) return;
	e.preventDefault();

	quitCliping(e);

	topNode.classList.add('read-mode-reading');

	//buttons
	if(butNodes)
	butNodes.style.display = '';
	else
	buildButNodes();
}


/*
	Main
 */
key('alt+r', function(){
	if(mode)
		quitCliping(new MouseEvent("main"));
	else
		enterCliping(new MouseEvent("main"));
});


/*
	bind action
 */
key('up',	onUp);
key('down',  onDown);
key('left',  onLeft);
key('right', onRight);

key('enter', onEnter);
key('esc',   quitCliping);
