There are 1 previous version of this script.
Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)
// ==UserScript==
// @name Focus Reading
// @namespace meh
// @description Focus page elements, fading the rest. Toggle at Greasemonkey menu; click any element to focus; use arrow keys to navigate; Esc to exit.
// @include http://*
// ==/UserScript==
/*XRAY version 0.91a
Copyright (c) 2007 Western Civilisation pty. ltd.
http://westciv.com/xray/
We aim to open source XRAY once the initial code is stabilized
please email any suggestions, errors, feedback and so on to john allsopp
john@westciv.com
Some portions (c) Apple Computer
Some portions adapted from Quirksmode http://quirksmode.org and
a tutorial aby Patrick Hunlock http://www.hunlock.com/
bookmark loading code adapted from leftlogic http://leftlogic.com/lounge/articles/microformats_bookmarklet/
The XRAYHUD style inspired by the Shiira Project's HMBlkAppKit http://shiira.jp/hmblkappkit/en.html
Concept inspired by Left Logic's Microformats Bookmarklet http://leftlogic.com/lounge/articles/microformats_bookmarklet/
itself from an original concept by Jon Hicks http://www.hicksdesign.co.uk/
XRAY uses jQuery, at present for one small but crucial aspect allowing support for Safari 2, though hopefully we'll take advantage of their fine effects in upcoming releases
*/
/*
Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
const OPACITY = '.7';
var body = document.body;
var on = false;
GM_registerMenuCommand('Toogle Focus Reading', toggle);
function GetNextStructuredSibling( objNode ){
// Copyright Ben Nadel @ KinkySolutions.com 2006
// Check for a valid starting node.
if (objNode){
// Travel down the sibling chain looking for a non-text node.
for (
objNode = objNode.nextSibling ;
(
objNode &&
objNode.nodeType == 3
) ;
objNode = objNode.nextSibling
){
// Nothing has to happen here. The FOR loop itself is taking care
// of the node traversing. We don't have to really worry about any
// error checking as we can't really make it outside of HTML DOM
// elements without hitting a structured node, or coming up with NULL.
}
}
// Return the sibling node.
if (!objNode) return (objNode);
if (objNode.nodeName=="SCRIPT") return;
if ((objNode.nodeName=='WCIECanvas') || (objNode.nodeName=='WCCanvas')) return;
return( objNode );
}
function GetPreviousStructuredSibling( objNode ){
// Travel up the sibling chain looking for a non-text node.
for (
objNode = objNode.previousSibling ;
(
objNode &&
objNode.nodeType == 3
) ;
objNode = objNode.previousSibling
){
// Nothing has to happen here. The FOR loop itself is taking care
// of the node traversing. We don't have to really worry about any
// error checking as we can't really make it outside of HTML DOM
// elements without hitting a structured node, or coming up with NULL.
}
// Return the sibling node.
return( objNode );
}
function GetFirstStructuredChild( theElement ){
// var nodeChildren=theElement.children;
var nodeChildren=theElement.childNodes;
if(!nodeChildren) return theElement;
//if it's the head, return the body
if (theElement.nodeName=='HTML') return document.body;
for (var i = 0; i < nodeChildren.length; i++)
{
var aChild=nodeChildren[i];
if (aChild.nodeName!=="#text") {
break;
}
}
if(!aChild) return theElement;
if (aChild.nodeName=="SCRIPT") return theElement;
if (aChild.nodeName=="#text") return theElement;
return aChild;
}
function scrollToElement(theElement){
// http://radio.javaranch.com/pascarello/2005/01/09/1105293729000.html
whereIs=getElementOffsetLocation(theElement);
elementTop=whereIs[1];
elementLeft=whereIs[0];
elementHeight=theElement.offsetHeight
if (elementTop>getClientHeight()+getScrollXY()[1] || elementTop+elementHeight<getScrollXY()[1])
window.scrollTo(0,elementTop-(getClientHeight()/2));
}
function addCSS (){
var theHead = getTag('head');
//var theCSS = createElement('link', {type:'text/css', rel:'stylesheet', href:'http://westciv.com/xray/xraycore.css'});
var theCSS = createElement('style');
theCSS.innerHTML = 'canvas#WCcanvas {'+
' position: absolute;'+
' top: 0;'+
' left: 0;'+
' z-index: 9999;'+
' }'+
'#XRAYHUD {'+
' position: fixed;'+
' top:100px;'+
' left:100px;'+
' z-index:9999;'+
' border: 1px rgb(0,0,0) solid;'+
' padding: 0em 0em 0em;'+
' font-family: "Lucida Grande", Helvetica, Arial, sans-serif;'+
' background-color: rgb(48,53,60);'+
' font-size: 8pt;'+
' -moz-box-shadow: 0px 0px 2px #777777;'+
' box-shadow: 0px 0px 5px #777777;'+
' color: #ffffff;'+
' cursor: move;'+
' width: 42em;'+
' line-height: 0em;'+
' border-top-left-radius: 8px;'+
' border-top-right-radius: 8px;'+
' opacity: 0.9; '+
'}'+
//debug(theCSS);
//this zeros style that the style seet of the page visited may apply
'#XRAYHUD * {'+
' text-align: left;'+
' color: white;'+
' background-color: transparent;'+
' list-style-image: none;'+
' font-family: "Lucida Grande", Helvetica, Arial, sans-serif;'+
' font-size: 1em;'+
' line-height: 1.4 '+
'}'+
'#HUDHierarchy {'+
' border-bottom: 1px #74777d solid;'+
' padding-bottom: .5em '+
'}'+
'#XRAYHUD p {'+
' padding: 0 .5em;'+
' margin: 0; '+
'}'+
'#XRAYHUD .XRAYtitlebar {'+
' padding: 0;'+
' text-shadow: 1px 1px 1px #bfbfbf;'+
' text-align: center;'+
' line-height: 0em;'+
' margin-bottom: 1em;'+
' margin-top: 8px}'+
'.XRAYclosebox {'+
'margin: -6px 0;'+
'padding: 0 0 0 12px;'+
'float: right;'+
//'height: 14px;'+
//'width: 8px;'+
//'background-image: url('images/closebox.png');'+
//'background-repeat: no-repeat;'+
'cursor: pointer;}'+
'#XRAYHUD p+ul {'+
' padding-top: .5em; '+
'}'+
'#XRAYHUD ul {'+
' padding: 0 .5em;'+
' margin: 0 0 .5em 0;'+
' }'+
'#XRAYHUD .group ul li {'+
' list-style-type: none;'+
' list-style-image: none;'+
' background-image: none}'+
'#XRAYHUD>.elementInfo {'+
' clear: both;'+
' margin: .5em 0;'+
' border-bottom: 1px #74777c solid;'+
' padding-bottom: .5em;'+
' font-size: 1.1em;'+
' text-align: left; '+
'}'+
'#XRAYHUD>.elementInfo p {'+
' padding-right: 1em; '+
'}'+
'#XRAYHUD>.group {'+
' float: left;'+
' margin-top: .5em;'+
' margin-left: auto;'+
' margin-right: auto}'+
'#XRAYHUD #XRAYabout {'+
' clear: both;'+
' margin: 0;'+
' padding-right: .5em;'+
' border-top: 1px #74777b solid;'+
' padding-top: .5em;'+
' font-size: .9em;'+
' background-color: rgb(41,45,50);'+
' }'+
'#XRAYHUD #XRAYabout p { text-align: right;'+
' padding:6px 0}'+
'#XRAYHUD a:link, #XRAYHUD a:visited, #XRAYHUD a:hover,#XRAYHUD a:active {'+
' color: white;'+
' text-decoration: none; '+
' cursor: pointer;'+
' border: none;'+
' background-image: none;'+
' }'+
'#XRAYHUD .XRAYdetailedLink {'+
//'/* background-image: url('images/about.png');'+
//' background-repeat: no-repeat;'+
//' background-position: right;'+
' padding-right: 6px;'+
'}'+
//do the labels
'#XRAYWidthLabel, #XRAYHeightLabel, #XRAYTopLeftLabel {'+
' position: absolute;'+
' z-index: 1002;'+
' background-color: #e16820;'+
' border: 2px #ffffff solid;'+
' color: #ffffff;'+
' font-size: 9pt;'+
' padding: .2em;'+
' -webkit-box-shadow: 1px 1px 3px #5f5f5f;'+
' -moz-box-shadow: 1px 1px 3px #5f5f5f;'+
' box-shadow: 1px 1px 3px #5f5f5f;'+
' visibility: hidden;'+
' font-family: "Lucida Grande", Helvetica, Arial, sans-serif;'+
' -webkit-border-radius: 5px;'+
' border-radius: 5px; '+
'}';
//*/
var theCSS = theHead[0].appendChild(theCSS);
}
function windowResized(){
//called by the resize event on the document
hideCanvas();
}
function keyPressed(e){
//called by the onkeypress event on the document
var keythatwaspressed;
if (window.event) keythatwaspressed = window.event.keyCode;
else if (e) keythatwaspressed = e.which;
switch (keythatwaspressed){
case 27: //esc
toggle();
break;
case 38: //up
if (currentPatient.parentNode){
while (currentPatient.parentNode.nodeName == '#text'){
currentPatient = currentPatient.parentNode;
}
if (!(currentPatient.nodeName=='HTML')){
xRayElement(currentPatient.parentNode);
}
return false;
}
break;
case 37: //left
if (GetPreviousStructuredSibling(currentPatient)) xRayElement(GetPreviousStructuredSibling(currentPatient));
return false;
break;
case 39: //right
if (GetNextStructuredSibling(currentPatient)) xRayElement(GetNextStructuredSibling(currentPatient));
return false;
break;
case 40: //down
if (GetFirstStructuredChild(currentPatient)) xRayElement(GetFirstStructuredChild(currentPatient));
return false;
break;
default : return true;
}
}
function getElementOffsetLocation(obj) {
//adapted from an example at quirksmode.org - a must read resource for javascript, DOM and all web development
try{
var curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft;
curtop = obj.offsetTop;
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
}
}
}catch(e){
//debug("getElementOffsetLocation > exception > "+obj+" > "+e);
}
return [curleft,curtop];
}
function insertCanvas () {
// inserts a canvas element to do the drawing
var theCanvas = createElement('CANVAS', {id:'WCcanvas', width:getDocumentWidth(), height:getDocumentHeight()});
body.appendChild(theCanvas);
theCanvas.addEventListener('mousedown',hideCanvas,false);
}
function deleteNodeByID(nodeId) {
//delete the node with the given id, if it exists
try {
var theNode = getId(nodeId);
if (theNode) {
theNode.parentNode.removeChild(theNode);
}
}
catch (err) {
}
}
function hideCanvas() {
var canvas = getId("WCcanvas");
canvas.style.visibility='hidden';
}
function showCanvas() {
var canvas = getId("WCcanvas");
//canvas.style.display='block';
canvas.style.visibility='visible';
}
function getClientSize() {
//http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return [myHeight, myWidth];
}
function getClientHeight(){
//return the height of the display area
theSize=getClientSize();
theHeight=theSize[0];
return theHeight
}
function getClientWidth(){
//return the height of the display area
theSize=getClientSize();
theWidth=theSize[1];
return theWidth
}
function getDocumentWidth() {
if (document.body.scrollWidth)
return document.body.scrollWidth;
var w = document.documentElement.offsetWidth;
if (window.scrollMaxX)
w += window.scrollMaxX;
return w;
}
function getDocumentHeight() {
if (document.body.scrollHeight)
return document.body.scrollHeight;
return document.documentElement.offsetHeight;
}
function getScrollXY() {
//http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
var scrOfX = 0, scrOfY = 0;
if( typeof( window.pageYOffset ) == 'number' ) {
//Netscape compliant
scrOfY = window.pageYOffset;
scrOfX = window.pageXOffset;
} else if( body && ( body.scrollLeft || body.scrollTop ) ) {
//DOM compliant
scrOfY = body.scrollTop;
scrOfX = body.scrollLeft;
} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
//IE6 standards compliant mode
scrOfY = document.documentElement.scrollTop;
scrOfX = document.documentElement.scrollLeft;
}
return [scrOfX,scrOfY];
}
function getScrollX(){
//return the current x scroll - now that the canvas is abosolute not fixed for all but Safari 2, we return 0,except for Safari 2
return 0;
}
function getScrollY(){
//return the current y scroll - now that the canvas is abosolute not fixed for all but Safari 2, we return 0,except for Safari 2
return 0;
}
function getElementProperty(theElement, whichStyle)
{
//adapted from quirksmode.org
try{
////debug('getElementProperty > '+theElement+' > '+theElement.nodeName+' > '+whichStyle);
return document.defaultView.getComputedStyle(theElement,null).getPropertyValue(whichStyle);
}catch(e){
//if(theElement.nodeName!='html')
//debug('getElementProperty > '+theElement.nodeName+' > '+whichStyle+' > '+e);
return null;
}
}
function getBorderWidth(theElement, whichBorder){
return getIntegerValue(getElementProperty(theElement, whichBorder+"-width"));
}
function getIntegerValue(theVal) {
//these are for the values of border widths. All but IE return an integer value - here we translate based on what IE does
if (theVal=='thin') return 2;
if (theVal=='medium') return 4;
if (theVal=='thick') return 6;
var newVal= theVal.substr(0, theVal.length-2).valueOf();
if (isNaN(newVal)) {
return 0;
}
else
{
return parseInt(newVal);
}
}
function clearCanvas () {
//delete it and reinsert it
var canvas = getId("WCcanvas");
canvas.removeEventListener('mousedown',hideCanvas,false);
canvas.parentNode.removeChild(canvas);
}
function eraseCanvas (elementTop, elementLeft, elementWidth, elementHeight) {
var canvas = getId("WCcanvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(elementLeft, elementTop, elementWidth, elementHeight);
}
function draw(elementTop, elementLeft, elementWidth, elementHeight, fillColor) {
var canvas = getId("WCcanvas");
var ctx = canvas.getContext("2d");
showCanvas();
ctx.fillStyle = fillColor;
ctx.fillRect (elementLeft, elementTop, elementWidth, elementHeight);
}
function xRayElement(theElement) {
//debug('xRayElement > '+theElement+' > '+theElement.nodeName);
if(!theElement) return;
currentPatient=theElement;
drawElementSkeleton(theElement);//
//showElementDetails(theElement);
//showWidthLabel(theElement);
//showHeightLabel(theElement);
//showTopLeftLabel(theElement);
//if not in sight, scroll to it
scrollToElement(theElement);
}
var currentPatient; //this is the element currently being xrayed
function xRayEvent(e) {
//xray the element - called by the click handler
//debug('xRayEvent > '+e.type+' > '+e.timeStamp);
var e;
if (!e)
return;//e = window.event;
var tg = e.target;
while (tg.nodeName == '#text'){//TODO
//debug('xRayEvent > #text > '+tg );
tg = tg.parentNode;
}
if (tg.className=='XRAYclosebox'){ //todo
////debug('xRayEvent > XRAYclosebox' );
uninstallXRAY();
return false;
}
if (tg.className=='XRAYdetailedLink'){ //todo
document.navigate("http://westciv.com");
return true;
}
xRayElement(tg);
return false;
}
function drawElementSkeleton(theElement){//
if(theElement.nodeName.search(/document/) > -1)
return;
//draws the 'skeleton' of the given element
//debug('drawElementSkeleton > '+theElement+' > '+theElement.nodeName);
whereIs=getElementOffsetLocation(theElement);
////debug('drawElementSkeleton > ' +theElement+ ' > '+whereIs);
elementTop=parseInt(whereIs[1]);
elementLeft=parseInt(whereIs[0]);
elementWidth=theElement.offsetWidth.valueOf();
elementHeight=theElement.offsetHeight.valueOf();
topPadding=getElementProperty(theElement,'padding-top');
topPadding=getIntegerValue(topPadding);
bottomPadding=getElementProperty(theElement,'padding-bottom');
bottomPadding=getIntegerValue(bottomPadding);
leftPadding=getElementProperty(theElement,'padding-left');
leftPadding=getIntegerValue(leftPadding);
rightPadding=getElementProperty(theElement,'padding-right');
rightPadding=getIntegerValue(rightPadding);
topMargin=getElementProperty(theElement,'margin-top');
topMargin=getIntegerValue(topMargin);
bottomMargin=getElementProperty(theElement,'margin-bottom');
bottomMargin=getIntegerValue(bottomMargin);
leftMargin=getElementProperty(theElement,'margin-left');
leftMargin=getIntegerValue(leftMargin);
rightMargin=getElementProperty(theElement,'margin-right');
rightMargin=getIntegerValue(rightMargin);
topBorder=getBorderWidth(theElement,'border-top');
bottomBorder=getBorderWidth(theElement,'border-bottom');
leftBorder=getBorderWidth(theElement,'border-left');
rightBorder=getBorderWidth(theElement,'border-right');
clearCanvas();
insertCanvas();
windowScrollX=getScrollX();
windowScrollY=getScrollY();
//add opaque background
//semi opaque the whole window- needs to adjust canvas width and scale for window without scrollbars
draw(0,0,getDocumentWidth() ,getDocumentHeight(), 'rgba(0,0,0,'+OPACITY+')');
//clear the area where the element is
eraseCanvas(elementTop-topMargin-topBorder-windowScrollY, elementLeft-leftMargin-leftBorder-windowScrollX, elementWidth+leftMargin+rightMargin+leftBorder+rightBorder, elementHeight+ topMargin + bottomMargin+bottomBorder+topBorder);
//draw the content box
eraseCanvas(elementTop+topPadding+topBorder-windowScrollY, elementLeft+leftPadding+leftBorder-windowScrollX, elementWidth-leftPadding-rightPadding-leftBorder-rightBorder, elementHeight-topPadding-bottomPadding-topBorder-bottomBorder);
}
function uninstallXRAY(){
document.removeEventListener('click',xRayEvent,false);
document.removeEventListener('mouseup',xRayEvent,false);
window.removeEventListener('resize',windowResized,false);
document.removeEventListener('keydown',keyPressed,false);
//clearCanvas();
deleteNodeByID('XRAYHUD');
deleteNodeByID('WCcanvas');
}
function installXRAY(e) {
addCSS();
insertCanvas();
document.addEventListener('click',xRayEvent,false);
document.addEventListener('mouseup',xRayEvent,false);
unsafeWindow.addEventListener('resize',windowResized,false);
document.addEventListener('keydown',keyPressed,false);
}
function toggle(){
if(on)
try{uninstallXRAY();}catch(e){}
else
try{installXRAY();}catch(e){}
on = !on;
}
function createElement(type, attrArray, evtListener, html)
{
var node;
try{
node = document.getElementsByTagName('body')[0].createElement(type);
}catch(e){
node = document.createElement(type);
}
for (var attr in attrArray) if (attrArray.hasOwnProperty(attr)){
node.setAttribute(attr, attrArray[attr]);
}
if(evtListener){
var a = evtListener.split(' ');
node.addEventListener(a[0], eval(a[1]), eval(a[2]));
}
if(html)
node.innerHTML = html;
return node;
}
function getId(id, parent){
if(!parent)
return document.getElementById(id);
return parent.getElementById(id);
}
function getTag(name, parent){
if(!parent)
return document.getElementsByTagName(name);
return parent.getElementsByTagName(name);
}