rails/app/assets/javascripts/livepipe/resizable.js
// script.aculo.us Resizables.js
// Copyright(c) 2007 - Orr Siloni, Comet Information Systems http://www.comet.co.il/en/
//
// Resizable.js is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
var Resizables = {
instances: [],
observers: [],
register: function(resizable) {
if(this.instances.length == 0) {
this.eventMouseUp = this.endResize.bindAsEventListener(this);
this.eventMouseMove = this.updateResize.bindAsEventListener(this);
Event.observe(document, "mouseup", this.eventMouseUp);
Event.observe(document, "mousemove", this.eventMouseMove);
}
this.instances.push(resizable);
},
unregister: function(resizable) {
this.instances = this.instances.reject(function(d) { return d==resizable });
if(this.instances.length == 0) {
Event.stopObserving(document, "mouseup", this.eventMouseUp);
Event.stopObserving(document, "mousemove", this.eventMouseMove);
}
},
activate: function(resizable) {
if(resizable.options.delay) {
this._timeout = setTimeout(function() {
Resizables._timeout = null;
Resizables.activeResizable = resizable;
}.bind(this), resizable.options.delay);
} else {
this.activeResizable = resizable;
}
},
deactivate: function() {
this.activeResizable = null;
},
updateResize: function(event) {
if(!this.activeResizable) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
// Mozilla-based browsers fire successive mousemove events with
// the same coordinates, prevent needless redrawing (moz bug?)
if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
this._lastPointer = pointer;
this.activeResizable.updateResize(event, pointer);
},
endResize: function(event) {
if(this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
if(!this.activeResizable) return;
this._lastPointer = null;
this.activeResizable.endResize(event);
this.activeResizable = null;
},
addObserver: function(observer) {
this.observers.push(observer);
this._cacheObserverCallbacks();
},
removeObserver: function(element) { // element instead of observer fixes mem leaks
this.observers = this.observers.reject( function(o) { return o.element==element });
this._cacheObserverCallbacks();
},
notify: function(eventName, resizable, event) { // 'onStart', 'onEnd', 'onResize'
if(this[eventName+'Count'] > 0)
this.observers.each( function(o) {
if(o[eventName]) o[eventName](eventName, resizable, event);
});
if(resizable.options[eventName]) resizable.options[eventName](resizable, event);
},
_cacheObserverCallbacks: function() {
['onStart','onEnd','onResize'].each( function(eventName) {
Resizables[eventName+'Count'] = Resizables.observers.select(
function(o) { return o[eventName]; }
).length;
});
}
}
var Resizable = Class.create();
Resizable._resizing = {};
Resizable.prototype = {
initialize: function(element){
var defaults = {
handle: false,
snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
delay: 0,
minHeight: false,
minwidth: false,
maxHeight: false,
maxWidth: false
}
this.element = $(element);
var options = Object.extend(defaults, arguments[1] || {});
if(options.handle && typeof options.handle == 'string')
this.handle = $(options.handle);
else if(options.handle)
this.handle = options.handle;
if(!this.handle) this.handle = this.element;
this.options = options;
this.dragging = false;
this.eventMouseDown = this.initResize.bindAsEventListener(this);
Event.observe(this.handle, "mousedown", this.eventMouseDown);
Resizables.register(this);
},
destroy: function() {
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
},
currentDelta: function() {
return([
parseInt(Element.getStyle(this.element,'width') || '0'),
parseInt(Element.getStyle(this.element,'height') || '0')]);
},
initResize: function(event) {
if(typeof Resizable._resizing[this.element] != 'undefined' &&
Resizable._resizing[this.element]) return;
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if((tag_name = src.tagName.toUpperCase()) && (
tag_name=='INPUT' || tag_name=='SELECT' || tag_name=='OPTION' ||
tag_name=='BUTTON' || tag_name=='TEXTAREA')) return;
this.pointer = [Event.pointerX(event), Event.pointerY(event)];
this.size = [parseInt(this.element.getStyle('width')) || 0, parseInt(this.element.getStyle('height')) || 0];
Resizables.activate(this);
Event.stop(event);
}
},
startResize: function(event) {
this.resizing = true;
if(this.options.zindex) {
this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
this.element.style.zIndex = this.options.zindex;
}
Resizables.notify('onStart', this, event);
Resizable._resizing[this.element] = true;
},
updateResize: function(event, pointer) {
if(!this.resizing) this.startResize(event);
Resizables.notify('onResize', this, event);
this.draw(pointer);
if(this.options.change) this.options.change(this);
// fix AppleWebKit rendering
if(Prototype.Browser.WebKit) window.scrollBy(0,0);
Event.stop(event);
},
finishResize: function(event, success) {
this.resizing = false;
Resizables.notify('onEnd', this, event);
if(this.options.zindex) this.element.style.zIndex = this.originalZ;
Resizable._resizing[this.element] = false;
Resizables.deactivate(this);
},
endResize: function(event) {
if(!this.resizing) return;
this.finishResize(event, true);
Event.stop(event);
},
draw: function(point) {
var p = [0,1].map(function(i){
return (this.size[i] + point[i] - this.pointer[i]);
}.bind(this));
if(this.options.snap) {
if(typeof this.options.snap == 'function') {
p = this.options.snap(p[0],p[1],this);
} else {
if(this.options.snap instanceof Array) {
p = p.map( function(v, i) {
return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
} else {
p = p.map( function(v) {
return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
}
}}
var minWidth = (typeof(this.options.minWidth) == 'function') ? this.options.minWidth(this.element) : this.options.minWidth;
var maxWidth = (typeof(this.options.maxWidth) == 'function') ? this.options.maxWidth(this.element) : this.options.maxWidth;
var minHeight = (typeof(this.options.minHeight) == 'function') ? this.options.minHeight(this.element) : this.options.minHeight;
var maxHeight = (typeof(this.options.maxHeight) == 'function') ? this.options.maxHeight(this.element) : this.options.maxHeight;
if (minWidth && p[0] <= minWidth) p[0] = minWidth;
if (maxWidth && p[0] >= maxWidth) p[0] = maxWidth;
if (minHeight && p[1] <= minHeight) p[1] = minHeight;
if (maxHeight && p[1] >= maxHeight) p[1] = maxHeight;
var style = this.element.style;
if((!this.options.constraint) || (this.options.constraint=='horizontal')){
style.width = p[0] + "px";
}
if((!this.options.constraint) || (this.options.constraint=='vertical')){
style.height = p[1] + "px";
}
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
}
};