Skip to content

Instantly share code, notes, and snippets.

@xulapp
Created July 6, 2011 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save xulapp/1067352 to your computer and use it in GitHub Desktop.
Save xulapp/1067352 to your computer and use it in GitHub Desktop.
checkmate.uc.js
// ==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