Created
July 6, 2011 14:27
-
-
Save xulapp/1067352 to your computer and use it in GitHub Desktop.
checkmate.uc.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name checkmate.uc.js | |
// @description | |
// @include main | |
// @compatibility Firefox | |
// @namespace http://twitter.com/xulapp | |
// @author xulapp | |
// @license MIT License | |
// @version 2011/07/06 23:20 +09:00 | |
// ==/UserScript== | |
(function checkmate() { | |
const {interfaces: Ci} = Components; | |
function Checkmate({target, pageX, pageY}) { | |
if (!isCheckable(target)) return; | |
var doc = target.ownerDocument; | |
this.document = doc; | |
this.startX = pageX; | |
this.startY = pageY; | |
this.lastNodes = []; | |
var wrapper = doc.createElement('div'); | |
var shield = doc.createElement('div'); | |
var {style} = shield; | |
style.position = 'fixed'; | |
style.left = '0'; | |
style.top = '0'; | |
style.width = '100%'; | |
style.height = '100%'; | |
style.zIndex = '9998'; | |
var overlay = doc.createElement('div'); | |
var {style} = overlay; | |
style.position = 'absolute'; | |
style.MozBoxSizing = 'border-box'; | |
style.boxSizing = 'border-box'; | |
style.border = '1px dotted rgba(0, 0, 0, 0.5)'; | |
style.backgroundColor = 'rgba(0, 127, 255, 0.2)'; | |
style.zIndex = '9999'; | |
wrapper.appendChild(shield); | |
wrapper.appendChild(overlay); | |
this.dom = { | |
wrapper: wrapper, | |
shield: shield, | |
overlay: overlay, | |
}; | |
doc.addEventListener('mouseup', this, true, false); | |
doc.addEventListener('mousemove', this, true, false); | |
} | |
Checkmate.prototype = { | |
constructor: Checkmate, | |
dragging: false, | |
handleEvent: function handleEvent(event) { | |
this[event.type](event); | |
}, | |
mousemove: function onMouseMove({view, pageX, pageY, clientX, clientY}) { | |
var {document: doc, dom: {wrapper, shield, overlay}, startX, startY, padX, padY, lastNodes} = this; | |
var {style} = overlay; | |
var w = pageX - startX; | |
var h = pageY - startY; | |
if (!this.dragging) { | |
if (w * w + h * h < 64) return; | |
style.left = '0'; | |
style.top = '0'; | |
doc.body.appendChild(wrapper); | |
var rect = overlay.getBoundingClientRect(); | |
this.padX = padX = rect.left + view.scrollX; | |
this.padY = padY = rect.top + view.scrollY; | |
this.dragging = true; | |
} | |
var x = startX; | |
var y = startY; | |
if (w < 0) { | |
x += w; | |
w = -w; | |
} | |
if (h < 0) { | |
y += h; | |
h = -h; | |
} | |
style.left = x - padX + 'px'; | |
style.top = y - padY + 'px'; | |
style.width = w + 1 + 'px'; | |
style.height = h + 1 + 'px'; | |
var {clientWidth, clientHeight} = doc.compatMode === 'CSS1Compat' ? doc.documentElement : doc.body; | |
if (clientX < 0) | |
view.scrollBy(clientX, 0); | |
else if (clientWidth < clientX) | |
view.scrollBy(clientX - clientWidth, 0); | |
if (clientY < 0) | |
view.scrollBy(0, clientY); | |
else if (clientHeight < clientY) | |
view.scrollBy(0, clientY - clientHeight); | |
var nodes = this.getNodesFromRect(overlay.getBoundingClientRect()); | |
nodes = Array.filter(nodes, isCheckable); | |
nodes.reverse(); | |
lastNodes.forEach(function(node) { | |
if (nodes.indexOf(node) === -1) | |
clickElement(node); | |
}); | |
nodes.forEach(function(node) { | |
if (lastNodes.indexOf(node) === -1) | |
clickElement(node); | |
}); | |
this.lastNodes = nodes; | |
}, | |
mouseup: function onMouseUp(event) { | |
this.document.removeEventListener('mouseup', this, true); | |
this.document.removeEventListener('mousemove', this, true); | |
this.document.adoptNode(this.dom.wrapper); | |
}, | |
getNodesFromRect: function getNodesFromRect({left, right, top, bottom, width, height}) { | |
var centerX = (left + right) / 2; | |
var centerY = (top + bottom) / 2; | |
var leftSize = width / 2; | |
var topSize = height / 2; | |
return this.document.defaultView | |
.QueryInterface(Ci.nsIInterfaceRequestor) | |
.getInterface(Ci.nsIDOMWindowUtils) | |
.nodesFromRect(centerX, centerY, topSize, leftSize, topSize, leftSize, true, false); | |
}, | |
}; | |
gBrowser.addEventListener('mousedown', function onMouseDown(event) { | |
new Checkmate(event); | |
}, false, false); | |
function isCheckable(node) { | |
return node.localName === 'input' && (node.type === 'checkbox' || node.type === 'radio'); | |
} | |
function clickElement(element) { | |
var event = element.ownerDocument.createEvent('MouseEvent'); | |
event.initMouseEvent('click', true, true, element.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null); | |
return element.dispatchEvent(event); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment