{"action":"opened","issue":{"url":"https://api.github.com/repos/SpeedyShortcutJS/SpeedyShortcut.js/issues/18","labels_url":"https://api.github.com/repos/SpeedyShortcutJS/SpeedyShortcut.js/issues/18/labels{/name}","comments_url":"https://api.github.com/repos/SpeedyShortcutJS/SpeedyShortcut.js/issues/18/comments","events_url":"https://api.github.com/repos/SpeedyShortcutJS/SpeedyShortcut.js/issues/18/events","html_url":"https://github.com/SpeedyShortcutJS/SpeedyShortcut.js/issues/18","id":115987271,"number":18,"title":"RectangleSelection.js","user":{"login":"jnbdz","id":237008,"avatar_url":"https://avatars.githubusercontent.com/u/237008?v=3","gravatar_id":"","url":"https://api.github.com/users/jnbdz","html_url":"https://github.com/jnbdz","followers_url":"https://api.github.com/users/jnbdz/followers","following_url":"https://api.github.com/users/jnbdz/following{/other_user}","gists_url":"https://api.github.com/users/jnbdz/gists{/gist_id}","starred_url":"https://api.github.com/users/jnbdz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jnbdz/subscriptions","organizations_url":"https://api.github.com/users/jnbdz/orgs","repos_url":"https://api.github.com/users/jnbdz/repos","events_url":"https://api.github.com/users/jnbdz/events{/privacy}","received_events_url":"https://api.github.com/users/jnbdz/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/SpeedyShortcutJS/SpeedyShortcut.js/labels/Proposal","name":"Proposal","color":"0052cc"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-11-09T23:00:26Z","updated_at":"2015-11-09T23:00:26Z","closed_at":null,"body":"/*\r\n---\r\ndescription: RectangleSelection utility makes it easy to select multiple elements on a page with a mouse.\r\n\r\nauthors:\r\n  - Jean-Nicolas Boulay (http://jean-nicolas.com/)\r\n\r\nlicense:\r\n  - MIT-style license\r\n\r\nrequires:\r\n - core/1.4\r\n - More:/Element.Measure\r\n - Element.Collide/0.5\r\n\r\nprovides:\r\n  - RectangleSelection\r\n...\r\n*/\r\n\r\nvar RectangleSelection = new Class({\r\n\r\n    Implements: [Options, Events],\r\n    \r\n    options: {/*\r\n        onAttach: function(thisSelectionRectangleEl){},\r\n        onDetach: function(){},\r\n        onDisplay: function(thisPoy, thisPox){},\r\n        onSelection: function(thisMy, thisMx, thisHeight, thisWidth, thisPtop, thisPleft){},\r\n        onSelected: function(thisSelectionRectangleEl){},\r\n        onLeave: function(thisSelectionRectangleEl, thisSelectables, thisOvered){},\r\n        onEnter: function(thisSelectionRectangleEl, thisSelectables, overed){},\r\n        onDeselect: function(){},\r\n        */\r\n        container: null,\r\n        className: 'selection-rectangle',\r\n        fadeOut: true,\r\n        selectionMethod: 'collide'\r\n    },\r\n\r\n    initialize: function(selectables, options) {\r\n    \r\n        this.setOptions(options || {});\r\n        \r\n        this.selectables = $$(selectables);\r\n        this.container = document.id(this.options.container);\r\n        \r\n        if (this.container && typeOf(this.container) != 'element')\r\n                this.container = document.id(this.container.getDocument().body);\r\n        \r\n        this.bound = {\r\n                start: this.start.bind(this),\r\n                drag: this.drag.bind(this),\r\n                stop: this.stop.bind(this),\r\n                select: this.select.bind(this),\r\n                deselect: this.deselect.bind(this)\r\n        };\r\n        \r\n        this.attach();\r\n        \r\n        this.addEvent('selection', this.bound.select, true);\r\n    },\r\n    \r\n    attach: function(){\r\n    \r\n        this.pox = null;\r\n        this.poy = null;\r\n        this.ptop = null;\r\n        this.pleft = null;\r\n        this.height = null;\r\n        this.width = null;\r\n        this.newSelector = true;\r\n        this.mousedown = false;\r\n        this.periodicalRectChange = null;\r\n        \r\n        this.selectionRectangleEl = new Element('div', {\r\n            'display': 'none',\r\n            'position': 'absolute',\r\n            'class': this.options.className\r\n        }).inject(this.container);\r\n    \r\n        this.document = this.selectionRectangleEl.getDocument();\r\n        \r\n        this.opacity = this.selectionRectangleEl.getStyle('opacity');\r\n        \r\n        this.tween = this.selectionRectangleEl.get('tween');\r\n\r\n        this.document.addEvents({\r\n            'mousedown': this.bound.start,\r\n            'mousemove': this.bound.drag,\r\n            'mousewheel': this.bound.drag,\r\n            'mouseup': this.bound.stop\r\n        });\r\n\r\n        this.selectables.addEvent('mousedown', function(e){\r\n            e.stopPropagation();\r\n        });\r\n \r\n        this.fireEvent('attach', [this.selectionRectangleEl]);\r\n        \r\n        return this;\r\n        \r\n    },\r\n    \r\n    detach: function(){\r\n        this.selectionRectangleEl.dispose();\r\n        this.fireEvent('detach');\r\n        return this;\r\n    },\r\n\r\n    start: function(e) {\r\n        this.deselect();\r\n        \r\n        var target = document.id(e.target);\r\n        if (!target.match(this.container) && !target.match(this.selectionRectangleEl)) return;\r\n        e.stop();\r\n        if (e.rightClick) return;\r\n        \r\n        this.addScrollY = 0;\r\n        this.addScrollX = 0;\r\n        this.poy = e.page.y;\r\n        this.pox = e.page.x;\r\n        this.mousedown = true;\r\n        this.newSelector = false;\r\n\r\n        this.tween.stop();\r\n\r\n        this.selectionRectangleEl.setStyles({\r\n            'display': 'block',\r\n            'height': 0,\r\n            'width': 0,\r\n            'top': this.poy,\r\n            'left': this.pox,\r\n            'opacity': this.opacity,\r\n            'filter': 'alpha(opacity=' + this.opacity + ')'\r\n        });\r\n        \r\n        this.element = this.selectionRectangleEl;\r\n        \r\n        this.limits = this.calculateLimit();\r\n\r\n        this.fireEvent('display', [this.poy, this.pox]);\r\n    \r\n    },\r\n\r\n    resizeRectangle: function(e) {\r\n\r\n        var mx = e.page.x,\r\n            my = e.page.y;\r\n\r\n        if(this.scrollToX != 0 || this.scrollToY != 0) {\r\n        \r\n            var rectSelHeight = this.selectionRectangleEl.getStyle('height').toInt();\r\n            this.winScroll = window.getScroll();\r\n            this.winScrollY = this.winScroll.y;\r\n            this.winScrollX = this.winScroll.x;\r\n            this.toScrollToX = this.winScrollX + this.scrollToX;\r\n            this.toScrollToY = this.winScrollY + this.scrollToY;\r\n            \r\n            this.toScrollToX = (this.toScrollToX >= 0) ? this.toScrollToX : 0;\r\n            this.toScrollToY = (this.toScrollToY >= 0) ? this.toScrollToY : 0;\r\n\r\n            if((this.winScrollY <= 8 && this.scrollToY < 0) ||\r\n                (((this.winSizeY + this.winScrollY) == this.scrollSize.y) && this.scrollToY > 0) ||\r\n                (this.winScrollX <= 8 && this.scrollToX < 0) ||\r\n                (((this.winSizeX + this.winScrollX) == this.scrollSize.x) && this.scrollToX > 0)\r\n            ) {\r\n                clearInterval(this.periodicalRectChange);\r\n            } else {\r\n                window.scrollTo(this.toScrollToX, this.toScrollToY);\r\n            }\r\n            \r\n            my = my + this.toScrollToY - this.toRemoveY;\r\n            mx = mx + this.toScrollToX - this.toRemoveX;\r\n            \r\n        }\r\n        \r\n        mx = (mx >= this.limits['left']) ? mx : this.limits['left'];\r\n        mx = (mx <= this.limits['right']) ? mx : this.limits['right'];\r\n        my = (my >= this.limits['top']) ? my : this.limits['top'];\r\n        my = (my <= this.limits['bottom']) ? my : this.limits['bottom'];\r\n        \r\n        if (mx >= this.limits['left'] && mx <= this.limits['right']) {\r\n            if (this.pox < mx) {\r\n                this.width = (mx - this.pox).abs();\r\n                this.pleft = this.pox;\r\n            } else {\r\n                this.width = (mx - this.pox).abs();\r\n                this.pleft = mx;\r\n            }\r\n        }\r\n        \r\n        if (my >= this.limits['top'] && my <= this.limits['bottom']) {\r\n            if (this.poy < my) {\r\n                this.height = (my - this.poy).abs();\r\n                this.ptop = this.poy;\r\n            } else {\r\n                this.height = (my - this.poy).abs();\r\n                this.ptop = my;\r\n            }\r\n        }\r\n        \r\n        this.selectionRectangleEl.setStyles({\r\n            height: this.height,\r\n            width: this.width,\r\n            top: this.ptop,\r\n            left: this.pleft\r\n        });\r\n        \r\n        this.fireEvent('selection', [my, mx, this.height, this.width, this.ptop, this.pleft]);\r\n\r\n    },\r\n\r\n    drag: function(e){\r\n\r\n        if (this.mousedown) {\r\n            \r\n            clearInterval(this.periodicalRectChange);\r\n            \r\n            this.scrollSize = window.getScrollSize();\r\n            this.winSize = window.getSize();\r\n            this.winSizeY = this.winSize.y;\r\n            this.winSizeX = this.winSize.x;\r\n            var getScroll = window.getScroll();\r\n            this.toRemoveY = getScroll.y;\r\n            this.toRemoveX = getScroll.x;\r\n            this.clientY = e.client.y;\r\n            this.clientX = e.client.x;\r\n            this.scrollToX = 0;\r\n            this.scrollToY = 0;\r\n            this.toScrollToX = 0;\r\n            this.toScrollToY = 0;\r\n\r\n            // For the Bottom\r\n            if ((this.winSizeY - 5).abs() < this.clientY) {\r\n                this.scrollToY = 30;\r\n            } else if((this.winSizeY - 10).abs() < this.clientY) {\r\n                this.scrollToY = 20;\r\n            } else if((this.winSizeY - 20).abs() < this.clientY) {\r\n                this.scrollToY = 10;\r\n            }\r\n            // For the Top\r\n            else if(5 > this.clientY) {\r\n                this.scrollToY = -30;\r\n            } else if(10 > this.clientY) {\r\n                this.scrollToY = -20;\r\n            } else if(20 > this.clientY) {\r\n                this.scrollToY = -10;\r\n            }\r\n\r\n            // For the Right\r\n            if ((this.winSizeX - 5).abs() < this.clientX) {\r\n                this.scrollToX = 30;\r\n            } else if((this.winSizeX - 10).abs() < this.clientX) {\r\n                this.scrollToX = 20;\r\n            } else if((this.winSizeX - 20).abs() < this.clientX) {\r\n                this.scrollToX = 10;\r\n            }\r\n            // For the Left\r\n            else if(5 > this.clientX) {\r\n                this.scrollToX = -30;\r\n            } else if(10 > this.clientX) {\r\n                this.scrollToX = -20;\r\n            } else if(20 > this.clientX) {\r\n                this.scrollToX = -10;\r\n            }\r\n\r\n            if(this.scrollToX != 0 || this.scrollToY != 0) {\r\n                this.periodicalRectChange = this.resizeRectangle.periodical(10, this, e);\r\n            } else {\r\n                this.resizeRectangle(e);\r\n            }\r\n            \r\n        }\r\n\r\n    },\r\n\r\n    stop: function(e){\r\n    \r\n        clearInterval(this.periodicalRectChange);\r\n        this.mousedown = false;\r\n        if(!this.options.fadeOut){\r\n                    \r\n            this.selectionRectangleEl.setStyle('display', 'none');\r\n            \r\n            this.fireEvent('selected', [this.selectionRectangleEl]);\r\n            return;\r\n        }\r\n\r\n        this.tween.start('opacity', 0);\r\n        this.tween.chain(function() {\r\n            this.selectionRectangleEl.setStyle('display', 'none');\r\n            this.fireEvent('selected', [this.selectionRectangleEl]);\r\n        }.bind(this));\r\n    \r\n    },\r\n    \r\n    select: function(){\r\n            \r\n\t\t\tvar overed = this.selectables.filter(function(el, i){\r\n                return el[this.options.selectionMethod](this.selectionRectangleEl);\r\n\t\t\t}, this);\r\n\r\n\t\t\tif (this.overed != overed){\r\n\t\t\t\tif (this.overed) this.fireEvent('leave', [this.selectionRectangleEl, this.selectables, this.overed]);\r\n\t\t\t\tif (overed) this.fireEvent('enter', [this.selectionRectangleEl, this.selectables, overed]);\r\n\t\t\t\tthis.overed = overed;\r\n\t\t\t}\r\n\r\n    },\r\n    \r\n    deselect: function(){\r\n            this.fireEvent('deselect', [this.selectables]);\r\n    },\r\n    \r\n    calculateLimit: function(){\r\n        var container = this.container,\r\n            selRectEl = this.selectionRectangleEl,\r\n            borderTop = selRectEl.getStyle('border-top').toInt(),\r\n            borderLeft = selRectEl.getStyle('border-left').toInt(),\r\n            coors = container.getCoordinates();\r\n\r\n        coors['top'] += borderTop;\r\n        coors['left'] += borderLeft;\r\n        coors['bottom'] -= selRectEl.getStyle('border-bottom').toInt() + borderTop;\r\n        coors['right'] -= selRectEl.getStyle('border-right').toInt() + borderLeft;\r\n        \r\n        return coors;\r\n    }\r\n\r\n});"}}