// vim: et:ts=4:sw=4:sts=4:ft=js // check out http://ejohn.org/apps/learn/#36 (-#38, making fns work w/o new) Ox.Element = function() { /*** Basic element object ***/ /* tooltip option can be any of the following: string function(e), returns string {mousemove: true, title: function(e)} */ return function(options, self) { if (!(this instanceof arguments.callee)) { return new arguments.callee(options, self); } self = self || {}; self.options = options || {}; // allow for Ox.Element('tagname', self) if (typeof self.options == 'string') { self.options = { element: self.options }; } if (!self.$eventHandler) { self.$eventHandler = $('
'); } var that = new Ox.JQueryElement( $('<' + (self.options.element || 'div') + '>') ) .mousedown(mousedown); /* self.options.tooltip && that.bind(Ox.extend({ mouseenter: mouseenter, mouseleave: mouseleave }, self.options.tooltip.mousemove ? { mousemove: mousemove } : {})); */ function mousedown(e) { /* better mouse events mousedown: trigger mousedown within 250 msec: mouseup: trigger anyclick ("click" would collide with click events of certain widgets) mouseup + mousedown: trigger doubleclick after 250 msec: mouseup + no mousedown within 250 msec: trigger singleclick no mouseup within 250 msec: trigger mouserepeat every 50 msec trigger dragstart mousemove: trigger drag no mousemove within 250 msec: trigger dragpause mouseup: trigger dragend */ var clientX, clientY, dragTimeout = 0, mouseInterval = 0; if (!self.mouseTimeout) { // first mousedown that.triggerEvent('mousedown', e); self.mouseup = false; self.mouseTimeout = setTimeout(function() { self.mouseTimeout = 0; if (self.mouseup) { // singleclick that.triggerEvent('singleclick', e); } else { // mouserepeat, drag clientX = e.clientX; clientY = e.clientY; that.triggerEvent('dragstart', e); mouserepeat(); mouseInterval = setInterval(mouserepeat, 50); Ox.UI.$window.unbind('mouseup', mouseup) .mousemove(mousemove) .one('mouseup', function(e) { clearInterval(mouseInterval); clearTimeout(dragTimeout); Ox.UI.$window.unbind('mousemove', mousemove); that.triggerEvent('dragend', extend(e)); }); that.one('mouseleave', function() { clearInterval(mouseInterval); }); } }, 250); } else { // second mousedown clearTimeout(self.mouseTimeout); self.mouseTimeout = 0; that.triggerEvent('doubleclick', e); } Ox.UI.$window.one('mouseup', mouseup); function extend(e) { return Ox.extend({ clientDX: e.clientX - clientX, clientDY: e.clientY - clientY }, e); } function mousemove(e) { e = extend(e); clearTimeout(dragTimeout); dragTimeout = setTimeout(function() { that.triggerEvent('dragpause', e); }, 250); that.triggerEvent('drag', e); } function mouserepeat() { that.triggerEvent('mouserepeat'); } function mouseup(e) { // only trigger on firse mouseup if (!self.mouseup) { that.triggerEvent('anyclick', e); self.mouseup = true; } } } /* function mouseenter(e) { self.$tooltip = new Ox.Tooltip({ title: Ox.isString(self.options.tooltip) ? self.options.tooltip : Ox.isFunction(self.options.tooltip) ? self.options.tooltip(e) : self.options.tooltip.title(e) }).show(); } function mouseleave(e) { self.$tooltip.hide(); } function mousemove(e) { self.$tooltip.options({ title: self.options.tooltip.title(e) }); } */ self.onChange = function() { // self.onChange(key, value) // is called when an option changes // (to be implemented by widget) // fixme: rename to self.setOption }; that._leakSelf = function() { // fixme: remove return self; } that.bindEvent = function() { /*** binds a function to an event triggered by this object Usage bindEvent(event, fn) or bindEvent({event0: fn0, event1: fn1, ...}) ***/ if (arguments.length == 1) { Ox.forEach(arguments[0], function(fn, event) { // Ox.print(that.id, 'bind', event); self.$eventHandler.bind('ox_' + event, fn); }); } else { // Ox.print(that.id, 'bind', arguments[0]); self.$eventHandler.bind('ox_' + arguments[0], arguments[1]); } return that; } that.bindEventOnce = function() { if (arguments.length == 1) { Ox.forEach(arguments[0], function(fn, event) { self.$eventHandler.one('ox_' + event, fn); }); } else { self.$eventHandler.one('ox_' + arguments[0], arguments[1]); } return that; }; that.defaults = function(defaults) { /*** sets the default options Usage that.defaults({key0: value0, key1: value1, ...}) ***/ self.defaults = defaults; delete self.options; // fixme: hackish fix for that = Ox.Foo({...}, self).defaults({...}).options({...}) return that; }; that.gainFocus = function() { /*** make this object gain focus ***/ Ox.Focus.focus(that.id); return that; }; that.hasFocus = function() { /*** returns true if this object has focus ***/ return Ox.Focus.focused() == that.id; }; that.loseFocus = function() { /*** make this object lose focus ***/ Ox.Focus.blur(that.id); return that; }; that.options = function() { // fixme: use Ox.getset /*** get or set options Usage that.options() returns self.options that.options('foo') returns self.options.foo that.options('foo', x) sets self.options.foo, returns that that.options({foo: x, bar: y}) sets self.options.foo and self.options.bar, returns that ***/ var args, length = arguments.length, oldOptions, ret; if (length == 0) { // options() ret = self.options; } else if (length == 1 && typeof arguments[0] == 'string') { // options(str) ret = self.options ? self.options[arguments[0]] : options[arguments[0]]; } else { // options (str, val) or options({str: val, ...}) // translate (str, val) to ({str: val}) args = Ox.makeObject.apply(that, arguments || {}); oldOptions = $.extend({}, self.options); // if options have not been set, extend defaults, // otherwise, extend options //self.options = $.extend(self.options, self.options ? {} : self.defaults, args); self.options = $.extend({}, self.defaults, self.options, args); //self.options = $.extend(self.options || self.defaults, args); Ox.forEach(args, function(val, key) { // key == 'id' && id && Ox.Event.changeId(id, value); /*!Ox.equals(value, oldOptions[key]) &&*/ self.onChange(key, val); }); ret = that; } return ret; }; that.removeElement = function() { /*** remove this element, including its event handler ***/ that.loseFocus(); delete self.$eventHandler; that.remove(); delete Ox.UI.elements[that.id]; return that; }; that.triggerEvent = function() { /*** triggers an event Usage triggerEvent(event) triggerEvent(event, data) triggerEvent({event0: data0, event1: data1, ...}) ***/ if (Ox.isObject(arguments[0])) { Ox.forEach(arguments[0], function(data, event) { if (['mousedown', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick', 'dragstart', 'drag', 'dragpause', 'dragend', 'playing'].indexOf(event) == -1) { Ox.print(that.id, self.options.id, 'trigger', event, data); } self.$eventHandler.trigger('ox_' + event, data); }); } else { if (['mousedown', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick', 'dragstart', 'drag', 'dragpause', 'dragend', 'playing'].indexOf(arguments[0]) == -1) { Ox.print(that.id, self.options ? self.options.id : '', 'trigger', arguments[0], arguments[1] || {}); } self.$eventHandler.trigger('ox_' + arguments[0], arguments[1] || {}); } return that; }; that.unbindEvent = function() { /*** unbinds a function from an event triggered by this element Usage unbindEvent(event, fn) unbindEvent({event0: fn0, event1: fn1, ...}) ***/ if (arguments.length == 1) { Ox.forEach(arguments[0], function(fn, event) { // Ox.print(that.id, 'unbind', arguments[0]); self.$eventHandler.unbind('ox_' + event, fn); }); } else { // Ox.print(that.id, 'unbind', arguments[0]); self.$eventHandler.unbind('ox_' + arguments[0], arguments[1]); } return that; }; return that; } }();