forked from 0x2620/oxjs
rename Ox.UI source files, remove Ox. prefix
This commit is contained in:
parent
005d50c389
commit
91e1065aab
101 changed files with 0 additions and 0 deletions
558
source/Ox.UI/js/Core/Element.js
Normal file
558
source/Ox.UI/js/Core/Element.js
Normal file
|
|
@ -0,0 +1,558 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Element <f:Ox.JQueryElement> Basic UI element object
|
||||
# Usage --------------------------------------------------------------------
|
||||
(element) -> <object> UI element
|
||||
(options) -> <object> UI element
|
||||
(options, self) -> <object> UI element
|
||||
# Arguments ----------------------------------------------------------------
|
||||
element <string> Tagname or CSS selector
|
||||
options <object> Options of the element
|
||||
# Properties
|
||||
element <string> Tagname or CSS selector
|
||||
tooltip <string|function> Tooltip title, or a function that returns one
|
||||
(e) -> <string> tooltip title
|
||||
e <object> mouse event
|
||||
self <object> Shared private variable
|
||||
# Events -------------------------------------------------------------------
|
||||
anyclick <event> anyclick
|
||||
Fires on mouseup, but not on any subsequent mouseup within 250 ms (this
|
||||
is useful if one wants to listen for singleclicks, but not doubleclicks,
|
||||
since it will fire immediately, and won't fire again in case of a
|
||||
doubleclick)
|
||||
* <*> original event properties
|
||||
doubleclick <event> doubleclick
|
||||
Fires on the second mousedown within 250 ms (this is useful if one wants
|
||||
to listen for both singleclicks and doubleclicks, since it will not
|
||||
trigger a singleclick event)
|
||||
* <*> original event properties
|
||||
drag <event> drag
|
||||
Fires on mousemove after dragstart, stops firing on mouseup
|
||||
clientDX <number> horizontal drag delta in px
|
||||
clientDY <number> vertical drag delta in px
|
||||
* <*> original event properties
|
||||
dragend <event> dragpause
|
||||
Fires on mouseup after dragstart
|
||||
clientDX <number> horizontal drag delta in px
|
||||
clientDY <number> vertical drag delta in px
|
||||
* <*> original event properties
|
||||
dragenter <event> dragenter
|
||||
Fires when entering an element during drag (this fires on the element
|
||||
being dragged -- the target element is the event's target property)
|
||||
clientDX <number> horizontal drag delta in px
|
||||
clientDY <number> vertical drag delta in px
|
||||
* <*> original event properties
|
||||
dragleave <event> dragleave
|
||||
Fires when leaving an element during drag (this fires on the element
|
||||
being dragged -- the target element is the event's target property)
|
||||
clientDX <number> horizontal drag delta in px
|
||||
clientDY <number> vertical drag delta in px
|
||||
* <*> original event properties
|
||||
dragpause <event> dragpause
|
||||
Fires once when the mouse doesn't move for 250 ms during drag (this is
|
||||
useful in order to execute operations that are too expensive to be
|
||||
attached to the drag event)
|
||||
clientDX <number> horizontal drag delta in px
|
||||
clientDY <number> vertical drag delta in px
|
||||
* <*> original event properties
|
||||
mousedown <event> mousedown
|
||||
Fires on mousedown (this is useful if one wants to listen for
|
||||
singleclicks, but not doubleclicks or drag events, and wants the event
|
||||
to fire as early as possible)
|
||||
* <*> original event properties
|
||||
dragstart <event> dragstart
|
||||
Fires when the mouse is down for 250 ms
|
||||
* <*> original event properties
|
||||
mouserepeat <event> mouserepeat
|
||||
Fires every 50 ms after the mouse was down for 250 ms, stops firing on
|
||||
mouseleave or mouseup (this fires like a key that is being pressed and
|
||||
held, and is useful for buttons like scrollbars arrows that need to
|
||||
react to both clicking and holding)
|
||||
singleclick <event> singleclick
|
||||
Fires 250 ms after mouseup, if there was no subsequent mousedown (this
|
||||
is useful if one wants to listen for both singleclicks and doubleclicks,
|
||||
since it will not fire for doubleclicks)
|
||||
* <*> original event properties
|
||||
@*/
|
||||
|
||||
Ox.Element = function(options, self) {
|
||||
|
||||
// create private object
|
||||
self = self || {};
|
||||
// create defaults and options objects
|
||||
self.defaults = {};
|
||||
self.options = options || {};
|
||||
// allow for Ox.TestElement('<tagname>')
|
||||
// or Ox.TestElement('cssSelector')
|
||||
if (Ox.isString(self.options)) {
|
||||
self.options = {
|
||||
element: self.options
|
||||
};
|
||||
}
|
||||
// create event handler
|
||||
// (this can be passed as part of self)
|
||||
if (!self.$eventHandler) {
|
||||
self.$eventHandler = $('<div>');
|
||||
}
|
||||
// array of callbacks bound to any event
|
||||
self.eventCallbacks = [];
|
||||
// stack of callbacks bound to option updates
|
||||
self.updateCallbacks = [];
|
||||
|
||||
// create public object
|
||||
var that = new Ox.JQueryElement($(self.options.element || '<div>'))
|
||||
.addClass('OxElement')
|
||||
.mousedown(mousedown);
|
||||
|
||||
setTooltip();
|
||||
|
||||
function bind(event, callback, once) {
|
||||
self.$eventHandler[
|
||||
once ? 'one' : 'on'
|
||||
]('ox_' + event, function(event, data) {
|
||||
call(callback, data, event);
|
||||
});
|
||||
}
|
||||
|
||||
function call(callback, data, event) {
|
||||
event.ox_type = event.type.replace(/^ox_/, '');
|
||||
callback.call(that, data || {}, event);
|
||||
}
|
||||
|
||||
function mousedown(e) {
|
||||
/*
|
||||
better mouse events
|
||||
mousedown:
|
||||
trigger mousedown
|
||||
within 250 msec:
|
||||
mouseup: trigger anyclick
|
||||
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 for 250 msec:
|
||||
trigger dragpause
|
||||
mouseup: trigger dragend
|
||||
"anyclick" is not called "click" since this would collide with the click
|
||||
events of some widgets
|
||||
*/
|
||||
var clientX, clientY,
|
||||
dragTimeout = 0,
|
||||
mouseInterval = 0;
|
||||
if (!self._mouseTimeout) {
|
||||
// first mousedown
|
||||
that.triggerEvent('mousedown', e);
|
||||
self._drag = false;
|
||||
self._mouseup = false;
|
||||
self._mouseTimeout = setTimeout(function() {
|
||||
// 250 ms later, no subsequent click
|
||||
self._mouseTimeout = 0;
|
||||
if (self._mouseup) {
|
||||
// mouse went up, trigger singleclick
|
||||
that.triggerEvent('singleclick', e);
|
||||
} else {
|
||||
// mouse is still down, trigger mouserepeat
|
||||
// every 50 ms until mouseleave or mouseup
|
||||
mouserepeat();
|
||||
mouseInterval = setInterval(mouserepeat, 50);
|
||||
that.one('mouseleave', function() {
|
||||
clearInterval(mouseInterval);
|
||||
});
|
||||
// trigger dragstart, set up drag events
|
||||
that.triggerEvent('dragstart', e);
|
||||
$('*').on({
|
||||
mouseenter: dragenter,
|
||||
mouseleave: dragleave
|
||||
});
|
||||
clientX = e.clientX;
|
||||
clientY = e.clientY;
|
||||
Ox.UI.$window
|
||||
.off('mouseup', mouseup)
|
||||
.mousemove(mousemove)
|
||||
.one('mouseup', function(e) {
|
||||
// stop checking for mouserepeat
|
||||
clearInterval(mouseInterval);
|
||||
// stop checking for dragpause
|
||||
clearTimeout(dragTimeout);
|
||||
// stop checking for drag
|
||||
Ox.UI.$window.off('mousemove', mousemove);
|
||||
// stop checking for dragenter and dragleave
|
||||
$('*').off({
|
||||
mouseenter: dragenter,
|
||||
mouseleave: dragleave
|
||||
});
|
||||
// trigger dragend
|
||||
that.triggerEvent('dragend', extend(e));
|
||||
});
|
||||
self._drag = true;
|
||||
}
|
||||
}, 250);
|
||||
} else {
|
||||
// second mousedown within 250 ms, trigger doubleclick
|
||||
clearTimeout(self._mouseTimeout);
|
||||
self._mouseTimeout = 0;
|
||||
that.triggerEvent('doubleclick', e);
|
||||
}
|
||||
Ox.UI.$window.one('mouseup', mouseup);
|
||||
function dragenter(e) {
|
||||
that.triggerEvent('dragenter', extend(e));
|
||||
}
|
||||
function dragleave(e) {
|
||||
that.triggerEvent('dragleave', extend(e));
|
||||
}
|
||||
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() {
|
||||
// mouse did not move for 250 ms, trigger dragpause
|
||||
that.triggerEvent('dragpause', e);
|
||||
}, 250);
|
||||
that.triggerEvent('drag', e);
|
||||
}
|
||||
function mouserepeat(e) {
|
||||
that.triggerEvent('mouserepeat', e);
|
||||
}
|
||||
function mouseup(e) {
|
||||
if (!self._mouseup && !self._drag) {
|
||||
// mouse went up for the first time, trigger anyclick
|
||||
that.triggerEvent('anyclick', e);
|
||||
self._mouseup = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mouseenter(e) {
|
||||
that.$tooltip.show(e);
|
||||
}
|
||||
|
||||
function mouseleave(e) {
|
||||
that.$tooltip.hide();
|
||||
}
|
||||
|
||||
function mousemove(e) {
|
||||
that.$tooltip.options({
|
||||
title: self.options.tooltip(e)
|
||||
}).show(e);
|
||||
}
|
||||
|
||||
// FIXME: in other widgets, use this,
|
||||
// rather than some self.$tooltip that
|
||||
// will not get garbage collected
|
||||
function setTooltip() {
|
||||
if (self.options.tooltip) {
|
||||
if (Ox.isString(self.options.tooltip)) {
|
||||
that.$tooltip = Ox.Tooltip({
|
||||
title: self.options.tooltip
|
||||
});
|
||||
that.on({
|
||||
mouseenter: mouseenter
|
||||
}).off({
|
||||
mousemove: mousemove
|
||||
});
|
||||
} else {
|
||||
that.$tooltip = Ox.Tooltip({
|
||||
animate: false
|
||||
});
|
||||
that.on({
|
||||
mousemove: mousemove
|
||||
}).off({
|
||||
mouseenter: mouseenter
|
||||
});
|
||||
}
|
||||
that.on({
|
||||
mouseleave: mouseleave
|
||||
});
|
||||
} else {
|
||||
if (that.$tooltip) {
|
||||
that.$tooltip.remove();
|
||||
that.off({
|
||||
mouseenter: mouseenter,
|
||||
mousemove: mousemove,
|
||||
mouseleave: mouseleave
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function update(key, value) {
|
||||
// update is called whenever an option is modified or added
|
||||
Ox.loop(self.updateCallbacks.length - 1, -1, -1, function(i) {
|
||||
self.updateCallbacks[i](key, value) === false && Ox.Break();
|
||||
});
|
||||
}
|
||||
|
||||
/*@
|
||||
bindEvent <function> Binds a function to an event
|
||||
(callback) -> <o> This element
|
||||
(event, callback) -> <o> This element
|
||||
({event: callback, ...}) -> <o> This element
|
||||
callback <f> Callback function
|
||||
data <o> event data (key/value pairs)
|
||||
event <s> Event name
|
||||
Event names can be namespaced, like <code>'click.foo'</code>
|
||||
@*/
|
||||
that.bindEvent = function() {
|
||||
if (Ox.typeOf(arguments[0]) == 'function') {
|
||||
self.eventCallbacks.push(arguments[0]);
|
||||
} else {
|
||||
Ox.forEach(Ox.makeObject(arguments), function(callback, event) {
|
||||
bind(event, callback);
|
||||
});
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
bindEventOnce <function> Binds a function to an event, once
|
||||
(event, callback) -> <obj> This element object
|
||||
({event: callback, ...}) -> <obj> This element object
|
||||
callback <f> Callback function
|
||||
data <o> event data (key/value pairs)
|
||||
event <s> Event name
|
||||
Event names can be namespaced, like <code>'click.foo'</code>
|
||||
@*/
|
||||
that.bindEventOnce = function() {
|
||||
Ox.forEach(Ox.makeObject(arguments), function(callback, event) {
|
||||
bind(event, callback, true);
|
||||
});
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
bindKeyboard <f> bind keyboard
|
||||
() -> <o> object
|
||||
@*/
|
||||
that.bindKeyboard = function() {
|
||||
Ox.Keyboard.bind(that.oxid);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
defaults <function> Gets or sets the default options for an element object
|
||||
({key: value, ...}) -> <obj> This element object
|
||||
key <str> The name of the default option
|
||||
value <val> The value of the default option
|
||||
@*/
|
||||
that.defaults = function() {
|
||||
var ret;
|
||||
if (arguments.length == 0) {
|
||||
ret = self.defaults;
|
||||
} else if (Ox.isString(arguments[0])) {
|
||||
ret = self.defaults[arguments[0]];
|
||||
} else {
|
||||
self.defaults = arguments[0];
|
||||
self.options = Ox.clone(self.defaults);
|
||||
ret = that;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
/*@
|
||||
gainFocus <function> Makes an element object gain focus
|
||||
() -> <obj> This element object
|
||||
@*/
|
||||
that.gainFocus = function() {
|
||||
Ox.Focus.focus(that.oxid);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
hasFocus <function> Returns true if an element object has focus
|
||||
() -> <boolean> True if the element has focus
|
||||
@*/
|
||||
that.hasFocus = function() {
|
||||
return Ox.Focus.focused() == that.oxid;
|
||||
};
|
||||
|
||||
/*@
|
||||
loseFocus <function> Makes an element object lose focus
|
||||
() -> <object> This element object
|
||||
@*/
|
||||
that.loseFocus = function() {
|
||||
Ox.Focus.blur(that.oxid);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
options <function> Gets or sets the options of an element object
|
||||
# Usage
|
||||
() -> <obj> all options
|
||||
(key) -> <any> the value of option[key]
|
||||
(key, value) -> <obj> this element
|
||||
Sets options[key] to value and calls update(key, value)
|
||||
if the key/value pair was added or modified
|
||||
({key: value, ...}) -> <obj> this element
|
||||
Sets multiple options and calls update(key, value)
|
||||
for every key/value pair that was added or modified
|
||||
# Arguments
|
||||
key <str> the name of the option
|
||||
value <val> the value of the option
|
||||
@*/
|
||||
that.options = function() {
|
||||
return Ox.getset(self.options, arguments, update, that);
|
||||
};
|
||||
|
||||
/*@
|
||||
removeElement <function> Removes an element object and its event handler
|
||||
() -> <obj> This element
|
||||
@*/
|
||||
that.remove = function(remove) {
|
||||
remove !== false && that.find('.OxElement').each(function() {
|
||||
var oxid = $(this).data('oxid'),
|
||||
element = Ox.UI.elements[oxid];
|
||||
element && element.remove(false);
|
||||
});
|
||||
Ox.Focus.remove(that.oxid);
|
||||
Ox.Keyboard.unbind(that.oxid);
|
||||
delete self.$eventHandler;
|
||||
delete Ox.UI.elements[that.oxid];
|
||||
that.$tooltip && that.$tooltip.remove();
|
||||
remove !== false && that.$element.remove();
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
setElement <f> set $element
|
||||
($element) -> null
|
||||
@*/
|
||||
that.setElement = function($element) {
|
||||
$element.addClass('OxElement').data({oxid: that.oxid});
|
||||
that.$element.replaceWith($element);
|
||||
that.$element = $element;
|
||||
that[0] = that.$element[0];
|
||||
};
|
||||
|
||||
/*@
|
||||
toggleOption <f> toggle option
|
||||
() -> <o> object
|
||||
@*/
|
||||
that.toggleOption = function() {
|
||||
var options = {};
|
||||
Ox.makeArray(arguments[0]).forEach(function(key) {
|
||||
options[key] == !self.options[key];
|
||||
});
|
||||
that.options(options);
|
||||
};
|
||||
|
||||
/*@
|
||||
triggerEvent <function> Triggers an event
|
||||
(event) -> <object> This element object
|
||||
(event, data) -> <object> This element object
|
||||
({event: data, ...}) -> <object> This element object
|
||||
event <string> Event name
|
||||
data <object> Event data (key/value pairs)
|
||||
@*/
|
||||
that.triggerEvent = function() {
|
||||
Ox.forEach(Ox.makeObject(arguments), function(data, event) {
|
||||
var type = 'ox_' + event;
|
||||
if ([
|
||||
'mousedown', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick',
|
||||
'dragstart', 'drag', 'dragenter', 'dragleave', 'dragpause', 'dragend',
|
||||
'draganddropstart', 'draganddrop', 'draganddropenter', 'draganddropleave', 'draganddropend',
|
||||
'playing', 'position', 'progress', 'request'
|
||||
].indexOf(event) == -1) {
|
||||
if (!/^pandora_/.test(event)) {
|
||||
Ox.Log('EVENT', that.oxid, self.options.id, 'trigger', event, data);
|
||||
}
|
||||
}
|
||||
// it is necessary to check if self.$eventHandler exists,
|
||||
// since, for example, when removing the element on click,
|
||||
// singleclick will fire after the removal of the event handler
|
||||
self.$eventHandler && self.$eventHandler.trigger(type, data);
|
||||
self.eventCallbacks.forEach(function(callback) {
|
||||
call(callback, data, {type: type});
|
||||
});
|
||||
});
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
unbindEvent <function> Unbinds all callbacks from an event
|
||||
To unbind a specific handler, use namespaced events, like
|
||||
<code>bindEvent('click.foo', callback)</code>, and then
|
||||
<code>unbindEvent('click.foo')</code>.
|
||||
() -> <object> This element
|
||||
Unbinds all callbacks from all events
|
||||
(callback) -> <o> This element
|
||||
Unbinds one callback from all events
|
||||
(event) -> <o> This element
|
||||
Unbinds all callbacks from one event
|
||||
(event, callback) -> <o> This element
|
||||
Unbinds one callback from one event
|
||||
({event: callback}, ...) -> <o> This element
|
||||
Unbinds multiple callbacks from multiple events
|
||||
event <string> Event name
|
||||
@*/
|
||||
that.unbindEvent = function() {
|
||||
var callback = arguments[0];
|
||||
if (arguments.length == 0) {
|
||||
self.eventCallbacks = [];
|
||||
self.$eventHandler.off();
|
||||
} else if (Ox.typeOf(callback) == 'function') {
|
||||
self.eventCallbacks = self.eventCallbacks.filter(function(fn) {
|
||||
return fn !== callback;
|
||||
});
|
||||
} else {
|
||||
Ox.makeObject(arguments).forEach(function(callback, event) {
|
||||
self.$eventHandler.off('ox_' + event, callback);
|
||||
});
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
unbindKeyboard <f> unbind keyboard
|
||||
() -> <o> object
|
||||
@*/
|
||||
that.unbindKeyboard = function() {
|
||||
Ox.Keyboard.unbind(that.oxid);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
update <f> Adds one or more handlers for options updates
|
||||
(callback) -> <o> that
|
||||
(key, callback) -> <o> that
|
||||
({key: callback, ...}) -> <o> that
|
||||
@*/
|
||||
that.update = function() {
|
||||
var callbacks;
|
||||
if (Ox.typeOf(arguments[0]) == 'function') {
|
||||
self.updateCallbacks.push(arguments[0]);
|
||||
} else {
|
||||
callbacks = Ox.makeObject(arguments);
|
||||
self.updateCallbacks.push(function(key) {
|
||||
if (callbacks[key]) {
|
||||
return callbacks[key]();
|
||||
}
|
||||
});
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
value <f> Shortcut to get or set self.options.value
|
||||
@*/
|
||||
that.value = function() {
|
||||
return that.options(
|
||||
arguments.length == 0 ? 'value' : {value: arguments[0]}
|
||||
);
|
||||
};
|
||||
|
||||
that.update({
|
||||
tooltip: setTooltip
|
||||
});
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue