2192 lines
75 KiB
JavaScript
2192 lines
75 KiB
JavaScript
/*
|
|
################################################################################
|
|
ox.ui.js
|
|
|
|
requires
|
|
jquery-1.4.js
|
|
ox.js
|
|
################################################################################
|
|
*/
|
|
|
|
// also see test.js, in demos ...
|
|
|
|
(function() {
|
|
|
|
var oxui = {
|
|
defaultTheme: "classic",
|
|
elements: {},
|
|
getDimensions: function(orientation) {
|
|
return orientation == "horizontal" ?
|
|
["width", "height"] : ["height", "width"];
|
|
},
|
|
getEdges: function(orientation) {
|
|
return orientation == "horizontal" ?
|
|
["left", "right", "top", "bottom"] :
|
|
["top", "bottom", "left", "right"];
|
|
},
|
|
getBarSize: function(size) {
|
|
var sizes = {
|
|
xsmall: 16,
|
|
small: 24,
|
|
medium: 28,
|
|
large: 32,
|
|
xlarge: 40
|
|
};
|
|
return sizes[size];
|
|
},
|
|
jQueryFunctions: function() {
|
|
var functions = [],
|
|
$element = $("<div>");
|
|
//delete $element.length;
|
|
Ox.each($element, function(k, v) {
|
|
if (typeof v == "function") {
|
|
functions.push(k);
|
|
}
|
|
});
|
|
return functions.sort();
|
|
}(),
|
|
path: $("script[src*=ox.ui.js]").attr("src")
|
|
.replace("js/ox.ui.js", ""),
|
|
stack: [], // fixme: used?
|
|
symbols: { // fixme: make lowercase
|
|
alt: "\u2325",
|
|
apple: "\uF8FF",
|
|
arrow_down: "\u2193",
|
|
arrow_left: "\u2190",
|
|
"arrow right": "\u2192",
|
|
"arrow up": "\u2191",
|
|
"backspace": "\u232B",
|
|
"backup": "\u2707",
|
|
"ballot": "\u2717",
|
|
"black star": "\u2605",
|
|
"burn": "\u2622",
|
|
"caps lock": "\u21EA",
|
|
"check": "\u2713",
|
|
"CLEAR": "\u2327",
|
|
"CLICK": "\uF803",
|
|
"CLOSE": "\u2715",
|
|
"COMMAND": "\u2318",
|
|
"CONTROL": "\u2303",
|
|
"CUT": "\u2702",
|
|
"DELETE": "\u2326",
|
|
"DIAMOND": "\u25C6",
|
|
"EDIT": "\uF802",
|
|
"EJECT": "\u23CF",
|
|
"ESCAPE": "\u238B",
|
|
"END": "\u2198",
|
|
"ENTER": "\u2324",
|
|
"FLY": "\u2708",
|
|
"GEAR": "\u2699",
|
|
"HOME": "\u2196",
|
|
"INFO": "\u24D8",
|
|
"NAVIGATE": "\u2388",
|
|
"OPTION": "\u2387",
|
|
"PAGE UP": "\u21DE",
|
|
"PAGE DOWN": "\u21DF",
|
|
"REDO": "\u21BA",
|
|
"RETURN": "\u21A9",
|
|
"SELECT": "\u21D5",
|
|
"SHIFT": "\u21E7",
|
|
"SOUND": "\u266B",
|
|
"SPACE": "\u2423",
|
|
"TAB": "\u21E5",
|
|
"TRASH": "\u267A",
|
|
"TRIANGLE DOWN": "\u25BC",
|
|
"TRIANGLE LEFT": "\u25C0",
|
|
triangle_right: "\u25BA",
|
|
"TRIANGLE UP": "\u25B2",
|
|
"UNDO": "\u21BB",
|
|
"VOLTAGE": "\u26A1",
|
|
"WARNING": "\u26A0",
|
|
"WHITE STAR": "\u2606"
|
|
}
|
|
},
|
|
$window, $document, $body;
|
|
|
|
$(function() {
|
|
$window = $(window),
|
|
$document = $(document),
|
|
$body = $("body");
|
|
Ox.theme(oxui.defaultTheme);
|
|
})
|
|
|
|
/*
|
|
============================================================================
|
|
Application
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.App
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.App = function() {
|
|
/*
|
|
options:
|
|
requestTimeout
|
|
requestType
|
|
requestURL
|
|
*/
|
|
return function(options) {
|
|
|
|
options = options || {};
|
|
var self = {},
|
|
that = this;
|
|
|
|
self.options = $.extend({
|
|
requestTimeout: oxui.requestTimeout,
|
|
requestType: oxui.requestType,
|
|
requestURL: oxui.requestURL
|
|
}, options);
|
|
|
|
self.change = function() {
|
|
|
|
};
|
|
|
|
that.launch = function() {
|
|
$.ajaxSetup({
|
|
timeout: self.options.requestTimeout,
|
|
type: self.options.requestType,
|
|
url: self.options.requestURL
|
|
});
|
|
};
|
|
|
|
that.options = function() {
|
|
return Ox.getset(self.options, Array.slice.call(arguments), self.change, that);
|
|
};
|
|
|
|
that.request = function(action, data, callback) {
|
|
if (arguments.length == 2) {
|
|
callback = data;
|
|
data = {};
|
|
}
|
|
return Ox.Request.send({
|
|
url: self.options.requestURL,
|
|
data: {
|
|
action: action,
|
|
data: JSON.stringify(data)
|
|
},
|
|
callback: callback
|
|
});
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Event
|
|
----------------------------------------------------------------------------
|
|
|
|
naming convention for event/trigger
|
|
verb.id.namespace, i.e. verb.sourceId.targetId (?)
|
|
...
|
|
bind("keydown.shift+dot.numpad", function() {
|
|
// ...
|
|
})
|
|
keyboard handler then would:
|
|
$.each(stack, function(i, v) {
|
|
elements[v].trigger("keydown.shift+0.numpad");
|
|
});
|
|
and the element would implement
|
|
this.trigger(event, data) {
|
|
|
|
}
|
|
...
|
|
keyboard handler also triggers keydown.buffer
|
|
*/
|
|
|
|
// use dom elements / jquery instead
|
|
|
|
Ox.Event = function() {
|
|
var $eventHandler = $("<div>");
|
|
return {
|
|
bind: function(event, callback) {
|
|
$eventHandler.bind(event, callback);
|
|
},
|
|
trigger: function(event, data) {
|
|
$eventHandler.trigger(event, data);
|
|
},
|
|
unbind: function(event) {
|
|
$eventHandler.unbind(event, callback);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ox.Event_ = function() {
|
|
var events = {};
|
|
return {
|
|
// make these bind, trigger, unbind
|
|
publish: function(event, data) {
|
|
console.log("publish", event, data);
|
|
if (events[event]) {
|
|
$.each(events[event], function(i, v) {
|
|
setTimeout(function() {
|
|
v(data);
|
|
}, 0);
|
|
});
|
|
}
|
|
},
|
|
subscribe: function(event, callback) {
|
|
console.log("subscribe", event, callback);
|
|
if (events[event]) {
|
|
events[event].push(callback);
|
|
} else {
|
|
events[event] = [callback];
|
|
}
|
|
},
|
|
unsubscribe: function(event, callback) {
|
|
console.log("unsubscribe", event, callback);
|
|
$.each(events[event], function(i, v) {
|
|
if (Ox.startsWith(callback.toString(), v.toString())) {
|
|
events[event].splice(i, 1);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Focus
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Focus = function() {
|
|
var stack = [];
|
|
return {
|
|
focus: function(id) {
|
|
var index = stack.indexOf(id);
|
|
if (index > -1) {
|
|
oxui.stack.splice(i, 1);
|
|
}
|
|
oxui.stack.push(id);
|
|
},
|
|
blur: function(id) {
|
|
oxui.stack.pop();
|
|
}
|
|
};
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.History
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Keyboard
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
(function() {
|
|
|
|
var buffer = "",
|
|
bufferTime = 0,
|
|
bufferTimeout = 1000,
|
|
keyNames = function() {
|
|
return {
|
|
0: "section",
|
|
8: "backspace",
|
|
9: "tab",
|
|
12: "clear",
|
|
13: "enter",
|
|
16: "shift",
|
|
17: "control",
|
|
18: "alt",
|
|
20: "capslock",
|
|
27: "escape",
|
|
32: "space",
|
|
33: "pageup",
|
|
34: "pagedown",
|
|
35: "end",
|
|
36: "home",
|
|
37: "left",
|
|
38: "up",
|
|
39: "right",
|
|
40: "down",
|
|
45: "insert",
|
|
46: "delete",
|
|
47: "help",
|
|
48: "0",
|
|
49: "1",
|
|
50: "2",
|
|
51: "3",
|
|
52: "4",
|
|
53: "5",
|
|
54: "6",
|
|
55: "7",
|
|
56: "8",
|
|
57: "9",
|
|
65: "A",
|
|
66: "B",
|
|
67: "C",
|
|
68: "D",
|
|
69: "E",
|
|
70: "F",
|
|
71: "G",
|
|
72: "H",
|
|
73: "I",
|
|
74: "J",
|
|
75: "K",
|
|
76: "L",
|
|
77: "M",
|
|
78: "N",
|
|
79: "O",
|
|
80: "P",
|
|
81: "Q",
|
|
82: "R",
|
|
83: "S",
|
|
84: "T",
|
|
85: "U",
|
|
86: "V",
|
|
87: "W",
|
|
88: "X",
|
|
89: "Y",
|
|
90: "Z",
|
|
91: "meta.left",
|
|
92: "meta.right",
|
|
93: "select",
|
|
96: "0.numpad",
|
|
97: "1.numpad",
|
|
98: "2.numpad",
|
|
99: "3.numpad",
|
|
100: "4.numpad",
|
|
101: "5.numpad",
|
|
102: "6.numpad",
|
|
103: "7.numpad",
|
|
104: "8.numpad",
|
|
105: "9.numpad",
|
|
106: "asterisk.numpad",
|
|
107: "plus.numpad",
|
|
109: "minus.numpad",
|
|
108: "enter.numpad",
|
|
110: "dot.numpad",
|
|
111: "slash.numpad",
|
|
112: "f1",
|
|
113: "f2",
|
|
114: "f3",
|
|
115: "f4",
|
|
116: "f5",
|
|
117: "f6",
|
|
118: "f7",
|
|
119: "f8",
|
|
120: "f9",
|
|
121: "f10",
|
|
122: "f11",
|
|
123: "f12",
|
|
124: "f13",
|
|
125: "f14",
|
|
126: "f15",
|
|
127: "f16",
|
|
144: "numlock",
|
|
145: "scrolllock",
|
|
186: "semicolon",
|
|
187: "equal",
|
|
188: "comma",
|
|
189: "minus",
|
|
190: "dot",
|
|
191: "slash",
|
|
192: "backtick",
|
|
219: "openbracket",
|
|
220: "backslash",
|
|
221: "closebracket",
|
|
222: "quote"
|
|
// see dojo, for ex.
|
|
};
|
|
}(),
|
|
modifierNames = {
|
|
altKey: "alt", // mac: option
|
|
ctrlKey: "control",
|
|
metaKey: "meta", // mac: command
|
|
shiftKey: "shift"
|
|
};
|
|
|
|
return function() {
|
|
document.keydown(keydown);
|
|
function keydown(e) {
|
|
var key = [],
|
|
ret = true,
|
|
time;
|
|
$.each(modifierNames, function(k, v) {
|
|
if (e[k]) {
|
|
key.push(v);
|
|
}
|
|
});
|
|
// avoid pushing modifier twice
|
|
if (keyNames[e.keyCode] && keys.indexOf(keyNames[e.keyCode]) == -1) {
|
|
key.push(keyNames[e.keyCode]);
|
|
}
|
|
key = key.join(" ");
|
|
if (key.match(/^[\w\d-]$|SPACE/)) {
|
|
time = Ox.time();
|
|
if (time - bufferTime > bufferTimeout) {
|
|
buffer = "";
|
|
}
|
|
buffer += key == "SPACE" ? " " : key;
|
|
bufferTime = time;
|
|
}
|
|
$.each(stack, function(i, v) {
|
|
// fixme: we dont get the return value!
|
|
ret = Ox.event.publish(keyboard + Ox.toCamelCase(key) + "." + v);
|
|
return ret;
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Mouse (??)
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Request
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Request = function() {
|
|
|
|
var cache = {},
|
|
pending = {},
|
|
requests = {},
|
|
self = {
|
|
options: {
|
|
timeout: 15000,
|
|
type: "POST",
|
|
url: "api"
|
|
}
|
|
};
|
|
|
|
return {
|
|
|
|
cancel: function() {
|
|
var index;
|
|
if (arguments.length == 0) {
|
|
requests = {};
|
|
} else if (Ox.isFunction(arguments[0])) {
|
|
// cancel with function
|
|
$.each(requests, function(id, req) {
|
|
if (arguments[0](req)) {
|
|
delete requests[id];
|
|
}
|
|
})
|
|
} else {
|
|
// cancel by id
|
|
delete requests[arguments[0]]
|
|
}
|
|
},
|
|
|
|
emptyCache: function() {
|
|
cache = {};
|
|
},
|
|
|
|
options: function(options) {
|
|
return Ox.getset(self.options, options, $.noop(), this);
|
|
},
|
|
|
|
send: function(options) {
|
|
|
|
options = $.extend({
|
|
age: -1,
|
|
callback: function() {},
|
|
id: Ox.uid(),
|
|
timeout: self.options.timeout,
|
|
type: self.options.type,
|
|
url: self.options.url
|
|
}, options);
|
|
|
|
var req = JSON.stringify({
|
|
url: options.url,
|
|
data: options.data
|
|
});
|
|
|
|
function callback(data) {
|
|
delete requests[options.id];
|
|
options.callback(data);
|
|
}
|
|
|
|
function debug(request) {
|
|
var $iframe = $("<iframe>")
|
|
.css({ // fixme: should go into a class
|
|
width: 768,
|
|
height: 384
|
|
}),
|
|
$dialog = new Ox.Dialog({
|
|
title: "Application Error",
|
|
buttons: [
|
|
{
|
|
value: "Close",
|
|
click: function() {
|
|
$dialog.close();
|
|
}
|
|
}
|
|
],
|
|
width: 800,
|
|
height: 400
|
|
})
|
|
.append($iframe)
|
|
.open(),
|
|
iframe = $iframe[0].contentDocument || $iframe[0].contentWindow.document;
|
|
iframe.open();
|
|
iframe.write(request.responseText);
|
|
iframe.close();
|
|
}
|
|
|
|
function error(request, status, error) {
|
|
var data;
|
|
if (arguments.length == 1) {
|
|
data = arguments[0]
|
|
} else {
|
|
try {
|
|
data = JSON.parse(request.responseText);
|
|
} catch (err) {
|
|
data = {
|
|
status: {
|
|
code: request.status,
|
|
text: request.statusText
|
|
}
|
|
};
|
|
}
|
|
}
|
|
if (data.status.code < 500) {
|
|
callback(data);
|
|
} else {
|
|
var $dialog = new Ox.Dialog({
|
|
title: "Application Error",
|
|
buttons: [
|
|
{
|
|
value: "Details",
|
|
click: function() {
|
|
$dialog.close(function() {
|
|
debug(request);
|
|
});
|
|
}
|
|
},
|
|
{
|
|
value: "Close",
|
|
click: function() {
|
|
$dialog.close(function() {
|
|
callback(data);
|
|
});
|
|
}
|
|
}
|
|
],
|
|
width: 400,
|
|
height: 100
|
|
})
|
|
.append("Sorry, we have encountered an application error while handling your request. To help us find out what went wrong, you may want to report this error to an administrator. Otherwise, please try again later.")
|
|
.open();
|
|
// fixme: change this to Send / Don't Send
|
|
Ox.print({
|
|
request: request,
|
|
status: status,
|
|
error: error
|
|
});
|
|
}
|
|
pending[options.id] = false;
|
|
}
|
|
|
|
function success(data) {
|
|
pending[options.id] = false;
|
|
try {
|
|
data = JSON.parse(data);
|
|
} catch (err) {
|
|
error({
|
|
status: {
|
|
code: 500,
|
|
text: "Internal Server Error"
|
|
},
|
|
data: {}
|
|
});
|
|
return;
|
|
}
|
|
cache[req] = {
|
|
data: data,
|
|
time: Ox.getTime()
|
|
};
|
|
callback(data);
|
|
}
|
|
|
|
if (pending[options.id]) {
|
|
setTimeout(function() {
|
|
Ox.Request.send(options);
|
|
}, 0);
|
|
} else {
|
|
requests[options.id] = {
|
|
url: options.url,
|
|
data: options.data
|
|
};
|
|
if (cache[req] && (options.age == -1 || options.age > Ox.getTime() - cache[req].time)) {
|
|
setTimeout(function() {
|
|
callback(cache[req].data);
|
|
}, 0);
|
|
} else {
|
|
pending[options.id] = true;
|
|
$.ajax({
|
|
data: options.data,
|
|
error: error,
|
|
success: success,
|
|
timeout: options.timeout,
|
|
type: options.type,
|
|
url: options.url
|
|
});
|
|
}
|
|
}
|
|
return options.id;
|
|
}
|
|
|
|
};
|
|
}();
|
|
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.URL
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
============================================================================
|
|
Core
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Container
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
// 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 = function() {
|
|
var that = new Ox.Element()
|
|
.addClass("OxContainer");
|
|
that.$content = new Ox.Element()
|
|
.addClass("OxContent")
|
|
.appendTo(that);
|
|
return that;
|
|
}
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Element
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
// check out http://ejohn.org/apps/learn/#36 (-#38, making fns work w/o new)
|
|
|
|
Ox.Element = function() {
|
|
|
|
var elements = {};
|
|
|
|
return function(options, self) {
|
|
|
|
// construct
|
|
options = options || {};
|
|
self = self || {};
|
|
var that = this;
|
|
|
|
// init
|
|
(function() {
|
|
// allow for Ox.Widget("tagname", self)
|
|
if (typeof options == "string") {
|
|
options = {
|
|
element: options
|
|
};
|
|
}
|
|
that.ox = Ox.version;
|
|
that.id = Ox.uid();
|
|
that.$element = $("<" + (options.element || "div") + "/>", {
|
|
data: {
|
|
ox: that.id
|
|
}
|
|
});
|
|
elements[that.id] = that;
|
|
wrapjQuery();
|
|
})();
|
|
|
|
// private
|
|
function wrapjQuery() {
|
|
$.each(oxui.jQueryFunctions, function(i, v) {
|
|
that[v] = function() {
|
|
var args = arguments,
|
|
length = args.length,
|
|
id, ret;
|
|
$.each(args, function(i, v) {
|
|
// if an ox object was passed
|
|
// then pass its $element instead
|
|
// so we can do oxObj.jqFn(oxObj)
|
|
if (v.ox) {
|
|
args[i] = v.$element;
|
|
}
|
|
});
|
|
// why does this not work?
|
|
// ret = that.$element[v].apply(this, arguments);
|
|
if (length == 0) {
|
|
ret = that.$element[v]();
|
|
} else if (length == 1) {
|
|
ret = that.$element[v](args[0]);
|
|
} else if (length == 2) {
|
|
ret = that.$element[v](args[0], args[1]);
|
|
} else if (length == 3) {
|
|
ret = that.$element[v](args[0], args[1], args[2]);
|
|
} else if (length == 4) {
|
|
ret = that.$element[v](args[0], args[1], args[2], args[3]);
|
|
}
|
|
// if the $element of an ox object was returned
|
|
// then return the ox object instead
|
|
// so we can do oxObj.jqFn().oxFn()
|
|
return ret.jquery && elements[id = ret.data("ox")] ?
|
|
elements[id] : ret;
|
|
}
|
|
});
|
|
}
|
|
|
|
// shared
|
|
self.onChange = function() {
|
|
// self.onChange(option, value)
|
|
// is called when an option changes
|
|
// (to be implemented by widget)
|
|
};
|
|
|
|
// public
|
|
that.defaults = function(defaults) {
|
|
/*
|
|
that.defaults({foo: x}) sets self.defaults
|
|
*/
|
|
self.defaults = defaults;
|
|
return that;
|
|
}
|
|
that.gain = function() {
|
|
Ox.Focus.gain(that.id);
|
|
}
|
|
that.lose = function() {
|
|
Ox.Focus.lose(that.id);
|
|
}
|
|
that.options = function() {
|
|
/*
|
|
that.options() returns self.options
|
|
that.options("foo") returns self.options.foo
|
|
that.options("foo", x) sets self.options.foo,
|
|
returns that
|
|
that.options({foo: x, bar: y}) sets self.options.foo
|
|
and self.options.bar,
|
|
returns that
|
|
*/
|
|
var length = arguments.length,
|
|
args, ret;
|
|
if (length == 0) {
|
|
// options()
|
|
ret = self.options;
|
|
} else if (length == 1 && typeof arguments[0] == "string") {
|
|
// options(str)
|
|
ret = self.options[arguments[0]]
|
|
} else {
|
|
// options (str, val) or options({str: val, ...})
|
|
// translate (str, val) to ({str: val})
|
|
args = Ox.makeObject.apply(that, arguments);
|
|
// if options have not been set, extend defaults,
|
|
// otherwise, extend options
|
|
self.options = $.extend(
|
|
self.options || self.defaults, args);
|
|
$.each(args, function(k, v) {
|
|
self.onChange(k, v);
|
|
});
|
|
ret = that;
|
|
}
|
|
return ret;
|
|
}
|
|
that.publish = function() {
|
|
arguments[0] = arguments[0] + "." + that.id;
|
|
Ox.Event.publish.apply(that, arguments);
|
|
// or, maybe better:
|
|
$(".OxWidget").trigger.apply(that, arguments);
|
|
return that;
|
|
}
|
|
that.remove = function() {
|
|
that.$element.remove();
|
|
delete elements[that.ox];
|
|
}
|
|
that.subscribe = function() {
|
|
Ox.Event.subscribe.apply(that, arguments);
|
|
// or
|
|
that.$element.bind.apply(that, arguments);
|
|
return that;
|
|
}
|
|
that.unsubscribe = function() {
|
|
Ox.Event.unsubscribe.apply(that, arguments);
|
|
return that;
|
|
}
|
|
|
|
// return
|
|
return that;
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
Ox._Element = function(element) {
|
|
var that = this;
|
|
that.def = {};
|
|
that.opt = {};
|
|
that.ox = Ox.version;
|
|
that.id = Ox.uid();
|
|
//console.log("that.id", that.id)
|
|
that.$element = $("<" + (element || "div") + "/>")
|
|
//.addClass("OxElement")
|
|
.data("ox", that.id);
|
|
oxui.elements[that.id] = that;
|
|
// console.log("oxui.elements", oxui.elements)
|
|
//function setOption() {};
|
|
that.setOption = function() {};
|
|
/*
|
|
*/
|
|
that.destroy = function() {
|
|
that.$element.remove();
|
|
delete oxui.elements[that.ox];
|
|
}
|
|
/*
|
|
*/
|
|
that.disable = function() {
|
|
|
|
}
|
|
/*
|
|
*/
|
|
that.enable = function() {
|
|
|
|
}
|
|
/*
|
|
*/
|
|
///*
|
|
that.defaults = function() {
|
|
var length = arguments.length,
|
|
ret;
|
|
if (length == 0) {
|
|
ret = that.def
|
|
} else if (length == 1 && typeof arguments[0] == "string") {
|
|
ret = that.def[arguments[0]];
|
|
} else {
|
|
// translate ("key", "value") to {"key": "value"}
|
|
that.def = $.extend(
|
|
that.def, Ox.makeObject.apply(that, arguments)
|
|
);
|
|
ret = that;
|
|
}
|
|
return ret;
|
|
}
|
|
//*/
|
|
/*
|
|
Ox.Element.options()
|
|
get options
|
|
Ox.Element.options("foo")
|
|
get options.foo
|
|
Ox.Element.options("foo", 0)
|
|
set options.foo
|
|
Ox.Element.options({foo: 0, bar: 1})
|
|
set options.foo and options.bar
|
|
*/
|
|
///*
|
|
that.options = function() {
|
|
var length = arguments.length,
|
|
args, ret;
|
|
if (length == 0) {
|
|
//console.log("getting all options", options);
|
|
ret = that.opt;
|
|
} else if (length == 1 && typeof arguments[0] == "string") {
|
|
//console.log("getting one option", options, arguments[0], options[arguments[0]]);
|
|
ret = that.opt[arguments[0]];
|
|
} else {
|
|
// translate ("key", "value") to {"key": "value"}
|
|
args = Ox.makeObject.apply(that, arguments);
|
|
// if options have been set then extend options,
|
|
// otherwise extend defaults
|
|
that.opt = $.extend(Ox.length(that.opt) ?
|
|
that.opt : that.def, args);
|
|
// that.trigger("OxElement" + that.id + "SetOptions", args);
|
|
$.each(args, function(k, v) {
|
|
that.setOption(k, v);
|
|
//console.log("triggering", "OxElement" + that.id + "SetOption", {k: v})
|
|
//that.trigger("OxElement" + that.id + "SetOption", {k: v});
|
|
})
|
|
ret = that;
|
|
}
|
|
return ret;
|
|
}
|
|
// should become self.publish
|
|
that.publish = function(event, data) {
|
|
Ox.Event.publish(event + that.id, data);
|
|
return that;
|
|
}
|
|
that.subscribe = function(event, callback) {
|
|
Ox.Event.subscribe(event, callback);
|
|
return that;
|
|
}
|
|
//that.setOptions = function() {};
|
|
//*/
|
|
// wrap jquery functions
|
|
// so we can do oxObj.jqFn()
|
|
$.each(oxui.jqueryFunctions, function(i, v) {
|
|
that[v] = function() {
|
|
var args = arguments,
|
|
length = args.length,
|
|
$element, id, ret;
|
|
$.each(args, function(i, v) {
|
|
// if an oxui object was passed
|
|
// then pass its $element instead
|
|
// so we can do jqObj.append(oxObj)
|
|
if (v.ox) {
|
|
args[i] = v.$element;
|
|
}
|
|
});
|
|
if (v == "html" && that.$content) {
|
|
$element = that.$content;
|
|
} else {
|
|
$element = that.$element;
|
|
}
|
|
// why does this not work?
|
|
// ret = that.$element[v].apply(this, arguments);
|
|
// maybe because we pass this, and not that.$element[v] ... ?
|
|
// ret = that.$element[v].apply(that.$element[v], arguments);
|
|
// doesn't work either ...
|
|
if (length == 0) {
|
|
ret = $element[v]();
|
|
} else if (length == 1) {
|
|
ret = $element[v](args[0]);
|
|
} else if (length == 2) {
|
|
ret = $element[v](args[0], args[1]);
|
|
} else if (length == 3) {
|
|
ret = $element[v](args[0], args[1], args[2]);
|
|
} else if (length == 4) {
|
|
ret = $element[v](args[0], args[1], args[2], args[3]);
|
|
}
|
|
// if the $element of an oxui object was returned
|
|
// then return the oxui object instead
|
|
// so we can do oxObj.jqFn().oxFn()
|
|
//console.log("v", v, "arguments", arguments)
|
|
if (ret.jquery) {
|
|
//console.log("ret", ret, "ret.data('id')", ret.data("ox"))
|
|
}
|
|
return ret.jquery && oxui.elements[id = ret.data("ox")] ?
|
|
oxui.elements[id] : ret;
|
|
}
|
|
});
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.theme()
|
|
get theme
|
|
Ox.theme("foo")
|
|
set theme to "foo"
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.theme = function() {
|
|
var length = arguments.length,
|
|
classes = $body.attr("class").split(" "),
|
|
arg, theme;
|
|
$.each(classes, function(i, v) {
|
|
if (Ox.startsWith(v, "OxTheme")) {
|
|
theme = v.replace("OxTheme", "").toLowerCase();
|
|
if (length == 1) {
|
|
$body.removeClass(v);
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
if (length == 1) {
|
|
arg = arguments[0]
|
|
$body.addClass("OxTheme" + Ox.toTitleCase(arg));
|
|
if (theme) {
|
|
$("input[type=image]").each(function() {
|
|
var $this = $(this);
|
|
$this.attr({
|
|
src: $this.attr("src").replace(
|
|
"/ox.ui." + theme + "/", "/ox.ui." + arg + "/"
|
|
)
|
|
});
|
|
});
|
|
}
|
|
}
|
|
return theme;
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Bars
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.Bar = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
orientation: "horizontal",
|
|
size: 16
|
|
})
|
|
.options(options || {}),
|
|
dimensions = oxui.getDimensions(self.options.orientation);
|
|
that.addClass("OxBar Ox" + Ox.toTitleCase(self.options.orientation))
|
|
.css(dimensions[0], "100%")
|
|
.css(dimensions[1], self.options.size + "px");
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Tabbar
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Tabbar = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Bar({
|
|
size: 20
|
|
}, self)
|
|
.defaults({
|
|
selected: 0,
|
|
values: []
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxTabbar");
|
|
|
|
(function() {
|
|
Ox.ButtonGroup({
|
|
selectable: true,
|
|
selected: self.options.selected,
|
|
size: "small",
|
|
style: "tab",
|
|
values: self.options.values
|
|
}).appendTo(that);
|
|
})();
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
Ox.Toolbar = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Bar({
|
|
size: oxui.getBarSize(options.size)
|
|
}, self);
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Ox.Dialog
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.Dialog = function(options, self) {
|
|
var self = self || {},
|
|
options = $.extend({
|
|
title: "",
|
|
buttons: [],
|
|
width: 384,
|
|
height: 128
|
|
}, options),
|
|
that = new Ox.Element()
|
|
.addClass("OxDialog")
|
|
.css({
|
|
left: (($(document).width() - options.width) / 2) + "px",
|
|
top: (($(document).height() - options.height - 92) / 2) + "px",
|
|
width: options.width + "px",
|
|
height: (options.height + 92) + "px"
|
|
});
|
|
that.$titlebar = new Ox.Bar({
|
|
size: "medium"
|
|
})
|
|
.addClass("OxTitleBar")
|
|
//.html(options.title)
|
|
.mousedown(function(e) {
|
|
var offset = that.offset(),
|
|
//maxLeft = $(document).width() - that.width(),
|
|
//maxTop = $(document).height() - that.height(),
|
|
x = e.clientX,
|
|
y = e.clientY,
|
|
documentWidth = $(document).width();
|
|
documentHeight = $(document).height();
|
|
$(window).mousemove(function(e) {
|
|
$("*").css({
|
|
WebkitUserSelect: "none"
|
|
});
|
|
var left = Ox.limit(offset.left - x + e.clientX, 24 - options.width, documentWidth - 24),
|
|
top = Ox.limit(offset.top - y + e.clientY, 24, documentHeight - 24);
|
|
that.css({
|
|
left: left + "px",
|
|
top: top + "px"
|
|
});
|
|
});
|
|
$(window).one("mouseup", function() {
|
|
$(window).unbind("mousemove");
|
|
$("*").css({
|
|
WebkitUserSelect: "auto"
|
|
});
|
|
});
|
|
})
|
|
.appendTo(that);
|
|
that.$title = new Ox.Element().addClass("OxTitle").html(options.title).appendTo(that.$titlebar);
|
|
that.$content = new Ox.Container()
|
|
.addClass("OxContent")
|
|
.css({
|
|
height: options.height + "px"
|
|
})
|
|
.appendTo(that);
|
|
that.$buttonsbar = new Ox.Element()
|
|
.addClass("OxButtonsBar")
|
|
.appendTo(that);
|
|
that.$buttons = [];
|
|
$.each(options.buttons, function(i, button) {
|
|
that.$buttons[i] = new Ox.Button({
|
|
size: "medium",
|
|
value: button.value
|
|
}).click(button.click).appendTo(that.$buttonsbar);
|
|
});
|
|
that.$buttons[0].focus();
|
|
that.$layer = $(".OxLayer"); // fixme: lazy loading of layer is fine, but save in var, dont look up
|
|
self.onChange = function(key, value) {
|
|
if (key == "title") {
|
|
that.$title.html(value);
|
|
}
|
|
}
|
|
that.append = function($element) {
|
|
that.$content.append($element);
|
|
return that;
|
|
}
|
|
that.close = function(callback) {
|
|
callback = callback || function() {};
|
|
that.animate({
|
|
opacity: 0
|
|
}, 200, function() {
|
|
that.remove();
|
|
that.$layer.remove();
|
|
callback();
|
|
})
|
|
}
|
|
that.open = function() {
|
|
if (!that.$layer.length) {
|
|
that.$layer = new Ox.Element()
|
|
.addClass("OxLayer")
|
|
.appendTo($("body"));
|
|
}
|
|
that.css({
|
|
opacity: 0
|
|
}).appendTo(that.$layer).animate({
|
|
opacity: 1
|
|
}, 200);
|
|
return that;
|
|
}
|
|
return that;
|
|
}
|
|
|
|
/*
|
|
============================================================================
|
|
Forms
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Button
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Button = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element("input", self)
|
|
.defaults({
|
|
buttonId: null,
|
|
click: function() {},
|
|
disabled: false,
|
|
groupId: null,
|
|
selectable: false,
|
|
selected: false,
|
|
size: "small",
|
|
style: "", // can be symbol or tab
|
|
type: "text",
|
|
value: "",
|
|
values: []
|
|
})
|
|
.options($.extend(options, {
|
|
value: $.isArray(options.value) ?
|
|
options.value[0] : options.value,
|
|
values: $.makeArray(options.value)
|
|
}));
|
|
that.attr({
|
|
disabled: self.options.disabled ? "disabled" : "",
|
|
type: self.options.type == "text" ? "button" : "image"
|
|
})
|
|
.addClass("OxButton Ox" + Ox.toTitleCase(self.options.size) +
|
|
(self.options.style ? " Ox" + Ox.toTitleCase(self.options.style) : "") +
|
|
(self.options.disabled ? " OxDisabled": "") +
|
|
(self.options.selected ? " OxSelected": ""))
|
|
.mousedown(mousedown)
|
|
.click(click);
|
|
//console.log(self.options.value, self.options.disabled)
|
|
/*
|
|
that.bind("OxElement" + that.id + "SetOptions", function(e, data) {
|
|
if (typeof data.selected != "undefined") {
|
|
if (data.selected != that.hasClass("OxSelected")) {
|
|
that.toggleClass("OxSelected");
|
|
}
|
|
}
|
|
if (typeof data.value != "undefined") {
|
|
if (self.options.type == "image") {
|
|
that.attr({
|
|
src: oxui.path + "png/" + Ox.theme() +
|
|
"/button" + Ox.toTitleCase(options.value) + ".png"
|
|
});
|
|
} else {
|
|
that.val(self.options.value);
|
|
}
|
|
}
|
|
})
|
|
*/
|
|
function mousedown(e) {
|
|
if (self.options.type == "image" && $.browser.safari) {
|
|
// keep image from being draggable
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
function click() {
|
|
if (self.options.selectable && !(self.options.groupId !== null && self.options.selected)) {
|
|
that.toggleSelected();
|
|
}
|
|
if (self.options.values.length == 2) {
|
|
console.log("2 values")
|
|
that.options({
|
|
value: self.options.value == self.options.values[0] ?
|
|
self.options.values[1] : self.options.values[0]
|
|
});
|
|
}
|
|
self.options.click();
|
|
}
|
|
self.onChange = function(option, value) {
|
|
//console.log("setOption", option, value)
|
|
if (option == "selected") {
|
|
if (value != that.hasClass("OxSelected")) {
|
|
that.toggleClass("OxSelected");
|
|
}
|
|
}
|
|
if (option == "value") {
|
|
if (self.options.type == "image") {
|
|
that.attr({
|
|
src: oxui.path + "png/ox.ui." + Ox.theme() +
|
|
"/button" + Ox.toTitleCase(value) + ".png"
|
|
});
|
|
} else {
|
|
that.val(value);
|
|
}
|
|
}
|
|
}
|
|
that.toggleDisabled = function() {
|
|
that.options({
|
|
enabled: !self.options.disabled
|
|
});
|
|
}
|
|
that.toggleSelected = function() {
|
|
that.options({
|
|
selected: !self.options.selected
|
|
});
|
|
that.trigger("OxButtonToggle", self.options);
|
|
}
|
|
that.options("value", self.options.value);
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.ButtonGroup
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.ButtonGroup = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
groupId: Ox.uid(),
|
|
selectable: false,
|
|
selected: -1,
|
|
size: "small",
|
|
style: "",
|
|
type: "text",
|
|
values: []
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxButtonGroup");
|
|
(function() {
|
|
that.$buttons = [];
|
|
$.each(self.options.values, function(i, v) {
|
|
that.$buttons[i] = Ox.Button({
|
|
buttonId: i,
|
|
groupId: self.options.groupId,
|
|
selectable: self.options.selectable,
|
|
selected: i == self.options.selected,
|
|
size: self.options.size,
|
|
style: self.options.style,
|
|
type: self.options.type,
|
|
value: v
|
|
}).appendTo(that);
|
|
});
|
|
that.$element.bind("OxButtonToggle", function(e, data) {
|
|
console.log("Data", data, self.options)
|
|
if (data.groupId = self.options.groupId) {
|
|
if (data.selected) {
|
|
if (self.options.selected > -1) {
|
|
that.$buttons[self.options.selected].toggleSelected();
|
|
}
|
|
self.options.selected = data.buttonId;
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Input
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Input = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element("input", self)
|
|
.defaults({
|
|
placeholder: "",
|
|
size: "small",
|
|
type: "text"
|
|
})
|
|
.options(options || {});
|
|
that.attr({
|
|
type: self.options.type,
|
|
placeholder: self.options.placeholder
|
|
})
|
|
.addClass("OxInput Ox" +
|
|
Ox.toTitleCase(self.options.size) + " OxPlaceholder")
|
|
//.change(change)
|
|
.focus(focus)
|
|
.blur(blur);
|
|
/* doesn't work yet
|
|
function change() {
|
|
console.log("change", that.val(), that.hasClass("OxPlaceholder"))
|
|
if ((that.val() !== "") != that.hasClass("OxPlaceholder")) {
|
|
that.toggleClass("OxPlaceholder");
|
|
}
|
|
}
|
|
*/
|
|
function focus() {
|
|
console.log("focus", that.val(), that.attr("class"))
|
|
if (that.hasClass("OxPlaceholder")) {
|
|
that.val("").removeClass("OxPlaceholder");
|
|
}
|
|
}
|
|
function blur() {
|
|
console.log("blur", that.val(), that.attr("class"))
|
|
if (that.val() === "") {
|
|
that.addClass("OxPlaceholder").val(that.attr("placeholder"));
|
|
}
|
|
}
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Range
|
|
|
|
options:
|
|
animate boolean if true, animate thumb
|
|
arrows boolean if true, show arrows
|
|
arrowImages array arrow symbols, like ["minus", "plus"]
|
|
arrowStep number step when clicking arrows
|
|
max number maximum value
|
|
min number minimum value
|
|
orientation string "horizontal" or "vertical"
|
|
step number step between values
|
|
size number width or height, in px
|
|
thumbSize number minimum width or height of thumb, in px
|
|
thumbValue boolean if true, display value on thumb
|
|
trackImages string or array one or multiple track background image URLs
|
|
trackStep number 0 (scroll here) or step when clicking track
|
|
value number initial value
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Range = function(options, self) {
|
|
|
|
/*
|
|
init
|
|
*/
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
animate: false,
|
|
arrows: false,
|
|
arrowImages: ["previous", "next"],
|
|
arrowStep: 1,
|
|
max: 100,
|
|
min: 0,
|
|
orientation: "horizontal",
|
|
step: 1,
|
|
size: 128,
|
|
thumbSize: 16,
|
|
thumbValue: false,
|
|
trackImages: [],
|
|
trackStep: 0,
|
|
value: 0
|
|
})
|
|
.options($.extend(options, {
|
|
arrowStep: options.arrowStep ?
|
|
options.arrowStep : options.step,
|
|
trackImages: $.makeArray(options.trackImages || [])
|
|
}))
|
|
.addClass("OxRange");
|
|
|
|
// fixme: self. ... ?
|
|
var trackImages = self.options.trackImages.length,
|
|
values = (self.options.max - self.options.min + self.options.step) /
|
|
self.options.step;
|
|
|
|
/*
|
|
construct
|
|
*/
|
|
that.$element
|
|
.css({
|
|
width: self.options.size + "px"
|
|
});
|
|
if (self.options.arrows) {
|
|
var $arrowDec = Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: self.options.arrowImages[0]
|
|
})
|
|
.addClass("OxArrow")
|
|
.mousedown(mousedownArrow)
|
|
.click(clickArrowDec)
|
|
.appendTo(that.$element);
|
|
}
|
|
var $track = new Ox.Element()
|
|
.addClass("OxTrack")
|
|
.mousedown(clickTrack)
|
|
.appendTo(that.$element); // fixme: make that work
|
|
|
|
if (trackImages) {
|
|
var width = parseFloat(screen.width / trackImages),
|
|
$image = $("<canvas/>")
|
|
.attr({
|
|
width: width * trackImages,
|
|
height: 14
|
|
})
|
|
.addClass("OxImage")
|
|
.appendTo($track.$element), // fixme: make that work
|
|
c = $image[0].getContext('2d');
|
|
c.mozImageSmoothingEnabled = false; // we may want to remove this later
|
|
$.each(self.options.trackImages, function(i, v) {
|
|
//console.log(v)
|
|
$("<img/>")
|
|
.attr({
|
|
src: v
|
|
})
|
|
.load(function() {
|
|
c.drawImage(this, i * width, 0, width, 14);
|
|
});
|
|
});
|
|
}
|
|
var $thumb = Ox.Button({})
|
|
.addClass("OxThumb")
|
|
.appendTo($track);
|
|
if (self.options.arrows) {
|
|
var $arrowInc = Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: self.options.arrowImages[1]
|
|
})
|
|
.addClass("OxArrow")
|
|
.mousedown(mousedownArrow)
|
|
.click(clickArrowInc)
|
|
.appendTo(that.$element);
|
|
}
|
|
var rangeWidth, trackWidth, imageWidth, thumbWidth;
|
|
setWidth(self.options.size);
|
|
|
|
/*
|
|
private functions
|
|
*/
|
|
|
|
function clickArrowDec() {
|
|
that.removeClass("OxActive");
|
|
setValue(self.options.value - self.options.arrowStep, 200)
|
|
}
|
|
function clickArrowInc() {
|
|
that.removeClass("OxActive");
|
|
setValue(self.options.value + self.options.arrowStep, 200);
|
|
}
|
|
function clickTrack(e) {
|
|
Ox.Focus.focus();
|
|
var left = $track.offset().left,
|
|
offset = $(e.target).hasClass("OxThumb") ?
|
|
e.clientX - $thumb.offset().left - thumbWidth / 2 - 2 : 0;
|
|
function val(e) {
|
|
return getVal(e.clientX - left - offset);
|
|
}
|
|
setValue(val(e), 200);
|
|
$window.mousemove(function(e) {
|
|
setValue(val(e));
|
|
});
|
|
$window.one("mouseup", function() {
|
|
$window.unbind("mousemove");
|
|
});
|
|
}
|
|
function getPx(val) {
|
|
var pxPerVal = (trackWidth - thumbWidth - 2) /
|
|
(self.options.max - self.options.min);
|
|
return Math.ceil((val - self.options.min) * pxPerVal + 1);
|
|
}
|
|
function getVal(px) {
|
|
var px = trackWidth / values >= 16 ? px : px - 8,
|
|
valPerPx = (self.options.max - self.options.min) /
|
|
(trackWidth - thumbWidth);
|
|
return Ox.limit(self.options.min +
|
|
Math.floor(px * valPerPx / self.options.step) * self.options.step,
|
|
self.options.min, self.options.max);
|
|
}
|
|
function mousedownArrow() {
|
|
that.addClass("OxActive");
|
|
}
|
|
function setThumb(animate) {
|
|
var animate = typeof animate != "undefined" ? animate : 0;
|
|
$thumb.animate({
|
|
marginLeft: (getPx(self.options.value) - 2) + "px",
|
|
width: thumbWidth + "px"
|
|
}, self.options.animate ? animate : 0, function() {
|
|
if (self.options.thumbValue) {
|
|
$thumb.options({
|
|
value: self.options.value
|
|
});
|
|
}
|
|
});
|
|
}
|
|
function setValue(val, animate) {
|
|
val = Ox.limit(val, self.options.min, self.options.max);
|
|
if (val != self.options.value) {
|
|
that.options({
|
|
value: val
|
|
});
|
|
setThumb(animate);
|
|
//console.log("triggering OxRange" + that.id + "Change")
|
|
that.publish("change", { value: val });
|
|
}
|
|
}
|
|
function setWidth(width) {
|
|
trackWidth = width - self.options.arrows * 32;
|
|
thumbWidth = Math.max(trackWidth / values - 2, self.options.thumbSize - 2);
|
|
that.$element.css({
|
|
width: (width - 2) + "px"
|
|
});
|
|
$track.css({
|
|
width: (trackWidth - 2) + "px"
|
|
});
|
|
if (trackImages) {
|
|
$image.css({
|
|
width: (trackWidth - 2) + "px"
|
|
});
|
|
}
|
|
$thumb.css({
|
|
width: (thumbWidth - 2) + "px",
|
|
padding: 0
|
|
});
|
|
setThumb();
|
|
}
|
|
|
|
/*
|
|
shared functions
|
|
*/
|
|
|
|
self.onChange = function(option, value) {
|
|
|
|
}
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Menus
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.MainMenu = function(options, self) {
|
|
|
|
}
|
|
|
|
Ox.Menu = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
element: null,
|
|
id: "",
|
|
items: [],
|
|
offset: {
|
|
left: 0,
|
|
top: 0
|
|
},
|
|
side: "bottom",
|
|
size: "medium"
|
|
})
|
|
.options(options)
|
|
.addClass(
|
|
"OxMenu Ox" + Ox.toTitleCase(self.options.side) +
|
|
" Ox" + Ox.toTitleCase(self.options.size)
|
|
),
|
|
itemHeight = options.size == "small" ? 12 : (options.size == "medium" ? 16 : 20),
|
|
selected = -1,
|
|
scrollSpeed = 1,
|
|
$item;
|
|
|
|
// construct
|
|
that.items = [];
|
|
that.submenus = {};
|
|
that.$scrollbars = [];
|
|
that.$top = $("<div>")
|
|
.addClass("OxTop")
|
|
.appendTo(that.$element);
|
|
that.$scrollbars.up = constructScrollbar("up")
|
|
.appendTo(that.$element);
|
|
that.$container = $("<div>")
|
|
.addClass("OxContainer")
|
|
.appendTo(that.$element);
|
|
that.$content = $("<table>")
|
|
.addClass("OxContent")
|
|
.appendTo(that.$container);
|
|
$.each(self.options.items, function(i, item) {
|
|
if (item.id) {
|
|
if (!$.isEmptyObject(item.submenu)) {
|
|
that.submenus[item.id] = new Ox.Menu(item.submenu);
|
|
}
|
|
$.extend(item, {
|
|
menu: that,
|
|
submenu: that.submenus[item.id] || null
|
|
});
|
|
item = new Ox.MenuItem(item)
|
|
.data("pos", i)
|
|
.appendTo(that.$content);
|
|
that.items.push(item);
|
|
that.$content.append($item);
|
|
} else {
|
|
that.$content.append(constructSpace());
|
|
that.$content.append(constructLine());
|
|
that.$content.append(constructSpace());
|
|
}
|
|
});
|
|
that.$scrollbars.down = constructScrollbar("down")
|
|
.appendTo(that.$element);
|
|
that.$bottom = $("<div>")
|
|
.addClass("OxBottom")
|
|
.appendTo(that.$element);
|
|
|
|
function constructLine() {
|
|
return $("<tr>").append(
|
|
$("<td>", {
|
|
"class": "OxLine",
|
|
colspan: 5
|
|
})
|
|
);
|
|
}
|
|
|
|
function constructScrollbar(direction) {
|
|
var interval;
|
|
return $("<div/>", {
|
|
addClass: "OxScrollbar Ox" + Ox.toTitleCase(direction),
|
|
html: oxui.symbols["triangle_" + direction],
|
|
click: function() { // fixme: do we need to listen to click event?
|
|
return false;
|
|
},
|
|
mousedown: function() {
|
|
scrollSpeed = 2;
|
|
return false;
|
|
},
|
|
mouseenter: function() {
|
|
var $otherScrollbar = that.$scrollbars[direction == "up" ? "down" : "up"];
|
|
$(this).addClass("OxSelected");
|
|
if ($otherScrollbar.is(":hidden")) {
|
|
$otherScrollbar.show();
|
|
that.$container.height(that.$container.height() - itemHeight);
|
|
if (direction == "down") {
|
|
that.$content.css({
|
|
top: -itemHeight + "px"
|
|
});
|
|
}
|
|
}
|
|
scrollMenu(direction == "up" ? -1 : 1);
|
|
interval = setInterval(function() {
|
|
scrollMenu(direction == "up" ? -1 : 1);
|
|
}, 100);
|
|
},
|
|
mouseleave: function() {
|
|
$(this).removeClass("OxSelected");
|
|
clearInterval(interval);
|
|
},
|
|
mouseup: function() {
|
|
scrollSpeed = 1;
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
function constructSpace() {
|
|
return $("<tr>").append(
|
|
$("<td>", {
|
|
"class": "OxSpace",
|
|
colspan: 5
|
|
})
|
|
);
|
|
}
|
|
|
|
function getElement(id) {
|
|
return $("#" + Ox.toCamelCase(options.id + "/" + id));
|
|
}
|
|
|
|
function scrollMenu(speed) {
|
|
var containerHeight = that.$container.height(),
|
|
contentHeight = that.$content.height(),
|
|
top = parseInt(that.$content.css("top")) || 0,
|
|
min = containerHeight - contentHeight + itemHeight,
|
|
max = 0;
|
|
top += speed * scrollSpeed * -itemHeight;
|
|
if (top <= min) {
|
|
top = min;
|
|
that.$scrollbars.down.hide().trigger("mouseleave");
|
|
that.$container.css({
|
|
height: (containerHeight + itemHeight) + "px"
|
|
});
|
|
that.$items[that.$items.length - 1].trigger("mouseover");
|
|
} else if (top >= max - itemHeight) {
|
|
top = max;
|
|
that.$scrollbars.up.hide().trigger("mouseleave");
|
|
that.$container.css({
|
|
height: (containerHeight + itemHeight) + "px"
|
|
});
|
|
that.$items[0].trigger("mouseover");
|
|
}
|
|
that.$content.css({
|
|
top: top + "px"
|
|
});
|
|
|
|
}
|
|
|
|
function selectNextItem() {
|
|
|
|
}
|
|
|
|
function selectPreviousItem() {
|
|
|
|
}
|
|
|
|
that.hideMenu = function() {
|
|
Ox.print("hideMenu")
|
|
$.each(that.submenus, function(i, submenu) {
|
|
if (!submenu.is(":hidden")) {
|
|
submenu.hideMenu();
|
|
return false;
|
|
}
|
|
});
|
|
// fixme: scroll menu back up!
|
|
that.hide();
|
|
};
|
|
|
|
that.showMenu = function() {
|
|
Ox.print("showMenu")
|
|
that.parent().length || that.appendTo($body);
|
|
var offset = self.options.element.offset(),
|
|
width = self.options.element.outerWidth(),
|
|
height = self.options.element.outerHeight(),
|
|
left = offset.left + self.options.offset.left + (self.options.side == "bottom" ? 0 : width),
|
|
top = offset.top + self.options.offset.top + (self.options.side == "bottom" ? height : 0),
|
|
maxHeight = Math.floor(($window.height() - top - 12) / itemHeight) * itemHeight;
|
|
that.css({
|
|
left: left + "px",
|
|
top: top + "px"
|
|
}).show();
|
|
if (height > maxHeight) {
|
|
that.$container.height(maxHeight - itemHeight);
|
|
that.$scrollbars.down.show();
|
|
}
|
|
};
|
|
|
|
that.toggleMenu = function() {
|
|
Ox.print("toggleMenu")
|
|
that.is(":hidden") ? that.showMenu() : that.hideMenu();
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
Ox.MenuItem = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element("tr", self)
|
|
.defaults({
|
|
bind: [],
|
|
checked: null,
|
|
disabled: false,
|
|
group: "",
|
|
icon: "",
|
|
id: "",
|
|
keyboard: "",
|
|
menu: null, // fixme: is passing the menu to 100s of menu items really memory-neutral?
|
|
submenu: null,
|
|
title: [],
|
|
})
|
|
.options($.extend(options, {
|
|
keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard),
|
|
title: Ox.makeArray(options.title || self.defaults.title)
|
|
}))
|
|
.addClass("OxItem" + (self.options.disabled ? " OxDisabled" : ""))
|
|
.attr({
|
|
id: Ox.toCamelCase(self.options.menu.id + "/" + self.options.id)
|
|
})
|
|
.click(click)
|
|
.data("group", self.options.group)
|
|
.mouseenter(mouseenter)
|
|
.mouseleave(mouseleave);
|
|
|
|
// construct
|
|
that.append(
|
|
that.$status = $("<td>", {
|
|
"class": "OxCell OxStatus",
|
|
html: self.options.checked ? oxui.symbols.check : ""
|
|
})
|
|
)
|
|
.append(
|
|
that.$icon = $("<td>", {
|
|
"class": "OxCell OxIcon"
|
|
})
|
|
.append(self.options.icon ?
|
|
$("<img>", {
|
|
src: self.options.icon
|
|
}) : null
|
|
)
|
|
)
|
|
.append(
|
|
that.$title = $("<td>", {
|
|
"class": "OxCell OxTitle",
|
|
html: self.options.title[0]
|
|
})
|
|
)
|
|
.append(
|
|
$("<td>", {
|
|
"class": "OxCell OxModifiers",
|
|
html: $.map(self.options.keyboard.modifiers, function(modifier) {
|
|
return oxui.symbol[modifier];
|
|
}).join("")
|
|
})
|
|
)
|
|
.append(
|
|
$("<td>", {
|
|
"class": "OxCell Ox" + (self.options.submenu ? "Submenu" : "Key"),
|
|
html: self.options.submenu ? oxui.symbols.triangle_right :
|
|
oxui.symbols[self.options.keyboard.key] || self.options.keyboard.key
|
|
})
|
|
)
|
|
|
|
function click() {
|
|
if (!that.hasClass("OxDisabled") && !self.options.submenu) {
|
|
self.options.menu.hideMenu();
|
|
if (self.options.checked !== null && (!self.options.group || !self.options.checked)) {
|
|
that.options({
|
|
checked: !self.options.checked
|
|
});
|
|
}
|
|
if (self.options.title.length == 2) {
|
|
that.toggleTitle();
|
|
}
|
|
$("*").trigger("OxClickMenu", {
|
|
id: self.options.id,
|
|
value: self.options.title // fixme: value or title?
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function mouseenter() {
|
|
if (!that.is(".OxDisabled") && !that.is(".OxSelected")) {
|
|
$.each(self.options.menu.submenus, function(id, submenu) {
|
|
submenu.hideMenu();
|
|
});
|
|
$(".OxMenu .OxItem[id!=" + self.options.id + "]").removeClass("selected");
|
|
self.options.submenu && self.options.submenu.showMenu(); // fixme: do we want to switch to this style?
|
|
that.addClass("OxSelected");
|
|
}
|
|
}
|
|
|
|
function mouseleave() {
|
|
if (!that.hasClass("OxDisabled") && !self.options.submenu) {
|
|
that.removeClass("OxSelected");
|
|
}
|
|
}
|
|
|
|
function parseKeyboard(str) {
|
|
var modifiers = str.split(' '),
|
|
key = modifiers.pop();
|
|
return {
|
|
modifiers: modifiers,
|
|
key: key
|
|
}
|
|
}
|
|
|
|
self.onChange = function(key, value) {
|
|
Ox.print("MenuItem", self.options.id, "onChange", key, value);
|
|
if (key == "checked") {
|
|
if (value && self.options.group) {
|
|
$.each(self.options.menu.items, function(i, item) {
|
|
if (
|
|
item.options("id") != self.options.id &&
|
|
item.options("group") == self.options.group &&
|
|
item.options("checked")
|
|
) {
|
|
item.options({
|
|
checked: false
|
|
});
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
that.$status.html(value ? oxui.symbols.check : "")
|
|
} else if (key == "disabled") {
|
|
that.toggleClass("disabled"); // fixme: this will only work if onChange is only invoked on actual change
|
|
}
|
|
}
|
|
|
|
that.insertItemAfter = function(item) {
|
|
|
|
};
|
|
|
|
that.insertItemBefore = function(item) {
|
|
|
|
};
|
|
|
|
that.removeItem = function() {
|
|
|
|
};
|
|
|
|
that.toggleChecked = function() {
|
|
|
|
};
|
|
|
|
that.toggleDisabled = function() {
|
|
|
|
};
|
|
|
|
that.toggleTitle = function() {
|
|
that.options({
|
|
title: that.$title.html() == self.options.title[0] ?
|
|
self.options.title[1] : self.options.title[0]
|
|
})
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Panels
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.CollapsePanel
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.CollapsePanel = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Panel({}, self)
|
|
.defaults({
|
|
collapsed: false,
|
|
size: 20,
|
|
title: ""
|
|
})
|
|
.options(options)
|
|
.addClass("OxCollapsePanel"),
|
|
value = self.options.collapsed ?
|
|
["expand", "collapsed"] : ["collapse", "expand"],
|
|
$titlebar = new Ox.Bar({
|
|
orientation: "horizontal",
|
|
size: self.options.size,
|
|
})
|
|
.dblclick(dblclickTitlebar)
|
|
.appendTo(that),
|
|
$switch = new Ox.Button({
|
|
size: "small",
|
|
style: "symbol",
|
|
type: "image",
|
|
value: value,
|
|
})
|
|
.click(toggleCollapsed)
|
|
.appendTo($titlebar),
|
|
$title = new Ox.Element()
|
|
.addClass("OxTitle")
|
|
.html(self.options.title/*.toUpperCase()*/)
|
|
.appendTo($titlebar);
|
|
that.$content = new Ox.Element()
|
|
.addClass("OxContent")
|
|
.appendTo(that);
|
|
// fixme: doesn't work, content still empty
|
|
// need to hide it if collapsed
|
|
if (self.options.collapsed) {
|
|
that.$content.css({
|
|
marginTop: -that.$content.height() + "px"
|
|
});
|
|
}
|
|
function dblclickTitlebar(e) {
|
|
if (!$(e.target).hasClass("OxButton")) {
|
|
toggleCollapsed();
|
|
}
|
|
}
|
|
function toggleCollapsed() {
|
|
that.options({
|
|
collapsed: !self.options.collapsed
|
|
});
|
|
var top = self.options.collapsed ?
|
|
-that.$content.height() : 0;
|
|
that.$content.animate({
|
|
marginTop: top + "px"
|
|
}, 200);
|
|
}
|
|
self.onChange = function(option, value) {
|
|
if (option == "collapsed") {
|
|
$switch.options({
|
|
value: value ? "expand" : "collapse"
|
|
});
|
|
} else if (option == "title") {
|
|
$title.html(self.options.title);
|
|
}
|
|
};
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Panel
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Panel = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.addClass("OxPanel");
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.SplitPanel
|
|
options:
|
|
orientation: "" "horizontal" or "vertical"
|
|
elements: [{
|
|
element, Ox Element
|
|
size: 0, size in px
|
|
resizable: false resizable or not
|
|
}]
|
|
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.SplitPanel = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
elements: [],
|
|
orientation: "horizontal"
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxSplitPanel"),
|
|
length = self.options.elements.length,
|
|
dimensions = oxui.getDimensions(self.options.orientation),
|
|
edges = oxui.getEdges(self.options.orientation);
|
|
$.each(self.options.elements, function(i, v) {
|
|
var element = v.element
|
|
.css({
|
|
position: "absolute" // fixme: this can go into a class
|
|
})
|
|
.css(edges[2], 0)
|
|
.css(edges[3], 0);
|
|
if (v.size != undefined) {
|
|
element.css(dimensions[0], v.size + "px");
|
|
}
|
|
if (i == 0) {
|
|
element.css(edges[0], 0);
|
|
if (v.size == undefined) {
|
|
element.css(
|
|
edges[1],
|
|
(self.options.elements[1].size + (length == 3 ? self.options.elements[2].size : 0)) + "px"
|
|
);
|
|
}
|
|
} else if (i == 1) {
|
|
if (self.options.elements[0].size != undefined) {
|
|
element.css(edges[0], self.options.elements[0].size + "px");
|
|
}
|
|
if (self.options.elements[0].size == undefined || v.size == undefined) {
|
|
element.css(
|
|
edges[1],
|
|
(length == 3 ? self.options.elements[2].size : 0) + "px"
|
|
);
|
|
}
|
|
} else {
|
|
element.css(edges[1], 0);
|
|
if (v.size == undefined) {
|
|
element.css(
|
|
edges[0],
|
|
(self.options.elements[0].size + self.options.elements[1].size) + "px"
|
|
);
|
|
}
|
|
}
|
|
element.appendTo(that);
|
|
//that.append(element)
|
|
});
|
|
return that;
|
|
};
|
|
|
|
})();
|
|
|
|
/*
|
|
============================================================================
|
|
Requests
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Progressbar
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Spinner
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|