oxjstmp/build/js/ox.ui.js

2485 lines
85 KiB
JavaScript
Raw Normal View History

2010-01-07 20:21:07 +00:00
/*
################################################################################
ox.ui.js
requires
2010-01-25 11:42:28 +00:00
jquery-1.4.js
2010-01-07 20:21:07 +00:00
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];
},
2010-01-25 11:42:28 +00:00
jQueryFunctions: function() {
2010-01-07 20:21:07 +00:00
var functions = [],
2010-01-25 11:42:28 +00:00
$element = $("<div>");
//delete $element.length;
Ox.each($element, function(k, v) {
2010-01-07 20:21:07 +00:00
if (typeof v == "function") {
functions.push(k);
}
});
return functions.sort();
}(),
path: $("script[src*=ox.ui.js]").attr("src")
.replace("js/ox.ui.js", ""),
2010-02-03 12:12:21 +00:00
symbols: { // fixme: make lowercase
alt: "\u2325",
apple: "\uF8FF",
arrow_down: "\u2193",
arrow_left: "\u2190",
2010-02-05 05:20:13 +00:00
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",
2010-02-03 12:12:21 +00:00
triangle_right: "\u25BA",
2010-02-05 05:20:13 +00:00
triangle_up: "\u25B2",
undo: "\u21BB",
voltage: "\u26A1",
warning: "\u26A0",
white_star: "\u2606"
2010-02-03 12:12:21 +00:00
}
2010-01-07 20:21:07 +00:00
},
$window, $document, $body;
$(function() {
$window = $(window),
$document = $(document),
$body = $("body");
Ox.theme(oxui.defaultTheme);
2010-02-04 09:50:45 +00:00
});
2010-01-07 20:21:07 +00:00
/*
============================================================================
Application
============================================================================
*/
/*
----------------------------------------------------------------------------
Ox.App
----------------------------------------------------------------------------
*/
2010-01-27 12:30:00 +00:00
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);
};
2010-01-31 08:03:22 +00:00
that.request = function(action, data, callback) {
if (arguments.length == 2) {
2010-01-27 13:25:37 +00:00
callback = data;
data = {};
}
return Ox.Request.send({
url: self.options.requestURL,
data: {
2010-01-31 08:03:22 +00:00
action: action,
2010-01-27 13:25:37 +00:00
data: JSON.stringify(data)
},
callback: callback
});
};
2010-01-27 12:30:00 +00:00
return that;
};
}();
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
Ox.Event
----------------------------------------------------------------------------
2010-02-03 12:12:21 +00:00
2010-01-07 20:21:07 +00:00
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
2010-02-03 12:12:21 +00:00
2010-02-05 09:13:03 +00:00
2010-01-07 20:21:07 +00:00
Ox.Event = function() {
2010-02-05 09:13:03 +00:00
var keyboardEvents = {};
$eventHandler = $("<div>");
function isKeyboardEvent(event) {
return event.substr(0, 4) == "key_";
}
2010-02-04 08:02:23 +00:00
return {
2010-02-05 09:13:03 +00:00
bind: function(id, event, callback) {
if (isKeyboardEvent(event)) {
2010-02-05 09:34:07 +00:00
keyboardEvents[id] = keyboardEvents[id] || {};
keyboardEvents[id][event] = callback;
2010-02-05 09:13:03 +00:00
}
if (!isKeyboardEvent(event) || Ox.Focus.focused() == id) {
$eventHandler.bind(event, callback);
}
2010-02-04 08:02:23 +00:00
},
2010-02-05 09:13:03 +00:00
bindKeyboard: function(id) {
2010-02-05 09:34:07 +00:00
$.each(keyboardEvents[id] || [], function(event, callback) {
Ox.Event.bind(id, event, callback);
2010-02-05 09:13:03 +00:00
});
2010-02-04 09:50:45 +00:00
},
2010-02-04 08:02:23 +00:00
trigger: function(event, data) {
2010-02-04 09:50:45 +00:00
Ox.print("trigger", event, data || {});
$eventHandler.trigger(event, data || {});
2010-02-04 08:02:23 +00:00
},
2010-02-05 09:13:03 +00:00
unbind: function(id, event, callback) {
if (isKeyboardEvent(event)) {
2010-02-05 09:34:07 +00:00
$.each(keyboardEvents[id] || [], function(e, callback) {
if (e == event) {
delete keyboardEvents[id][e];
2010-02-05 09:13:03 +00:00
return false;
}
});
}
2010-02-04 08:02:23 +00:00
$eventHandler.unbind(event, callback);
2010-02-05 09:13:03 +00:00
},
unbindKeyboard: function(id) {
//Ox.print(keyboardEvents)
//Ox.print("unbindKeyboard", id, keyboardEvents[id])
2010-02-05 09:34:07 +00:00
$.each(keyboardEvents[id] || [], function(event, callback) {
$eventHandler.unbind(event, callback);
2010-02-05 09:13:03 +00:00
});
2010-02-04 08:02:23 +00:00
}
}
2010-02-04 09:50:45 +00:00
}();
2010-02-04 08:02:23 +00:00
Ox.Event_ = function() {
2010-01-07 20:21:07 +00:00
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) {
2010-02-05 09:13:03 +00:00
/*
if (stack.length) {
Ox.Event.unbindKeyboard(stack[stack.length - 1]);
}
*/
2010-01-07 20:21:07 +00:00
var index = stack.indexOf(id);
if (index > -1) {
2010-02-05 09:13:03 +00:00
stack.splice(index, 1);
2010-01-07 20:21:07 +00:00
}
2010-02-05 09:13:03 +00:00
stack.push(id);
Ox.Event.bindKeyboard(id);
2010-02-05 09:13:54 +00:00
Ox.print("focus", stack);
2010-02-05 09:13:03 +00:00
},
focused: function() {
return stack[stack.length - 1];
2010-01-07 20:21:07 +00:00
},
blur: function(id) {
2010-02-05 09:13:03 +00:00
if (stack.indexOf(id) > -1) {
stack.splice(stack.length - 2, 0, stack.pop());
}
Ox.Event.unbindKeyboard(id);
/*
Ox.Event.bindKeyboard(stack[stack.length - 1]);
*/
2010-02-05 09:13:54 +00:00
Ox.print("blur", stack);
2010-01-07 20:21:07 +00:00
}
};
}();
/*
----------------------------------------------------------------------------
Ox.History
----------------------------------------------------------------------------
*/
/*
----------------------------------------------------------------------------
Ox.Keyboard
----------------------------------------------------------------------------
*/
(function() {
2010-01-25 11:42:28 +00:00
2010-01-07 20:21:07 +00:00
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",
2010-02-04 09:50:45 +00:00
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",
2010-01-07 20:21:07 +00:00
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"
};
2010-02-04 09:50:45 +00:00
$(function() {
2010-02-05 15:31:19 +00:00
if ($.browser.safari) {
$document.keydown(keydown);
} else {
$document.keypress(keydown);
}
2010-02-04 09:50:45 +00:00
});
function keydown(event) {
var key,
keys = [],
ret = true,
time;
$.each(modifierNames, function(k, v) {
if (event[k]) {
keys.push(v);
2010-01-07 20:21:07 +00:00
}
2010-02-04 09:50:45 +00:00
});
// avoid pushing modifier twice
if (keyNames[event.keyCode] && keys.indexOf(keyNames[event.keyCode]) == -1) {
keys.push(keyNames[event.keyCode]);
}
key = keys.join(".");
if (key.match(/^[\w\d-]$|SPACE/)) {
time = Ox.getTime();
if (time - bufferTime > bufferTimeout) {
buffer = "";
2010-01-07 20:21:07 +00:00
}
2010-02-04 09:50:45 +00:00
buffer += key == "SPACE" ? " " : key;
bufferTime = time;
2010-01-07 20:21:07 +00:00
}
2010-02-05 09:13:03 +00:00
Ox.Event.trigger("key_" + key);
2010-02-04 09:50:45 +00:00
/*
$.each(stack, function(i, v) {
// fixme: we dont get the return value!
ret = Ox.event.trigger(keyboard + Ox.toCamelCase(key) + "." + v);
return ret;
});
*/
}
2010-01-07 20:21:07 +00:00
})();
/*
----------------------------------------------------------------------------
Ox.Mouse (??)
----------------------------------------------------------------------------
*/
2010-01-27 12:30:00 +00:00
/*
----------------------------------------------------------------------------
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]]
}
},
2010-01-27 12:34:27 +00:00
emptyCache: function() {
cache = {};
2010-01-27 12:35:37 +00:00
},
2010-01-27 12:34:27 +00:00
2010-01-27 12:30:00 +00:00
options: function(options) {
2010-01-27 12:34:27 +00:00
return Ox.getset(self.options, options, $.noop(), this);
2010-01-27 12:30:00 +00:00
},
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
});
2010-01-31 10:06:52 +00:00
function callback(data) {
2010-01-27 12:30:00 +00:00
delete requests[options.id];
2010-01-31 10:06:52 +00:00
options.callback(data);
2010-01-27 12:30:00 +00:00
}
2010-01-31 09:32:41 +00:00
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();
}
2010-01-27 12:30:00 +00:00
function error(request, status, error) {
2010-01-31 10:06:52 +00:00
var data;
2010-02-01 06:11:35 +00:00
if (arguments.length == 1) {
data = arguments[0]
} else {
try {
data = JSON.parse(request.responseText);
} catch (err) {
data = {
status: {
code: request.status,
text: request.statusText
}
};
}
2010-01-27 13:25:37 +00:00
}
2010-01-31 10:06:52 +00:00
if (data.status.code < 500) {
callback(data);
} else {
2010-01-27 13:25:37 +00:00
var $dialog = new Ox.Dialog({
2010-01-31 09:32:41 +00:00
title: "Application Error",
buttons: [
{
value: "Details",
click: function() {
$dialog.close(function() {
debug(request);
});
}
},
{
value: "Close",
click: function() {
2010-01-31 10:06:52 +00:00
$dialog.close(function() {
callback(data);
});
2010-01-31 09:32:41 +00:00
}
}
],
width: 400,
height: 100
})
2010-01-31 10:06:52 +00:00
.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.")
2010-01-31 09:32:41 +00:00
.open();
2010-02-01 06:11:35 +00:00
// fixme: change this to Send / Don't Send
2010-01-27 13:25:37 +00:00
Ox.print({
request: request,
status: status,
error: error
});
}
2010-01-27 12:30:00 +00:00
pending[options.id] = false;
}
function success(data) {
pending[options.id] = false;
try {
data = JSON.parse(data);
2010-02-01 06:11:35 +00:00
} catch (err) {
error({
2010-01-31 09:32:41 +00:00
status: {
code: 500,
text: "Internal Server Error"
},
data: {}
2010-02-01 06:11:35 +00:00
});
return;
2010-01-27 12:30:00 +00:00
}
cache[req] = {
data: data,
time: Ox.getTime()
};
2010-01-31 10:06:52 +00:00
callback(data);
2010-01-27 12:30:00 +00:00
}
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() {
2010-01-31 10:06:52 +00:00
callback(cache[req].data);
2010-01-27 12:30:00 +00:00
}, 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;
}
};
}();
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
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() {
2010-01-25 11:42:28 +00:00
var elements = {};
2010-01-07 20:21:07 +00:00
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();
2010-01-25 11:42:28 +00:00
that.$element = $("<" + (options.element || "div") + "/>", {
data: {
ox: that.id
}
});
2010-01-07 20:21:07 +00:00
elements[that.id] = that;
wrapjQuery();
})();
// private
function wrapjQuery() {
2010-01-25 11:42:28 +00:00
$.each(oxui.jQueryFunctions, function(i, v) {
2010-01-07 20:21:07 +00:00
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
2010-02-05 09:13:03 +00:00
that.bindEvent = function() {
/*
bindEvent(event, fn) or bindEvent({event0: fn0, event1: fn1, ...})
*/
if (arguments.length == 1) {
$.each(arguments[0], function(event, fn) {
Ox.Event.bind(that.id, event, fn);
})
} else {
Ox.Event.bind(that.id, arguments[0], arguments[1]);
}
};
2010-01-07 20:21:07 +00:00
that.defaults = function(defaults) {
/*
that.defaults({foo: x}) sets self.defaults
*/
self.defaults = defaults;
return that;
2010-02-05 09:13:03 +00:00
};
that.gainFocus = function() {
Ox.Focus.focus(that.id);
};
that.hasFocus = function() {
return Ox.Focus.focused() == that.id;
};
that.loseFocus = function() {
Ox.Focus.blur(that.id);
};
that.options = function() { // fixme: use Ox.getset
2010-01-07 20:21:07 +00:00
/*
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.remove = function() {
that.$element.remove();
delete elements[that.ox];
}
2010-02-05 09:13:03 +00:00
that.unbindEvent = function() {
/*
unbindEvent(event, fn) or unbindEvent({event0: fn0, event1: fn1, ...})
*/
if (arguments.length == 1) {
$.each(arguments[0], function(event, fn) {
Ox.Event.unbind(that.id, event, fn);
})
} else {
Ox.Event.unbind(that.id, arguments[0], arguments[1]);
}
2010-01-07 20:21:07 +00:00
}
// 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;
};
2010-01-27 12:30:00 +00:00
/*
============================================================================
2010-01-31 08:03:22 +00:00
Ox.Dialog
2010-01-27 12:30:00 +00:00
============================================================================
*/
Ox.Dialog = function(options, self) {
var self = self || {},
options = $.extend({
title: "",
buttons: [],
2010-01-31 08:03:22 +00:00
width: 384,
2010-01-27 12:30:00 +00:00
height: 128
}, options),
that = new Ox.Element()
.addClass("OxDialog")
.css({
left: (($(document).width() - options.width) / 2) + "px",
2010-01-31 09:32:41 +00:00
top: (($(document).height() - options.height - 92) / 2) + "px",
2010-01-27 12:30:00 +00:00
width: options.width + "px",
2010-01-31 09:32:41 +00:00
height: (options.height + 92) + "px"
2010-01-27 12:30:00 +00:00
});
2010-01-31 08:03:22 +00:00
that.$titlebar = new Ox.Bar({
size: "medium"
})
2010-01-27 12:30:00 +00:00
.addClass("OxTitleBar")
2010-01-31 08:03:22 +00:00
//.html(options.title)
2010-01-27 12:30:00 +00:00
.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) {
2010-01-31 08:03:22 +00:00
$("*").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);
2010-01-27 12:30:00 +00:00
that.css({
left: left + "px",
top: top + "px"
});
});
$(window).one("mouseup", function() {
$(window).unbind("mousemove");
2010-01-31 08:03:22 +00:00
$("*").css({
WebkitUserSelect: "auto"
});
2010-01-27 12:30:00 +00:00
});
})
.appendTo(that);
2010-01-31 08:03:22 +00:00
that.$title = new Ox.Element().addClass("OxTitle").html(options.title).appendTo(that.$titlebar);
2010-01-27 12:30:00 +00:00
that.$content = new Ox.Container()
.addClass("OxContent")
.css({
height: options.height + "px"
})
.appendTo(that);
that.$buttonsbar = new Ox.Element()
.addClass("OxButtonsBar")
.appendTo(that);
2010-01-31 09:32:41 +00:00
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);
2010-01-27 12:30:00 +00:00
});
2010-01-31 09:32:41 +00:00
that.$buttons[0].focus();
2010-01-27 12:30:00 +00:00
that.$layer = $(".OxLayer"); // fixme: lazy loading of layer is fine, but save in var, dont look up
2010-01-31 08:03:22 +00:00
self.onChange = function(key, value) {
if (key == "title") {
that.$title.html(value);
}
}
2010-01-27 12:30:00 +00:00
that.append = function($element) {
that.$content.append($element);
return that;
}
2010-01-31 09:32:41 +00:00
that.close = function(callback) {
callback = callback || function() {};
2010-01-27 12:30:00 +00:00
that.animate({
opacity: 0
}, 200, function() {
that.remove();
that.$layer.remove();
2010-01-31 09:32:41 +00:00
callback();
2010-01-27 12:30:00 +00:00
})
}
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;
}
2010-01-07 20:21:07 +00:00
/*
============================================================================
Forms
============================================================================
*/
/*
----------------------------------------------------------------------------
Ox.Button
----------------------------------------------------------------------------
*/
Ox.Button = function(options, self) {
var self = self || {},
that = new Ox.Element("input", self)
.defaults({
buttonId: null,
2010-02-03 12:12:21 +00:00
click: function() {},
2010-01-07 20:21:07 +00:00
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]
});
}
2010-02-03 12:12:21 +00:00
self.options.click();
2010-01-07 20:21:07 +00:00
}
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);
}
}
}
2010-01-31 08:03:22 +00:00
that.toggleDisabled = function() {
that.options({
enabled: !self.options.disabled
});
}
2010-01-07 20:21:07 +00:00
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() {
2010-02-03 12:12:21 +00:00
that.$buttons = [];
2010-01-07 20:21:07 +00:00
$.each(self.options.values, function(i, v) {
2010-02-03 12:12:21 +00:00
that.$buttons[i] = Ox.Button({
2010-01-07 20:21:07 +00:00
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) {
2010-02-03 12:12:21 +00:00
that.$buttons[self.options.selected].toggleSelected();
2010-01-07 20:21:07 +00:00
}
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 || {});
2010-01-25 11:42:28 +00:00
that.attr({
2010-01-07 20:21:07 +00:00
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');
2010-01-25 15:10:44 +00:00
c.mozImageSmoothingEnabled = false; // we may want to remove this later
2010-01-07 20:21:07 +00:00
$.each(self.options.trackImages, function(i, v) {
2010-01-25 15:10:44 +00:00
//console.log(v)
2010-01-07 20:21:07 +00:00
$("<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;
};
2010-02-05 05:20:13 +00:00
/*
----------------------------------------------------------------------------
Ox.Select
----------------------------------------------------------------------------
*/
Ox.Select = function(options, self) {
var self = self || {},
that = new Ox.Button({}, self)
.defaults({
id: "",
items: []
})
.options(options)
.click(click),
items;
$.each(self.options.items, function(i, item) {
items.push({
checked: false,
group: self.options.id,
title: item.title
})
})
that.$menu = new Ox.Menu({
})
function click() {
}
return that;
}
2010-01-07 20:21:07 +00:00
/*
============================================================================
2010-02-02 16:03:11 +00:00
Menus
============================================================================
*/
Ox.MainMenu = function(options, self) {
}
Ox.Menu = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
2010-02-04 08:02:23 +00:00
element: null,
2010-02-02 16:03:11 +00:00
id: "",
items: [],
offset: {
left: 0,
top: 0
},
2010-02-05 09:13:03 +00:00
parent: null,
2010-02-04 09:50:45 +00:00
selected: -1,
2010-02-02 16:03:11 +00:00
side: "bottom",
2010-02-05 09:13:03 +00:00
size: "medium",
2010-02-02 16:03:11 +00:00
})
2010-02-03 12:12:21 +00:00
.options(options)
.addClass(
"OxMenu Ox" + Ox.toTitleCase(self.options.side) +
" Ox" + Ox.toTitleCase(self.options.size)
),
2010-02-05 14:59:24 +00:00
itemHeight = self.options.size == "small" ? 12 : (self.options.size == "medium" ? 16 : 20),
scrollSpeed = 1, // fixme: should this be self.scrollSpeed?
$item; // fixme: used?
2010-02-02 16:03:11 +00:00
// construct
2010-02-04 08:02:23 +00:00
that.items = [];
that.submenus = {};
2010-02-02 16:03:11 +00:00
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);
2010-02-03 12:12:21 +00:00
$.each(self.options.items, function(i, item) {
2010-02-05 05:20:13 +00:00
var position;
2010-02-02 16:03:11 +00:00
if (item.id) {
2010-02-04 08:02:23 +00:00
$.extend(item, {
menu: that,
});
2010-02-04 09:50:45 +00:00
that.items.push(new Ox.MenuItem($.extend(item, {
2010-02-05 05:20:13 +00:00
position: position = that.items.length
2010-02-04 09:50:45 +00:00
})).appendTo(that.$content));
2010-02-05 05:20:13 +00:00
if (item.items) {
that.submenus[item.id] = new Ox.Menu({
element: that.items[position],
id: Ox.toCamelCase(self.options.id + "/" + item.id),
items: item.items,
offset: {
left: 0,
top: -4
},
2010-02-05 09:13:03 +00:00
parent: that,
2010-02-05 05:20:13 +00:00
side: "right",
2010-02-05 09:13:03 +00:00
size: self.options.size,
2010-02-05 05:20:13 +00:00
});
}
2010-02-02 16:03:11 +00:00
} 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);
2010-02-05 09:13:03 +00:00
function click(event) {
if (!$(event.target).is(".OxCell")) {
that.hideMenu();
}
}
2010-02-04 09:50:45 +00:00
function clickItem() {
if (self.options.selected > -1) {
that.items[self.options.selected].trigger("click");
2010-02-05 05:20:13 +00:00
} else {
that.hideMenu();
2010-02-04 09:50:45 +00:00
}
}
2010-02-02 16:03:11 +00:00
function constructLine() {
2010-02-03 12:12:21 +00:00
return $("<tr>").append(
2010-02-04 08:02:23 +00:00
$("<td>", {
"class": "OxLine",
colspan: 5
2010-02-03 12:12:21 +00:00
})
);
2010-02-02 16:03:11 +00:00
}
function constructScrollbar(direction) {
2010-02-05 14:59:24 +00:00
var interval,
speed = direction == "up" ? -1 : 1;
2010-02-03 12:12:21 +00:00
return $("<div/>", {
2010-02-05 05:20:13 +00:00
"class": "OxScrollbar Ox" + Ox.toTitleCase(direction),
2010-02-03 12:12:21 +00:00
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"
});
}
}
2010-02-05 14:59:24 +00:00
scrollMenu(speed);
2010-02-03 12:12:21 +00:00
interval = setInterval(function() {
2010-02-05 14:59:24 +00:00
scrollMenu(speed);
2010-02-03 12:12:21 +00:00
}, 100);
},
mouseleave: function() {
$(this).removeClass("OxSelected");
clearInterval(interval);
},
mouseup: function() {
scrollSpeed = 1;
return false;
}
});
2010-02-02 16:03:11 +00:00
}
function constructSpace() {
2010-02-03 12:12:21 +00:00
return $("<tr>").append(
2010-02-04 08:02:23 +00:00
$("<td>", {
"class": "OxSpace",
colspan: 5
2010-02-03 12:12:21 +00:00
})
);
2010-02-02 16:03:11 +00:00
}
function getElement(id) {
2010-02-05 09:13:03 +00:00
// fixme: needed?
2010-02-02 16:03:11 +00:00
return $("#" + Ox.toCamelCase(options.id + "/" + id));
}
2010-02-05 05:20:13 +00:00
function isFirstEnabledItem() {
var ret = true;
$.each(that.items, function(i, item) {
if (i < self.options.selected && !item.options("disabled")) {
return ret = false;
}
});
return ret;
}
function isLastEnabledItem() {
var ret = true;
$.each(that.items, function(i, item) {
if (i > self.options.selected && !item.options("disabled")) {
return ret = false;
}
});
return ret;
}
2010-02-03 12:12:21 +00:00
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");
2010-02-05 14:59:24 +00:00
that.$container.height(containerHeight + itemHeight);
that.items[that.items.length - 1].trigger("mouseover");
2010-02-03 12:12:21 +00:00
} else if (top >= max - itemHeight) {
top = max;
that.$scrollbars.up.hide().trigger("mouseleave");
2010-02-05 14:59:24 +00:00
that.$container.height(containerHeight + itemHeight);
that.items[0].trigger("mouseover");
2010-02-03 12:12:21 +00:00
}
that.$content.css({
top: top + "px"
});
2010-02-02 16:03:11 +00:00
}
function selectNextItem() {
2010-02-05 15:26:23 +00:00
var offset,
selected = self.options.selected;
2010-02-05 05:20:13 +00:00
if (!isLastEnabledItem()) {
2010-02-04 09:50:45 +00:00
if (selected > -1) {
that.items[selected].trigger("mouseleave");
}
2010-02-05 05:20:13 +00:00
do {
selected++;
} while (that.items[selected].options("disabled"))
2010-02-04 09:50:45 +00:00
that.items[selected].trigger("mouseenter");
2010-02-05 15:26:23 +00:00
offset = that.items[selected].offset().top + itemHeight -
that.$container.offset().top - that.$container.height();
if (offset > 0) {
if (that.$scrollbars.up.is(":hidden")) {
that.$scrollbars.up.show();
that.$container.height(that.$container.height() - itemHeight);
offset += itemHeight;
}
if (selected == that.items.length - 1) {
that.$scrollbars.down.hide();
that.$container.height(that.$container.height() + itemHeight);
} else {
that.$content.css({
top: ((parseInt(that.$content.css("top")) || 0) - offset) + "px"
});
}
}
2010-02-04 09:50:45 +00:00
}
2010-02-02 16:03:11 +00:00
}
function selectPreviousItem() {
2010-02-05 15:26:23 +00:00
var offset,
selected = self.options.selected;
2010-02-05 05:20:13 +00:00
if (!isFirstEnabledItem()) {
2010-02-04 09:50:45 +00:00
that.items[selected].trigger("mouseleave");
2010-02-05 05:20:13 +00:00
do {
selected--;
} while (that.items[selected].options("disabled"))
2010-02-04 09:50:45 +00:00
that.items[selected].trigger("mouseenter");
}
2010-02-05 15:26:23 +00:00
offset = that.items[selected].offset().top - that.$container.offset().top;
Ox.print(offset);
if (offset < 0) {
if (that.$scrollbars.down.is(":hidden")) {
that.$scrollbars.down.show();
that.$container.height(that.$container.height() - itemHeight);
}
if (selected == 0) {
that.$scrollbars.up.hide();
that.$container.height(that.$container.height() + itemHeight);
}
that.$content.css({
top: ((parseInt(that.$content.css("top")) || 0) - offset) + "px"
});
}
2010-02-02 16:03:11 +00:00
}
2010-02-05 09:13:03 +00:00
function selectSubmenu() {
var submenu = that.submenus[that.items[self.options.selected].options("id")];
if (submenu && submenu.hasEnabledItems()) {
that.loseFocus();
submenu.gainFocus();
submenu.selectFirstItem();
}
}
function selectSupermenu() {
if (self.options.parent) {
that.items[self.options.selected].trigger("mouseleave");
that.loseFocus();
self.options.parent.gainFocus();
}
}
self.onChange = function(key, value) {
}
that.hasEnabledItems = function() {
var ret = false;
$.each(that.items, function(i, item) {
if (!item.options("disabled")) {
return ret = true;
}
});
return ret;
};
2010-02-02 16:03:11 +00:00
that.hideMenu = function() {
2010-02-04 08:02:23 +00:00
Ox.print("hideMenu")
$.each(that.submenus, function(i, submenu) {
2010-02-05 14:59:24 +00:00
if (submenu.is(":visible")) {
2010-02-04 08:02:23 +00:00
submenu.hideMenu();
2010-02-03 12:12:21 +00:00
return false;
}
});
2010-02-05 14:59:24 +00:00
if (that.$scrollbars.up.is(":visible")) {
that.$content.css({
top: "0px"
});
that.$scrollbars.up.hide();
that.$container.height(that.$container.height() + itemHeight);
}
2010-02-03 12:12:21 +00:00
that.hide();
2010-02-04 09:50:45 +00:00
if (self.options.selected > -1) {
that.items[self.options.selected].trigger("mouseleave");
}
2010-02-05 09:13:03 +00:00
that.loseFocus();
that.unbindEvent({
key_up: selectPreviousItem,
key_down: selectNextItem,
key_left: selectSupermenu,
key_right: selectSubmenu,
key_escape: that.hideMenu,
key_enter: clickItem
});
$document.unbind("click", click);
};
that.selectFirstItem = function() {
selectNextItem();
2010-02-02 16:03:11 +00:00
};
that.showMenu = function() {
2010-02-03 12:12:21 +00:00
Ox.print("showMenu")
2010-02-04 08:02:23 +00:00
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),
2010-02-05 14:59:24 +00:00
menuHeight = that.outerHeight(),
maxHeight = Math.floor($window.height() - top - 16);
Ox.print("height", height, "maxHeight", maxHeight);
2010-02-03 12:12:21 +00:00
that.css({
left: left + "px",
top: top + "px"
}).show();
2010-02-05 14:59:24 +00:00
if (menuHeight > maxHeight) {
2010-02-03 12:12:21 +00:00
that.$container.height(maxHeight - itemHeight);
that.$scrollbars.down.show();
}
2010-02-05 09:13:03 +00:00
if (!self.options.parent) {
that.gainFocus();
}
that.bindEvent({
key_up: selectPreviousItem,
key_down: selectNextItem,
key_left: selectSupermenu,
key_right: selectSubmenu,
key_escape: that.hideMenu,
key_enter: clickItem
});
2010-02-04 09:50:45 +00:00
setTimeout(function() {
2010-02-05 09:13:03 +00:00
$document.bind("click", click);
2010-02-04 09:50:45 +00:00
}, 100);
2010-02-02 16:03:11 +00:00
};
2010-02-03 12:12:21 +00:00
that.toggleMenu = function() {
Ox.print("toggleMenu")
that.is(":hidden") ? that.showMenu() : that.hideMenu();
2010-02-02 16:03:11 +00:00
};
return that;
2010-02-03 12:12:21 +00:00
};
2010-02-02 16:03:11 +00:00
Ox.MenuItem = function(options, self) {
var self = self || {},
2010-02-03 12:12:21 +00:00
that = new Ox.Element("tr", self)
2010-02-02 16:03:11 +00:00
.defaults({
bind: [],
2010-02-04 08:02:23 +00:00
checked: null,
2010-02-02 16:03:11 +00:00
disabled: false,
group: "",
icon: "",
id: "",
2010-02-05 05:20:13 +00:00
items: [],
2010-02-03 12:12:21 +00:00
keyboard: "",
menu: null, // fixme: is passing the menu to 100s of menu items really memory-neutral?
2010-02-04 09:50:45 +00:00
position: 0,
2010-02-03 12:12:21 +00:00
title: [],
})
.options($.extend(options, {
keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard),
title: Ox.makeArray(options.title || self.defaults.title)
}))
2010-02-04 08:02:23 +00:00
.addClass("OxItem" + (self.options.disabled ? " OxDisabled" : ""))
2010-02-03 12:12:21 +00:00
.attr({
2010-02-04 08:02:23 +00:00
id: Ox.toCamelCase(self.options.menu.id + "/" + self.options.id)
2010-02-03 12:12:21 +00:00
})
.click(click)
2010-02-04 09:50:45 +00:00
.data("group", self.options.group) // fixme: why?
2010-02-03 12:12:21 +00:00
.mouseenter(mouseenter)
2010-02-04 09:50:45 +00:00
.mouseleave(mouseleave)
2010-02-05 05:20:13 +00:00
.mousemove(mousemove); // in case selection has goes elsewhere via keyboard
2010-02-03 12:12:21 +00:00
// construct
that.append(
that.$status = $("<td>", {
2010-02-04 08:02:23 +00:00
"class": "OxCell OxStatus",
2010-02-03 12:12:21 +00:00
html: self.options.checked ? oxui.symbols.check : ""
})
)
.append(
that.$icon = $("<td>", {
2010-02-04 08:02:23 +00:00
"class": "OxCell OxIcon"
2010-02-02 16:03:11 +00:00
})
2010-02-03 12:12:21 +00:00
.append(self.options.icon ?
$("<img>", {
2010-02-04 08:02:23 +00:00
src: self.options.icon
2010-02-03 12:12:21 +00:00
}) : null
)
)
.append(
that.$title = $("<td>", {
2010-02-04 08:02:23 +00:00
"class": "OxCell OxTitle",
2010-02-03 12:12:21 +00:00
html: self.options.title[0]
})
)
.append(
$("<td>", {
2010-02-04 08:02:23 +00:00
"class": "OxCell OxModifiers",
2010-02-03 12:12:21 +00:00
html: $.map(self.options.keyboard.modifiers, function(modifier) {
return oxui.symbol[modifier];
}).join("")
})
)
.append(
$("<td>", {
2010-02-05 05:20:13 +00:00
"class": "OxCell Ox" + (self.options.items.length ? "Submenu" : "Key"),
html: self.options.items.length ? oxui.symbols.triangle_right :
2010-02-03 12:12:21 +00:00
oxui.symbols[self.options.keyboard.key] || self.options.keyboard.key
})
2010-02-05 05:20:13 +00:00
);
2010-02-03 12:12:21 +00:00
function click() {
2010-02-05 14:59:24 +00:00
if (!that.hasClass("OxDisabled")) {
2010-02-04 08:02:23 +00:00
self.options.menu.hideMenu();
2010-02-05 09:17:04 +00:00
if (self.options.menu.options("parent")) {
self.options.menu.options("parent").hideMenu();
}
2010-02-05 14:59:24 +00:00
if (!self.options.items.length) {
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();
}
Ox.Event.trigger("OxClickMenu", {
id: self.options.id,
value: self.options.title // fixme: value or title?
2010-02-04 08:02:23 +00:00
});
2010-02-03 12:12:21 +00:00
}
}
}
2010-02-05 05:20:13 +00:00
function isSelected() {
return self.options.position == self.options.menu.options("selected");
}
2010-02-03 12:12:21 +00:00
function mouseenter() {
2010-02-05 05:20:13 +00:00
if (!self.options.disabled && !isSelected()) {
2010-02-03 12:12:21 +00:00
$.each(self.options.menu.submenus, function(id, submenu) {
2010-02-05 09:13:03 +00:00
if (!submenu.is(":hidden")) {
submenu.hideMenu();
return false;
}
2010-02-03 12:12:21 +00:00
});
2010-02-05 05:20:13 +00:00
if (self.options.menu.options("selected") > -1) {
self.options.menu.items[self.options.menu.options("selected")].trigger("mouseleave");
}
self.options.items.length && self.options.menu.submenus[self.options.id].showMenu(); // fixme: do we want to switch to this style?
2010-02-03 12:12:21 +00:00
that.addClass("OxSelected");
2010-02-04 09:50:45 +00:00
self.options.menu.options({
selected: self.options.position
});
2010-02-03 12:12:21 +00:00
}
}
function mouseleave() {
2010-02-05 05:20:13 +00:00
if (!self.options.disabled && !self.options.submenu) {
2010-02-03 12:12:21 +00:00
that.removeClass("OxSelected");
2010-02-04 09:50:45 +00:00
self.options.menu.options({
selected: -1
});
2010-02-03 12:12:21 +00:00
}
}
2010-02-05 05:20:13 +00:00
function mousemove() {
var selected = self.options.menu.options("selected");
if (!self.options.disabled && !isSelected()) {
self.options.menu.items[self.options.menu.options("selected")]
.trigger("mouseleave");
mouseenter();
}
}
2010-02-03 12:12:21 +00:00
function parseKeyboard(str) {
var modifiers = str.split(' '),
key = modifiers.pop();
return {
modifiers: modifiers,
key: key
}
}
self.onChange = function(key, value) {
2010-02-04 08:02:23 +00:00
Ox.print("MenuItem", self.options.id, "onChange", key, value);
2010-02-03 12:12:21 +00:00
if (key == "checked") {
2010-02-04 08:02:23 +00:00
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 : "")
2010-02-03 12:12:21 +00:00
} else if (key == "disabled") {
that.toggleClass("disabled"); // fixme: this will only work if onChange is only invoked on actual change
}
}
that.insertItemAfter = function(item) {
2010-02-02 16:03:11 +00:00
2010-02-03 12:12:21 +00:00
};
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]
2010-02-02 16:03:11 +00:00
})
2010-02-03 12:12:21 +00:00
};
2010-02-02 16:03:11 +00:00
return that;
2010-02-03 12:12:21 +00:00
};
2010-02-02 16:03:11 +00:00
/*
============================================================================
2010-01-07 20:21:07 +00:00
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;
};
2010-01-25 15:06:44 +00:00
})();
2010-01-27 12:30:00 +00:00
/*
============================================================================
Requests
============================================================================
*/
/*
----------------------------------------------------------------------------
Ox.Progressbar
----------------------------------------------------------------------------
*/
/*
----------------------------------------------------------------------------
Ox.Spinner
----------------------------------------------------------------------------
*/