/* RubberbandSelector version 0.1 * (c) 2007 Stanislav Müller * * RubberbandSelector is freely distributable under the terms of an MIT-style license. * /*--------------------------------------------------------------------------*/ Number.prototype.between = function(first, second){ return this >= first && this <= second; }; var RubberbandSelector = Class.create(); RubberbandSelector.prototype = { initialize: function(options){ this.lastMouseCoordinates = { x: 0, y: 0 }; var body = this.body = { element: $$("body")[0] } Object.extend(this.options, options); this.options.selectIn = $$(this.options.selectInSelector)[0]; this.enable(); return this; }, options: { scrollSensitivity: (window.innerHeight || document.documentElement.clientHeight)/4, afterSelectElement: function(element){}, afterDeselectElement: function(element){}, beforeSelect: function(event){}, afterSelect: function(event){}, elementsSelector: ".selectable", selectInSelector: "body" }, addSelected: function(element){ element.className = "selectable selected"; }, removeSelected: function(element){ element.className = "selectable"; }, selectElements: function(event){ if(typeof(this.selector) != "undefined"){ selector_coordinates = this.getCoordinates(this.selector); this.selectableCoordinates.each(function(elm){ with(elm){ if(this.__overlay(elm, selector_coordinates)){ if(this.addSelection && selected){ this.removeSelected(element); this.options.afterDeselectElement(element); }else{ this.addSelected(element); this.options.afterSelectElement(element); } }else if(this.addSelection && selected){ this.addSelected(element); this.options.afterSelectElement(element); }else{ this.removeSelected(element); element.className = element.className.substr() this.options.afterDeselectElement(element); } } }.bind(this)); }; }, __overlay: function(elm, selector_coordinates){ return ( ( (elm.lt.x.between(selector_coordinates.lt.x, selector_coordinates.rt.x)) || (selector_coordinates.lt.x.between(elm.lt.x, elm.rt.x)) ) && ( (elm.lt.y.between(selector_coordinates.lt.y, selector_coordinates.lb.y)) || (selector_coordinates.lt.y.between(elm.lt.y, elm.lb.y)) ) ); }, enableSelection: function(){ element = this.body.element; with(Prototype.Browser){ if(Gecko){ element.style.MozUserSelect = ""; }else if(WebKit){ element.style.KhtmlUserSelect = ""; }else if(IE){ element.unselectable = "off"; element.onselectstart = function() { return true; }; }else{ return false; } } return true; }, disableSelection: function(){ http://openjsan.org/doc/j/jc/jcap/Dojo/common/0.4.1/lib/src/html/selection.html if(window.getSelection){ if(Prototype.Browser.WebKit){ // pulled from WebCore/ecma/kjs_window.cpp, line 2536 window.getSelection().collapse(); }else{ window.getSelection().removeAllRanges(); } }else if(document.selection){ if(document.selection.empty){ document.selection.empty(); }else if(document.selection.clear){ document.selection.clear(); } } element = this.body.element; with(Prototype.Browser){ if(Gecko){ element.style.MozUserSelect = "none"; }else if(WebKit){ element.style.KhtmlUserSelect = "none"; }else if(IE){ element.unselectable = "on"; element.onselectstart = function() { return false; }; } } }, startScroll: function(event){ var mousePosition = this.getCurrentMousePosition(event); this.event = { pageX: mousePosition.x, pageY: mousePosition.y }; this.scrollWindow(); if(this.interval){ clearInterval(this.interval); delete this.interval; } this.interval = setInterval(this.scrollWindow.bind(this, this.event, true), 150); }, scrollWindow: function(){ var event = arguments[0] || this.event; Position.prepare(); var windowHeight = window.innerHeight || document.documentElement.clientHeight; var pageYOffset = Position.deltaY; var pageHeight = document.height || window.height || document.body.scrollHeight; var pageBottomY = pageYOffset + windowHeight; var pageBottomQuarterY = pageBottomY - this.options.scrollSensitivity; var pageTopY = pageYOffset; var pageTopQuarterY = pageTopY + this.options.scrollSensitivity; if(event.pageY.between(pageTopY, pageTopQuarterY) && (event.pageY <= this.lastMouseCoordinates.y || arguments[1])){ var step = this.scrollStep(event.pageY, pageTopQuarterY); if(event.pageY - this.options.scrollSensitivity > 0){ window.scrollTo(false, pageYOffset - step); this.event.pageY = event.pageY - step; }else{ window.scrollTo(false, 0); } }else if(event.pageY.between(pageBottomQuarterY, pageBottomY) && (event.pageY >= this.lastMouseCoordinates.y || arguments[1])){ var step = this.scrollStep(pageBottomQuarterY, event.pageY); if(pageBottomY + step < pageHeight){ window.scrollTo(false, pageBottomY + step - windowHeight); this.event.pageY = event.pageY + step; }else{ window.scrollTo(false, (pageHeight - windowHeight) + this.options.scrollSensitivity); } } arguments[1] ? this.mousemove(event, true) : ""; this.lastMouseCoordinates = { x: event.pageX, y: event.pageY }; }, scrollStep: function(upperPoint, pointer){ return pointer - upperPoint; }, getCurrentMousePosition: function(event, interval){ var pointerX = Event.pointerX(event); var pointerY = Event.pointerY(event); return { x: pointerX, y: pointerY } }, getStye: function(event, isMoving){ var mousePosition = isMoving ? { x: Event.pointerX(event), y: Event.pointerY(event) } : this.getCurrentMousePosition(event); var L, T, W, H, pointerX = mousePosition.x, pointerY = mousePosition.y; W = (pointerX - this.startCoordinates.x) + "px"; H = (pointerY - this.startCoordinates.y) + "px"; T = this.startCoordinates.y+"px"; L = this.startCoordinates.x+"px"; if(this.startCoordinates.x - pointerX > 0){ W = this.startCoordinates.x - pointerX + "px"; L = (pointerX) + "px"; } if(this.startCoordinates.y - pointerY > 0){ H = this.startCoordinates.y - pointerY + "px"; T = (pointerY) + "px"; } return { top: T, left: L, width: W, height: H }; }, getCoordinates: function(elm){ var position = Position.positionedOffset(elm); var dimensions = elm.getDimensions(); return { lb : { x: position[0], y: position[1] + dimensions.height }, lt : { x: position[0], y: position[1] }, rt : { x: position[0] + dimensions.width, y: position[1]}, rb : { x: position[0] + dimensions.width, y: position[1] + dimensions.height}, element: elm, selected: /selected/.test(elm.className) }; }, findSelectablesCoordinates: function(){ this.selectableCoordinates = []; $$(this.options.elementsSelector).each(function(selectable){ this.selectableCoordinates.push(this.getCoordinates(selectable)); }.bind(this)); return this.selectableCoordinates; }, createSelector: function(){ var selector = $("rubberbandSelector"); if(!selector){ var selector = document.createElement("div"); selector.id = "rubberbandSelector"; this.body.element.appendChild(selector); } this.selector = $(selector); Position.absolutize(this.selector); this.selector.setOpacity(0.5); return this.selector; }, setStartMousePosition: function(event){ var mousePosition = this.getCurrentMousePosition(event); this.startCoordinates = { x: mousePosition.x, y: mousePosition.y } return this.startCoordinates; }, getAllSelectedElements: function(){ var selectedElements = []; this.findSelectablesCoordinates().each(function(element){ if(element.selected){ selectedElements.push(element.element); } }); return selectedElements; }, // EVENTS mousedown: function(event) { this.options.beforeSelect(event); this.disableSelection(); this.setStartMousePosition(event); this.findSelectablesCoordinates(); this.createSelector(); this.keyevents(event); this.move(event); Event.stop(event); Event.observe(document, 'mousemove', this.move); }, mousemove: function(event, isScolling){ if(!this.selector){ return this.mouseup(event); } this.selector.setStyle(this.getStye(event, isScolling)); if(!isScolling) this.startScroll(event); this.selectElements(event); }, mouseup: function(event){ try{ this.selector.remove(); delete this.selector; clearInterval(this.interval); delete this.interval; }catch(e){} this.enableSelection(); this.keyevents(event); Event.stopObserving(document, 'mousemove', this.move); this.options.afterSelect(event); }, keyevents: function(event){ this.addSelection = event.shiftKey ? true : false; }, enable: function(){ this.down = this.mousedown.bindAsEventListener(this); this.move = this.mousemove.bindAsEventListener(this); this.up = this.mouseup.bindAsEventListener(this); Event.observe(this.options.selectIn, 'mousedown', this.down); Event.observe(document, 'mouseup', this.up); }, disable: function(){ Event.stopObserving(this.options.selectIn, 'mousedown', this.down); } };