$ SelectElement

module to easily select any element on a page.

by Laurens Maneschijn

HTML

<div>
	oneliner for testing as bookmarklet on any website:<br>
	(as long as jQuery >= 1.7 is loaded there)<br>
	<textarea>javascript:(function(f,e,c){function r(){h&&f.console&&f.console.log&&f.console.log.apply(f.console,[].slice.call(arguments))}function g(a){var d={type:a,elements:b.elements,start_element:b.elements[0],selected_element:b.elements[b.element_i]};r("SelectElement trigger event: "+a,d);c(e).trigger("selectelement"+a,d);c(e).trigger("selectelement",d)}function k(a){a=Math.max(-1,a);a=Math.min(1,a);a=Math.round(a);var c=b.element_i;b.element_i+=a;b.element_i=Math.max(b.element_i,0);b.element_i=Math.min(b.element_i, b.elements.length-1);c!=b.element_i&&g("change");l()}function n(){c("style#style_selectelement").remove();var a=c("<style>",{id:"style_selectelement"});a.appendTo(c("head,body").eq(0));a.append(".selectelement_target { outline: 2px dashed rgba(255,0,255,1 )!important; background: rgba(255,0,255, 0.5); }");a.append(".selectelement_targetparent { outline: 1px dashed rgba(255,0,200,0.5)!important; background: rgba(255,0,200, 0.1); }");a.append(".selectelement_targetchild { outline: 1px dashed rgba(200,0,255,0.5)!important; background: rgba(200,0,255, 0.1); }"); c(e.body).off(".selectelementinternal");c(e.body).on("click.selectelementinternal",t);c(e.body).on("keyup.selectelementinternal",u);c(e.body).on("mousewheel.selectelementinternal",v)}function t(a){b.selector_active?(a.preventDefault(),a.stopImmediatePropagation(),g("selected"),m()):h&&a.ctrlKey&&a.altKey&&(a.preventDefault(),a.stopImmediatePropagation(),p(a.target))}function u(a){b.selector_active&&(27==a.which?(a.preventDefault(),a.stopImmediatePropagation(),q()):13==a.which?(a.preventDefault(), a.stopImmediatePropagation(),g("selected"),m()):38==a.which?(a.preventDefault(),a.stopImmediatePropagation(),k(1)):40==a.which&&(a.preventDefault(),a.stopImmediatePropagation(),k(-1)))}function v(a){if(b.selector_active){a.preventDefault();a.stopImmediatePropagation();var...

CSS

.demo, .demo div {
	display: inline-block;
	margin: 4px;
	padding: 4px;
	border: 1px dotted #888;
}
.demo table tbody tr td { border: 1px dotted #888; }

JavaScript

(function(window, document, $){
	if(!$ || !$.fn.on){return alert('missing $ or $.fn.on');}
	// triggers events on document:
	// 'selectelementstart.selectelement'
	// 'selectelementchange.selectelement'
	// 'selectelementcancel.selectelement'
	// 'selectelementselected.selectelement'
	// private static data:
	var eventnameprepend = 'selectelement';
	var debug = false;
	var data = {
		selector_active: false,
		elements: [],
		element_i: null,
	};
	
	function log(){
		if(debug && window.console && window.console.log){
			window.console.log.apply(window.console, [].slice.call(arguments));
		}
	}
	function trigger(name, data){
		// TODO: trigger on document? or document.body? or ... ?
		$(document).trigger(eventnameprepend + name, data);
		$(document).trigger(eventnameprepend, data);
	}
	function triggerType(eventtype){
		// NB: call BEFORE calling reset() so data is still there.
		var eventdata = {
			type: eventtype,
			elements: data.elements,
			start_element: data.elements[0],
			selected_element: data.elements[data.element_i]
		}
		log('SelectElement trigger event: ' + eventtype, eventdata);
		trigger(eventtype, eventdata);
	}
	function triggerStart(){
		triggerType('start');
	}
	function triggerCancel(){
		triggerType('cancel');
	}
	function triggerChange(){
		triggerType('change');
	}
	function triggerSelected(){
		triggerType('selected');
	}
	
	function selectN(n){
		var prev = data.element_i;
		data.element_i = n;
		data.element_i = Math.max(data.element_i, 0);
		data.element_i = Math.min(data.element_i, data.elements.length - 1);
		if(prev != data.element_i){
			triggerChange();
		}
		DisplayUpdate();
	}
	function selectDiffN(d){
		// never hop more that 1 up/down the parent-child chain,
		// normalize to -1,0,1:
		d = Math.max(-1, d);
		d = Math.min(+1, d);
		d = Math.round(d);
		selectN(data.element_i + d);
	}
	
	function init(){
		setupcss();
		$(document.body).off('.selectelementinternal');
		$(document.body).on('click.selectelementinternal',...