remove unneeded Ox. prefix from path and file names
This commit is contained in:
parent
4138e4e558
commit
51696562f1
1365 changed files with 43 additions and 43 deletions
82
source/UI/js/Core/API.js
Normal file
82
source/UI/js/Core/API.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.API <f> Remote API controller
|
||||
options <o> Options object
|
||||
timeout <n|60000> request timeout
|
||||
url <s> request url
|
||||
callback <f> called once api discover is done
|
||||
([options, ] callback) -> <o> API controller
|
||||
api <f> Remote API discovery (calls the API's `api` method)
|
||||
(callback) -> <n> Request id
|
||||
callback <f> Callback functions
|
||||
.* <f> Remote API method call
|
||||
([data, [age, ]]callback) -> <n> Request id
|
||||
data <o> Request data
|
||||
age <n|-1> Max-age in ms (0: not from cache, -1: from cache)
|
||||
callback <f> Callback function
|
||||
cancel <f> Cancels a request
|
||||
(id) -> <u> undefined
|
||||
id <n> Request id
|
||||
@*/
|
||||
|
||||
Ox.API = function(options, callback) {
|
||||
|
||||
var self = {
|
||||
options: Ox.extend({
|
||||
timeout: 60000,
|
||||
type: 'POST',
|
||||
url: '/api/'
|
||||
}, options || {}),
|
||||
time: new Date()
|
||||
},
|
||||
that = {
|
||||
api: function(callback) {
|
||||
return Ox.Request.send({
|
||||
url: self.options.url,
|
||||
data: {action: 'api'},
|
||||
callback: callback
|
||||
});
|
||||
},
|
||||
cancel: function(id) {
|
||||
Ox.Request.cancel(id);
|
||||
}
|
||||
};
|
||||
|
||||
$.ajaxSetup({
|
||||
timeout: self.options.timeout,
|
||||
type: self.options.type,
|
||||
url: self.options.url
|
||||
});
|
||||
|
||||
that.api(function(result) {
|
||||
Ox.forEach(result.data.actions, function(val, key) {
|
||||
that[key] = function(/*data, age, callback*/) {
|
||||
var data = {}, age = -1, callback = null;
|
||||
Ox.forEach(arguments, function(argument) {
|
||||
var type = Ox.typeOf(argument);
|
||||
if (type == 'object') {
|
||||
data = argument;
|
||||
} else if (type == 'number') {
|
||||
age = argument;
|
||||
} else if (type == 'function') {
|
||||
callback = argument;
|
||||
}
|
||||
});
|
||||
return Ox.Request.send(Ox.extend({
|
||||
age: age,
|
||||
callback: callback,
|
||||
data: {
|
||||
action: key,
|
||||
data: JSON.stringify(data)
|
||||
},
|
||||
url: self.options.url
|
||||
}, !val.cache ? {age: 0} : {}));
|
||||
};
|
||||
});
|
||||
callback && callback(that);
|
||||
});
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
107
source/UI/js/Core/App.js
Normal file
107
source/UI/js/Core/App.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.App <f> Basic application instance that communicates with a JSON API
|
||||
options <o> Options object
|
||||
name <s> App name
|
||||
timeout <n> Request timeout
|
||||
type <s> HTTP Request type, i.e. 'GET' or 'POST'
|
||||
url <s> JSON API URL
|
||||
([options]) -> <o> App object
|
||||
load <!> App loaded
|
||||
@*/
|
||||
|
||||
Ox.App = function(options) {
|
||||
|
||||
var self = {
|
||||
options: Ox.extend({
|
||||
name: 'App',
|
||||
socket: '',
|
||||
timeout: 60000,
|
||||
type: 'POST',
|
||||
url: '/api/'
|
||||
}, options || {}),
|
||||
time: new Date()
|
||||
},
|
||||
that = Ox.Element({}, Ox.extend({}, self));
|
||||
|
||||
//@ api <o> API endpoint
|
||||
that.api = Ox.API({
|
||||
type: self.options.type,
|
||||
timeout: self.options.timeout,
|
||||
url: self.options.url
|
||||
}, function() {
|
||||
that.api.init(getUserData(), function(result) {
|
||||
that.triggerEvent({load: result.data});
|
||||
});
|
||||
});
|
||||
|
||||
self.options.socket && connectSocket();
|
||||
|
||||
//@ localStorage <f> Ox.localStorage instance
|
||||
that.localStorage = Ox.localStorage(self.options.name);
|
||||
|
||||
function connectSocket() {
|
||||
that.socket = new WebSocket(self.options.socket);
|
||||
that.socket.onopen = function(event) {
|
||||
that.triggerEvent('open', event);
|
||||
};
|
||||
that.socket.onmessage = function(event) {
|
||||
var data = JSON.parse(event.data);
|
||||
that.triggerEvent(data[0], data[1]);
|
||||
};
|
||||
that.socket.onerror = function(event) {
|
||||
that.triggerEvent('error', event);
|
||||
that.socket.close();
|
||||
};
|
||||
that.socket.onclose = function(event) {
|
||||
that.triggerEvent('close', event);
|
||||
setTimeout(connectSocket, 1000);
|
||||
};
|
||||
}
|
||||
|
||||
function getUserData() {
|
||||
return {
|
||||
document: {referrer: document.referrer},
|
||||
history: {length: history.length},
|
||||
location: {href: location.href},
|
||||
navigator: {
|
||||
cookieEnabled: navigator.cookieEnabled,
|
||||
plugins: Ox.slice(navigator.plugins).map(function(plugin) {
|
||||
return plugin.name;
|
||||
}),
|
||||
userAgent: navigator.userAgent
|
||||
},
|
||||
screen: screen,
|
||||
time: (+new Date() - self.time) / 1000,
|
||||
window: {
|
||||
innerHeight: window.innerHeight,
|
||||
innerWidth: window.innerWidth,
|
||||
outerHeight: window.outerHeight,
|
||||
outerWidth: window.outerWidth,
|
||||
screenLeft: window.screenLeft,
|
||||
screenTop: window.screenTop
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function update() {
|
||||
// ...
|
||||
}
|
||||
|
||||
/*@
|
||||
options <f> Gets or sets options (see Ox.getset)
|
||||
() -> <o> All options
|
||||
(key) -> <*> The value of option[key]
|
||||
(key, value) -> <o> Sets one option, returns App object
|
||||
({key: value, ...}) -> <o> Sets multiple options, returns App object
|
||||
key <s> The name of the option
|
||||
value <*> The value of the option
|
||||
@*/
|
||||
that.options = function() {
|
||||
return Ox.getset(self.options, arguments, update, that);
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
70
source/UI/js/Core/Clipboard.js
Normal file
70
source/UI/js/Core/Clipboard.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Clipboard <o> Basic clipboard handler
|
||||
add <f> Add items to clipboard
|
||||
(items[, type]) -> <n> Number of items
|
||||
clear <f> Clear clipboard
|
||||
() -> <n> Number of items
|
||||
copy <f> Copy items to clipboard
|
||||
(items[, type]) -> <n> Number of items
|
||||
paste <f> Paste items from clipboard
|
||||
() -> <a> Items
|
||||
type <f> Get item type
|
||||
() -> <s|undefined> Item type
|
||||
@*/
|
||||
Ox.Clipboard = function() {
|
||||
var clipboard = {items: [], type: void 0},
|
||||
$element;
|
||||
return {
|
||||
_print: function() {
|
||||
Ox.print(JSON.stringify(clipboard));
|
||||
},
|
||||
add: function(items, type) {
|
||||
items = Ox.makeArray(items);
|
||||
if (items.length) {
|
||||
if (type != clipboard.type) {
|
||||
Ox.Clipboard.clear();
|
||||
}
|
||||
clipboard = {
|
||||
items: Ox.unique(clipboard.items.concat(items)),
|
||||
type: type
|
||||
};
|
||||
$element && $element.triggerEvent('add');
|
||||
}
|
||||
return clipboard.items.length;
|
||||
},
|
||||
bindEvent: function() {
|
||||
if (!$element) {
|
||||
$element = Ox.Element();
|
||||
}
|
||||
$element.bindEvent.apply($element, arguments);
|
||||
},
|
||||
clear: function() {
|
||||
clipboard = {items: [], type: void 0};
|
||||
$element && $element.triggerEvent('clear');
|
||||
return clipboard.items.length;
|
||||
},
|
||||
copy: function(items, type) {
|
||||
items = Ox.makeArray(items);
|
||||
if (items.length) {
|
||||
clipboard = {items: items, type: type};
|
||||
$element && $element.triggerEvent('copy');
|
||||
}
|
||||
return clipboard.items.length;
|
||||
},
|
||||
items: function(type) {
|
||||
return !type || type == clipboard.type ? clipboard.items.length : 0;
|
||||
},
|
||||
paste: function(type) {
|
||||
$element && $element.triggerEvent('paste');
|
||||
return !type || type == clipboard.type ? clipboard.items : [];
|
||||
},
|
||||
type: function() {
|
||||
return clipboard.type;
|
||||
},
|
||||
unbindEvent: function() {
|
||||
$element && $element.unbindEvent.apply($element, arguments);
|
||||
}
|
||||
};
|
||||
};
|
||||
26
source/UI/js/Core/Container.js
Normal file
26
source/UI/js/Core/Container.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
'use strict';
|
||||
|
||||
// fixme: wouldn't it be better to let the elements be,
|
||||
// rather then $element, $content, and potentially others,
|
||||
// 0, 1, 2, etc, so that append would append 0, and appendTo
|
||||
// would append (length - 1)?
|
||||
/*@
|
||||
Ox.Container <f> Container element
|
||||
options <o> Options object
|
||||
self <o> Shared private variable
|
||||
([options[, self]]) -> <o:Ox.Element> Container object
|
||||
@*/
|
||||
Ox.Container = function(options, self) {
|
||||
var that = Ox.Element({}, self)
|
||||
.options(options || {})
|
||||
.addClass('OxContainer');
|
||||
// fixme: we used to pass self _again_ to the content,
|
||||
// which obviously makes clicks trigger twice
|
||||
// removed for now, but may break something else.
|
||||
// (maybe, if needed, content can pass a container event along)
|
||||
that.$content = Ox.Element({})
|
||||
.options(options || {})
|
||||
.addClass('OxContent')
|
||||
.appendTo(that);
|
||||
return that;
|
||||
};
|
||||
20
source/UI/js/Core/Cookies.js
Normal file
20
source/UI/js/Core/Cookies.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Ox.Cookies = function() {
|
||||
var name, value, cookies;
|
||||
if (arguments.length == 1) {
|
||||
name = arguments[0];
|
||||
return Ox.Cookies()[name];
|
||||
} else if (arguments.length == 2) {
|
||||
name = arguments[0];
|
||||
value = arguments[1];
|
||||
document.cookie = name + '=' + encodeURIComponent(value);
|
||||
} else {
|
||||
value = {}
|
||||
if (document.cookie && document.cookie != '') {
|
||||
document.cookie.split('; ').forEach(function(cookie) {
|
||||
name = cookie.split('=')[0];
|
||||
value[name] = Ox.decodeURIComponent(cookie.substring(name.length + 1));
|
||||
});
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
843
source/UI/js/Core/Element.js
Normal file
843
source/UI/js/Core/Element.js
Normal file
|
|
@ -0,0 +1,843 @@
|
|||
'use strict';
|
||||
|
||||
(function(_) {
|
||||
|
||||
/*@
|
||||
Ox.Element <f> Basic UI element object
|
||||
# Arguments -----------------------------------------------------------
|
||||
options <o|s> Options of the element, or just the `element` option
|
||||
element <s> Tagname or CSS selector
|
||||
tooltip <s|f> Tooltip title, or a function that returns one
|
||||
(e) -> <s> Tooltip title
|
||||
e <o> Mouse event
|
||||
self <o> Shared private variable
|
||||
# Usage ---------------------------------------------------------------
|
||||
([options[, self]]) -> <o> Element object
|
||||
# Events ----------------------------------------------------------
|
||||
anyclick <!> 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 <!> 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 <!> drag
|
||||
Fires on mousemove after dragstart, stops firing on mouseup
|
||||
clientDX <n> Horizontal drag delta in px
|
||||
clientDY <n> Vertical drag delta in px
|
||||
* <*> Original event properties
|
||||
dragend <!> dragpause
|
||||
Fires on mouseup after dragstart
|
||||
clientDX <n> Horizontal drag delta in px
|
||||
clientDY <n> Vertical drag delta in px
|
||||
* <*> Original event properties
|
||||
dragenter <!> 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 <n> Horizontal drag delta in px
|
||||
clientDY <n> Vertical drag delta in px
|
||||
* <*> Original event properties
|
||||
dragleave <!> 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 <n> Horizontal drag delta in px
|
||||
clientDY <n> Vertical drag delta in px
|
||||
* <*> Original event properties
|
||||
dragpause <!> 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 <n> Horizontal drag delta in px
|
||||
clientDY <n> Vertical drag delta in px
|
||||
* <*> Original event properties
|
||||
dragstart <!> dragstart
|
||||
Fires when the mouse is down for 250 ms
|
||||
* <*> Original event properties
|
||||
mousedown <!> 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
|
||||
mouserepeat <!> 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
|
||||
scrollbar arrows that need to react to both clicking and
|
||||
holding)
|
||||
mousewheel <!> mousewheel
|
||||
Fires on mousewheel scroll or trackpad swipe
|
||||
deltaFactor <n> Original delta = normalized delta * delta factor
|
||||
deltaX <n> Normalized horizontal scroll delta in px
|
||||
deltaY <n> Normalized vertical scroll delta in px
|
||||
* <*> Original event properties
|
||||
singleclick <!> 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 Element(options, self) {
|
||||
|
||||
// create private object
|
||||
self = self || {};
|
||||
self.boundTooltipEvents = {}; // FIXME?
|
||||
self.defaults = {};
|
||||
self.eventCallbacks = self.eventCallbacks || {};
|
||||
// allow for Ox.Element('<tagname>') or Ox.Element('cssSelector')
|
||||
self.options = Ox.isString(options) ? {element: options} : options || {};
|
||||
self.unbindKeyboard = function unbindKeyboard() {
|
||||
Object.keys(self.eventCallbacks).filter(function(event) {
|
||||
return /^key([\._][\w\.]+)?$/.test(event);
|
||||
}).forEach(function(event) {
|
||||
that.unbindEvent(event);
|
||||
});
|
||||
};
|
||||
self.update = function update(key, value) {
|
||||
// update is called whenever an option is modified or added
|
||||
Ox.loop(self.updateCallbacks.length - 1, -1, -1, function(index) {
|
||||
// break if the callback returns false
|
||||
return self.updateCallbacks[index](key, value) !== false;
|
||||
});
|
||||
};
|
||||
self.updateCallbacks = self.updateCallbacks || [];
|
||||
|
||||
// create public object
|
||||
var that = Object.create(Ox.Element.prototype);
|
||||
that.oxid = Ox.uid();
|
||||
that.$element = $(self.options.element || '<div>')
|
||||
.addClass('OxElement')
|
||||
.data({oxid: that.oxid})
|
||||
.on({
|
||||
mousedown: onMousedown,
|
||||
mousewheel: onMousewheel
|
||||
});
|
||||
that[0] = that.$element[0];
|
||||
that.length = 1;
|
||||
that.self = function _self() {
|
||||
return arguments[0] === _ ? self : {};
|
||||
};
|
||||
Ox.$elements[that.oxid] = that;
|
||||
|
||||
if (self.options.element == '<iframe>') {
|
||||
self.messageCallbacks = self.messageCallbacks || {};
|
||||
that.on({
|
||||
load: function init() {
|
||||
if (that.attr('src')) {
|
||||
// send oxid to iframe
|
||||
that.postMessage({init: {oxid: that.oxid}});
|
||||
self.initTime = self.initTime || new Date();
|
||||
if (new Date() < self.initTime + 60000) {
|
||||
self.initTimeout = setTimeout(init, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).bindEvent({
|
||||
init: function() {
|
||||
// iframe has received oxid
|
||||
clearTimeout(self.initTimeout);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setTooltip();
|
||||
|
||||
function bindTooltipEvents(events) {
|
||||
that.off(Ox.filter(self.boundTooltipEvents, function(value, key) {
|
||||
return !events[key];
|
||||
})).on(self.boundTooltipEvents = Ox.filter(events, function(value, key) {
|
||||
return !self.boundTooltipEvents[key];
|
||||
}));
|
||||
}
|
||||
|
||||
function onMousedown(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;
|
||||
that.triggerEvent('mousedown', e);
|
||||
if (!self._mouseTimeout) {
|
||||
// first mousedown
|
||||
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);
|
||||
$('.OxElement').live({
|
||||
mouseenter: dragenter,
|
||||
mouseleave: dragleave
|
||||
});
|
||||
clientX = e.clientX;
|
||||
clientY = e.clientY;
|
||||
Ox.$window
|
||||
.off('mouseup', mouseup)
|
||||
.on({mousemove: mousemove})
|
||||
.one('mouseup', function(e) {
|
||||
// stop checking for mouserepeat
|
||||
clearInterval(mouseInterval);
|
||||
// stop checking for dragpause
|
||||
clearTimeout(dragTimeout);
|
||||
// stop checking for drag
|
||||
Ox.$window.off({mousemove: mousemove});
|
||||
// stop checking for dragenter and dragleave
|
||||
$('.OxElement').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.$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 onMouseenter(e) {
|
||||
if (!that.$tooltip) {
|
||||
that.$tooltip = Ox.Tooltip({title: self.options.tooltip});
|
||||
}
|
||||
that.$tooltip.show(e);
|
||||
}
|
||||
|
||||
function onMouseleave(e) {
|
||||
that.$tooltip && that.$tooltip.hide();
|
||||
}
|
||||
|
||||
function onMousemove(e) {
|
||||
that.$tooltip.options({title: self.options.tooltip(e)}).show(e);
|
||||
}
|
||||
|
||||
function onMousewheel(e) {
|
||||
// see https://github.com/brandonaaron/jquery-mousewheel/blob/master/jquery.mousewheel.js
|
||||
e = e.originalEvent;
|
||||
var absDelta,
|
||||
deltaX = 'deltaX' in e ? e.deltaX
|
||||
: 'wheelDeltaX' in e ? -e.wheelDeltaX
|
||||
: 0,
|
||||
deltaY = 'deltaY' in e ? -e.deltaY
|
||||
: 'wheelDeltaY' in e ? e.wheelDeltaY
|
||||
: 'wheelDelta' in e ? e.wheelDelta
|
||||
: 0;
|
||||
// Firefox < 17
|
||||
if ('axis' in e && e.axis === e.HORIZONTAL_AXIS) {
|
||||
deltaX = -deltaY;
|
||||
deltaY = 0;
|
||||
}
|
||||
if (deltaX || deltaY) {
|
||||
absDelta = Math.max(Math.abs(deltaY), Math.abs(deltaX));
|
||||
if (!self._deltaFactor || self._deltaFactor > absDelta) {
|
||||
self._deltaFactor = absDelta;
|
||||
}
|
||||
that.triggerEvent('mousewheel', Ox.extend(e, {
|
||||
deltaFactor: self._deltaFactor,
|
||||
deltaX: Ox.trunc(deltaX / self._deltaFactor),
|
||||
deltaY: Ox.trunc(deltaY / self._deltaFactor)
|
||||
}));
|
||||
clearTimeout(self._deltaTimeout)
|
||||
self._deltaTimeout = setTimeout(function() {
|
||||
self._deltaFactor = null;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 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)) {
|
||||
bindTooltipEvents({
|
||||
mouseenter: onMouseenter,
|
||||
mouseleave: onMouseleave
|
||||
});
|
||||
that.$tooltip && that.$tooltip.options({
|
||||
title: self.options.tooltip,
|
||||
animate: true
|
||||
});
|
||||
} else {
|
||||
that.$tooltip = Ox.Tooltip({animate: false});
|
||||
bindTooltipEvents({
|
||||
mousemove: onMousemove,
|
||||
mouseleave: onMouseleave
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (that.$tooltip) {
|
||||
that.$tooltip.remove();
|
||||
}
|
||||
bindTooltipEvents({});
|
||||
}
|
||||
}
|
||||
|
||||
that.update({tooltip: setTooltip});
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
|
||||
// add all jQuery methods to the prototype of Ox.Element
|
||||
Ox.methods($('<div>'), true).forEach(function(method) {
|
||||
Ox.Element.prototype[method] = function() {
|
||||
var ret = this.$element[method].apply(this.$element, arguments),
|
||||
oxid;
|
||||
// If exactly one $element of an Ox Element was returned, then
|
||||
// return the Ox Element instead, so that we can do
|
||||
// oxObj.jqFn().oxFn()
|
||||
return ret && ret.jquery && ret.length == 1
|
||||
&& Ox.$elements[oxid = ret.data('oxid')]
|
||||
? Ox.$elements[oxid] : ret;
|
||||
};
|
||||
});
|
||||
|
||||
/*@
|
||||
bindEvent <f> Adds event handler(s)
|
||||
(callback) -> <o> This element object
|
||||
Adds a catch-all handler
|
||||
(event, callback) -> <o> This element object
|
||||
Adds a handler for a single event
|
||||
({event: callback, ...}) -> <o> This element object
|
||||
Adds handlers for one or more events
|
||||
callback <f> Callback function
|
||||
data <o> event data (key/value pairs)
|
||||
event <s> Event name
|
||||
Event names can be namespaced, like `'click.foo'`
|
||||
callback <f> Callback function
|
||||
@*/
|
||||
Ox.Element.prototype.bindEvent = function bindEvent() {
|
||||
Ox.Event.bind.apply(this, [this.self(_)].concat(Ox.slice(arguments)));
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
bindEventOnce <f> Adds event handler(s) that run(s) only once
|
||||
(callback) -> <o> This element
|
||||
Adds a catch-all handler
|
||||
(event, callback) -> <o> This element
|
||||
Adds a handler for a single event
|
||||
({event: callback, ...}) -> <o> This element
|
||||
Adds handlers for one or more events
|
||||
callback <f> Callback function
|
||||
data <o> event data (key/value pairs)
|
||||
event <s> Event name
|
||||
Event names can be namespaced, like `'click.foo'`
|
||||
callback <f> Callback function
|
||||
@*/
|
||||
Ox.Element.prototype.bindEventOnce = function bindEventOnce() {
|
||||
Ox.Event.bindOnce.apply(
|
||||
this, [this.self(_)].concat(Ox.slice(arguments))
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
bindMessage <f> Adds message handler(s) (if the element is an iframe)
|
||||
(callback) -> <o> This element object
|
||||
Adds a catch-all handler
|
||||
(message, callback) -> <o> This element object
|
||||
Adds a handler for a single message
|
||||
({message: callback, ...}) -> <o> This element object
|
||||
Adds handlers for one or more messages
|
||||
message <s> Message name
|
||||
callback <f> Callback function
|
||||
data <o> Message data (key/value pairs)
|
||||
event <s> Event name
|
||||
element <o> Element object
|
||||
@*/
|
||||
Ox.Element.prototype.bindMessage = Ox.Element.prototype.onMessage = function bindMessage() {
|
||||
var self = this.self(_);
|
||||
if (self.options.element == '<iframe>') {
|
||||
Ox.Message.bind.apply(this, [self].concat(Ox.slice(arguments)));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
bindMessageOnce <f> Adds message handler(s) that run only once
|
||||
(callback) -> <o> This element object
|
||||
Adds a catch-all handler
|
||||
(message, callback) -> <o> This element object
|
||||
Adds a handler for a single message
|
||||
({message: callback, ...}) -> <o> This element object
|
||||
Adds handlers for one or more messages
|
||||
event <s> Message name
|
||||
callback <f> Callback function
|
||||
data <o> Message data (key/value pairs)
|
||||
event <s> Event name
|
||||
element <o> Element object
|
||||
@*/
|
||||
Ox.Element.prototype.bindMessageOnce = Ox.Element.prototype.onMessageOnce = function bindMessageOnce() {
|
||||
var self = this.self(_);
|
||||
if (self.options.element == '<iframe>') {
|
||||
Ox.Message.bindOnce.apply(
|
||||
this, [self].concat(Ox.slice(arguments))
|
||||
);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
childrenElements <f> Gets all direct children element objects
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.childrenElements = function childrenElements() {
|
||||
return Ox.compact(
|
||||
Ox.slice(this.children())
|
||||
.filter(Ox.UI.isElement)
|
||||
.map(Ox.UI.getElement)
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
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 <*> The value of the default option
|
||||
@*/
|
||||
Ox.Element.prototype.defaults = function defaults() {
|
||||
var self = this.self(_);
|
||||
var ret;
|
||||
if (arguments.length == 0) {
|
||||
ret = self.defaults;
|
||||
} else if (Ox.isString(arguments[0])) {
|
||||
ret = self.defaults[arguments[0]];
|
||||
} else {
|
||||
self.defaults = Ox.makeObject(arguments);
|
||||
self.options = Ox.clone(self.defaults);
|
||||
ret = this;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
Ox.Element.prototype.empty = function empty() {
|
||||
this.childrenElements().forEach(function($element) {
|
||||
$element.removeElement();
|
||||
});
|
||||
this.$element.empty.apply(this, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
findElements <f> Gets all descendant element objects
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.findElements = function findElements() {
|
||||
return Ox.compact(
|
||||
Ox.slice(this.find('.OxElement')).map(Ox.UI.getElement)
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
gainFocus <function> Makes an element object gain focus
|
||||
() -> <obj> This element object
|
||||
@*/
|
||||
Ox.Element.prototype.gainFocus = function gainFocus() {
|
||||
Ox.Focus.gainFocus(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
hasFocus <function> Returns true if an element object has focus
|
||||
() -> <boolean> True if the element has focus
|
||||
@*/
|
||||
Ox.Element.prototype.hasFocus = function hasFocus() {
|
||||
return Ox.Focus.focusedElement() === this;
|
||||
};
|
||||
|
||||
Ox.Element.prototype.html = function html() {
|
||||
var ret;
|
||||
this.childrenElements().forEach(function($element) {
|
||||
$element.removeElement();
|
||||
});
|
||||
ret = this.$element.html.apply(this, arguments);
|
||||
return arguments.length == 0 ? ret : this;
|
||||
};
|
||||
|
||||
/*@
|
||||
loseFocus <function> Makes an element object lose focus
|
||||
() -> <object> This element object
|
||||
@*/
|
||||
Ox.Element.prototype.loseFocus = function loseFocus() {
|
||||
Ox.Focus.loseFocus(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
nextElement <f> Gets the closest following sibling element object
|
||||
() -> <o> Element object
|
||||
@*/
|
||||
Ox.Element.prototype.nextElement = function nextElement() {
|
||||
return this.nextElements()[0];
|
||||
};
|
||||
|
||||
/*@
|
||||
nextElements <f> Gets all following sibling element objects
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.nextElements = function nextElements() {
|
||||
return Ox.compact(
|
||||
this.nextAll().filter(Ox.UI.isElement).map(Ox.UI.getElement)
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
options <f> Gets or sets the options of an element object
|
||||
() -> <o> All options
|
||||
(key) -> <*> The value of option[key]
|
||||
(key, value) -> <o> This element
|
||||
Sets options[key] to value and calls update(key, value)
|
||||
if the key/value pair was added or modified
|
||||
({key: value, ...}) -> <o> This element
|
||||
Sets one or more options and calls update(key, value)
|
||||
for every key/value pair that was added or modified
|
||||
key <s> The name of the option
|
||||
value <*> The value of the option
|
||||
@*/
|
||||
Ox.Element.prototype.options = function options() {
|
||||
var self = this.self(_);
|
||||
return Ox.getset(self.options, arguments, self.update, this);
|
||||
};
|
||||
|
||||
/*@
|
||||
parentElement <f> Gets the closest parent element object
|
||||
() -> <o> Element object
|
||||
@*/
|
||||
Ox.Element.prototype.parentElement = function parentElement() {
|
||||
return Ox.last(this.parentElements());
|
||||
};
|
||||
|
||||
/*@
|
||||
parentElements <f> Gets all parent element objects
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.parentElements = function parentElements() {
|
||||
return Ox.compact(
|
||||
Ox.slice(this.parents())
|
||||
.filter(Ox.UI.isElement)
|
||||
.map(Ox.UI.getElement)
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
postMessage <f> Sends a message (if the element is an iframe)
|
||||
(event, data) -> This element object
|
||||
event <s> Event name
|
||||
data <o> Event data
|
||||
@*/
|
||||
Ox.Element.prototype.postMessage = function postMessage(event, data) {
|
||||
if (this.self(_).options.element == '<iframe>') {
|
||||
Ox.Message.post.apply(this, Ox.slice(arguments));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
prevElement <f> Gets the closest preceding sibling element object
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.prevElement = function prevElement() {
|
||||
return Ox.last(this.prevElements());
|
||||
};
|
||||
|
||||
/*@
|
||||
prevElements <f> Gets all preceding sibling element objects
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.prevElements = function prevElements() {
|
||||
return Ox.compact(
|
||||
this.prevAll().filter(Ox.UI.isElement).map(Ox.UI.getElement)
|
||||
);
|
||||
};
|
||||
|
||||
Ox.Element.prototype.remove = function remove() {
|
||||
var parent = this[0].parentNode;
|
||||
this.removeElement();
|
||||
parent && parent.removeChild(this[0]);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
removeElement <f> Clean up after removal from DOM
|
||||
This gets invoked on .remove()
|
||||
@*/
|
||||
Ox.Element.prototype.removeElement = function removeElement(includeChildren) {
|
||||
if (includeChildren !== false) {
|
||||
this.findElements().forEach(function($element) {
|
||||
if (!$element) {
|
||||
Ox.print(
|
||||
'*** Found undefined descendant element,'
|
||||
+ ' this should never happen. ***'
|
||||
);
|
||||
return;
|
||||
}
|
||||
$element.removeElement(false);
|
||||
});
|
||||
}
|
||||
Ox.Focus.removeElement(this.oxid);
|
||||
this.self(_).unbindKeyboard();
|
||||
this.$tooltip && this.$tooltip.remove();
|
||||
delete Ox.$elements[this.oxid];
|
||||
// If setElement($element) was used, delete $element too
|
||||
delete Ox.$elements[this.$element.oxid];
|
||||
return this;
|
||||
};
|
||||
|
||||
Ox.Element.prototype.replace = function replace() {
|
||||
arguments[0].removeElement();
|
||||
this.$element.replace.apply(this.$element, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
Ox.Element.prototype.replaceWith = function replaceWith() {
|
||||
this.removeElement();
|
||||
this.$element.replaceWith.apply(this.$element, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
setElement <f> Sets the element to the element of another element object
|
||||
This is useful if an element has specific options, but uses another
|
||||
generic element as its DOM representation
|
||||
($element) -> <o> This element object
|
||||
@*/
|
||||
Ox.Element.prototype.setElement = function setElement($element) {
|
||||
this.findElements().forEach(function($element) {
|
||||
$element.removeElement(false);
|
||||
});
|
||||
this.$element.replaceWith($element);
|
||||
if ($element.$element) { // $element is Ox.Element
|
||||
this.$element = $element.$element;
|
||||
this.$element.oxid = $element.oxid;
|
||||
} else { // $element is jQuery Element
|
||||
this.$element = $element;
|
||||
}
|
||||
this.$element.addClass('OxElement').data({oxid: this.oxid});
|
||||
this[0] = $element[0];
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
siblingElements <f> Gets all sibling element objects
|
||||
() -> <[o]> Array of element objects
|
||||
@*/
|
||||
Ox.Element.prototype.siblingElements = function siblingElements() {
|
||||
return Ox.compact(
|
||||
Ox.slice(this.siblings())
|
||||
.filter(Ox.UI.isElement)
|
||||
.map(Ox.UI.getElement)
|
||||
);
|
||||
};
|
||||
|
||||
Ox.Element.prototype.text = function text() {
|
||||
var ret;
|
||||
this.childrenElements().forEach(function($element) {
|
||||
$element.removeElement();
|
||||
});
|
||||
ret = this.$element.text.apply(this, arguments);
|
||||
return arguments.length == 0 ? ret : this;
|
||||
};
|
||||
|
||||
/*@
|
||||
toggleOption <f> Toggle boolean option(s)
|
||||
(key[, key[, ...]]) -> <o> This element object
|
||||
@*/
|
||||
Ox.Element.prototype.toggleOption = function toggleOption() {
|
||||
var options = {}, self = this.self(_);
|
||||
Ox.slice(arguments).forEach(function(key) {
|
||||
options[key] == !self.options[key];
|
||||
});
|
||||
return this.options(options);
|
||||
};
|
||||
|
||||
/*@
|
||||
triggerEvent <f> Triggers all handlers for one or more events
|
||||
(event) -> <o> This element object
|
||||
Triggers an event
|
||||
(event, data) -> <o> This element object
|
||||
Triggers an event with data
|
||||
({event: data, ...}) -> <o> This element object
|
||||
Triggers one or more events with data
|
||||
event <s> Event name
|
||||
data <o> Event data (key/value pairs)
|
||||
@*/
|
||||
Ox.Element.prototype.triggerEvent = function triggerEvent() {
|
||||
Ox.Event.trigger.apply(
|
||||
this, [this.self(_)].concat(Ox.slice(arguments))
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
triggerMessage <f> Triggers all handlers for one or more messages
|
||||
(message) -> <o> This element object
|
||||
Triggers an event
|
||||
(message, data) -> <o> This element object
|
||||
Triggers a message with data
|
||||
({message: data, ...}) -> <o> This element object
|
||||
Triggers one or more messages with data
|
||||
message <s> Message name
|
||||
data <o> Message data (key/value pairs)
|
||||
@*/
|
||||
Ox.Element.prototype.triggerMessage = function triggerMessage() {
|
||||
var self = this.self(_);
|
||||
if (self.options.element == '<iframe>') {
|
||||
Ox.Message.trigger.apply(this, [self].concat(Ox.slice(arguments)));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
unbindEvent <f> Removes event handler(s)
|
||||
() -> <o> This element object
|
||||
Removes all handlers.
|
||||
(callback) -> <o> This element object
|
||||
Removes a specific catch-all handler
|
||||
(event) -> <o> This element object
|
||||
Removes all handlers for a single event (to remove all catch-all
|
||||
handlers, pass '*' as event)
|
||||
(event, callback) -> <o> This element object
|
||||
Removes a specific handler for a single event
|
||||
({event: callback}, ...) -> <o> This element object
|
||||
Removes specific handlers for one or more events
|
||||
event <s> Event name
|
||||
callback <f> Event handler
|
||||
@*/
|
||||
Ox.Element.prototype.unbindEvent = function unbindEvent() {
|
||||
Ox.Event.unbind.apply(this, [this.self(_)].concat(Ox.slice(arguments)));
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
unbindMessage <f> Removes message handler(s)
|
||||
() -> <o> This element
|
||||
Removes all handlers.
|
||||
(callback) -> <o> This element object
|
||||
Removes a specific catch-all handler
|
||||
(message) -> <o> This element object
|
||||
Removes all handlers for a single message (to remove all catch-all
|
||||
handlers, pass '*' as message)
|
||||
(message, callback) -> <o> This element object
|
||||
Removes a specific handler for a single event
|
||||
({message: callback}, ...) -> <o> This element object
|
||||
Removes specific handlers for one or more messages
|
||||
message <s> Message name
|
||||
callback <f> Message handler
|
||||
@*/
|
||||
Ox.Element.prototype.unbindMessage = function unbindMessage() {
|
||||
var self = this.self(_);
|
||||
if (self.options.element == '<iframe>') {
|
||||
Ox.Message.unbind.apply(this, [self].concat(Ox.slice(arguments)));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
update <f> Adds one or more handlers for options updates
|
||||
(callback) -> <o> This element object
|
||||
(key, callback) -> <o> This element object
|
||||
({key: callback, ...}) -> <o> This element object
|
||||
@*/
|
||||
Ox.Element.prototype.update = function update() {
|
||||
var callbacks, self = this.self(_);
|
||||
if (Ox.isFunction(arguments[0])) {
|
||||
self.updateCallbacks.push(arguments[0]);
|
||||
} else {
|
||||
callbacks = Ox.makeObject(arguments);
|
||||
self.updateCallbacks.push(function(key, value) {
|
||||
if (callbacks[key]) {
|
||||
return callbacks[key](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
value <f> Shortcut to get or set self.options.value
|
||||
() -> <*> Value
|
||||
(value) -> <o> This element object
|
||||
value <*> Value
|
||||
@*/
|
||||
Ox.Element.prototype.value = function value() {
|
||||
return this.options(
|
||||
arguments.length == 0 ? 'value' : {value: arguments[0]}
|
||||
);
|
||||
};
|
||||
|
||||
}({}));
|
||||
|
||||
502
source/UI/js/Core/Event.js
Normal file
502
source/UI/js/Core/Event.js
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
(function() {
|
||||
|
||||
var chars = {
|
||||
comma: ',',
|
||||
dot: '.',
|
||||
minus: '-',
|
||||
quote: '\'',
|
||||
semicolon: ';',
|
||||
slash: '/',
|
||||
space: ' '
|
||||
},
|
||||
keyboardCallbacks = {},
|
||||
keyboardEventRegExp = /^key(\.[\w\d.]+)?$/,
|
||||
keys = '',
|
||||
keysEventRegExp = new RegExp(
|
||||
'^[\\w\\d](\\.numpad)?$|^(' + Object.keys(chars).join('|') + ')$'
|
||||
),
|
||||
resetTimeout,
|
||||
triggerTimeout;
|
||||
|
||||
function bind(options) {
|
||||
var args = Ox.slice(arguments, 1),
|
||||
callbacks = options.callbacks,
|
||||
that = this,
|
||||
oxid = that.oxid || 0;
|
||||
Ox.forEach(
|
||||
Ox.isFunction(args[0]) ? {'*': args[0]} : Ox.makeObject(args),
|
||||
function(originalCallback, event) {
|
||||
event = event.replace(/^key_/, 'key.');
|
||||
callbacks[event] = (callbacks[event] || []).concat(
|
||||
options.once ? function callback() {
|
||||
unbind.call(
|
||||
that, {callbacks: callbacks}, event, callback
|
||||
);
|
||||
return originalCallback.apply(null, arguments);
|
||||
}
|
||||
: originalCallback
|
||||
);
|
||||
if (isKeyboardEvent(event)) {
|
||||
keyboardCallbacks[oxid] = (
|
||||
keyboardCallbacks[oxid] || []
|
||||
).concat(event);
|
||||
}
|
||||
}
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
function isKeyboardEvent(event) {
|
||||
return keyboardEventRegExp.test(event);
|
||||
}
|
||||
|
||||
function isKeysEventKey(key) {
|
||||
return keysEventRegExp.test(key);
|
||||
}
|
||||
|
||||
function onMessage(e) {
|
||||
var element, message = {};
|
||||
try {
|
||||
message = Ox.extend({data: {}}, JSON.parse(e.data));
|
||||
} catch (e) {}
|
||||
if (message.event == 'init') {
|
||||
if (message.data.oxid) {
|
||||
// The inner window receives the oxid of the outer iframe element
|
||||
Ox.oxid = message.data.oxid;
|
||||
Ox.$parent.postMessage('init', {})
|
||||
} else if (message.target) {
|
||||
// The outer window receives init from iframe
|
||||
Ox.$elements[message.target].triggerEvent('init');
|
||||
}
|
||||
} else {
|
||||
(message.target ? Ox.$elements[message.target] : Ox.$parent)
|
||||
.triggerMessage(message.event, message.data);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeydown(e) {
|
||||
var $element = Ox.Focus.focusedElement(),
|
||||
isInput = Ox.Focus.focusedElementIsInput(),
|
||||
keyName = Ox.KEYS[e.keyCode],
|
||||
keyBasename = keyName.split('.')[0],
|
||||
key = Object.keys(Ox.MODIFIER_KEYS).filter(function(key) {
|
||||
return e[key] && Ox.MODIFIER_KEYS[key] != keyBasename;
|
||||
}).map(function(key) {
|
||||
return Ox.MODIFIER_KEYS[key];
|
||||
}).concat(keyName).join('_'),
|
||||
event = 'key.' + key,
|
||||
triggerEvent = function() {
|
||||
if ($element) {
|
||||
$element.triggerEvent.apply($element, arguments);
|
||||
} else if (!isInput) {
|
||||
Ox.Event.trigger.apply(
|
||||
Ox.$body, [{}].concat(Ox.slice(arguments))
|
||||
);
|
||||
}
|
||||
};
|
||||
triggerEvent(event, e);
|
||||
if (!isInput) {
|
||||
if (isKeysEventKey(key)) {
|
||||
// don't register leading spaces or trailing double spaces
|
||||
if (keyName != 'space' || (
|
||||
keys != '' && !Ox.endsWith(keys, ' ')
|
||||
)) {
|
||||
keys += chars[keyName] || keyBasename;
|
||||
// clear the trigger timeout only if the key registered
|
||||
clearTimeout(triggerTimeout);
|
||||
triggerTimeout = setTimeout(function() {
|
||||
triggerEvent('keys', Ox.extend(e, {keys: keys}));
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
// clear the reset timeout even if the key didn't register
|
||||
clearTimeout(resetTimeout);
|
||||
resetTimeout = setTimeout(function() {
|
||||
keys = '';
|
||||
}, 1000);
|
||||
if ((
|
||||
keyboardCallbacks[0]
|
||||
&& Ox.contains(keyboardCallbacks[0], event)
|
||||
) || (
|
||||
$element && keyboardCallbacks[$element.oxid]
|
||||
&& Ox.contains(keyboardCallbacks[$element.oxid], event)
|
||||
)) {
|
||||
// if there is a global handler for this keyboard event, or a
|
||||
// handler on the focused element, then prevent default
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function trigger(options) {
|
||||
var args = Ox.slice(arguments, 1),
|
||||
callbacks = options.callbacks,
|
||||
that = this;
|
||||
Ox.forEach(Ox.makeObject(args), function(data, originalEvent) {
|
||||
var events = originalEvent.split('.'),
|
||||
triggerGlobally = !isKeyboardEvent(originalEvent)
|
||||
|| !Ox.Focus.focusedElementIsInput();
|
||||
['*'].concat(events.map(function(event, index) {
|
||||
return events.slice(0, index + 1).join('.');
|
||||
})).forEach(function(event) {
|
||||
(triggerGlobally ? callbacks[0][event] || [] : [])
|
||||
.concat(callbacks[1][event] || [])
|
||||
.forEach(function(callback) {
|
||||
callback.call(that, data, originalEvent, that);
|
||||
});
|
||||
});
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
function unbind(options) {
|
||||
var args = Ox.slice(arguments, 1),
|
||||
callbacks = options.callbacks,
|
||||
oxid = this.oxid || 0;
|
||||
if (args.length == 0) {
|
||||
// unbind all handlers for all events
|
||||
callbacks = [];
|
||||
} else {
|
||||
Ox.forEach(
|
||||
Ox.isFunction(args[0]) ? {'*': args[0]}
|
||||
: Ox.makeObject(args),
|
||||
function(callback, event) {
|
||||
if (!callback) {
|
||||
// unbind all handlers for this event
|
||||
delete callbacks[event];
|
||||
} else if (callbacks[event]) {
|
||||
// unbind this handler for this event
|
||||
callbacks[event] = callbacks[event].filter(
|
||||
function(eventCallback) {
|
||||
return eventCallback !== callback;
|
||||
}
|
||||
);
|
||||
if (callbacks[event].length == 0) {
|
||||
delete callbacks[event];
|
||||
}
|
||||
}
|
||||
if (isKeyboardEvent(event)) {
|
||||
var index = keyboardCallbacks[oxid].indexOf(event);
|
||||
keyboardCallbacks[oxid].splice(
|
||||
keyboardCallbacks[oxid].indexOf(event), 1
|
||||
)
|
||||
if (keyboardCallbacks[oxid].length == 0) {
|
||||
delete keyboardCallbacks[oxid];
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*@
|
||||
Ox.$parent <o> Proxy to be used by iframes for messaging with outer window
|
||||
@*/
|
||||
Ox.$parent = (function() {
|
||||
|
||||
var self = {messageCallbacks: {}},
|
||||
that = {oxid: Ox.uid()};
|
||||
|
||||
/*@
|
||||
bindMessage <f> Adds one or more message handlers
|
||||
@*/
|
||||
that.bindMessage = function() {
|
||||
return Ox.Message.bind.apply(
|
||||
this, [self].concat(Ox.slice(arguments))
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
bindMessageOnce <f> Adds one or more message handlers that run only once
|
||||
@*/
|
||||
that.bindMessageOnce = function() {
|
||||
return Ox.Message.bindOnce.apply(
|
||||
this, [self].concat(Ox.slice(arguments))
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
postMessage <f> Sends one or more messages
|
||||
@*/
|
||||
that.postMessage = function() {
|
||||
if (window !== window.top) {
|
||||
// There actually is an outer window
|
||||
if (!Ox.oxid) {
|
||||
// Inner window has not received init message yet
|
||||
self.initTime = self.initTime || new Date();
|
||||
if (new Date() < self.initTime + 60000) {
|
||||
setTimeout(function() {
|
||||
that.postMessage.apply(that, arguments);
|
||||
}, 250);
|
||||
}
|
||||
} else {
|
||||
return Ox.Message.post.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*@
|
||||
triggerMessage <f> Triggers all handlers for one or more messages
|
||||
@*/
|
||||
that.triggerMessage = function() {
|
||||
return Ox.Message.trigger.apply(
|
||||
this, [self].concat(Ox.slice(arguments))
|
||||
);
|
||||
};
|
||||
|
||||
/*@
|
||||
unbindMessage <f> Removes one or more message handlers
|
||||
@*/
|
||||
that.unbindMessage = function() {
|
||||
return Ox.Message.unbind.apply(
|
||||
this, [self].concat(Ox.slice(arguments))
|
||||
);
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
|
||||
/*@
|
||||
Ox.Event <o> Event controller
|
||||
@*/
|
||||
Ox.Event = (function() {
|
||||
|
||||
var callbacks = {},
|
||||
that = {};
|
||||
|
||||
/*@
|
||||
bind <f> Adds one or more event handlers
|
||||
([self, ]callback) -> <o> This method's `this` binding
|
||||
Adds a catch-all handler
|
||||
([self, ]event, callback) -> <o> This method's `this` binding
|
||||
Adds a handler for a single event
|
||||
([self, ]{event: callback, ...}) -> <o> This method's `this` binding
|
||||
Adds handlers for multiple events
|
||||
self <o> Object with `eventCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is global and is not bound to a specific `Ox.Element`
|
||||
event <s> Event name
|
||||
callback <f> Callback function
|
||||
data <o> Event data (key/value pairs)
|
||||
event <s> Event name
|
||||
element <o> Element object (this method's `this` binding)
|
||||
@*/
|
||||
that.bind = function() {
|
||||
var isElement = this !== that;
|
||||
return bind.apply(this, [{
|
||||
callbacks: isElement ? arguments[0].eventCallbacks : callbacks
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
/*@
|
||||
bindOnce <f> Adds one or more event handlers that run only once
|
||||
([self, ]callback) -> <o> This method's `this` binding
|
||||
Adds a catch-all handler
|
||||
([self, ]event, callback) -> <o> This method's `this` binding
|
||||
Adds a handler for a single event
|
||||
([self, ]{event: callback, ...}) -> <o> This method's `this` binding
|
||||
Adds handlers for multiple events
|
||||
self <o> Object with `eventCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is global and is not bound to a specific `Ox.Element`
|
||||
event <s> Event name
|
||||
callback <f> Callback function
|
||||
data <o> Event data (key/value pairs)
|
||||
event <s> Event name
|
||||
element <o> Element object (this method's `this` binding)
|
||||
@*/
|
||||
that.bindOnce = function() {
|
||||
var isElement = this !== that;
|
||||
return bind.apply(this, [{
|
||||
callbacks: isElement ? arguments[0].eventCallbacks : callbacks,
|
||||
once: true
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
/*@
|
||||
trigger <f> Triggers all event handlers for one or more events
|
||||
([self, ]event[, data]) -> <o> This method's `this` binding
|
||||
Triggers one event, with optional event data
|
||||
([self, ]{event: data, ...}) -> <o> This method's `this` binding
|
||||
Triggers multiple events
|
||||
self <o> Object with `eventCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is global and is not bound to a specific `Ox.Element`
|
||||
event <s> Event name
|
||||
data <o> Event data (key/value pairs)
|
||||
@*/
|
||||
that.trigger = function() {
|
||||
var isElement = this !== that;
|
||||
return trigger.apply(this, [{
|
||||
callbacks: [
|
||||
callbacks,
|
||||
isElement ? arguments[0].eventCallbacks || {} : {}
|
||||
]
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
/*@
|
||||
unbind <f> Removes one or more event handlers
|
||||
([self]) -> <o> This method's `this` binding
|
||||
Unbinds all handlers
|
||||
([self, ]callback) -> <o> This method's `this` binding
|
||||
Unbinds a catch-all handler
|
||||
([self, ]event, callback) -> <o> This method's `this` binding
|
||||
Unbinds a handler for a single event
|
||||
([self, ]{event: callback, ...}) -> <o> This method's `this` binding
|
||||
Unbinds handlers for multiple events
|
||||
self <o> Object with `eventCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is global and is not bound to a specific `Ox.Element`
|
||||
event <s> Event name
|
||||
callback <f> Event handler
|
||||
@*/
|
||||
that.unbind = function() {
|
||||
var isElement = this !== that;
|
||||
return unbind.apply(this, [{
|
||||
callbacks: isElement ? arguments[0].eventCallbacks : callbacks
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
|
||||
/*@
|
||||
Ox.Message <o> Message controller
|
||||
@*/
|
||||
Ox.Message = (function() {
|
||||
|
||||
var callbacks = {},
|
||||
that = {};
|
||||
|
||||
/*@
|
||||
bind <f> Adds one or more message handlers
|
||||
([self, ]callback) -> <o> This method's `this` binding
|
||||
Adds a catch-all handler
|
||||
([self, ]message, callback) -> <o> This method's `this` binding
|
||||
Adds a handler for a single message
|
||||
([self, ]{message: callback, ...}) -> <o> This method's `this` binding
|
||||
Adds handlers for multiple messages
|
||||
self <o> Object with `messageCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is bound to the outer window (via `Ox.$parent`)
|
||||
message <s> Message name
|
||||
callback <f> Callback function
|
||||
data <o> Message data (key/value pairs)
|
||||
message <s> Message name
|
||||
element <o> Element object (this method's `this` binding)
|
||||
@*/
|
||||
that.bind = function() {
|
||||
var isElement = this !== that;
|
||||
return bind.apply(this, [{
|
||||
callbacks: isElement ? arguments[0].messageCallbacks
|
||||
: callbacks
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
/*@
|
||||
bindOnce <f> Adds one or more message handlers that run only once
|
||||
([self, ]callback) -> <o> This method's `this` binding
|
||||
Adds a catch-all handler
|
||||
([self, ]message, callback) -> <o> This method's `this` binding
|
||||
Adds a handler for a single message
|
||||
([self, ]{message: callback, ...}) -> <o> This method's `this` binding
|
||||
Adds handlers for multiple messages
|
||||
self <o> Object with `messageCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is bound to the outer window (via `Ox.$parent`)
|
||||
message <s> Message name
|
||||
callback <f> Callback function
|
||||
data <o> Message data (key/value pairs)
|
||||
message <s> Message name
|
||||
element <o> Element object (this method's `this` binding)
|
||||
@*/
|
||||
that.bindOnce = function() {
|
||||
var isElement = this !== that;
|
||||
return bind.apply(this, [{
|
||||
callbacks: isElement ? arguments[0].messageCallbacks
|
||||
: callbacks,
|
||||
once: true
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
/*@
|
||||
post <f> Post a message into or out of an iframe
|
||||
(message[, data]) -> <o> This method's `this` binding
|
||||
Posts one message, with optional message data
|
||||
({message: data, ...}) -> <o> This method's `this` binding
|
||||
Posts multiple messages
|
||||
message <s> Message name
|
||||
data <o> Message data (key/value pairs)
|
||||
@*/
|
||||
that.post = function() {
|
||||
var isParent = this == Ox.$parent,
|
||||
target = isParent ? window.parent : this[0].contentWindow;
|
||||
Ox.forEach(
|
||||
Ox.makeObject(Ox.slice(arguments)),
|
||||
function(data, event) {
|
||||
target.postMessage(JSON.stringify({
|
||||
data: data,
|
||||
event: event,
|
||||
target: isParent ? Ox.oxid : null
|
||||
}), '*');
|
||||
}
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*@
|
||||
trigger <f> Triggers all message handlers for one or more messages
|
||||
([self, ]message[, data]) -> <o> This method's `this` binding
|
||||
Triggers one message, with optional message data
|
||||
([self, ]{message: data, ...}) -> <o> This method's `this` binding
|
||||
Triggers multiple messages
|
||||
self <o> Object with `eventCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is global and is not bound to a specific `Ox.Element`
|
||||
message <s> Message name
|
||||
data <o> Message data (key/value pairs)
|
||||
@*/
|
||||
that.trigger = function() {
|
||||
var isElement = this !== that;
|
||||
return trigger.apply(this, [{
|
||||
callbacks: [
|
||||
callbacks,
|
||||
isElement ? arguments[0].messageCallbacks || {} : {}
|
||||
]
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
/*@
|
||||
unbind <f> Removes one or more message handlers
|
||||
([self, ]callback) -> <o> This method's `this` binding
|
||||
Removes a catch-all handler
|
||||
([self, ]message, callback) -> <o> This method's `this` binding
|
||||
Removes a handler for a single message
|
||||
([self, ]{message: callback, ...}) -> <o> This method's `this` binding
|
||||
Removes handlers for multiple messages
|
||||
self <o> Object with `messageCallbacks` (`Ox.Element`'s `self`)
|
||||
If `self` is missing and this method is not rebound, then the
|
||||
handler is bound to the outer window (via `Ox.$parent`)
|
||||
message <s> Message name
|
||||
callback <f> Message handler
|
||||
@*/
|
||||
that.unbind = function() {
|
||||
var isElement = this !== that;
|
||||
return unbind.apply(this, [{
|
||||
callbacks: isElement ? arguments[0].messageCallbacks
|
||||
: callbacks
|
||||
}].concat(Ox.slice(arguments, isElement ? 1 : 0)));
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
|
||||
document.addEventListener('keydown', onKeydown);
|
||||
window.addEventListener('message', onMessage);
|
||||
|
||||
}());
|
||||
66
source/UI/js/Core/Focus.js
Normal file
66
source/UI/js/Core/Focus.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Focus <o> Basic focus controller
|
||||
@*/
|
||||
|
||||
Ox.Focus = (function() {
|
||||
|
||||
var stack = [],
|
||||
|
||||
that = {
|
||||
focusedElement: function() {
|
||||
return Ox.$elements[Ox.last(stack)];
|
||||
},
|
||||
focusedElementIsInput: function() {
|
||||
var $element = that.focusedElement();
|
||||
return $element && $element.hasClass('OxKeyboardFocus');
|
||||
},
|
||||
gainFocus: function($element) {
|
||||
var $focusedElement = that.focusedElement(),
|
||||
oxid = $element.oxid,
|
||||
index = stack.indexOf(oxid);
|
||||
if (index == -1 || index < stack.length - 1) {
|
||||
stack = $element.parentElements().map(function($element) {
|
||||
return $element.oxid;
|
||||
}).concat(oxid);
|
||||
if ($focusedElement) {
|
||||
$focusedElement
|
||||
.removeClass('OxFocus')
|
||||
.triggerEvent('losefocus');
|
||||
}
|
||||
$element
|
||||
.addClass('OxFocus')
|
||||
.triggerEvent('gainfocus');
|
||||
}
|
||||
},
|
||||
hasFocus: function($element) {
|
||||
return Ox.last(stack) == $element.oxid;
|
||||
},
|
||||
loseFocus: function($element) {
|
||||
var index = stack.indexOf($element.oxid);
|
||||
if (index > -1 && index == stack.length - 1) {
|
||||
stack.pop();
|
||||
$element
|
||||
.removeClass('OxFocus')
|
||||
.triggerEvent('losefocus');
|
||||
if (stack.length) {
|
||||
Ox.$elements[Ox.last(stack)]
|
||||
.addClass('OxFocus')
|
||||
.triggerEvent('gainfocus');
|
||||
}
|
||||
}
|
||||
},
|
||||
removeElement: function($element) {
|
||||
var index = stack.indexOf($element.oxid);
|
||||
if (index == stack.length - 1) {
|
||||
that.loseFocus($element);
|
||||
} else if (index > -1) {
|
||||
stack.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
147
source/UI/js/Core/Fullscreen.js
Normal file
147
source/UI/js/Core/Fullscreen.js
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Fullscreen <o> Fullscreen controller
|
||||
bind <f> Add a fullscreen event handler
|
||||
event <s> Event name ('change', 'enter' or 'exit')
|
||||
handler <f> Event handler
|
||||
state <b> Fullscreen state (present in case of a 'change' event)
|
||||
bindOnce <f> Add a fullscreen event handler that will run only once
|
||||
event <s> Event name ('change', 'enter' or 'exit')
|
||||
handler <f> Event handler
|
||||
state <b> Fullscreen state (present in case of a 'change' event)
|
||||
enter <f> Enter fullscreen
|
||||
exit <f> Exit fullscreen
|
||||
getState <f> Get fullscreen state (true, false or undefined)
|
||||
toggle <f> Toggle fullscreen
|
||||
unbind <f> Remove a fullscreen event handler
|
||||
event <s> Event name ('change', 'enter' or 'exit')
|
||||
handler <f> Event handler
|
||||
@*/
|
||||
|
||||
Ox.Fullscreen = (function() {
|
||||
|
||||
var documentElement = document.body,
|
||||
enter = document.body.requestFullscreen
|
||||
|| document.body.mozRequestFullScreen
|
||||
|| document.body.webkitRequestFullscreen,
|
||||
exit = document.exitFullscreen
|
||||
|| document.mozCancelFullScreen
|
||||
|| document.webkitExitFullscreen,
|
||||
state = 'fullscreen' in document ? 'fullscreen'
|
||||
: 'mozFullScreen' in document ? 'mozFullScreen'
|
||||
: 'webkitIsFullScreen' in document ? 'webkitIsFullScreen'
|
||||
: void 0,
|
||||
handlers = {
|
||||
'': {'change': [], 'enter': [], 'exit': []},
|
||||
'once': {'change': [], 'enter': [], 'exit': []}
|
||||
},
|
||||
types = Object.keys(handlers),
|
||||
that = {};
|
||||
|
||||
[
|
||||
'fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange'
|
||||
].forEach(function(originalEvent) {
|
||||
document.addEventListener(originalEvent, change);
|
||||
});
|
||||
|
||||
function bind(event, handler, once) {
|
||||
var type = once ? 'once' : '';
|
||||
if (
|
||||
handlers[type][event]
|
||||
&& handlers[type][event].indexOf(handler) == -1
|
||||
) {
|
||||
handlers[type][event].push(handler);
|
||||
}
|
||||
}
|
||||
|
||||
function change() {
|
||||
var state = that.getState(),
|
||||
events = ['change'].concat(state ? 'enter' : 'exit'),
|
||||
unbind = [];
|
||||
types.forEach(function(type) {
|
||||
events.forEach(function(event) {
|
||||
handlers[type][event].forEach(function(handler) {
|
||||
event == 'change' ? handler(state) : handler();
|
||||
type == 'once' && unbind.push(
|
||||
{event: event, handler: handler}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
unbind.forEach(function(value) {
|
||||
that.unbind(value.event, value.handler, true);
|
||||
});
|
||||
};
|
||||
|
||||
function unbind(event, handler, once) {
|
||||
var index;
|
||||
[once ? ['once'] : types].forEach(function(type) {
|
||||
if (handlers[type][event]) {
|
||||
while ((index = handlers[type][event].indexOf(handler)) > -1) {
|
||||
handlers[type][event].splice(index, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
that.available = document.fullscreenEnabled
|
||||
|| document.webkitFullscreenEnabled
|
||||
|| document.mozFullScreenEnabled
|
||||
|| false;
|
||||
|
||||
that.bind = function(event, handler) {
|
||||
bind(event, handler);
|
||||
};
|
||||
|
||||
that.bindOnce = function(event, handler) {
|
||||
bind(event, handler, true);
|
||||
};
|
||||
|
||||
that.enter = function(element) {
|
||||
var element = element || document.body;
|
||||
if (element.requestFullscreen) {
|
||||
element.requestFullscreen();
|
||||
} else if (element.mozRequestFullScreen) {
|
||||
element.mozRequestFullScreen();
|
||||
} else if (element.webkitRequestFullscreen) {
|
||||
element.webkitRequestFullscreen();
|
||||
}
|
||||
// FIXME: Why does storing the function in a variable not work?
|
||||
// enter && enter();
|
||||
// ^ Missing `this` binding
|
||||
};
|
||||
|
||||
that.exit = function() {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen()
|
||||
}
|
||||
// FIXME: Why does storing the function in a variable not work?
|
||||
// exit && exit();
|
||||
// ^ Missing `this` binding
|
||||
};
|
||||
|
||||
that.getState = function() {
|
||||
return document[state];
|
||||
};
|
||||
|
||||
that.toggle = function() {
|
||||
var state = that.getState();
|
||||
if (state === false) {
|
||||
that.enter();
|
||||
} else if (state === true) {
|
||||
that.exit();
|
||||
}
|
||||
};
|
||||
|
||||
that.unbind = function(event, handler) {
|
||||
unbind(event, handler);
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
52
source/UI/js/Core/GarbageCollection.js
Normal file
52
source/UI/js/Core/GarbageCollection.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.GarbageCollection <f> GarbageCollection
|
||||
() -> <o> run garbage collection
|
||||
debug() -> {} output debug information
|
||||
@*/
|
||||
|
||||
Ox.GarbageCollection = (function() {
|
||||
|
||||
var that = {},
|
||||
timeout;
|
||||
|
||||
that.collect = function() {
|
||||
var len = Ox.len(Ox.$elements);
|
||||
Object.keys(Ox.$elements).forEach(function(id) {
|
||||
var $element = Ox.$elements[id];
|
||||
if ($element && Ox.isUndefined($element.data('oxid'))) {
|
||||
$element.remove();
|
||||
delete Ox.$elements[id];
|
||||
}
|
||||
});
|
||||
timeout && clearTimeout(timeout);
|
||||
timeout = setTimeout(that.collect, 60000);
|
||||
Ox.Log('GC', len, '-->', Ox.len(Ox.$elements));
|
||||
};
|
||||
|
||||
/*@
|
||||
debug <f> debug info
|
||||
() -> <s>
|
||||
@*/
|
||||
that.debug = function() {
|
||||
var classNames = {}, sorted = [];
|
||||
Ox.forEach(Ox.$elements, function($element, id) {
|
||||
var className = $element[0].className;
|
||||
classNames[className] = (classNames[className] || 0) + 1;
|
||||
});
|
||||
Ox.forEach(classNames, function(count, className) {
|
||||
sorted.push({className: className, count: count});
|
||||
});
|
||||
return sorted.sort(function(a, b) {
|
||||
return a.count - b.count;
|
||||
}).map(function(v) {
|
||||
return v.count + ' ' + v.className
|
||||
}).join('\n');
|
||||
};
|
||||
|
||||
setTimeout(that.collect, 60000);
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
73
source/UI/js/Core/History.js
Normal file
73
source/UI/js/Core/History.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
'use strict';
|
||||
|
||||
Ox.History = function(options) {
|
||||
|
||||
options = Ox.extend({
|
||||
text: function(item) {
|
||||
return item.text;
|
||||
}
|
||||
}, options || {});
|
||||
|
||||
var history = [],
|
||||
position = 0,
|
||||
$element;
|
||||
|
||||
return {
|
||||
_print: function() {
|
||||
Ox.print(JSON.stringify({history: history, position: position}));
|
||||
},
|
||||
add: function(items) {
|
||||
items = Ox.makeArray(items);
|
||||
history = history.slice(0, position).concat(items);
|
||||
position += items.length;
|
||||
$element && $element.triggerEvent('add');
|
||||
return history.length;
|
||||
},
|
||||
bindEvent: function() {
|
||||
if (!$element) {
|
||||
$element = Ox.Element();
|
||||
}
|
||||
$element.bindEvent.apply($element, arguments);
|
||||
},
|
||||
clear: function() {
|
||||
history = [];
|
||||
position = 0;
|
||||
$element && $element.triggerEvent('clear');
|
||||
return history.length;
|
||||
},
|
||||
items: function() {
|
||||
return history.length;
|
||||
},
|
||||
redo: function() {
|
||||
if (position < history.length) {
|
||||
position++;
|
||||
$element && $element.triggerEvent('redo');
|
||||
return history[position - 1];
|
||||
}
|
||||
},
|
||||
redoText: function() {
|
||||
if (position < history.length) {
|
||||
return options.text(history[position]);
|
||||
}
|
||||
},
|
||||
remove: function(test) {
|
||||
|
||||
},
|
||||
unbindEvent: function() {
|
||||
$element && $element.unbindEvent.apply($element, arguments);
|
||||
},
|
||||
undo: function() {
|
||||
if (position > 0) {
|
||||
position--;
|
||||
$element && $element.triggerEvent('undo');
|
||||
return history[position];
|
||||
}
|
||||
},
|
||||
undoText: function() {
|
||||
if (position > 0) {
|
||||
return options.text(history[position - 1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
89
source/UI/js/Core/LoadingIcon.js
Normal file
89
source/UI/js/Core/LoadingIcon.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.LoadingIcon <f> Loading Icon Element
|
||||
options <o> Options object
|
||||
size <n|s|16> size of icon
|
||||
self <o> Shared private variable
|
||||
([options[, self]]) -> <o:Ox.Element> Loading Icon Element
|
||||
@*/
|
||||
|
||||
Ox.LoadingIcon = function(options, self) {
|
||||
|
||||
self = self || {};
|
||||
var that = Ox.Element('<img>', self)
|
||||
.defaults({
|
||||
size: 16,
|
||||
video: false
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxLoadingIcon')
|
||||
.attr({
|
||||
src: Ox.UI.getImageURL(
|
||||
'symbolLoading',
|
||||
self.options.video ? 'videoIcon' : null
|
||||
)
|
||||
});
|
||||
|
||||
Ox.isNumber(self.options.size)
|
||||
? that.css({width: self.options.size, height: self.options.size})
|
||||
: that.addClass('Ox' + Ox.toTitleCase(self.options.size));
|
||||
|
||||
that.stopAnimation = that.stop;
|
||||
|
||||
/*@
|
||||
start <f> Start loading animation
|
||||
() -> <f> Loading Icon Element
|
||||
@*/
|
||||
that.start = function(callback) {
|
||||
var css, deg = 0, previousTime = +new Date();
|
||||
if (!self.loadingInterval) {
|
||||
self.loadingInterval = setInterval(function() {
|
||||
var currentTime = +new Date(),
|
||||
delta = (currentTime - previousTime) / 1000;
|
||||
previousTime = currentTime;
|
||||
deg = Math.round((deg + delta * 360) % 360 / 30) * 30;
|
||||
css = 'rotate(' + deg + 'deg)';
|
||||
that.css({
|
||||
MozTransform: css,
|
||||
MsTransform: css,
|
||||
OTransform: css,
|
||||
WebkitTransform: css,
|
||||
transform: css
|
||||
});
|
||||
}, 83);
|
||||
that.stopAnimation().animate({opacity: 1}, 250, function() {
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
stop <f> Stop loading animation
|
||||
() -> <f> Loading Icon Element
|
||||
@*/
|
||||
that.stop = function(callback) {
|
||||
if (self.loadingInterval && !self.stopping) {
|
||||
self.stopping = true;
|
||||
that.stopAnimation().animate({opacity: 0}, 250, function() {
|
||||
var css = 'rotate(0deg)';
|
||||
clearInterval(self.loadingInterval);
|
||||
self.loadingInterval = null;
|
||||
self.stopping = false;
|
||||
that.css({
|
||||
MozTransform: css,
|
||||
MsTransform: css,
|
||||
OTransform: css,
|
||||
WebkitTransform: css,
|
||||
transform: css
|
||||
});
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
82
source/UI/js/Core/LoadingScreen.js
Normal file
82
source/UI/js/Core/LoadingScreen.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.LoadingScreen <f> Simple loading screen
|
||||
@*/
|
||||
|
||||
Ox.LoadingScreen = function(options, self) {
|
||||
|
||||
self = self || {};
|
||||
var that = Ox.Element({}, self)
|
||||
.defaults({
|
||||
height: 0,
|
||||
size: 32,
|
||||
text: '',
|
||||
width: 0
|
||||
})
|
||||
.options(options || {})
|
||||
.update({
|
||||
height: function() {
|
||||
!self.isAuto && setSizes();
|
||||
},
|
||||
text: function() {
|
||||
self.$text && self.$text.html(self.options.text);
|
||||
},
|
||||
width: function() {
|
||||
!self.isAuto && setSizes();
|
||||
}
|
||||
})
|
||||
.addClass('OxLoadingScreen');
|
||||
|
||||
self.isAuto = !self.options.width && !self.options.height;
|
||||
self.isAuto && that.addClass('OxAuto')
|
||||
|
||||
self.$box = $('<div>').appendTo(that);
|
||||
|
||||
setSizes();
|
||||
|
||||
self.$loadingIcon = Ox.LoadingIcon({
|
||||
size: self.options.size
|
||||
})
|
||||
.appendTo(self.$box);
|
||||
|
||||
if (self.options.text) {
|
||||
self.$text = $('<div>')
|
||||
.html(self.options.text)
|
||||
.appendTo(self.$box);
|
||||
}
|
||||
|
||||
function setSizes() {
|
||||
var css = {
|
||||
width: (self.options.text ? 256 : self.options.size),
|
||||
height: self.options.size + (self.options.text ? 24 : 0)
|
||||
};
|
||||
if (!self.isAuto) {
|
||||
css.left = Math.floor((self.options.width - css.width) / 2);
|
||||
css.top = Math.floor((self.options.height - css.height) / 2);
|
||||
that.css({
|
||||
width: self.options.width + 'px',
|
||||
height: self.options.height + 'px'
|
||||
});
|
||||
}
|
||||
css = Ox.map(css, function(value) {
|
||||
return value + 'px';
|
||||
});
|
||||
self.$box.css(css);
|
||||
}
|
||||
|
||||
that.start = function(callback) {
|
||||
self.$loadingIcon.start(callback);
|
||||
self.$text && self.$text.stop().animate({opacity: 1}, 250);
|
||||
return that;
|
||||
};
|
||||
|
||||
that.stop = function(callback) {
|
||||
self.$loadingIcon.stop(callback);
|
||||
self.$text && self.$text.stop().animate({opacity: 0}, 250);
|
||||
return that;
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
226
source/UI/js/Core/Request.js
Normal file
226
source/UI/js/Core/Request.js
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Request <o> Basic request controller
|
||||
# FIXME: options is not a property, just documenting defaults
|
||||
# options <o> Options object
|
||||
# timeout <n|60000> request timeout
|
||||
# type <s|"POST"> request type, possible values POST, GET, PUT, DELETE
|
||||
# url <s> request url
|
||||
@*/
|
||||
|
||||
Ox.Request = (function() {
|
||||
|
||||
var cache = {},
|
||||
pending = {},
|
||||
requests = {},
|
||||
self = {
|
||||
options: {
|
||||
cache: true,
|
||||
timeout: 60000,
|
||||
type: 'POST',
|
||||
url: '/api/'
|
||||
}
|
||||
},
|
||||
$element;
|
||||
|
||||
return {
|
||||
|
||||
/*@
|
||||
bindEvent <f> Bind event
|
||||
@*/
|
||||
bindEvent: function() {
|
||||
if (!$element) {
|
||||
$element = Ox.Element();
|
||||
}
|
||||
$element.bindEvent.apply($element, arguments);
|
||||
},
|
||||
|
||||
/*@
|
||||
cancel <f> cancel pending requests
|
||||
() -> <u> cancel all requests
|
||||
(fn) -> <u> cancel all requests where function returns true
|
||||
(id) -> <u> cancel request by id
|
||||
@*/
|
||||
cancel: function() {
|
||||
if (arguments.length == 0) {
|
||||
// cancel all requests
|
||||
requests = {};
|
||||
} else if (Ox.isFunction(arguments[0])) {
|
||||
// cancel with function
|
||||
Ox.forEach(requests, function(req, id) {
|
||||
if (arguments[0](req)) {
|
||||
delete requests[id];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// cancel by id
|
||||
delete requests[arguments[0]];
|
||||
}
|
||||
$element && $element.triggerEvent('request', {
|
||||
requests: Ox.len(requests)
|
||||
});
|
||||
},
|
||||
|
||||
/*@
|
||||
clearCache <f> clear cached results
|
||||
() -> <u> ...
|
||||
@*/
|
||||
clearCache: function(query) {
|
||||
if (!query) {
|
||||
cache = {};
|
||||
} else {
|
||||
cache = Ox.filter(cache, function(val, key) {
|
||||
return key.indexOf(query) == -1;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*@
|
||||
options <f> get/set options
|
||||
() -> <o> get options
|
||||
(options) -> <o> set options
|
||||
options <o> Options Object
|
||||
@*/
|
||||
options: function() {
|
||||
return Ox.getset(self.options, arguments, function() {}, this);
|
||||
},
|
||||
|
||||
/*@
|
||||
requests <f> pending requests
|
||||
() -> <n> returns number of requests
|
||||
@*/
|
||||
requests: function() {
|
||||
return Ox.len(requests);
|
||||
},
|
||||
|
||||
/*@
|
||||
send <f> send request
|
||||
(options) -> <n> returns request id
|
||||
options <o> Options Object
|
||||
age <n|-1> cache age
|
||||
id <n|Ox.uid()> request id
|
||||
timeout <n|self.options.timeout> overwrite default timeout
|
||||
type <n|self.options.timeout> overwrite default type
|
||||
url <n|self.options.timeout> overwrite default url
|
||||
@*/
|
||||
send: function(options) {
|
||||
|
||||
var data,
|
||||
options = Ox.extend({
|
||||
age: -1,
|
||||
callback: null,
|
||||
id: Ox.uid(),
|
||||
timeout: self.options.timeout,
|
||||
type: self.options.type,
|
||||
url: self.options.url
|
||||
}, options),
|
||||
req = JSON.stringify({
|
||||
url: options.url,
|
||||
data: options.data
|
||||
});
|
||||
|
||||
if (pending[options.id]) {
|
||||
setTimeout(function() {
|
||||
Ox.Request.send(options);
|
||||
});
|
||||
} else {
|
||||
requests[options.id] = {
|
||||
url: options.url,
|
||||
data: options.data
|
||||
};
|
||||
if (cache[req] && (
|
||||
options.age == -1
|
||||
|| options.age > +new Date() - cache[req].time
|
||||
)) {
|
||||
data = cache[req].data;
|
||||
setTimeout(function() {
|
||||
callback(data, true);
|
||||
});
|
||||
} else {
|
||||
pending[options.id] = true;
|
||||
$.ajax({
|
||||
beforeSend: function(request) {
|
||||
var csrftoken = Ox.Cookies('csrftoken');
|
||||
if (csrftoken) {
|
||||
request.setRequestHeader('X-CSRFToken', csrftoken);
|
||||
}
|
||||
},
|
||||
complete: complete,
|
||||
data: options.data,
|
||||
// dataType: 'json',
|
||||
timeout: options.timeout,
|
||||
type: options.type,
|
||||
url: options.url
|
||||
});
|
||||
}
|
||||
$element && $element.triggerEvent('request', {
|
||||
requests: Ox.len(requests)
|
||||
});
|
||||
}
|
||||
|
||||
function callback(data, success) {
|
||||
if (requests[options.id]) {
|
||||
delete requests[options.id];
|
||||
$element && $element.triggerEvent('request', {
|
||||
requests: Ox.len(requests)
|
||||
});
|
||||
if (success) {
|
||||
options.callback && options.callback(data);
|
||||
} else {
|
||||
$element && $element.triggerEvent('error', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function complete(request) {
|
||||
var $dialog, data;
|
||||
try {
|
||||
data = JSON.parse(request.responseText);
|
||||
} catch (error) {
|
||||
try {
|
||||
data = {
|
||||
status: {
|
||||
code: request.status,
|
||||
text: request.statusText
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
data = {
|
||||
status: {
|
||||
code: '500',
|
||||
text: 'Unknown Error'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
if (Ox.contains([200, 404, 409], data.status.code)) {
|
||||
// we have to include not found and conflict
|
||||
// so that handlers can handle these cases
|
||||
if (self.options.cache) {
|
||||
cache[req] = {
|
||||
data: data,
|
||||
time: Ox.getTime()
|
||||
};
|
||||
}
|
||||
callback(data, true);
|
||||
} else {
|
||||
callback(data, false);
|
||||
}
|
||||
pending[options.id] = false;
|
||||
}
|
||||
|
||||
return options.id;
|
||||
|
||||
},
|
||||
|
||||
/*@
|
||||
unbindEvent <f> Unbind event
|
||||
@*/
|
||||
unbindEvent: function() {
|
||||
$element && $element.unbindEvent.apply($element, arguments);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}());
|
||||
192
source/UI/js/Core/Theme.js
Normal file
192
source/UI/js/Core/Theme.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Theme <f> get/set theme
|
||||
() -> <s> Get current theme
|
||||
(theme) -> <s> Set current theme
|
||||
theme <s> name of theme
|
||||
@*/
|
||||
|
||||
Ox.Theme = (function() {
|
||||
|
||||
var localStorage = Ox.localStorage('Ox'),
|
||||
that = function(theme) {
|
||||
return theme ? setTheme(theme) : getTheme();
|
||||
};
|
||||
|
||||
function getTheme() {
|
||||
var classNames = Ox.$body.attr('class'),
|
||||
theme = '';
|
||||
classNames && Ox.forEach(classNames.split(' '), function(className) {
|
||||
if (Ox.startsWith(className, 'OxTheme')) {
|
||||
theme = className.replace('OxTheme', '');
|
||||
theme = theme[0].toLowerCase() + theme.slice(1);
|
||||
return false; // break
|
||||
}
|
||||
});
|
||||
return theme;
|
||||
}
|
||||
|
||||
function renderElement(value, type) {
|
||||
var $element, background, color, data = that.getThemeData(), saturation;
|
||||
if (type == 'hue') {
|
||||
background = Ox.rgb(value, 1, data.themeBackgroundLightness);
|
||||
color = Ox.rgb(value, 1, data.themeColorLightness);
|
||||
} else if (type == 'saturation') {
|
||||
background = Ox.range(7).map(function(i) {
|
||||
return Ox.rgb(i * 60, value, data.themeBackgroundLightness);
|
||||
});
|
||||
color = Ox.rgb(0, 0, data.themeColorLightness);
|
||||
} else if (type == 'lightness') {
|
||||
background = Ox.range(3).map(function() {
|
||||
return Math.round(value * 255);
|
||||
});
|
||||
color = Ox.range(3).map(function() {
|
||||
return Math.round(value * 255) + (value < 0.5 ? 128 : -128);
|
||||
});
|
||||
} else if (type == 'gradient') {
|
||||
saturation = value === null ? 0 : 1;
|
||||
background = Ox.range(2).map(function(i) {
|
||||
return Ox.rgb(value || 0, saturation, data.themeBackgroundLightness).map(function(value) {
|
||||
return (value || 0) + (i == 0 ? 16 : -16);
|
||||
});
|
||||
});
|
||||
color = Ox.rgb(value || 0, saturation, data.themeColorLightness);
|
||||
}
|
||||
$element = $('<div>')
|
||||
.addClass(
|
||||
'OxColor'
|
||||
+ (type == 'lightness' ? '' : ' OxColor' + Ox.toTitleCase(type))
|
||||
)
|
||||
.css({
|
||||
color: 'rgb(' + color.join(', ') + ')'
|
||||
})
|
||||
.data(type == 'lightness' ? {} : {OxColor: value});
|
||||
if (Ox.isNumber(background[0])) {
|
||||
$element.css({
|
||||
background: 'rgb(' + background.join(', ') + ')'
|
||||
});
|
||||
} else {
|
||||
['moz', 'o', 'webkit'].forEach(function(browser) {
|
||||
$element.css({
|
||||
background: '-' + browser + '-linear-gradient('
|
||||
+ (background.length == 2 ? 'top' : 'left') + ', '
|
||||
+ background.map(function(rgb, i) {
|
||||
return 'rgb(' + rgb.join(', ') + ') '
|
||||
+ Math.round(i * 100 / (background.length - 1)) + '%';
|
||||
}).join(', ')
|
||||
+ ')'
|
||||
});
|
||||
});
|
||||
}
|
||||
return $element;
|
||||
};
|
||||
|
||||
function setTheme(theme) {
|
||||
var currentTheme = getTheme();
|
||||
if (theme != currentTheme && Ox.contains(that.getThemes(), theme)) {
|
||||
Ox.$body
|
||||
.addClass(
|
||||
'OxTheme'
|
||||
+ theme[0].toUpperCase()
|
||||
+ theme.substr(1)
|
||||
)
|
||||
.removeClass(
|
||||
'OxTheme'
|
||||
+ currentTheme[0].toUpperCase()
|
||||
+ currentTheme.substr(1)
|
||||
);
|
||||
$('.OxColor').each(function() {
|
||||
var $element = $(this);
|
||||
if ($element.hasClass('OxColorName')) {
|
||||
$element.attr({src: Ox.UI.getImageURL(
|
||||
$element.data('OxImage'), $element.data('OxColor'), theme
|
||||
)});
|
||||
} else {
|
||||
Ox.forEach(['hue', 'saturation', 'gradient'], function(type) {
|
||||
if ($element.hasClass('OxColor' + Ox.toTitleCase(type))) {
|
||||
var value = $element.data('OxColor'),
|
||||
$element_ = renderElement(value, type);
|
||||
$element.css({
|
||||
background: $element_.css('background'),
|
||||
color: $element_.css('color')
|
||||
});
|
||||
return false; // break
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$('img').add('input[type="image"]').not('.OxColor')
|
||||
.each(function(element) {
|
||||
var $element = $(this),
|
||||
data = Ox.UI.getImageData($element.attr('src'));
|
||||
data && $element.attr({
|
||||
src: Ox.UI.getImageURL(data.name, data.color, theme)
|
||||
});
|
||||
});
|
||||
}
|
||||
localStorage({theme: theme});
|
||||
return that;
|
||||
}
|
||||
|
||||
/*@
|
||||
getThemes <f> Returns the names of all available themes
|
||||
() -> <[s]> Theme names
|
||||
@*/
|
||||
that.getThemes = function() {
|
||||
return Object.keys(Ox.UI.THEMES);
|
||||
};
|
||||
|
||||
/*@
|
||||
getThemeData <f> Returns data for a given theme, or for the current theme
|
||||
([theme]) -> <o> Theme data
|
||||
theme <s> Theme name
|
||||
@*/
|
||||
that.getThemeData = function(theme) {
|
||||
return Ox.UI.THEMES[theme || Ox.Theme()];
|
||||
};
|
||||
|
||||
/*@
|
||||
formatColor <f> Returns a themed colored element
|
||||
@*/
|
||||
that.formatColor = function(value, type) {
|
||||
return renderElement(value, type)
|
||||
.css({textAlign: 'center'})
|
||||
.html(value === null ? '' : Ox.formatNumber(value, 3));
|
||||
};
|
||||
|
||||
/*@
|
||||
formatColorLevel <f> Returns a themed colored element
|
||||
@*/
|
||||
that.formatColorLevel = function(index, values, hueRange) {
|
||||
hueRange = hueRange || (Ox.isBoolean(index) ? [0, 120] : [120, 0]);
|
||||
var step = (hueRange[1] - hueRange[0]) / (values.length - 1),
|
||||
hue = hueRange[0] + index * step;
|
||||
return renderElement(hue, 'gradient')
|
||||
.css({textAlign: 'center'})
|
||||
.html(values[+index]);
|
||||
};
|
||||
|
||||
/*@
|
||||
formatColorPercent <f> Returns a themed colored element
|
||||
@*/
|
||||
that.formatColorPercent = function(value, decimals, sqrt) {
|
||||
var hue = (sqrt ? Math.sqrt(value) * 10 : value) * 1.2;
|
||||
return renderElement(hue, 'gradient')
|
||||
.css({textAlign: 'center'})
|
||||
.html(Ox.formatNumber(value, decimals) + '%')
|
||||
};
|
||||
|
||||
/*@
|
||||
getColorImage <f> Returns a themed colored image
|
||||
@*/
|
||||
that.getColorImage = function(name, value, tooltip) {
|
||||
return (tooltip ? Ox.Element({element: '<img>', tooltip: tooltip}) : $('<img>'))
|
||||
.addClass('OxColor OxColorName')
|
||||
.attr({src: Ox.UI.getImageURL(name, value)})
|
||||
.data({OxColor: value, OxImage: name});
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}());
|
||||
137
source/UI/js/Core/UI.js
Normal file
137
source/UI/js/Core/UI.js
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
'use strict';
|
||||
|
||||
Ox.documentReady(function() {
|
||||
// FIXME: use Ox.$foo everywhere!
|
||||
//@ Ox.$body <o> jQuery-wrapped body
|
||||
Ox.$body = $('body');
|
||||
//@ Ox.$document <o> jQuery-wrapped document
|
||||
Ox.$document = $(document);
|
||||
//@ Ox.$head <o> jQuery-wrapped head
|
||||
Ox.$head = $('head');
|
||||
//@ Ox.$window <o> jQuery-wrapped window
|
||||
Ox.$window = $(window);
|
||||
});
|
||||
|
||||
//@ Ox.$elements <o> Reference to all Ox Elements
|
||||
Ox.$elements = {};
|
||||
|
||||
//@ Ox.UI.DIMENSIONS <o> Names of horizontal and vertical dimensions
|
||||
Ox.DIMENSIONS = Ox.UI.DIMENSIONS = {
|
||||
horizontal: ['width', 'height'],
|
||||
vertical: ['height', 'width']
|
||||
};
|
||||
|
||||
//@ Ox.UI.EDGES <o> Names of horizontal and vertical edges
|
||||
Ox.EDGES = Ox.UI.EDGES = {
|
||||
horizontal: ['left', 'right', 'top', 'bottom'],
|
||||
vertical: ['top', 'bottom', 'left', 'right']
|
||||
};
|
||||
|
||||
//@ Ox.UI.SCROLLBAR_SIZE <n> Size of scrollbars
|
||||
Ox.SCROLLBAR_SIZE = Ox.UI.SCROLLBAR_SIZE = $.browser.webkit ? 8 : (function() {
|
||||
var inner = Ox.$('<p>').css({
|
||||
height: '200px',
|
||||
width: '100%'
|
||||
}),
|
||||
outer = Ox.$('<div>').css({
|
||||
height: '150px',
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
visibility: 'hidden',
|
||||
width: '200px'
|
||||
}).append(inner).appendTo($('body')),
|
||||
width = inner[0].offsetWidth;
|
||||
outer.css({overflow: 'scroll'});
|
||||
width = 1 + width - (inner[0].offsetWidth == width
|
||||
? outer[0].clientWidth : inner[0].offsetWidth);
|
||||
outer.remove();
|
||||
return width;
|
||||
})();
|
||||
|
||||
//@ Ox.UI.PATH <str> Path of Ox UI
|
||||
Ox.UI.PATH = Ox.PATH + 'UI/';
|
||||
|
||||
/*@
|
||||
Ox.UI.getImageData <f> Returns properties of an Ox UI image
|
||||
(url) -> <s> Image Name
|
||||
@*/
|
||||
Ox.UI.getImageData = Ox.cache(function(url) {
|
||||
var str = 'data:image/svg+xml;base64,';
|
||||
return Ox.startsWith(url, str)
|
||||
? JSON.parse(atob(url.split(',')[1]).match(/<!--(.+?)-->/)[1])
|
||||
: null;
|
||||
});
|
||||
|
||||
/*@
|
||||
Ox.UI.getImageURL <f> Returns the URL of an Ox UI image
|
||||
(name[, color[, theme]]) -> <s> Image URL
|
||||
name <s> Image name
|
||||
color <s|[n]> Color name or RGB values
|
||||
theme <s> Theme name
|
||||
@*/
|
||||
Ox.UI.getImageURL = Ox.cache(function(name, color, theme) {
|
||||
var colorName,
|
||||
colors = {
|
||||
marker: {
|
||||
'#000000': 'videoMarkerBorder',
|
||||
'#FFFFFF': 'videoMarkerBackground'
|
||||
},
|
||||
symbol: {
|
||||
'#FF0000': 'symbolWarningColor'
|
||||
}
|
||||
},
|
||||
image = Ox.UI.IMAGES[name],
|
||||
themeData,
|
||||
type = Ox.toDashes(name).split('-')[0];
|
||||
color = color || 'default';
|
||||
theme = theme || Ox.Theme();
|
||||
themeData = Ox.Theme.getThemeData(theme);
|
||||
if (type == 'symbol') {
|
||||
if (Ox.isString(color)) {
|
||||
colorName = color;
|
||||
color = themeData[
|
||||
'symbol' + color[0].toUpperCase() + color.slice(1) + 'Color'
|
||||
];
|
||||
}
|
||||
image = image.replace(/#808080/g, '#' + Ox.toHex(color));
|
||||
}
|
||||
Ox.forEach(colors[type], function(name, hex) {
|
||||
image = image.replace(
|
||||
new RegExp(hex, 'g'),
|
||||
'$' + Ox.toHex(themeData[name])
|
||||
);
|
||||
});
|
||||
image = image.replace(/\$/g, '#');
|
||||
return 'data:image/svg+xml;base64,' + btoa(
|
||||
image + '<!--' + JSON.stringify(Ox.extend(color ? {
|
||||
color: colorName
|
||||
} : {}, {
|
||||
name: name, theme: theme
|
||||
})) + '-->'
|
||||
);
|
||||
}, {
|
||||
key: function(args) {
|
||||
args[1] = args[1] || 'default';
|
||||
args[2] = args[2] || Ox.Theme();
|
||||
return JSON.stringify(args);
|
||||
}
|
||||
});
|
||||
|
||||
//@ Ox.UI.getElement <f> Returns the Ox.Element of a DOM element, or `undefined`
|
||||
Ox.UI.getElement = function(element) {
|
||||
return Ox.$elements[$(element).data('oxid')];
|
||||
};
|
||||
|
||||
/*@
|
||||
Ox.UI.hideScreen <f> Hide and remove Ox UI loading screen
|
||||
@*/
|
||||
Ox.UI.hideScreen = function() {
|
||||
Ox.UI.LoadingScreen.hide();
|
||||
};
|
||||
|
||||
//@ Ox.UI.isElement <f> Returns `true` if a DOM element is an Ox.Element
|
||||
Ox.UI.isElement = function(element) {
|
||||
return !!$(element).data('oxid');
|
||||
};
|
||||
1117
source/UI/js/Core/URL.js
Normal file
1117
source/UI/js/Core/URL.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue