/* Script: Drag.js The base Drag Class. Can be used to drag and resize Elements using mouse events. License: MIT-style license. */ var Drag = new Class({ Implements: [Events, Options], options: {/* onBeforeStart: $empty, onStart: $empty, onDrag: $empty, onCancel: $empty, onComplete: $empty,*/ snap: 6, unit: 'px', grid: false, style: true, limit: false, handle: false, invert: false, preventDefault: false, modifiers: {x: 'left', y: 'top'} }, initialize: function(){ var params = Array.link(arguments, {'options': Object.type, 'element': $defined}); this.element = $(params.element); this.document = this.element.getDocument(); this.setOptions(params.options || {}); var htype = $type(this.options.handle); this.handles = (htype == 'array' || htype == 'collection') ? $$(this.options.handle) : $(this.options.handle) || this.element; this.mouse = {'now': {}, 'pos': {}}; this.value = {'start': {}, 'now': {}}; this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown'; this.bound = { start: this.start.bind(this), check: this.check.bind(this), drag: this.drag.bind(this), stop: this.stop.bind(this), cancel: this.cancel.bind(this), eventStop: $lambda(false) }; this.attach(); }, attach: function(){ this.handles.addEvent('mousedown', this.bound.start); return this; }, detach: function(){ this.handles.removeEvent('mousedown', this.bound.start); return this; }, start: function(event){ if (this.options.preventDefault) event.preventDefault(); this.fireEvent('beforeStart', this.element); this.mouse.start = event.page; var limit = this.options.limit; this.limit = {'x': [], 'y': []}; for (var z in this.options.modifiers){ if (!this.options.modifiers[z]) continue; if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt(); else this.value.now[z] = this.element[this.options.modifiers[z]]; if (this.options.invert) this.value.now[z] *= -1; this.mouse.pos[z] = event.page[z] - this.value.now[z]; if (limit && limit[z]){ for (var i = 2; i--; i){ if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])(); } } } if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid}; this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel}); this.document.addEvent(this.selection, this.bound.eventStop); }, check: function(event){ if (this.options.preventDefault) event.preventDefault(); var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); if (distance > this.options.snap){ this.cancel(); this.document.addEvents({ mousemove: this.bound.drag, mouseup: this.bound.stop }); this.fireEvent('start', this.element).fireEvent('snap', this.element); } }, drag: function(event){ if (this.options.preventDefault) event.preventDefault(); this.mouse.now = event.page; for (var z in this.options.modifiers){ if (!this.options.modifiers[z]) continue; this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; if (this.options.invert) this.value.now[z] *= -1; if (this.options.limit && this.limit[z]){ if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ this.value.now[z] = this.limit[z][1]; } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ this.value.now[z] = this.limit[z][0]; } } if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]); if (this.options.style) this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); else this.element[this.options.modifiers[z]] = this.value.now[z]; } this.fireEvent('drag', this.element); }, cancel: function(event){ this.document.removeEvent('mousemove', this.bound.check); this.document.removeEvent('mouseup', this.bound.cancel); if (event){ this.document.removeEvent(this.selection, this.bound.eventStop); this.fireEvent('cancel', this.element); } }, stop: function(event){ this.document.removeEvent(this.selection, this.bound.eventStop); this.document.removeEvent('mousemove', this.bound.drag); this.document.removeEvent('mouseup', this.bound.stop); if (event) this.fireEvent('complete', this.element); } }); Element.implement({ makeResizable: function(options){ return new Drag(this, $merge({modifiers: {'x': 'width', 'y': 'height'}}, options)); } });