oxjstmp/build/js/ox.ui.js

5592 lines
193 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 = {
2010-02-20 03:58:46 +00:00
small: 20,
medium: 24,
large: 28,
2010-01-07 20:21:07 +00:00
};
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-06-30 18:47:10 +00:00
scrollbarSize: $.browser.mozilla ? 16 : 12,
2010-06-30 09:27:02 +00:00
symbols: {
2010-02-03 12:12:21 +00:00
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",
2010-03-06 09:13:17 +00:00
//clear: "\u2327",
clear: "\u00D7",
2010-02-05 05:20:13 +00:00
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",
2010-02-28 07:47:56 +00:00
//select: "\u21D5",
select: "\u25BE",
2010-02-05 05:20:13 +00:00
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),
2010-06-30 09:27:02 +00:00
$body = $("body"),
$elements = {};
2010-01-07 20:21:07 +00:00
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);
2010-07-07 12:36:12 +00:00
self.change = function(key, value) {
2010-01-27 12:30:00 +00:00
};
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-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) {
2010-07-05 16:52:12 +00:00
if (arguments.length == 2) {
callback = event;
event = id;
}
2010-02-05 09:13:03 +00:00
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) {
Ox.print("bind", id, event)
2010-02-05 09:13:03 +00:00
$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);
//$eventHandler.bind(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;
}
});
}
Ox.print("unbind", id, event)
2010-02-04 08:02:23 +00:00
$eventHandler.unbind(event, callback);
2010-02-05 09:13:03 +00:00
},
unbindKeyboard: function(id) {
2010-02-05 09:34:07 +00:00
$.each(keyboardEvents[id] || [], function(event, callback) {
Ox.print("unbind", id, event)
2010-02-05 09:34:07 +00:00
$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() { // unused
2010-01-07 20:21:07 +00:00
var events = {};
return {
// make these bind, trigger, unbind
publish: function(event, data) {
if (events[event]) {
$.each(events[event], function(i, v) {
setTimeout(function() {
v(data);
}, 0);
});
}
},
subscribe: function(event, callback) {
if (events[event]) {
events[event].push(callback);
} else {
events[event] = [callback];
}
},
unsubscribe: function(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 {
2010-06-30 09:27:02 +00:00
blur: function(id) {
if (stack.indexOf(id) == stack.length - 1) {
2010-06-30 09:27:02 +00:00
$elements[Ox.Focus.focused()].removeClass("OxFocus");
2010-06-30 18:47:10 +00:00
$(".OxFocus").removeClass("OxFocus"); // fixme: the above is better, and should work
2010-06-30 09:27:02 +00:00
stack.splice(stack.length - 2, 0, stack.pop());
Ox.Event.unbindKeyboard(id);
Ox.Event.bindKeyboard(stack[stack.length - 1]);
Ox.print("blur", id, stack);
2010-06-30 09:27:02 +00:00
}
},
2010-01-07 20:21:07 +00:00
focus: function(id) {
2010-02-07 15:01:22 +00:00
var index = stack.indexOf(id);
2010-02-05 09:13:03 +00:00
if (stack.length) {
2010-02-07 15:01:22 +00:00
Ox.Event.unbindKeyboard(stack[stack.length - 1])
2010-02-05 09:13:03 +00:00
}
2010-01-07 20:21:07 +00:00
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);
2010-06-30 09:27:02 +00:00
$elements[Ox.Focus.focused()].addClass("OxFocus");
2010-02-05 09:13:03 +00:00
Ox.Event.bindKeyboard(id);
Ox.print("focus", id, stack);
2010-02-05 09:13:03 +00:00
},
focused: function() {
return stack[stack.length - 1];
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",
2010-06-30 14:21:06 +00:00
// metaKey: "meta", // mac: command
2010-01-07 20:21:07 +00:00
shiftKey: "shift"
};
2010-02-05 15:42:52 +00:00
2010-02-04 09:50:45 +00:00
$(function() {
2010-02-05 15:42:52 +00:00
// fixme: how to do this better?
2010-02-19 14:19:48 +00:00
// in firefox on mac, keypress doesn't fire for up/down
2010-02-19 11:47:13 +00:00
// if the cursor is at the start/end of an input element
2010-02-19 14:19:48 +00:00
// on linux, it doesn't seem to fire if the input element has focus
2010-02-19 11:47:13 +00:00
if ($.browser.mozilla) {
2010-02-18 07:27:32 +00:00
$document.keypress(keypress);
2010-02-19 11:47:13 +00:00
$document.keydown(function(event) {
var $element = $("input:focus");
if ($element.length) {
if (
(
keyNames[event.keyCode] == "up" &&
$element[0].selectionStart + $element[0].selectionEnd == 0
) || (
keyNames[event.keyCode] == "down" &&
$element[0].selectionStart == $element.val().length &&
$element[0].selectionEnd == $element.val().length
)
) {
keypress(event);
}
}
});
} else {
$document.keydown(keypress);
2010-02-05 15:31:19 +00:00
}
2010-02-04 09:50:45 +00:00
});
2010-02-18 07:27:32 +00:00
function keypress(event) {
2010-02-04 09:50:45 +00:00
var key,
keys = [],
2010-02-20 03:58:46 +00:00
//ret = true,
2010-02-04 09:50:45 +00:00
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
2010-06-30 14:21:06 +00:00
Ox.print("keys", keys)
2010-02-04 09:50:45 +00:00
if (keyNames[event.keyCode] && keys.indexOf(keyNames[event.keyCode]) == -1) {
keys.push(keyNames[event.keyCode]);
}
2010-06-30 14:21:06 +00:00
key = keys.join("_");
2010-02-04 09:50:45 +00:00
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-18 14:24:17 +00:00
//return false;
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) {
2010-07-01 23:51:08 +00:00
var options = $.extend({
age: -1,
callback: function() {},
id: Ox.uid(),
timeout: self.options.timeout,
type: self.options.type,
url: self.options.url
}, options),
req = JSON.stringify({
2010-01-27 12:30:00 +00:00
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-07-01 23:51:08 +00:00
Ox.length(requests) == 0 && Ox.Event.trigger("requestStop");
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,
2010-06-30 18:47:10 +00:00
height: 200
2010-01-31 09:32:41 +00:00
})
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;
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,
2010-07-14 15:23:10 +00:00
dataType: "json",
2010-01-27 12:30:00 +00:00
error: error,
success: success,
timeout: options.timeout,
type: options.type,
url: options.url
});
2010-07-02 12:33:45 +00:00
Ox.print("request", options.data);
2010-07-01 23:51:08 +00:00
Ox.length(requests) == 1 && Ox.Event.trigger("requestStart");
2010-01-27 12:30:00 +00:00
}
}
2010-07-01 23:51:08 +00:00
2010-01-27 12:30:00 +00:00
return options.id;
2010-07-01 23:51:08 +00:00
},
requests: function() {
return Ox.length(requests);
2010-01-27 12:30:00 +00:00
}
};
}();
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)?
2010-06-28 11:19:04 +00:00
Ox.Container = function(options, self) {
var that = new Ox.Element(options, self)
2010-01-07 20:21:07 +00:00
.addClass("OxContainer");
2010-06-28 11:19:04 +00:00
that.$content = new Ox.Element(options, self)
2010-01-07 20:21:07 +00:00
.addClass("OxContent")
.appendTo(that);
return that;
2010-02-07 15:01:22 +00:00
};
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
Ox.Element
----------------------------------------------------------------------------
*/
// check out http://ejohn.org/apps/learn/#36 (-#38, making fns work w/o new)
Ox.Element = function() {
2010-06-30 09:27:02 +00:00
var elements = {}; // fixme: unused, we need this outside Element (for Focus)
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-06-30 09:27:02 +00:00
$elements[that.id] = that;
2010-01-07 20:21:07 +00:00
wrapjQuery();
})();
// private
function wrapjQuery() {
2010-02-10 18:42:59 +00:00
$.each(oxui.jQueryFunctions, function(i, fn) {
2010-02-10 18:52:46 +00:00
that[fn] = function() {
2010-01-07 20:21:07 +00:00
var args = arguments,
length = args.length,
2010-02-10 19:50:10 +00:00
id, ret;
2010-02-10 18:42:59 +00:00
$.each(args, function(i, arg) {
2010-07-20 20:04:13 +00:00
if (Ox.isUndefined(arg)) {
Ox.print("fn", fn, "undefined argument")
}
2010-01-07 20:21:07 +00:00
// if an ox object was passed
// then pass its $element instead
// so we can do oxObj.jqFn(oxObj)
2010-02-10 19:59:10 +00:00
if (arg.ox) {
args[i] = arg.$element;
}
2010-02-10 19:41:25 +00:00
/*
2010-02-10 18:52:46 +00:00
if (arg.ox) { // fixme: or is this too much magic?
2010-02-10 18:42:59 +00:00
if (fn == "appendTo" && arg.$content) {
2010-02-10 18:52:46 +00:00
args[i] = arg.$content
2010-02-10 18:42:59 +00:00
} else {
2010-02-10 18:52:46 +00:00
args[i] = arg.$element;
2010-02-10 18:42:59 +00:00
}
2010-01-07 20:21:07 +00:00
}
2010-02-10 19:41:25 +00:00
*/
2010-01-07 20:21:07 +00:00
});
2010-02-10 19:41:25 +00:00
/*
2010-02-10 18:52:46 +00:00
if (fn == "html" && that.$content) { // fixme: or is this too much magic?
2010-02-10 18:42:59 +00:00
$element = that.$content;
} else {
$element = that.$element;
}
2010-02-10 19:41:25 +00:00
*/
2010-07-17 08:46:27 +00:00
// why does this not work? (that?)
// ret = that.$element[fn].apply(this, arguments);
2010-01-07 20:21:07 +00:00
if (length == 0) {
2010-02-10 19:50:10 +00:00
ret = that.$element[fn]();
2010-01-07 20:21:07 +00:00
} else if (length == 1) {
2010-02-10 19:50:10 +00:00
ret = that.$element[fn](args[0]);
2010-01-07 20:21:07 +00:00
} else if (length == 2) {
2010-02-10 19:50:10 +00:00
ret = that.$element[fn](args[0], args[1]);
2010-01-07 20:21:07 +00:00
} else if (length == 3) {
2010-02-10 19:50:10 +00:00
ret = that.$element[fn](args[0], args[1], args[2]);
2010-01-07 20:21:07 +00:00
} else if (length == 4) {
2010-02-10 19:50:10 +00:00
ret = that.$element[fn](args[0], args[1], args[2], args[3]);
2010-01-07 20:21:07 +00:00
}
2010-02-10 18:42:59 +00:00
if (fn == "data") {
2010-02-08 09:35:24 +00:00
// Ox.print("data ret", ret, $(ret))
2010-02-07 15:01:22 +00:00
}
2010-01-07 20:21:07 +00:00
// if the $element of an ox object was returned
// then return the ox object instead
// so we can do oxObj.jqFn().oxFn()
2010-06-30 09:27:02 +00:00
return ret.jquery && $elements[id = ret.data("ox")] ?
$elements[id] : ret;
2010-01-07 20:21:07 +00:00
}
});
}
// shared
self.onChange = function() {
2010-02-07 15:01:22 +00:00
// self.onChange(key, value)
2010-01-07 20:21:07 +00:00
// is called when an option changes
// (to be implemented by widget)
};
// public
2010-02-05 09:13:03 +00:00
that.bindEvent = function() {
2010-02-06 10:29:27 +00:00
// fixme: shouldn't this work the other way around,
// and bind a function to an event triggered by this widget?
2010-02-05 09:13:03 +00:00
/*
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);
2010-02-10 16:37:26 +00:00
});
2010-02-05 09:13:03 +00:00
} else {
Ox.Event.bind(that.id, arguments[0], arguments[1]);
}
return that;
2010-02-05 09:13:03 +00:00
};
2010-01-07 20:21:07 +00:00
that.defaults = function(defaults) {
/*
that.defaults({foo: x}) sets self.defaults
*/
self.defaults = defaults;
delete self.options; // fixme: hackish fix for that = Ox.Foo({...}, self).defaults({...}).options({...})
2010-01-07 20:21:07 +00:00
return that;
2010-02-05 09:13:03 +00:00
};
that.gainFocus = function() {
Ox.Focus.focus(that.id);
2010-02-09 05:43:36 +00:00
return that;
2010-02-05 09:13:03 +00:00
};
that.hasFocus = function() {
return Ox.Focus.focused() == that.id;
};
that.loseFocus = function() {
Ox.Focus.blur(that.id);
2010-02-09 05:43:36 +00:00
return that;
2010-02-05 09:13:03 +00:00
};
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,
2010-02-06 08:23:42 +00:00
// args, options, ret;
2010-01-07 20:21:07 +00:00
args, ret;
if (length == 0) {
// options()
2010-07-06 18:28:58 +00:00
ret = self.options || options; // this is silly. make sure self.options get populated with options
2010-01-07 20:21:07 +00:00
} else if (length == 1 && typeof arguments[0] == "string") {
// options(str)
2010-07-06 18:28:58 +00:00
ret = self.options ? self.options[arguments[0]] : options[arguments[0]];
2010-01-07 20:21:07 +00:00
} else {
// options (str, val) or options({str: val, ...})
// translate (str, val) to ({str: val})
args = Ox.makeObject.apply(that, arguments);
2010-02-06 08:23:42 +00:00
/*
options = self.options;
*/
// if options have not been set, extend defaults,
// otherwise, extend options
2010-02-06 08:23:42 +00:00
self.options = $.extend(self.options || self.defaults, args);
$.each(args, function(key, value) {
self.onChange(key, value);
2010-02-06 08:23:42 +00:00
/*
fixme: why does this not work?
Ox.print("options", options, key, value)
//Ox.print(!options, !options || !options[key], !options || !options[key] || options[key] !== value)
if (!options || !options[key] || options[key] !== value) {
Ox.print("onChange...")
self.onChange(key, value);
} else {
Ox.print("NO CHANGE");
}
*/
2010-01-07 20:21:07 +00:00
});
ret = that;
}
return ret;
2010-02-10 16:37:26 +00:00
};
2010-01-07 20:21:07 +00:00
that.remove = function() {
that.$element.remove();
2010-06-30 09:27:02 +00:00
delete $elements[that.ox];
return that;
2010-02-10 16:37:26 +00:00
};
2010-02-06 08:23:42 +00:00
that.triggerEvent = function() {
/*
triggerEvent(event, fn) or triggerEvent({event0: fn0, event1: fn1, ...})
*/
2010-02-08 09:35:24 +00:00
if (Ox.isObject(arguments[0])) {
2010-02-06 08:23:42 +00:00
$.each(arguments[0], function(event, fn) {
2010-02-08 14:42:00 +00:00
Ox.Event.trigger(event + "_" + self.options.id, fn);
2010-02-06 08:23:42 +00:00
});
} else {
2010-02-08 14:42:00 +00:00
Ox.Event.trigger(arguments[0] + "_" + self.options.id, arguments[1] || {});
2010-02-06 08:23:42 +00:00
}
return that;
2010-02-10 16:37:26 +00:00
};
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]);
}
return that;
2010-02-10 16:37:26 +00:00
};
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();
2010-02-06 10:29:27 +00:00
//Ox.print("that.id", that.id)
2010-01-07 20:21:07 +00:00
that.$element = $("<" + (element || "div") + "/>")
//.addClass("OxElement")
.data("ox", that.id);
oxui.elements[that.id] = that;
2010-02-06 10:29:27 +00:00
// Ox.print("oxui.elements", oxui.elements)
2010-01-07 20:21:07 +00:00
//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) {
2010-02-06 10:29:27 +00:00
//Ox.print("getting all options", options);
2010-01-07 20:21:07 +00:00
ret = that.opt;
} else if (length == 1 && typeof arguments[0] == "string") {
2010-02-06 10:29:27 +00:00
//Ox.print("getting one option", options, arguments[0], options[arguments[0]]);
2010-01-07 20:21:07 +00:00
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);
2010-02-06 10:29:27 +00:00
//Ox.print("triggering", "OxElement" + that.id + "SetOption", {k: v})
2010-01-07 20:21:07 +00:00
//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()
2010-02-06 10:29:27 +00:00
//Ox.print("v", v, "arguments", arguments)
2010-01-07 20:21:07 +00:00
if (ret.jquery) {
2010-02-06 10:29:27 +00:00
//Ox.print("ret", ret, "ret.data('id')", ret.data("ox"))
2010-01-07 20:21:07 +00:00
}
return ret.jquery && oxui.elements[id = ret.data("ox")] ?
oxui.elements[id] : ret;
}
});
return that;
};
2010-07-24 01:32:08 +00:00
/*
----------------------------------------------------------------------------
Ox.Window
----------------------------------------------------------------------------
*/
Ox.Window = function(options, self) {
self = self || {},
that = new Ox.Element("div", self)
.defaults({
draggable: true,
fullscreenable: true, // fixme: silly name
height: 225,
resizeable: true,
scaleable: true,
width: 400
})
.options(options || {})
self.center = function() {
};
self.drag = function() {
};
self.fullscreen = function() {
};
self.onChange = function() {
};
self.reset = function() {
};
self.resize = function() {
};
self.scale = function() {
};
that.close = function() {
};
that.open = function() {
};
return that;
};
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
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 + "/"
)
});
});
2010-02-20 10:34:50 +00:00
$(".OxLoadingIcon").each(function() {
var $this = $(this);
$this.attr({
src: $this.attr("src").replace(
"/ox.ui." + theme + "/", "/ox.ui." + arg + "/"
)
});
})
2010-01-07 20:21:07 +00:00
}
}
return theme;
};
/*
============================================================================
Bars
============================================================================
*/
Ox.Bar = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
orientation: "horizontal",
2010-02-20 04:26:53 +00:00
size: "medium" // can be int
2010-01-07 20:21:07 +00:00
})
2010-02-18 07:27:32 +00:00
.options(options || {})
.addClass("OxBar Ox" + Ox.toTitleCase(self.options.orientation)),
2010-01-07 20:21:07 +00:00
dimensions = oxui.getDimensions(self.options.orientation);
2010-02-20 03:58:46 +00:00
self.options.size = Ox.isString(self.options.size) ?
oxui.getBarSize(self.options.size) : self.options.size;
2010-02-18 07:27:32 +00:00
that.css(dimensions[0], "100%")
2010-01-07 20:21:07 +00:00
.css(dimensions[1], self.options.size + "px");
return that;
};
2010-07-06 18:28:58 +00:00
/*
----------------------------------------------------------------------------
Ox.Resizebar
----------------------------------------------------------------------------
*/
Ox.Resizebar = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
2010-07-07 07:18:38 +00:00
collapsed: false,
2010-07-06 18:28:58 +00:00
collapsible: true,
edge: "left",
elements: [],
orientation: "horizontal",
parent: null,
resizable: true,
resize: [],
size: 0
})
.options(options || {}) // fixme: options function should be able to handle undefined, no need for || {}
.addClass("OxResizebar Ox" + Ox.toTitleCase(self.options.orientation))
/*
.attr({
draggable: "true"
})
.bind("dragstart", function(e) {
// e.originalEvent.dataTransfer.setDragImage($("<div>")[0], 0, 0);
})
.bind("drag", function(e) {
Ox.print("dragging", e)
})
*/
.mousedown(dragStart)
.dblclick(toggle)
.append($("<div>").addClass("OxSpace"))
.append($("<div>").addClass("OxLine"))
.append($("<div>").addClass("OxSpace"));
$.extend(self, {
clientXY: self.options.orientation == "horizontal" ? "clientY" : "clientX",
2010-07-15 19:04:47 +00:00
dimensions: oxui.getDimensions(self.options.orientation), // fixme: should orientation be the opposite orientation here?
edges: oxui.getEdges(self.options.orientation),
2010-07-06 18:28:58 +00:00
ids: $.map(self.options.elements, function(v, i) {
return v.options("id");
}),
length: self.options.resize.length,
startPos: 0,
startSize: 0
});
function drag(e) {
var d = e[self.clientXY] - self.startPos, i;
self.options.size = Ox.limit(self.startSize + d, self.options.resize[0], self.options.resize[self.length - 1]);
Ox.print("sS", self.startSize, "d", d, "s.o.s", self.options.size)
$.each(self.options.resize, function(i, v) {
if (self.options.size > v - 8 && self.options.size < v + 8) {
self.options.size = v;
return false;
}
});
2010-07-15 19:04:47 +00:00
that.css(self.edges[2], self.options.size + "px");
self.options.elements[0].css(self.dimensions[1], self.options.size + "px");
self.options.elements[1].css(self.edges[2], (self.options.size + 1) + "px");
2010-07-06 18:28:58 +00:00
Ox.Event.trigger("resize_" + self.ids[0], self.options.size);
2010-07-15 19:04:47 +00:00
Ox.Event.trigger("resize_" + self.ids[1], self.options.elements[1][self.dimensions[1]]());
2010-07-06 18:28:58 +00:00
}
function dragStart(e) {
self.startPos = e[self.clientXY];
self.startSize = self.options.size;
Ox.print("startSize", self.startSize)
$window.mousemove(drag);
2010-07-17 08:46:27 +00:00
$window.one("mouseup", dragStop);
2010-07-06 18:28:58 +00:00
}
function dragStop() {
$window.unbind("mousemove");
}
function toggle() {
Ox.print("toggle");
if (Ox.isUndefined(self.options.position)) {
self.options.position = parseInt(self.options.parent.css(self.options.edge)) +
(self.options.collapsed ? self.options.size : 0);
}
var size = self.options.position -
(self.options.collapsed ? 0 : self.options.size),
2010-07-07 07:18:38 +00:00
animate = {};
2010-07-15 19:04:47 +00:00
Ox.print("s.o.e", self.options.edge);
2010-07-07 07:18:38 +00:00
animate[self.options.edge] = size;
self.options.parent.animate(animate, 200, function() {
var i = (self.options.edge == "left" || self.options.edge == "top") ? 1 : 0;
2010-07-15 19:04:47 +00:00
Ox.Event.trigger("resize_" + self.ids[i], self.options.elements[i][self.dimensions[1]]());
2010-07-07 07:18:38 +00:00
self.options.collapsed = !self.options.collapsed;
});
2010-07-06 18:28:58 +00:00
}
return that;
};
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
Ox.Tabbar
----------------------------------------------------------------------------
*/
Ox.Tabbar = function(options, self) {
var self = self || {},
that = new Ox.Bar({
size: 20
}, self)
.defaults({
selected: 0,
2010-02-10 09:59:59 +00:00
tabs: []
2010-01-07 20:21:07 +00:00
})
.options(options || {})
.addClass("OxTabbar");
2010-02-08 09:35:24 +00:00
Ox.ButtonGroup({
2010-02-10 09:59:59 +00:00
buttons: self.options.tabs,
2010-02-08 09:35:24 +00:00
group: true,
selectable: true,
selected: self.options.selected,
size: "medium",
style: "tab",
}).appendTo(that);
2010-01-07 20:21:07 +00:00
return that;
};
2010-02-20 03:58:46 +00:00
// fixme: no need for this
2010-01-07 20:21:07 +00:00
Ox.Toolbar = function(options, self) {
var self = self || {},
that = new Ox.Bar({
2010-02-07 15:01:22 +00:00
size: oxui.getBarSize(options.size)
}, self);
2010-01-07 20:21:07 +00:00
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) {
2010-02-20 07:46:31 +00:00
2010-02-18 07:27:32 +00:00
// fixme: dialog should be derived from a generic draggable
2010-07-24 01:32:08 +00:00
// fixme: pass button elements directly
2010-01-27 12:30:00 +00:00
var self = self || {},
2010-02-20 03:42:03 +00:00
that = new Ox.Element("div", self)
.defaults({
title: "",
buttons: [],
2010-02-21 06:47:18 +00:00
height: 216,
minHeight: 144,
2010-02-21 05:40:11 +00:00
minWidth: 256,
2010-07-24 01:32:08 +00:00
padding: 16,
2010-02-21 05:20:39 +00:00
width: 384
2010-02-20 03:42:03 +00:00
})
.options(options || {})
2010-02-21 06:47:18 +00:00
.addClass("OxDialog");
2010-02-20 07:46:31 +00:00
2010-02-21 05:20:39 +00:00
if (!Ox.isArray(self.options.buttons[0])) {
self.options.buttons = [[], self.options.buttons];
}
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-02-21 05:20:39 +00:00
.mousedown(drag)
.dblclick(center)
2010-01-27 12:30:00 +00:00
.appendTo(that);
2010-02-09 05:43:36 +00:00
that.$title = new Ox.Element()
.addClass("OxTitle")
2010-02-20 03:42:03 +00:00
.html(self.options.title)
2010-02-09 05:43:36 +00:00
.appendTo(that.$titlebar);
2010-07-24 01:32:08 +00:00
// fixme: should the following be a container?
that.$content = new Ox.Element()
2010-01-27 12:30:00 +00:00
.addClass("OxContent")
2010-07-24 01:32:08 +00:00
.css({
padding: self.options.padding + "px",
overflow: "auto"
})
2010-01-27 12:30:00 +00:00
.appendTo(that);
2010-02-20 04:26:53 +00:00
that.$buttonsbar = new Ox.Bar({})
2010-01-27 12:30:00 +00:00
.addClass("OxButtonsBar")
.appendTo(that);
2010-01-31 09:32:41 +00:00
that.$buttons = [];
2010-02-21 05:20:39 +00:00
$.each(self.options.buttons[0], function(i, button) {
2010-01-31 09:32:41 +00:00
that.$buttons[i] = new Ox.Button({
2010-07-20 20:04:13 +00:00
disabled: button.disabled || false,
2010-02-21 05:20:39 +00:00
size: "medium",
2010-07-20 20:04:13 +00:00
value: button.value // fixme: use title
2010-02-21 05:20:39 +00:00
})
.addClass("OxLeft")
.click(button.click) // fixme: rather use event?
.appendTo(that.$buttonsbar);
});
that.$resize = new Ox.Element()
.addClass("OxResize")
.mousedown(resize)
2010-02-21 06:47:18 +00:00
.dblclick(reset)
2010-02-21 05:20:39 +00:00
.appendTo(that.$buttonsbar);
$.each(self.options.buttons[1].reverse(), function(i, button) {
that.$buttons[that.$buttons.length] = new Ox.Button({
2010-07-20 20:04:13 +00:00
disabled: button.disabled || false,
2010-07-24 01:32:08 +00:00
id: button.id,
2010-02-21 05:20:39 +00:00
size: "medium",
value: button.value
})
.addClass("OxRight")
.click(button.click) // fixme: rather use event?
.appendTo(that.$buttonsbar);
2010-01-27 12:30:00 +00:00
});
2010-01-31 09:32:41 +00:00
that.$buttons[0].focus();
2010-02-21 07:09:32 +00:00
that.$layer = new Ox.Element() // fixme: Layer widget, that would handle click?
.addClass("OxLayer")
.mousedown(mousedownLayer)
.mouseup(mouseupLayer);
2010-02-20 07:46:31 +00:00
function center() {
2010-07-20 20:04:13 +00:00
var documentHeight = $document.height();
that.css({
left: 0,
2010-07-20 20:04:13 +00:00
top: Math.max(parseInt(-documentHeight / 10), self.options.height - documentHeight + 40) + "px",
right: 0,
bottom: 0,
margin: "auto"
});
}
2010-02-21 05:20:39 +00:00
function drag(event) {
var bodyWidth = $body.width(),
bodyHeight = $document.height(),
2010-02-21 06:47:18 +00:00
elementWidth = that.width(),
2010-02-21 05:20:39 +00:00
offset = that.offset(),
x = event.clientX,
y = event.clientY;
$window.mousemove(function(event) {
that.css({
margin: 0
});
2010-02-21 05:20:39 +00:00
var left = Ox.limit(
offset.left - x + event.clientX,
24 - elementWidth, bodyWidth - 24
//0, documentWidth - elementWidth
2010-02-21 05:20:39 +00:00
),
top = Ox.limit(
offset.top - y + event.clientY,
24, bodyHeight - 24
//24, documentHeight - elementHeight
2010-02-21 05:20:39 +00:00
);
that.css({
left: left + "px",
top: top + "px"
});
});
$window.one("mouseup", function() {
$window.unbind("mousemove");
});
2010-02-21 05:20:39 +00:00
}
2010-07-24 01:32:08 +00:00
function getButtonById(id) {
var ret = null
$.each(that.$buttons, function(i, button) {
if (button.options("id") == id) {
ret = button;
return false;
}
});
return ret;
}
2010-02-21 07:09:32 +00:00
function mousedownLayer() {
that.$layer.stop().animate({
opacity: 0.5
}, 0);
2010-02-21 07:09:32 +00:00
}
function mouseupLayer() {
that.$layer.stop().animate({
opacity: 0
}, 0);
2010-02-21 07:09:32 +00:00
}
2010-02-21 06:47:18 +00:00
function reset() {
that.css({
2010-07-24 01:32:08 +00:00
left: Math.max(that.offset().left, 24 - that.width())
})
.width(self.options.width)
.height(self.options.height);
2010-07-24 01:32:08 +00:00
that.$content.height(self.options.height - 48 - 2 * self.options.padding); // fixme: this should happen automatically
2010-02-21 06:47:18 +00:00
}
2010-02-21 05:20:39 +00:00
function resize(event) {
2010-07-24 01:32:08 +00:00
var documentWidth = $document.width(),
2010-02-21 05:20:39 +00:00
documentHeight = $document.height(),
elementWidth = that.width(),
elementHeight = that.height(),
2010-02-21 05:40:11 +00:00
offset = that.offset(),
2010-02-21 05:20:39 +00:00
x = event.clientX,
y = event.clientY;
$window.mousemove(function(event) {
2010-02-21 05:34:17 +00:00
that.css({
2010-02-21 05:40:11 +00:00
left: offset.left,
top: offset.top,
2010-02-21 05:34:17 +00:00
margin: 0
});
2010-02-21 05:20:39 +00:00
var width = Ox.limit(
elementWidth - x + event.clientX,
2010-02-21 06:47:18 +00:00
self.options.minWidth, Math.min(documentWidth, documentWidth - offset.left)
2010-02-21 05:20:39 +00:00
),
height = Ox.limit(
elementHeight - y + event.clientY,
self.options.minHeight, documentHeight - offset.top
2010-02-21 05:20:39 +00:00
);
that.width(width);
that.height(height);
2010-07-24 01:32:08 +00:00
that.$content.height(height - 48 - 2 * self.options.padding); // fixme: this should happen automatically
2010-02-21 05:20:39 +00:00
});
$window.one("mouseup", function() {
$window.unbind("mousemove");
});
}
2010-01-31 08:03:22 +00:00
self.onChange = function(key, value) {
2010-07-24 01:32:08 +00:00
if (key == "height" || key == "width") {
that.animate({
height: self.options.height + "px",
width: self.options.width + "px"
}, 250);
that.$content.height(self.options.height - 48 - 2 * self.options.padding); // fixme: this should happen automatically
} else if (key == "title") {
2010-07-20 20:04:13 +00:00
that.$title.animate({
opacity: 0
}, 250, function() {
that.$title.html(value).animate({
opacity: 1
}, 250);
});
2010-01-31 08:03:22 +00:00
}
}
2010-02-20 07:46:31 +00:00
2010-01-27 12:30:00 +00:00
that.append = function($element) {
that.$content.append($element);
return that;
}
2010-02-20 07:46:31 +00:00
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();
});
$window.unbind("mouseup", mouseupLayer)
return that;
2010-01-27 12:30:00 +00:00
}
2010-02-20 07:46:31 +00:00
that.disable = function() {
2010-02-10 16:37:26 +00:00
// to be used on submit of form, like login
2010-02-20 07:46:31 +00:00
that.$layer.addClass("OxFront");
2010-07-20 20:04:13 +00:00
return that;
2010-02-10 16:37:26 +00:00
};
2010-02-20 07:46:31 +00:00
2010-07-24 01:32:08 +00:00
that.disableButton = function(id) {
getButtonById(id).options({
disabled: true
});
};
2010-02-20 07:46:31 +00:00
that.enable = function() {
that.$layer.removeClass("OxFront");
2010-07-20 20:04:13 +00:00
return that;
2010-07-24 01:32:08 +00:00
};
that.enableButton = function(id) {
getButtonById(id).options({
disabled: false
});
};
2010-02-20 07:46:31 +00:00
2010-01-27 12:30:00 +00:00
that.open = function() {
2010-02-20 07:46:31 +00:00
that.$layer.appendTo($body);
2010-02-21 06:32:48 +00:00
center();
2010-02-21 06:47:18 +00:00
reset();
2010-01-27 12:30:00 +00:00
that.css({
opacity: 0
2010-05-05 18:27:09 +00:00
}).appendTo($body).animate({
2010-01-27 12:30:00 +00:00
opacity: 1
}, 200);
$window.bind("mouseup", mouseupLayer)
2010-01-27 12:30:00 +00:00
return that;
2010-07-24 01:32:08 +00:00
};
2010-02-20 07:46:31 +00:00
2010-01-27 12:30:00 +00:00
return that;
2010-02-20 07:46:31 +00:00
2010-01-27 12:30:00 +00:00
}
2010-01-07 20:21:07 +00:00
/*
============================================================================
Forms
============================================================================
*/
2010-07-24 01:32:08 +00:00
/*
----------------------------------------------------------------------------
Ox.Filter
----------------------------------------------------------------------------
*/
Ox.Filter = function(options, self) {
var self = self || {}
that = new Ox.Element()
.defaults({
})
.options(options || {});
return that;
};
/*
----------------------------------------------------------------------------
Ox.Form
----------------------------------------------------------------------------
*/
2010-02-10 16:37:26 +00:00
Ox.Form = function(options, self) {
var self = self || {},
that = new Ox.Element("div", self)
.defaults({
2010-07-20 20:04:13 +00:00
error: "",
id: "",
2010-07-24 01:32:08 +00:00
items: [],
submit: null
})
.options(options || {}); // fixme: the || {} can be done once, in the options function
2010-07-20 20:04:13 +00:00
$.extend(self, {
2010-07-24 01:32:08 +00:00
$items: [],
$messages: [],
2010-07-20 20:04:13 +00:00
formIsValid: false,
2010-07-24 01:32:08 +00:00
itemIds: [],
itemIsValid: []
});
// fixme: form isn't necessarily empty/invalid
$.map(self.options.items, function(item, i) {
self.itemIds[i] = item.id || item.element.options("id");
self.itemIsValid[i] = false;
2010-07-20 20:04:13 +00:00
});
$.each(self.options.items, function(i, item) {
2010-07-24 01:32:08 +00:00
var id = item.element.options("id");
that.append(self.$items[i] = new Ox.FormItem(item))
.append(self.$messages[i] = new Ox.Element().addClass("OxFormMessage"));
Ox.Event.bind("validate_" + id, function(event, data) {
validate(i, data.valid);
});
Ox.Event.bind("blur_" + id, function(event, data) {
validate(i, data.valid);
if (data.valid) {
self.$messages[i].html("").hide();
} else {
self.$messages[i].html(data.message).show();
}
});
Ox.Event.bind("submit_" + id, function(event, data) {
self.formIsValid && that.submit();
});
});
2010-07-24 01:32:08 +00:00
function getItemPositionById(id) {
return self.itemIds.indexOf(id);
}
function setMessage(id, message) {
self.$messages[getItemPositionById(id)].html(message)[message !== "" ? "show" : "hide"]();
}
function submitCallback(data) {
$.each(data, function(i, v) {
setMessage(v.id, v.message);
});
}
function validate(pos, valid) {
Ox.print("validate", pos, valid)
self.itemIsValid[pos] = valid;
2010-07-20 20:04:13 +00:00
if (Ox.every(self.itemIsValid) != self.formIsValid) {
self.formIsValid = !self.formIsValid;
2010-07-24 01:32:08 +00:00
that.triggerEvent("validate", {
valid: self.formIsValid
2010-07-20 20:04:13 +00:00
});
}
}
2010-07-24 01:32:08 +00:00
that.submit = function() {
self.options.submit(that.values(), submitCallback);
};
that.values = function() { // fixme: can this be private?
var values = {};
if (arguments.length == 0) {
2010-07-24 01:32:08 +00:00
$.each(self.$items, function(i, $item) {
values[self.itemIds[i]] = self.$items[i].value();
});
return values;
} else {
$.each(arguments[0], function(key, value) {
});
return that;
}
};
return that;
2010-02-10 16:37:26 +00:00
};
Ox.FormItem = function(options, self) {
var self = self || {},
2010-07-20 20:04:13 +00:00
that = new Ox.Element("div", self)
.defaults({
2010-07-20 20:04:13 +00:00
element: null,
error: "",
})
2010-07-20 20:04:13 +00:00
.options(options || {})
.addClass("OxFormItem")
.append(self.options.element);
2010-07-24 01:32:08 +00:00
that.value = function() {
return self.options.element.$input.val();
};
return that;
}
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
Ox.Button
----------------------------------------------------------------------------
*/
Ox.Button = function(options, self) {
2010-02-10 09:59:59 +00:00
/*
events:
click non-selectable button was clicked
deselect selectable button was deselected
select selectable button was selected
*/
2010-01-07 20:21:07 +00:00
var self = self || {},
that = new Ox.Element("input", self)
.defaults({
disabled: false,
2010-02-10 09:59:59 +00:00
group: null,
id: "",
2010-01-07 20:21:07 +00:00
selectable: false,
selected: false,
size: "medium",
2010-02-10 09:59:59 +00:00
style: "default", // can be default, symbol or tab
2010-01-07 20:21:07 +00:00
type: "text",
value: "",
2010-07-01 15:06:04 +00:00
values: [] // fixme: shouldn't this go into self.values?
2010-01-07 20:21:07 +00:00
})
.options($.extend(options, {
value: $.isArray(options.value) ?
options.value[0] : options.value,
values: $.makeArray(options.value)
2010-02-06 08:23:42 +00:00
}))
.attr({
disabled: self.options.disabled ? "disabled" : "",
type: self.options.type == "text" ? "button" : "image"
})
.addClass("OxButton Ox" + Ox.toTitleCase(self.options.size) +
2010-03-06 09:54:30 +00:00
(self.options.style != "default" ? " Ox" + Ox.toTitleCase(self.options.style) : "") +
(self.options.disabled ? " OxDisabled": "") +
(self.options.selected ? " OxSelected": ""))
.mousedown(mousedown)
.click(click);
2010-02-06 10:29:27 +00:00
//Ox.print(self.options.value, self.options.disabled)
2010-01-07 20:21:07 +00:00
/*
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() {
2010-02-10 09:59:59 +00:00
if (!self.options.selectable) {
that.triggerEvent("click");
} else if (!self.options.group || !self.options.selected) {
if (self.options.group) {
that.triggerEvent("select");
} else {
that.toggleSelected();
}
2010-01-07 20:21:07 +00:00
}
if (self.options.values.length == 2) {
that.options({
value: self.options.value == self.options.values[0] ?
self.options.values[1] : self.options.values[0]
});
}
//self.options.click();
2010-01-07 20:21:07 +00:00
}
self.onChange = function(key, value) {
2010-02-06 10:29:27 +00:00
//Ox.print("setOption", option, value)
2010-07-24 01:32:08 +00:00
if (key == "disabled") {
that.attr({
disabled: value ? "disabled" : ""
})
.toggleClass("OxDisabled");
} else if (key == "selected") {
2010-02-08 09:35:24 +00:00
if (value != that.hasClass("OxSelected")) { // fixme: neccessary?
2010-01-07 20:21:07 +00:00
that.toggleClass("OxSelected");
}
2010-02-10 09:59:59 +00:00
that.triggerEvent("change");
} else if (key == "value") {
2010-01-07 20:21:07 +00:00
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.options("value", self.options.value);
return that;
};
/*
----------------------------------------------------------------------------
Ox.ButtonGroup
----------------------------------------------------------------------------
*/
Ox.ButtonGroup = function(options, self) {
2010-02-08 09:35:24 +00:00
2010-02-10 09:59:59 +00:00
/*
events:
change {id, value} selection within a group changed
*/
2010-01-07 20:21:07 +00:00
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
2010-02-10 09:59:59 +00:00
buttons: [],
2010-02-08 09:35:24 +00:00
group: false,
2010-01-07 20:21:07 +00:00
selectable: false,
selected: -1,
size: "medium",
2010-01-07 20:21:07 +00:00
style: "",
type: "text",
})
.options(options || {})
.addClass("OxButtonGroup");
2010-02-08 09:35:24 +00:00
self.position = {};
that.$buttons = [];
2010-02-10 09:59:59 +00:00
$.each(self.options.buttons, function(position, button) {
2010-02-08 09:35:24 +00:00
that.$buttons[position] = Ox.Button({
2010-02-10 09:59:59 +00:00
disabled: button.disabled,
group: self.options.group ? that : null,
id: button.id,
2010-02-08 09:35:24 +00:00
selectable: self.options.selectable,
selected: position == self.options.selected,
size: self.options.size,
style: self.options.style,
type: self.options.type,
2010-02-10 09:59:59 +00:00
value: button.value
2010-02-08 09:35:24 +00:00
}).appendTo(that);
self.position[that.$buttons.id] = position;
2010-02-10 09:59:59 +00:00
that.bindEvent("select_" + that.$buttons[position].options("id"), function() {
selectButton(position);
});
2010-02-08 09:35:24 +00:00
});
2010-02-10 09:59:59 +00:00
function onChange(event, data) {
2010-02-08 09:35:24 +00:00
console.log("event", event, "data", data)
var id = event.split("_")[1];
if (self.options.selected > -1) {
that.$buttons[self.options.selected].toggleSelected();
}
self.options.selected = self.position[id];
that.triggerEvent("change", {
value: id
2010-01-07 20:21:07 +00:00
});
2010-02-08 09:35:24 +00:00
}
2010-02-10 09:59:59 +00:00
function selectButton(position) {
that.$buttons[self.options.selected].toggleSelected();
self.options.selected = position;
that.$buttons[self.options.selected].toggleSelected();
};
2010-01-07 20:21:07 +00:00
return that;
};
/*
----------------------------------------------------------------------------
Ox.Input
----------------------------------------------------------------------------
*/
Ox.Input = function(options, self) {
2010-02-19 10:24:02 +00:00
/* options:
* autocomplete function, or array of values, or dict with array of values per label or placeholder
2010-07-24 01:32:08 +00:00
* autocorrect function for live correction
2010-02-19 10:24:02 +00:00
* clear boolean, clear button, or not
* highlight boolean, highlight value in autocomplete menu, or not
* id
2010-07-20 20:04:13 +00:00
* label string or array [{id, title}] (select) -- label and placeholder are mutually exclusive
2010-02-19 10:24:02 +00:00
* labelWidth integer (px)
2010-07-20 20:04:13 +00:00
* placeholder string or array [{id, title}] (select) -- label and placeholder are mutually exclusive
2010-02-19 10:24:02 +00:00
* selected integer, selected label or placeholder
* size "large", "medium" or "small"
* type "text", "password", "textarea", etc.
2010-07-24 01:32:08 +00:00
* validate function vor live validation, returns { message: "", valid: false }
* value string
2010-02-19 10:24:02 +00:00
*/
2010-01-07 20:21:07 +00:00
var self = self || {},
2010-02-19 10:24:02 +00:00
that = new Ox.Element("div", self)
2010-01-07 20:21:07 +00:00
.defaults({
2010-02-18 07:27:32 +00:00
autocomplete: null,
2010-07-24 01:32:08 +00:00
autocorrect: null,
2010-02-19 10:24:02 +00:00
clear: false,
highlight: false,
2010-02-18 09:11:47 +00:00
id: "",
2010-02-19 10:24:02 +00:00
label: "",
2010-02-27 08:16:58 +00:00
labelWidth: 64,
2010-02-19 10:24:02 +00:00
placeholder: "",
selected: 0,
size: "medium",
2010-07-24 01:32:08 +00:00
type: "text",
validate: null,
value: ""
2010-01-07 20:21:07 +00:00
})
2010-02-18 07:27:32 +00:00
.options(options || {})
2010-02-19 10:24:02 +00:00
.addClass("OxInput Ox" + Ox.toTitleCase(self.options.size)),
2010-07-02 12:33:45 +00:00
autocomplete; // fixme: should be self.autocomplete
2010-02-19 10:24:02 +00:00
if (self.options.label) {
self.options.label = Ox.makeArray(self.options.label);
2010-07-02 12:33:45 +00:00
self.option = self.options.label[self.options.selected]; // fixme: id or title? or not use this at all?
2010-02-20 07:46:31 +00:00
self.items = self.options.label;
2010-02-19 10:24:02 +00:00
} else if (self.options.placeholder) {
self.options.placeholder = Ox.makeArray(self.options.placeholder);
2010-02-20 10:51:55 +00:00
self.option = self.options.placeholder[self.options.selected];
2010-02-20 07:46:31 +00:00
self.items = self.options.placeholder;
2010-02-19 10:24:02 +00:00
}
if (Ox.isArray(self.options.autocomplete)) {
autocomplete = self.options.autocomplete;
self.options.autocomplete = {};
self.options.autocomplete[self.placeholder] = autocomplete;
}
if (self.options.label) {
2010-02-20 07:46:31 +00:00
that.$label = new Ox.Element()
2010-02-27 08:46:49 +00:00
.addClass("OxInputLabel")
2010-02-20 07:46:31 +00:00
.width(self.options.labelWidth)
2010-07-20 20:04:13 +00:00
.html(self.options.label.length == 1 ? self.options.label[0] : self.options.label[0].title)
2010-02-20 07:46:31 +00:00
.appendTo(that);
}
if (self.options.label.length > 1 || self.options.placeholder.length > 1) {
that.$label && that.$label.click(select);
2010-02-19 10:24:02 +00:00
that.$select = new Ox.Button({
style: "symbol",
2010-03-06 09:54:30 +00:00
type: "image",
value: "select"
// value: oxui.symbols.select
2010-02-19 10:24:02 +00:00
})
.click(select)
.appendTo(that);
2010-07-07 12:36:12 +00:00
self.selectId = Ox.toCamelCase(
self.options.id + "_" + (self.options.label.length > 1 ? "label" : "placeholder")
);
2010-02-20 07:46:31 +00:00
self.selectMenu = new Ox.Menu({
2010-02-19 10:24:02 +00:00
element: that,
2010-02-20 07:46:31 +00:00
id: self.selectId,
2010-07-02 12:33:45 +00:00
items: $.map(self.items, function(item, position) {
2010-02-19 10:24:02 +00:00
return {
checked: position == self.options.selected,
2010-07-02 12:33:45 +00:00
id: item.id,
2010-02-20 07:46:31 +00:00
group: self.selectId, // fixme: same id, works here, but should be different
2010-07-02 12:33:45 +00:00
title: item.title
2010-02-19 10:24:02 +00:00
};
2010-02-19 10:34:51 +00:00
}),
offset: {
left: 4,
top: 0
}
2010-02-19 10:24:02 +00:00
});
2010-02-20 07:46:31 +00:00
that.bindEvent("change_" + self.selectId, change);
2010-02-19 10:24:02 +00:00
}
that.$input = new Ox.Element(
self.options.type == "textarea" ? "textarea" : "input", self
)
.attr({
2010-02-26 13:22:27 +00:00
type: self.options.type == "textarea" ? undefined : self.options.type // fixme: make conditional?
2010-02-19 10:24:02 +00:00
})
.addClass(
"OxInput Ox" + Ox.toTitleCase(self.options.size) +
" OxPlaceholder"
)
.focus(focus)
.blur(blur)
.change(change)
.appendTo(that);
2010-07-24 19:27:39 +00:00
self.options.placeholder && that.$input.val(self.option.title);
2010-02-20 11:05:58 +00:00
2010-02-19 10:24:02 +00:00
if (self.options.clear) {
that.$clear = new Ox.Button({
style: "symbol",
2010-03-06 09:54:30 +00:00
type: "image",
value: "clear"
//value: oxui.symbols.clear
2010-02-18 07:27:32 +00:00
})
2010-02-19 10:24:02 +00:00
.click(clear)
.appendTo(that);
}
2010-02-27 08:46:49 +00:00
if (self.options.autocomplete) {
2010-02-19 14:19:48 +00:00
that.$input.attr({
autocomplete: "off"
});
2010-02-19 10:24:02 +00:00
self.autocompleteId = self.options.id + "_menu"; // fixme: we do this in other places ... are we doing it the same way? var name?
self.autocompleteMenu = new Ox.Menu({
2010-02-20 07:46:31 +00:00
element: that.$input,
2010-02-19 10:24:02 +00:00
id: self.autocompleteId,
2010-02-18 07:27:32 +00:00
offset: {
left: 4,
top: 0
},
size: self.options.size
});
2010-02-19 10:24:02 +00:00
that.bindEvent("click_" + self.autocompleteId, onClick);
2010-02-18 07:27:32 +00:00
}
2010-02-19 10:24:02 +00:00
2010-02-26 13:46:14 +00:00
if (self.options.type != "textarea") {
that.bindEvent({
key_enter: submit,
});
}
2010-07-24 01:32:08 +00:00
/*
if (self.options.validate) {
self.valid = self.options.validate(self.options.value);
}
*/
2010-02-19 10:24:02 +00:00
that.bindEvent({
key_escape: cancel
});
2010-07-24 01:32:08 +00:00
function autocomplete(value) {
2010-02-20 10:51:55 +00:00
var value = value.toLowerCase(),
items = [];
2010-02-19 10:24:02 +00:00
if (value === "") {
2010-02-19 10:34:51 +00:00
// items = self.options.autocomplete[self.placeholder];
2010-02-19 10:24:02 +00:00
} else {
2010-02-20 10:51:55 +00:00
$.each(self.options.autocomplete[self.option], function(i, item) {
2010-02-19 10:24:02 +00:00
if (item.toLowerCase().indexOf(value) > -1) {
items.push(item);
}
});
}
2010-07-24 01:32:08 +00:00
autocompleteCallback(items);
2010-02-20 11:05:58 +00:00
}
2010-07-24 01:32:08 +00:00
function autocompleteCall() {
2010-02-20 10:51:55 +00:00
var value = that.$input.val();
2010-07-02 12:33:45 +00:00
Ox.print("autocomplete call", self.option, value)
2010-02-19 10:24:02 +00:00
if (self.options.autocomplete) {
2010-07-02 12:33:45 +00:00
if (value !== "") {
Ox.isFunction(self.options.autocomplete) ? (
self.option ?
2010-07-24 01:32:08 +00:00
self.options.autocomplete(self.option.id, value, autocompleteCallback) :
self.options.autocomplete(value, autocompleteCallback)
) : autocomplete(value);
2010-07-02 12:33:45 +00:00
} else {
2010-07-24 01:32:08 +00:00
autocompleteCallback();
2010-07-02 12:33:45 +00:00
}
2010-02-19 10:24:02 +00:00
}
2010-02-18 07:27:32 +00:00
}
2010-02-19 10:24:02 +00:00
2010-07-24 01:32:08 +00:00
function autocompleteCallback(items) {
2010-07-02 12:33:45 +00:00
Ox.print("autocomplete callback", items)
var items = items || [],
selected = items.length == 1 ? 0 : -1,
value = that.$input.val().toLowerCase();
2010-02-18 07:56:37 +00:00
if (items.length) {
2010-02-18 15:11:14 +00:00
items = $.map(items, function(title, position) {
2010-02-20 10:51:55 +00:00
if (value == Ox.stripTags(title.toLowerCase())) {
2010-02-18 15:11:14 +00:00
selected = position;
}
2010-02-18 07:56:37 +00:00
return {
id: title.toLowerCase(), // fixme: need function to do lowercase, underscores etc?
title: self.options.highlight ? title.replace(
new RegExp("(" + value + ")", "ig"),
"<span class=\"OxHighlight\">$1</span>"
) : title
2010-02-18 09:11:47 +00:00
};
2010-02-18 07:56:37 +00:00
});
2010-02-20 07:46:31 +00:00
self.selectMenu.hideMenu();
2010-02-19 10:24:02 +00:00
self.autocompleteMenu.options({
2010-02-18 15:11:14 +00:00
items: items,
selected: selected
2010-02-18 07:56:37 +00:00
}).showMenu();
} else {
2010-02-19 10:24:02 +00:00
self.autocompleteMenu.hideMenu();
2010-02-18 07:56:37 +00:00
}
2010-02-10 15:49:33 +00:00
}
2010-02-19 10:24:02 +00:00
2010-07-24 01:32:08 +00:00
function autocorrect(blur) {
var blur = blur || false,
length = self.value.length;
pos = cursor(),
self.value = self.options.autocorrect(self.value, blur);
that.$input.val(self.value);
if (!blur) {
cursor(pos + self.value.length - length);
}
}
function blur() {
that.loseFocus();
that.removeClass("OxFocus");
self.options.autocorrect && autocorrect(that.$input.val(), true);
self.options.validate && that.triggerEvent("blur", { // fixme: is this a good event name for validation on blur?
message: self.message,
valid: self.valid
});
if (self.options.placeholder && that.$input.val() === "") {
2010-07-24 19:27:39 +00:00
that.$input.addClass("OxPlaceholder").val(self.option.title);
2010-07-24 01:32:08 +00:00
}
if (self.options.autocomplete || self.options.autocorrect || self.options.validate) { // fixme: duplicated, make a var
$document.unbind("keydown", keypress);
$document.unbind("keypress", keypress);
}
}
2010-02-19 10:24:02 +00:00
function cancel() {
2010-02-19 10:34:51 +00:00
that.$input.blur();
2010-02-19 10:24:02 +00:00
}
2010-02-20 07:46:31 +00:00
function change(event, data) {
2010-07-02 12:33:45 +00:00
Ox.print("input change", event, data)
if (data) {
self.option = {
id: data.id,
title: data.value // fixme: should be data.title
};
}
2010-02-20 07:46:31 +00:00
if (self.options.label) {
2010-07-02 12:33:45 +00:00
that.$label.html(self.option.title);
2010-02-19 10:34:51 +00:00
that.$input.focus();
2010-07-24 01:32:08 +00:00
autocompleteCall();
2010-02-20 07:46:31 +00:00
} else {
if (that.$input.is(".OxPlaceholder")) {
2010-07-24 19:27:39 +00:00
that.$input.val(self.option.title);
2010-02-20 07:46:31 +00:00
//that.$input.focus();
} else {
that.$input.focus();
2010-07-24 01:32:08 +00:00
autocompleteCall();
2010-02-20 07:46:31 +00:00
}
2010-02-19 10:24:02 +00:00
}
}
2010-02-20 11:05:58 +00:00
function clear() {
that.$input.val("").focus();
2010-07-24 01:32:08 +00:00
//autocompleteCall();
}
function cursor() {
// fixme: see selection()
if (arguments.length == 0) {
return that.$input.$element[0].selectionStart;
} else {
that.$input.$element[0].setSelectionRange(arguments[0], arguments[0]);
}
2010-01-07 20:21:07 +00:00
}
2010-02-19 10:24:02 +00:00
2010-01-07 20:21:07 +00:00
function focus() {
2010-07-02 12:33:45 +00:00
var value;
2010-02-19 10:24:02 +00:00
that.gainFocus();
2010-07-20 20:04:13 +00:00
that.addClass("OxFocus");
2010-02-19 10:24:02 +00:00
if (that.$input.is(".OxPlaceholder")) {
that.$input.val("").removeClass("OxPlaceholder");
2010-01-07 20:21:07 +00:00
}
2010-07-02 12:33:45 +00:00
value = that.$input.val();
2010-07-24 01:32:08 +00:00
if (self.options.autocomplete || self.options.autocorrect || self.options.validate) {
2010-02-18 07:27:32 +00:00
// fixme: different in webkit and firefox (?), see keyboard handler, need generic function
2010-02-18 14:24:17 +00:00
$document.bind("keydown", keypress);
2010-02-18 07:27:32 +00:00
$document.bind("keypress", keypress);
2010-07-24 01:32:08 +00:00
if (self.options.autocomplete) {
value !== "" && Ox.isFunction(self.options.autocomplete) ?
self.options.autocomplete(self.option.id, value, autocompleteCallback) :
autocomplete(value);
}
2010-02-18 07:27:32 +00:00
}
2010-01-07 20:21:07 +00:00
}
2010-02-19 10:24:02 +00:00
2010-02-18 14:24:17 +00:00
function keypress(event) {
2010-02-18 15:15:23 +00:00
if (event.keyCode != 13) {
setTimeout(function() {
2010-02-19 10:24:02 +00:00
var value = that.$input.val();
if (value != self.value) {
2010-02-18 15:15:23 +00:00
self.value = value;
2010-07-24 01:32:08 +00:00
self.options.autocomplete && autocompleteCall();
self.options.autocorrect && autocorrect();
self.options.validate && validateCall();
2010-02-18 15:15:23 +00:00
}
2010-02-18 15:19:36 +00:00
}, 25);
2010-02-18 15:15:23 +00:00
}
2010-02-18 07:56:37 +00:00
}
2010-02-19 10:24:02 +00:00
2010-02-18 14:24:17 +00:00
function onClick(event, data) {
Ox.print("onClick", data);
2010-07-02 15:20:46 +00:00
that.$input.val(Ox.stripTags(data.title));
2010-02-19 10:24:02 +00:00
self.autocompleteMenu.hideMenu();
submit();
2010-02-18 14:24:17 +00:00
}
2010-02-19 10:24:02 +00:00
function select() {
2010-02-20 07:46:31 +00:00
self.selectMenu.showMenu();
2010-02-19 10:24:02 +00:00
}
2010-02-18 14:24:17 +00:00
function selection() {
2010-02-19 10:24:02 +00:00
// fixme: not used!
2010-02-18 14:24:17 +00:00
var start, end;
if (arguments.length == 0) {
return [self.element.selectionStart, self.element.selectionEnd];
} else {
start = arguments[0];
end = arguments[1] || start;
2010-02-18 09:11:47 +00:00
self.element.setSelectionRange(start, end);
2010-01-07 20:21:07 +00:00
}
}
2010-02-19 10:24:02 +00:00
function submit() {
2010-07-02 12:33:45 +00:00
Ox.print("input submit", that.$input.val())
2010-02-19 10:24:02 +00:00
that.$input.trigger("blur");
2010-07-02 16:32:16 +00:00
that.triggerEvent("submit", self.option ? {
key: self.option.id,
value: that.$input.val()
} : that.$input.val());
2010-02-19 10:24:02 +00:00
}
2010-07-24 01:32:08 +00:00
function validate() {
var value = that.$input.val(),
valid = self.options.validate(value) != null;
validateCallback({
valid: valid,
message: "Invalid " + self.options.label
});
}
function validateCall() {
var value = that.$input.val();
Ox.print("validate call", value)
if (self.options.validate) {
if (value !== "") {
Ox.isFunction(self.options.validate) ?
self.options.validate(value, validateCallback) :
validate(value);
} else {
validateCallback({
valid: false,
message: ""
});
}
}
}
function validateCallback(data) {
if (data.valid != self.valid) {
self.message = data.message;
self.valid = data.valid;
that.triggerEvent("validate", data);
}
}
2010-07-07 12:36:12 +00:00
that.changeLabel = function(id) {
that.$label.html(Ox.getObjectById(self.options.label, id).title);
self.selectMenu.checkItem(id);
};
2010-02-26 13:22:27 +00:00
that.height = function(value) {
2010-02-27 08:16:58 +00:00
var stop = 8 / value;
2010-02-26 13:22:27 +00:00
if (self.options.type == "textarea") {
2010-02-27 08:16:58 +00:00
that.$element
.height(value)
.css({
background: "-moz-linear-gradient(top, rgb(224, 224, 224), rgb(208, 208, 208) " + (stop * 100) + "%, rgb(208, 208, 208) " + (100 - stop * 100) + "%, rgb(192, 192, 192))"
})
.css({
background: "-webkit-gradient(linear, left top, left bottom, from(rgb(224, 224, 224)), color-stop(" + stop + ", rgb(208, 208, 208)), color-stop(" + (1 - stop) + ", rgb(208, 208, 208)), to(rgb(192, 192, 192)))"
});
2010-02-26 13:42:21 +00:00
that.$input
.height(value)
.css({
2010-02-27 08:16:58 +00:00
background: "-moz-linear-gradient(top, rgb(224, 224, 224), rgb(240, 240, 240) " + (stop * 100) + "%, rgb(240, 240, 240) " + (100 - stop * 100) + "%, rgb(255, 255, 255))"
2010-02-26 13:42:21 +00:00
})
.css({
2010-02-27 08:16:58 +00:00
background: "-webkit-gradient(linear, left top, left bottom, from(rgb(224, 224, 224)), color-stop(" + stop + ", rgb(240, 240, 240)), color-stop(" + (1 - stop) + ", rgb(240, 240, 240)), to(rgb(255, 255, 255)))"
2010-02-26 13:42:21 +00:00
});
2010-02-26 13:22:27 +00:00
}
return that;
}
2010-02-19 10:24:02 +00:00
that.width = function(value) {
that.$element.width(value);
2010-02-26 13:22:27 +00:00
that.$input.width(value - (self.options.type == "textarea" ? 0 : 2) -
2010-07-24 19:27:39 +00:00
(self.options.label ? self.options.labelWidth + 25 : 0) -
(self.options.placeholder.length > 1 ? 16 : 0) -
(self.options.clear ? 25 : 0));
2010-02-20 07:46:31 +00:00
// fixme: the values above are all weird guesswork
2010-02-19 10:24:02 +00:00
return that;
}
2010-01-07 20:21:07 +00:00
return that;
2010-02-19 10:24:02 +00:00
2010-01-07 20:21:07 +00:00
};
2010-02-27 08:46:49 +00:00
/*
----------------------------------------------------------------------------
Ox.Label
----------------------------------------------------------------------------
*/
Ox.Label = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
id: "",
title: ""
})
.options(options)
.addClass("OxLabel");
that.html(self.options.title);
return that;
};
2010-01-07 20:21:07 +00:00
/*
----------------------------------------------------------------------------
Ox.Range
options:
2010-03-06 09:54:30 +00:00
animate boolean if true, animate thumb
arrows boolean if true, show arrows
arrowStep number step when clicking arrows
arrowSymbols array arrow symbols, like ["minus", "plus"]
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
2010-01-07 20:21:07 +00:00
----------------------------------------------------------------------------
*/
Ox.Range = function(options, self) {
/*
init
*/
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
animate: false,
arrows: false,
arrowStep: 1,
2010-03-06 09:54:30 +00:00
arrowSymbols: ["previous", "next"],
2010-01-07 20:21:07 +00:00
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",
2010-03-06 09:54:30 +00:00
value: self.options.arrowSymbols[0]
2010-01-07 20:21:07 +00:00
})
.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) {
$("<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",
2010-03-06 09:54:30 +00:00
value: self.options.arrowSymbols[1]
2010-01-07 20:21:07 +00:00
})
.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);
2010-02-06 08:23:42 +00:00
that.triggerEvent("change", { value: val });
2010-01-07 20:21:07 +00:00
}
}
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 || {},
2010-02-19 10:24:02 +00:00
that = new Ox.Element("div", self) // fixme: do we use "div", or {}, or "", by default?
2010-02-05 05:20:13 +00:00
.defaults({
id: "",
items: [],
size: "medium"
2010-02-05 05:20:13 +00:00
})
.options(options)
2010-02-08 14:42:00 +00:00
.addClass("OxSelect Ox" + Ox.toTitleCase(self.options.size));
2010-07-05 07:09:34 +00:00
self.buttonId = self.options.id + "_button";
self.groupId = self.options.id; // + "_group"
2010-02-08 14:42:00 +00:00
self.menuId = self.options.id + "_menu",
2010-02-05 05:20:13 +00:00
$.each(self.options.items, function(i, item) {
self.options.items[i] = $.extend(self.options.items[i], {
checked: item.checked || false,
group: self.groupId
});
if (item.checked) {
2010-02-08 14:42:00 +00:00
self.selected = i;
}
2010-02-07 15:01:22 +00:00
});
2010-02-05 05:20:13 +00:00
Ox.print(self.options.id)
that.$button = new Ox.Button($.extend(self.options, {
2010-02-08 14:42:00 +00:00
id: self.buttonId,
type: "text", // fixme: this shouldn't be necessary
2010-07-02 12:33:45 +00:00
value: self.options.items[self.selected].title // fixme: title instead of value?
}), {})
.click(clickButton)
.appendTo(that);
2010-03-06 09:54:30 +00:00
that.$symbol = new Ox.Button({
style: "symbol",
type: "image",
value: "select"
})
2010-03-06 09:54:30 +00:00
.click(clickButton)
.appendTo(that);
2010-02-05 05:20:13 +00:00
that.$menu = new Ox.Menu({
element: that.$button,
2010-02-08 14:42:00 +00:00
id: self.menuId,
items: self.options.items,
2010-02-06 10:29:27 +00:00
offset: {
left: 8,
top: 0
},
side: "bottom",
size: self.options.size
});
2010-02-06 08:23:42 +00:00
that.bindEvent("change_" + self.groupId, clickMenu);
2010-02-06 06:35:40 +00:00
function clickButton() {
that.$menu.toggleMenu();
}
function clickMenu(event, data) {
that.$button.options({
value: data.value
});
2010-02-09 11:50:29 +00:00
that.triggerEvent("change", data.value);
2010-02-05 05:20:13 +00:00
}
self.onChange = function(key, value) {
};
2010-07-07 12:36:12 +00:00
that.selectItem = function(id) {
that.$button.options({
value: Ox.getObjectById(self.options.items, id).title
});
that.$menu.checkItem(id);
};
that.width = function(val) {
// fixme: silly hack, and won't work for css()
2010-02-19 10:24:02 +00:00
that.$element.width(val + 16);
that.$button.width(val);
2010-03-06 09:54:30 +00:00
//that.$symbol.width(val);
return that;
};
2010-02-05 05:20:13 +00:00
return that;
}
2010-02-10 09:59:59 +00:00
/*
============================================================================
Lists
============================================================================
*/
2010-07-05 07:09:34 +00:00
Ox.IconList = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
id: "",
item: function() {},
keys: [],
orientation: "both",
request: function() {},
size: 128,
sort: [],
})
.options(options || {});
$.extend(self, {
itemHeight: self.options.size * 1.5,
itemWidth: self.options.size
});
that.$element = new Ox.List({
construct: constructItem,
itemHeight: self.itemHeight,
itemWidth: self.itemWidth,
keys: $,
orientation: "both",
request: function() {},
rowLength: 1,
size: 128,
type: "icon",
}, self)
.click(click)
.dblclick(dblclick)
.scroll(scroll);
function click() {
}
function constructItem(data) {
var data = self.options.item(data, self.options.sort);
return new Ox.IconItem($.extend(data, {
size: self.options.size
}));
}
function dblclick() {
}
function scroll() {
}
return that;
};
Ox.IconItem = function(options, self) {
var self = self || {}
that = new Ox.Element({}, self)
.defaults({
height: 0,
id: "",
info: "",
size: 128,
title: "",
width: 0,
url: ""
})
.options(options || {});
$.extend(self, {
height: self.options.size * 1.5,
url: oxui.path + "/png/ox.ui." + Ox.theme() + "/icon.png",
width: self.options.size + 4
});
that.css({
width: self.width + "px",
height: self.height + "px"
});
that.$icon = $("<div>")
.addClass("OxIcon")
.css({
top: self.options.size == 64 ? -70 : -128,
width: self.options.size + "px",
height: self.options.size + "px"
});
that.$iconImage = $("<img>")
.attr({
src: self.url
})
.css({
width: iconWidth + "px",
height: iconHeight + "px"
})
.mouseenter(mouseenter)
.mouseleave(mouseleave)
.one("load", function() {
that.$iconImage.attr({
src: self.options.url
});
});
that.$textBox = $("<div>")
.addClass("OxText")
.css({
top: (self.options.size / 2 + 2) + "px",
width: self.width + "px",
height: (self.options.size == 64 ? 38 : 58) + "px"
})
that.$text = $("<div>")
.html(self.options.title + "<br/><span class=\"OxInfo\">" + self.options.info + "</span>")
.mouseenter(mouseenter)
.mouseleave(mouseleave)
that.$reflection = $("<div>")
.addClass("OxReflection")
.css({
top: (self.options.size + 2) + "px",
width: self.options.size + "px",
height: (self.options.size / 2) + "px"
});
that.$reflectionImage = $("<img>")
.addClass("OxReflection")
.attr({
src: self.url
})
.css({
width: self.options.width + "px",
height: self.options.height + "px"
})
.one("load", function() {
that.$reflectionImage.attr({
src: self.options.url
});
});
that.$gradient = $("<div>")
.addClass("OxGradient")
.css({
top: (-self.options.size - 2) + "px"
});
that.append(
that.$reflection.append(
that.$reflectionImage
).append(
that.$gradientImage
)
).append(
that.$textBox.append(
that.$text
)
).append(
that.$icon.append(
that.$iconImage
)
);
function mouseenter() {
that.addClass("OxHover");
}
function mouseleave() {
that.removeClass("OxHover");
}
return that;
};
2010-02-10 09:59:59 +00:00
Ox.List = function(options, self) {
var self = self || {},
2010-06-25 15:55:25 +00:00
that = new Ox.Container({}, self)
.defaults({
2010-06-28 11:19:04 +00:00
construct: function() {},
2010-06-25 15:55:25 +00:00
itemHeight: 16,
itemWidth: 16,
2010-06-28 09:16:36 +00:00
keys: [],
2010-06-25 15:55:25 +00:00
orientation: "vertical",
request: function() {}, // {sort:, range:, callback:}, without parameter returns {items, size etc.}
rowLength: 1,
sort: [],
2010-06-30 18:47:10 +00:00
type: "text",
unique: ""
2010-06-25 15:55:25 +00:00
})
2010-06-28 09:16:36 +00:00
.options(options || {})
2010-06-29 22:19:41 +00:00
.click(click)
2010-06-28 09:16:36 +00:00
.scroll(scroll);
2010-06-25 15:55:25 +00:00
$.extend(self, {
$items: [],
$pages: [],
ids: {},
2010-06-30 14:21:06 +00:00
keyboardEvents: {
key_alt_control_a: invertSelection,
key_control_a: selectAll,
key_control_shift_a: selectNone,
key_end: scrollToFirst,
2010-07-20 20:04:13 +00:00
key_enter: open,
2010-06-30 14:21:06 +00:00
key_home: scrollToLast,
key_pagedown: scrollPageDown,
2010-07-20 20:04:13 +00:00
key_pageup: scrollPageUp,
key_space: preview
2010-06-30 14:21:06 +00:00
},
2010-06-25 15:55:25 +00:00
page: 0,
pageLength: 100,
2010-07-20 20:04:13 +00:00
preview: false,
2010-06-28 09:16:36 +00:00
requests: [],
2010-06-25 15:55:25 +00:00
selected: []
});
2010-06-30 14:21:06 +00:00
self.keyboardEvents["key_" + (self.options.orientation == "horizontal" ? "left" : "up")] = selectPrevious;
self.keyboardEvents["key_" + (self.options.orientation == "horizontal" ? "right" : "down")] = selectNext;
self.keyboardEvents["key_" + (self.options.orientation == "horizontal" ? "shift_left" : "shift_up")] = addPreviousToSelection;
self.keyboardEvents["key_" + (self.options.orientation == "horizontal" ? "shift_right" : "shift_down")] = addNextToSelection;
2010-06-28 09:16:36 +00:00
2010-06-30 18:47:10 +00:00
updateQuery();
2010-07-06 04:39:11 +00:00
Ox.print("s.o", self.options)
2010-06-30 18:47:10 +00:00
that.bindEvent(self.keyboardEvents);
2010-06-25 15:55:25 +00:00
function addAllToSelection(pos) {
var arr,
len = self.$items.length;
if (!isSelected(pos)) {
2010-06-30 09:02:13 +00:00
if (self.selected.length == 0) {
2010-06-25 15:55:25 +00:00
addToSelection(pos);
} else {
2010-06-30 09:02:13 +00:00
if (Ox.min(self.selected) < pos) {
2010-06-25 15:55:25 +00:00
var arr = [pos];
for (var i = pos - 1; i >= 0; i--) {
if (isSelected(i)) {
$.each(arr, function(i, v) {
addToSelection(v);
});
break;
}
arr.push(i);
}
}
2010-06-30 09:02:13 +00:00
if (Ox.max(self.selected) > pos) {
2010-06-25 15:55:25 +00:00
var arr = [pos];
for (var i = pos + 1; i < len; i++) {
if (isSelected(i)) {
$.each(arr, function(i, v) {
addToSelection(v);
});
break;
}
arr.push(i);
}
}
}
}
}
2010-06-30 14:21:06 +00:00
function addNextToSelection() {
var pos = getNext();
if (pos > -1) {
addToSelection(pos);
scrollTo(pos);
}
}
function addPreviousToSelection() {
var pos = getPrevious();
if (pos > -1) {
addToSelection(pos);
scrollTo(pos);
}
}
2010-06-25 15:55:25 +00:00
function addToSelection(pos) {
if (!isSelected(pos)) {
2010-06-30 09:02:13 +00:00
self.selected.push(pos);
2010-06-25 15:55:25 +00:00
if (!Ox.isUndefined(self.$items[pos])) {
self.$items[pos].addClass("OxSelected");
}
Ox.print("addToSelection")
2010-07-17 08:46:27 +00:00
triggerSelectEvent();
2010-06-25 15:55:25 +00:00
}
}
2010-06-30 18:47:10 +00:00
function clear() {
$.each(self.requests, function(i, v) {
2010-06-30 21:41:27 +00:00
Ox.print("Ox.Request.cancel", v);
2010-06-30 18:47:10 +00:00
Ox.Request.cancel(v);
});
$.extend(self, {
$items: [],
$pages: [],
page: 0,
requests: []
});
}
2010-06-29 22:19:41 +00:00
function click(e) {
2010-06-30 09:02:13 +00:00
var $element = $(e.target), pos;
2010-06-30 09:27:02 +00:00
that.gainFocus();
2010-06-30 09:02:13 +00:00
while (!$element.hasClass("OxItem") && !$element.hasClass("OxPage")) {
$element = $element.parent();
}
if ($element.hasClass("OxItem")) {
Ox.print($element.attr("id"), $element.data("position"));
pos = $element.data("position");
if (e.shiftKey) {
addAllToSelection(pos);
} else if (e.metaKey) {
toggleSelection(pos);
} else {
select(pos);
}
} else {
selectNone();
}
2010-06-29 22:19:41 +00:00
}
2010-06-25 15:55:25 +00:00
function deselect(pos) {
if (isSelected(pos)) {
2010-06-30 09:02:13 +00:00
self.selected.splice(self.selected.indexOf(pos), 1);
2010-06-25 15:55:25 +00:00
if (!Ox.isUndefined(self.$items[pos])) {
self.$items[pos].removeClass("OxSelected");
}
2010-07-17 08:46:27 +00:00
triggerSelectEvent();
2010-06-25 15:55:25 +00:00
}
}
2010-06-30 14:21:06 +00:00
function getHeight() {
2010-06-30 18:47:10 +00:00
return that.height() - (that.$content.width() > that.width() ? oxui.scrollbarSize : 0);
2010-06-30 14:21:06 +00:00
}
2010-06-25 15:55:25 +00:00
function getNext() {
var pos = -1;
2010-06-30 09:02:13 +00:00
if (self.selected.length) {
pos = Ox.max(self.selected) + 1;
2010-06-25 15:55:25 +00:00
if (pos == self.$items.length) {
pos = -1;
}
}
return pos;
}
function getPage() {
2010-06-30 21:41:27 +00:00
return self.options.orientation == "horizontal"
? Math.floor(that.scrollLeft() / self.pageWidth)
: Math.floor(that.scrollTop() / self.pageHeight);
2010-06-25 15:55:25 +00:00
}
2010-06-30 18:47:10 +00:00
function getPositions() {
Ox.print("getPositions", $.map(self.selected, function(v, i) {
return self.ids[v];
}));
// fixme: optimize: send non-selected ids if more than half of the items are selected
if (self.selected.length /*&& self.selected.length < self.listLength*/) {
self.requests.push(self.options.request({
callback: getPositionsCallback,
ids: $.map(self.selected, function(v, i) {
return self.ids[v];
}),
sort: self.options.sort
}));
} else {
getPositionsCallback();
}
}
function getPositionsCallback(result) {
Ox.print("getPositionsCallback", result)
if (result) {
$.extend(self, {
ids: {},
selected: []
});
$.each(result.data.positions, function(id, pos) {
Ox.print("id", id, "pos", pos)
self.selected.push(pos);
});
}
load();
}
2010-06-25 15:55:25 +00:00
function getPrevious() {
var pos = -1;
2010-06-30 09:02:13 +00:00
if (self.selected.length) {
pos = Ox.min(self.selected) - 1;
2010-06-25 15:55:25 +00:00
}
return pos;
}
2010-07-20 20:04:13 +00:00
function getSelectedIds() {
// fixme: is carring self.ids around the best way?
return $.map(self.selected, function(v, i) {
return self.ids[v];
});
}
2010-06-30 14:21:06 +00:00
function getWidth() {
2010-06-30 18:47:10 +00:00
return that.width() - (that.$content.height() > that.height() ? oxui.scrollbarSize : 0);
2010-06-30 14:21:06 +00:00
}
2010-06-25 15:55:25 +00:00
function invertSelection() {
2010-06-30 14:21:06 +00:00
$.each(Ox.range(self.listLength), function(i, v) {
toggleSelection(v);
2010-06-25 15:55:25 +00:00
});
}
function isSelected(pos) {
2010-06-28 09:16:36 +00:00
return self.selected.indexOf(pos) > -1;
2010-06-25 15:55:25 +00:00
}
2010-06-30 18:47:10 +00:00
function load() {
that.scrollTop(0);
that.$content.empty();
loadPages(self.page);
}
2010-06-25 15:55:25 +00:00
function loadPage(page, callback) {
2010-06-29 22:19:41 +00:00
Ox.print("loadPage", page)
2010-06-30 18:47:10 +00:00
if (page < 0 || page >= self.pages) {
!Ox.isUndefined(callback) && callback();
2010-06-25 15:55:25 +00:00
return;
}
2010-06-30 09:02:13 +00:00
var keys = $.inArray("id", self.options.keys) > -1 ? self.options.keys :
$.merge(self.options.keys, ["id"]),
offset = page * self.pageLength,
2010-06-25 15:55:25 +00:00
range = [offset, offset + (page < self.pages - 1 ?
self.pageLength : self.listLength % self.pageLength)];
if (Ox.isUndefined(self.$pages[page])) {
2010-06-28 09:16:36 +00:00
self.requests.push(self.options.request({
2010-06-28 11:19:04 +00:00
callback: function(result) {
2010-06-25 15:55:25 +00:00
self.$pages[page] = new Ox.ListPage();
if (self.options.type == "text") {
self.$pages[page].css({
top: (page * self.pageHeight) + "px"
});
} else {
self.$pages[page].css({
});
}
2010-06-28 11:19:04 +00:00
$.each(result.data.items, function(i, v) {
2010-06-25 15:55:25 +00:00
var pos = offset + i;
2010-06-28 11:19:04 +00:00
self.$items[pos] = new Ox.ListItem({
construct: self.options.construct,
data: v,
2010-06-30 18:47:10 +00:00
id: v[self.options.unique],
2010-06-30 09:02:13 +00:00
position: pos
2010-06-28 11:19:04 +00:00
});
2010-06-30 18:47:10 +00:00
self.ids[pos] = v[self.options.unique];
2010-06-25 15:55:25 +00:00
if (isSelected(pos)) {
self.$items[pos].addClass("OxSelected");
}
self.$items[pos].appendTo(self.$pages[page]);
2010-06-25 15:55:25 +00:00
});
if (self.options.type == "text" && page == 0) {
2010-07-05 16:52:12 +00:00
var height = that.height() - (that.width() < that.$content.width() ? oxui.scrollbarSize : 0),
visibleItems = Math.ceil(height / self.options.itemHeight);
if (result.data.items.length < visibleItems) {
self.$pages[page].height(height).css({
overflow: "hidden"
});
$.each(Ox.range(result.data.items.length, visibleItems), function(i, v) {
new Ox.ListItem({
construct: self.options.construct,
data: {},
id: "",
position: v
}).appendTo(self.$pages[page]);
});
}
}
2010-06-28 09:16:36 +00:00
self.$pages[page].appendTo(that.$content);
2010-06-30 18:47:10 +00:00
!Ox.isUndefined(callback) && callback();
2010-06-25 15:55:25 +00:00
},
2010-06-30 09:02:13 +00:00
keys: keys,
2010-06-25 15:55:25 +00:00
range: range,
sort: self.options.sort
2010-06-28 09:16:36 +00:00
}));
} else {
self.$pages[page].appendTo(that.$content);
2010-06-25 15:55:25 +00:00
}
}
function loadPages(page, callback) {
var counter = 0,
fn = function() {
counter++;
counter == 2 && !Ox.isUndefined(callback) && callback();
};
loadPage(page, function() {
loadPage(page - 1, fn);
loadPage(page + 1, fn);
});
}
2010-07-20 20:04:13 +00:00
function open() {
that.triggerEvent("open", {
ids: getSelectedIds()
});
}
function preview() {
self.preview = !self.preview;
if (self.preview) {
that.triggerEvent("openpreview", {
ids: getSelectedIds()
});
} else {
that.triggerEvent("closepreview");
}
}
2010-06-28 09:16:36 +00:00
function scroll() {
var page = self.page;
self.page = getPage();
setTimeout(function() {
if (self.page == getPage()) {
if (self.page == page - 1) {
unloadPage(self.page + 2);
loadPage(self.page - 1);
} else if (self.page == page + 1) {
unloadPage(self.page - 2);
loadPage(self.page + 1);
} else if (self.page == page - 2) {
unloadPage(self.page + 3);
unloadPage(self.page + 2);
loadPage(self.page);
loadPage(self.page - 1);
} else if (self.page == page + 2) {
unloadPage(self.page - 3);
unloadPage(self.page - 2);
loadPage(self.page);
loadPage(self.page + 1);
} else if (self.page != page) {
unloadPages(page);
loadPages(self.page);
}
}
}, 100);
2010-06-28 09:16:36 +00:00
}
2010-06-30 14:21:06 +00:00
function scrollPageDown() {
that.scrollBy(getHeight());
}
function scrollPageUp() {
that.scrollBy(-getHeight());
}
function scrollTo(pos) {
var positions = [], scroll, size;
if (self.options.orientation == "horizontal") {
} else if (self.options.orientation == "vertical") {
positions[0] = self.options.itemHeight * pos;
positions[1] = positions[0] + self.options.itemHeight;
scroll = that.scrollTop();
size = getHeight();
if (positions[0] < scroll) {
that.animate({
scrollTop: positions[0] + "px"
}, 0);
} else if (positions[1] > scroll + size) {
that.animate({
scrollTop: (positions[1] - size) + "px"
}, 0);
}
} else {
}
}
function scrollToFirst() {
that.scrollTop(0);
}
function scrollToLast() {
2010-06-30 18:47:10 +00:00
that.scrollTop(self.listHeight);
2010-06-30 14:21:06 +00:00
}
2010-06-25 15:55:25 +00:00
function select(pos) {
2010-06-30 09:02:13 +00:00
if (!isSelected(pos) || self.selected.length > 1) {
2010-06-25 15:55:25 +00:00
selectNone();
addToSelection(pos);
}
}
function selectAll() {
2010-06-30 14:21:06 +00:00
$.each(Ox.range(self.listLength), function(i, v) {
Ox.print("adding", v);
addToSelection(v);
2010-06-25 15:55:25 +00:00
});
}
function selectNext() {
var pos = getNext();
if (pos > -1) {
select(pos);
scrollTo(pos);
}
}
function selectNone() {
$.each(self.$items, function(i, v) {
deselect(i);
});
}
function selectPrevious() {
var pos = getPrevious();
if (pos > -1) {
select(pos);
scrollTo(pos);
}
}
function selectQuery(str) {
$.each(self.$items, function(i, v) {
if (Ox.toLatin(v.title).toUpperCase().indexOf(str) == 0) {
select(i);
scrollTo(i);
return false;
}
});
}
function toggleSelection(pos) {
if (!isSelected(pos)) {
addToSelection(pos);
} else {
deselect(pos);
}
}
2010-07-17 08:46:27 +00:00
function triggerSelectEvent() {
2010-07-20 20:04:13 +00:00
var ids = getSelectedIds();
2010-07-17 08:46:27 +00:00
setTimeout(function() {
2010-07-20 20:04:13 +00:00
var ids_ = getSelectedIds();
2010-07-17 08:46:27 +00:00
if (ids.length == ids_.length && (ids.length == 0 || ids[0] == ids_[0])) {
that.triggerEvent("select", {
ids: ids
});
2010-07-20 20:04:13 +00:00
self.preview && that.triggerEvent("openpreview", {
ids: ids
});
2010-07-17 08:46:27 +00:00
} else {
2010-07-20 20:04:13 +00:00
Ox.print("select event not triggered after timeout");
2010-07-17 08:46:27 +00:00
}
}, 100);
}
2010-06-25 15:55:25 +00:00
function unloadPage(page) {
2010-06-29 22:19:41 +00:00
if (page < 0 || page >= self.pages) {
return;
}
Ox.print("unloadPage", page)
Ox.print("self.$pages", self.$pages)
Ox.print(!Ox.isUndefined(self.$pages[page]))
2010-06-25 15:55:25 +00:00
!Ox.isUndefined(self.$pages[page]) && self.$pages[page].remove();
}
function unloadPages(page) {
unloadPage(page);
unloadPage(page - 1);
unloadPage(page + 1)
}
2010-02-10 09:59:59 +00:00
2010-06-30 18:47:10 +00:00
function updateQuery() {
clear();
self.requests.push(self.options.request({
callback: function(result) {
var keys = {};
2010-07-01 12:26:32 +00:00
that.triggerEvent("load", result.data);
$.extend(self, {
2010-06-30 18:47:10 +00:00
listHeight: result.data.items * self.options.itemHeight, // fixme: should be listSize
listLength: result.data.items,
pages: Math.ceil(result.data.items / self.pageLength),
pageWidth: self.options.orientation == "horizontal" ?
self.pageLength * self.options.itemWidth : 0,
pageHeight: self.options.orientation == "horizontal" ? 0 :
self.pageLength * self.options.itemHeight / self.options.rowLength
});
2010-06-30 18:47:10 +00:00
that.$content.css({
height: self.listHeight + "px"
});
2010-06-30 18:47:10 +00:00
getPositions();
}
2010-06-30 18:47:10 +00:00
}));
}
2010-06-30 18:47:10 +00:00
function updateSort() {
2010-07-03 08:35:28 +00:00
if (self.listLength > 1) {
clear();
getPositions();
}
2010-06-28 09:16:36 +00:00
}
2010-06-30 18:47:10 +00:00
self.onChange = function(key, value) {
Ox.print("list onChange", key, value);
if (key == "request") {
updateQuery();
}
};
that.clearCache = function() { // fixme: unused? make private?
self.$pages = [];
};
2010-06-28 09:16:36 +00:00
that.sort = function(key, operator) {
if (key != self.options.sort[0].key || operator != self.options.sort[0].operator) {
self.options.sort[0] = {
key: key,
operator: operator
}
2010-06-30 21:41:27 +00:00
that.triggerEvent("sort", self.options.sort[0]);
2010-06-30 18:47:10 +00:00
updateSort();
2010-06-28 09:16:36 +00:00
}
}
2010-02-10 09:59:59 +00:00
return that;
};
Ox.ListItem = function(options, self) {
2010-06-28 11:19:04 +00:00
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
construct: function() {},
data: {},
2010-06-30 18:47:10 +00:00
id: "",
2010-06-30 09:02:13 +00:00
position: 0
2010-06-28 11:19:04 +00:00
})
.options(options || {});
2010-06-28 11:19:04 +00:00
$.each(self.options.data, function(k, v) {
self.options.data[k] = $.isArray(v) ? v.join(", ") : v;
});
2010-06-30 09:02:13 +00:00
that.$element = self.options.construct(self.options.data)
2010-07-05 07:09:34 +00:00
.addClass("OxItem")
2010-06-30 09:02:13 +00:00
.attr({
2010-06-30 18:47:10 +00:00
id: self.options.id
2010-06-30 09:02:13 +00:00
})
.data("position", self.options.position);
2010-06-28 11:19:04 +00:00
return that;
2010-02-10 09:59:59 +00:00
};
2010-06-25 15:55:25 +00:00
Ox.ListPage = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
2010-06-29 21:58:17 +00:00
.addClass("OxPage");
2010-06-25 15:55:25 +00:00
return that;
};
Ox.TextList = function(options, self) {
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
columns: [],
2010-06-29 21:24:07 +00:00
columnWidth: [40, 800],
2010-06-30 09:27:02 +00:00
id: "",
2010-06-25 15:55:25 +00:00
request: function() {}, // {sort, range, keys, callback}
2010-06-28 09:16:36 +00:00
sort: []
2010-06-25 15:55:25 +00:00
})
.options(options || {})
.addClass("OxTextList");
2010-06-30 18:47:10 +00:00
$.each(self.options.columns, function(i, v) { // fixme: can this go into a generic ox.js function?
if (Ox.isUndefined(v.unique)) {
v.unique = false;
}
if (Ox.isUndefined(v.visible)) {
v.visible = false;
}
if (v.unique) {
self.unique = v.id;
}
});
2010-06-25 15:55:25 +00:00
$.extend(self, {
2010-07-03 11:31:25 +00:00
columnPositions: [],
2010-06-25 15:55:25 +00:00
columnWidths: [],
itemHeight: 16,
page: 0,
pageLength: 100,
scrollLeft: 0,
2010-06-29 21:24:07 +00:00
selectedColumn: getColumnIndexById(self.options.sort[0].key),
2010-06-28 09:16:36 +00:00
visibleColumns: $.map(self.options.columns, function(v, i) {
return v.visible ? v : null;
})
2010-06-25 15:55:25 +00:00
});
$.extend(self, {
pageHeight: self.pageLength * self.itemHeight
});
// Head
that.$bar = new Ox.Bar({
orientation: "horizontal",
size: 16
}).appendTo(that);
that.$head = new Ox.Container()
.addClass("OxHead")
.appendTo(that.$bar);
that.$head.$content.addClass("OxTitles");
that.$titles = [];
2010-06-28 09:16:36 +00:00
$.each(self.visibleColumns, function(i, v) {
2010-07-03 11:31:25 +00:00
var $order, $resize, $left, $center, $right, timeout = 0;
2010-06-25 15:55:25 +00:00
self.columnWidths[i] = v.width;
that.$titles[i] = $("<div>")
2010-07-03 11:31:25 +00:00
.addClass("OxTitle OxColumn" + Ox.toTitleCase(v.id))
2010-06-25 15:55:25 +00:00
.css({
width: (v.width - 9) + "px",
textAlign: v.align
})
.html(v.title)
2010-07-03 11:31:25 +00:00
.mousedown(function(e) {
timeout = setTimeout(function() {
dragColumn(v.id, e);
timeout = 0;
}, 250);
})
.mouseup(function() {
if (timeout) {
clearTimeout(timeout);
timeout = 0;
clickColumn(v.id);
}
2010-06-25 15:55:25 +00:00
})
.appendTo(that.$head.$content.$element);
2010-07-03 11:31:25 +00:00
self.columnPositions[i] = Ox.sum(self.columnWidths) - self.columnWidths[i] / 2;
2010-06-25 15:55:25 +00:00
$order = $("<div>")
.addClass("OxOrder")
.html(oxui.symbols["triangle_" + (
2010-07-07 12:36:12 +00:00
v.operator === "" ? "up" : "down"
2010-06-25 15:55:25 +00:00
)])
.click(function() {
$(this).prev().trigger("click")
})
.appendTo(that.$head.$content.$element);
$resize = $("<div>")
.addClass("OxResize")
.mousedown(function(e) {
2010-07-03 11:31:25 +00:00
var startWidth = self.columnWidths[i],
startX = e.clientX;
2010-06-25 15:55:25 +00:00
$window.mousemove(function(e) {
var x = e.clientX,
2010-06-29 21:24:07 +00:00
width = Ox.limit(
2010-07-03 11:31:25 +00:00
startWidth - startX + x,
2010-06-29 21:24:07 +00:00
self.options.columnWidth[0],
self.options.columnWidth[1]
);
resizeColumn(v.id, width);
2010-06-25 15:55:25 +00:00
});
$window.mouseup(function() {
$window.unbind("mousemove");
$window.unbind("mouseup");
});
})
.dblclick(function() {
2010-06-29 21:24:07 +00:00
resizeColumn(v.id, v.width);
2010-06-25 15:55:25 +00:00
})
.appendTo(that.$head.$content.$element);
$left = $("<div>").addClass("OxLeft").appendTo($resize);
$center = $("<div>").addClass("OxCenter").appendTo($resize);
$right = $("<div>").addClass("OxRight").appendTo($resize);
});
that.$head.$content.css({
2010-06-29 17:39:21 +00:00
width: (Ox.sum(self.columnWidths) + 2) + "px"
2010-06-25 15:55:25 +00:00
});
2010-07-24 01:32:08 +00:00
Ox.print("s.sC", self.selectedColumn)
if (getColumnPositionById(self.options.columns[self.selectedColumn].id) > -1) { // fixme: save in var
toggleSelected(self.options.columns[self.selectedColumn].id);
that.$titles[getColumnPositionById(self.options.columns[self.selectedColumn].id)].css({
width: (self.options.columns[self.selectedColumn].width - 25) + "px"
});
}
2010-06-30 15:49:49 +00:00
that.$select = new Ox.Button({
style: "symbol",
type: "image",
value: "select"
}).appendTo(that.$bar.$element);
2010-06-25 15:55:25 +00:00
// Body
2010-06-28 09:16:36 +00:00
that.$body = new Ox.List({
2010-06-28 11:19:04 +00:00
construct: constructItem,
2010-06-30 09:27:02 +00:00
id: self.options.id,
2010-06-28 09:16:36 +00:00
itemHeight: 16,
2010-06-30 09:02:13 +00:00
itemWidth: getItemWidth(),
2010-06-28 11:19:04 +00:00
keys: $.map(self.visibleColumns, function(v, i) {
return v.id;
}),
2010-06-28 09:16:36 +00:00
orientation: "vertical",
request: self.options.request,
sort: self.options.sort,
2010-06-30 18:47:10 +00:00
type: "text",
unique: self.unique
2010-06-28 11:19:04 +00:00
})
2010-06-28 09:16:36 +00:00
.addClass("OxBody")
.scroll(function() {
var scrollLeft = $(this).scrollLeft();
if (scrollLeft != self.scrollLeft) {
self.scrollLeft = scrollLeft;
that.$head.scrollLeft(scrollLeft);
}
})
.appendTo(that);
that.$body.$content.css({
2010-06-30 09:02:13 +00:00
width: getItemWidth() + "px"
2010-06-25 15:55:25 +00:00
});
2010-07-06 04:39:11 +00:00
Ox.print("s.vC", self.visibleColumns)
2010-06-28 09:16:36 +00:00
function addColumn(id) {
}
2010-06-29 21:24:07 +00:00
function clickColumn(id) {
2010-07-03 11:31:25 +00:00
Ox.print("clickColumn", id);
2010-06-29 21:24:07 +00:00
var i = getColumnIndexById(id),
isSelected = self.options.sort[0].key == self.options.columns[i].id;
2010-06-29 16:28:22 +00:00
that.sort(
2010-06-29 21:24:07 +00:00
self.options.columns[i].id, isSelected ?
2010-07-07 12:36:12 +00:00
(self.options.sort[0].operator === "" ? "-" : "") :
2010-06-29 21:24:07 +00:00
self.options.columns[i].operator
2010-06-29 16:28:22 +00:00
);
}
2010-06-30 09:02:13 +00:00
function constructItem(data) {
2010-06-28 11:19:04 +00:00
var $item = $("<div>")
2010-06-25 15:55:25 +00:00
.css({
2010-06-30 18:47:10 +00:00
width: Math.max(Ox.sum(self.columnWidths), that.$element.width() - oxui.scrollbarSize) + "px"
2010-06-30 09:02:13 +00:00
});
2010-06-28 11:19:04 +00:00
$.each(self.visibleColumns, function(i, v) {
2010-06-25 15:55:25 +00:00
var $cell = $("<div>")
.addClass("OxCell OxColumn" + Ox.toTitleCase(v.id))
.css({
2010-06-28 11:19:04 +00:00
width: (self.columnWidths[i] - 9) + "px",
2010-06-25 15:55:25 +00:00
textAlign: v.align
})
.html(!$.isEmptyObject(data) ? data[v.id] : "")
.appendTo($item);
2010-06-25 15:55:25 +00:00
});
return $item;
}
2010-07-03 11:31:25 +00:00
function dragColumn(id, e) {
var startX = e.clientX,
startPos = getColumnPositionById(id),
pos = startPos,
stopPos = startPos,
positions = $.map(self.visibleColumns, function(v, i) {
return self.columnPositions[i] - self.columnPositions[startPos]
});
2010-07-05 07:09:34 +00:00
$(".OxColumn" + Ox.toTitleCase(id)).css({
opacity: 0.1
});
2010-07-03 11:31:25 +00:00
that.$titles[startPos].addClass("OxDrag").css({ // fixme: why does the class not work?
cursor: "move"
});
Ox.print("positions", positions)
$window.mousemove(function(e) {
var d = e.clientX - startX;
$.each(positions, function(i, v) {
if (d < 0 && d < v) {
stopPos = i;
return false;
} else if (d > 0 && d > v) {
stopPos = i;
}
});
if (stopPos != pos) {
pos = stopPos;
moveColumn(id, pos);
}
});
$window.mouseup(function() {
dropColumn(id, pos);
$window.unbind("mousemove");
$window.unbind("mouseup");
});
}
function dropColumn(id, pos) {
Ox.print("dropColumn", id, pos)
var startPos = getColumnPositionById(id),
stopPos = pos,
$title = that.$titles.splice(startPos, 1)[0],
column = self.visibleColumns.splice(startPos, 1)[0],
width = self.columnWidths.splice(startPos, 1)[0];
that.$titles.splice(stopPos, 0, $title);
self.visibleColumns.splice(stopPos, 0, column);
self.columnWidths.splice(stopPos, 0, width);
Ox.print("s.vC", self.visibleColumns)
2010-07-05 07:09:34 +00:00
$(".OxColumn" + Ox.toTitleCase(id)).css({
opacity: 1
});
2010-07-03 11:31:25 +00:00
that.$titles[stopPos].removeClass("OxDrag").css({
cursor: "pointer"
});
}
2010-06-29 21:24:07 +00:00
function getColumnIndexById(id) {
2010-06-25 15:55:25 +00:00
var pos = -1;
$.each(self.options.columns, function(i, v) {
if (v.id == id) {
pos = i;
return false;
}
});
return pos;
}
2010-06-29 21:24:07 +00:00
function getColumnPositionById(id) {
var pos = -1;
$.each(self.visibleColumns, function(i, v) {
if (v.id == id) {
pos = i;
return false;
}
});
return pos;
}
2010-06-30 09:02:13 +00:00
function getItemWidth() {
2010-07-06 04:39:11 +00:00
return Ox.sum(self.columnWidths)
2010-06-30 18:47:10 +00:00
return Math.max(Ox.sum(self.columnWidths), that.$element.width() - oxui.scrollbarSize);
2010-06-30 09:02:13 +00:00
}
2010-07-03 11:31:25 +00:00
function moveColumn(id, pos) {
Ox.print("moveColumn", id, pos)
var startPos = getColumnPositionById(id),
stopPos = pos,
startClassName = ".OxColumn" + Ox.toTitleCase(id),
stopClassName = ".OxColumn" + Ox.toTitleCase(self.visibleColumns[stopPos].id),
$column = $(".OxTitle" + startClassName),
$order = $column.next(),
$resize = $order.next();
$column.detach().insertBefore($(".OxTitle" + stopClassName));
$order.detach().insertAfter($column);
$resize.detach().insertAfter($order);
$.each(that.$body.find(".OxItem"), function(i, v) {
var $v = $(v);
$v.children(startClassName).detach().insertBefore($v.children(stopClassName));
});
2010-06-28 09:16:36 +00:00
}
function removeColumn(id) {
}
2010-06-29 22:19:41 +00:00
function resize() {
}
2010-06-29 21:24:07 +00:00
function resizeColumn(id, width) {
var i = getColumnIndexById(id),
pos = getColumnPositionById(id);
2010-06-25 15:55:25 +00:00
self.columnWidths[pos] = width;
that.$head.$content.css({
width: (Ox.sum(self.columnWidths) + 2) + "px"
});
that.$titles[pos].css({
2010-06-29 21:24:07 +00:00
width: (width - 9 - (i == self.selectedColumn ? 16 : 0)) + "px"
2010-06-25 15:55:25 +00:00
});
that.$body.$content.find(".OxItem").css({ // fixme: can we avoid this lookup?
2010-06-30 09:02:13 +00:00
width: getItemWidth() + "px"
2010-06-25 15:55:25 +00:00
});
that.$body.$content.css({
2010-06-30 09:02:13 +00:00
width: getItemWidth() + "px" // fixme: check if scrollbar visible, and listen to resize/toggle event
2010-06-25 15:55:25 +00:00
});
2010-07-06 04:39:11 +00:00
$(".OxCell.OxColumn" + Ox.toTitleCase(self.options.columns[i].id)).css({
2010-06-25 15:55:25 +00:00
width: (width - 9) + "px"
});
that.$body.clearCache();
}
2010-06-29 21:24:07 +00:00
function toggleSelected(id) {
var pos = getColumnPositionById(id);
2010-07-07 12:36:12 +00:00
if (pos > -1) {
updateOrder(id);
pos > 0 && that.$titles[pos].prev().children().eq(2).toggleClass("OxSelected");
that.$titles[pos].toggleClass("OxSelected");
that.$titles[pos].next().toggleClass("OxSelected");
that.$titles[pos].next().next().children().eq(0).toggleClass("OxSelected");
that.$titles[pos].css({
width: (
that.$titles[pos].width() + (that.$titles[pos].hasClass("OxSelected") ? -16 : 16)
) + "px"
});
}
2010-06-25 15:55:25 +00:00
}
2010-06-29 21:24:07 +00:00
function updateOrder(id) {
var pos = getColumnPositionById(id);
Ox.print(id, pos)
2010-06-29 17:39:21 +00:00
that.$titles[pos].next().html(oxui.symbols[
2010-07-07 12:36:12 +00:00
"triangle_" + (self.options.sort[0].operator === "" ? "up" : "down")
2010-06-29 17:39:21 +00:00
]);
}
2010-06-30 18:47:10 +00:00
self.onChange = function(key, value) {
if (key == "request") {
that.$body.options(key, value);
}
};
2010-07-20 20:04:13 +00:00
that.closePreview = function() {
self.preview = false;
};
that.resizeColumn = function(id, width) {
resizeColumn(id, width);
return that;
}
2010-06-25 15:55:25 +00:00
that.sort = function(key, operator) {
2010-06-29 16:28:22 +00:00
var isSelected = key == self.options.sort[0].key;
self.options.sort = [
{
key: key,
operator: operator
}
];
if (isSelected) {
2010-06-29 21:24:07 +00:00
updateOrder(self.options.columns[self.selectedColumn].id);
2010-06-29 16:28:22 +00:00
} else {
2010-06-29 21:24:07 +00:00
toggleSelected(self.options.columns[self.selectedColumn].id);
self.selectedColumn = getColumnIndexById(key);
toggleSelected(self.options.columns[self.selectedColumn].id);
2010-06-25 15:55:25 +00:00
}
2010-06-29 16:28:22 +00:00
that.$body.sort(self.options.sort[0].key, self.options.sort[0].operator);
return that;
2010-06-25 15:55:25 +00:00
};
return that;
};
2010-07-24 01:32:08 +00:00
/*
============================================================================
Maps
============================================================================
*/
Ox.Map = function(options, self) {
var self = self || {}
that = new Ox.Element("div", self)
.defaults({
places: [],
type: "satellite"
})
.options(options || {});
init();
2010-07-24 19:27:39 +00:00
function canContain(outerBounds, innerBounds) {
var outerSpan = outerBounds.toSpan(),
innerSpan = innerBounds.toSpan();
return outerSpan.lat() > innerSpan.lat() &&
outerSpan.lng() > innerSpan.lng();
}
function click(event) {
Ox.print("event", event);
getLocationByLatLng(event.latLng, self.map.getBounds(), function(location) {
self.marker && self.marker.remove();
self.polygon && self.polygon.remove();
if (location) {
self.marker = location.marker.add();
self.polygon = location.polygon.add();
}
})
}
function getLocationByLatLng(latlng, bounds, callback) {
Ox.print("ll b", latlng, bounds)
var callback = arguments.length == 3 ? callback : bounds,
bounds = arguments.length == 3 ? bounds : null;
2010-07-24 01:32:08 +00:00
self.geocoder.geocode({
2010-07-24 19:27:39 +00:00
latLng: latlng
2010-07-24 01:32:08 +00:00
}, function(results, status) {
2010-07-24 19:27:39 +00:00
Ox.print("results", results)
var length = results.length;
2010-07-24 01:32:08 +00:00
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
2010-07-24 19:27:39 +00:00
if (bounds) {
$.each(results.reverse(), function(i, result) {
if (
i == length - 1 ||
canContain(bounds, result.geometry.bounds || result.geometry.viewport)
) {
callback(new Location(results[i]));
return false;
}
});
} else {
callback(new Location(results[0]));
}
2010-07-24 01:32:08 +00:00
} else {
callback(null);
}
} else {
Ox.print("geocode failed:", status);
callback(null);
}
});
}
2010-07-24 19:27:39 +00:00
function getLocationByName(name, callback) {
self.geocoder.geocode({
address: name
}, function(results, status) {
2010-07-24 01:32:08 +00:00
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
2010-07-24 19:27:39 +00:00
callback(new Location(results[0]))
} else {
callback(null);
2010-07-24 01:32:08 +00:00
}
2010-07-24 19:27:39 +00:00
} else {
Ox.print("geocode failed:", status);
callback(null);
2010-07-24 01:32:08 +00:00
}
});
}
function init() {
var counter = 0,
length = self.options.places.length;
$.extend(self, {
geocoder: new google.maps.Geocoder(),
2010-07-24 19:27:39 +00:00
locations: [],
selectedMarker: null
2010-07-24 01:32:08 +00:00
});
$.each(self.options.places, function(i, place) {
if (Ox.isString(place)) {
self.options.places[i] = {
name: place
};
} else if (Ox.isArray(place)) {
self.options.places[i] = {
name: "",
point: place
};
}
"point" in self.options.places[i] ?
getLocationByPoint(self.options.places[i].point, callback) :
getLocationByName(self.options.places[i].name, callback);
});
function callback(location) {
if (location) {
Ox.print("counter", counter, location)
self.locations.push(location);
self.bounds = counter == 0 ? location.rectangle.bounds :
self.bounds.union(location.rectangle.bounds);
}
if (counter++ == length - 1) {
loadMap();
}
}
}
function loadMap() {
Ox.print("loadMap");
$.extend(self, {
map: new google.maps.Map(that.$element[0], {
center: self.bounds.getCenter(),
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId[self.options.type.toUpperCase()],
zoom: 0
})
});
self.map.fitBounds(self.bounds)
2010-07-24 19:27:39 +00:00
google.maps.event.addListener(self.map, "click", click);
2010-07-24 01:32:08 +00:00
google.maps.event.addListener(self.map, "zoom_changed", zoom);
$.each(self.locations, function(i, location) {
location.marker.add();
});
};
2010-07-24 19:27:39 +00:00
function resize() {
google.maps.event.trigger(self.map, "resize");
}
2010-07-24 01:32:08 +00:00
function zoom() {
}
function Location(geocode) {
Ox.print("geocode", geocode);
var bounds = geocode.geometry.bounds || geocode.geometry.viewport,
area = [
[bounds.getSouthWest().lat(), bounds.getSouthWest().lng()],
[bounds.getNorthEast().lat(), bounds.getNorthEast().lng()]
],
location = {
geocode: geocode,
name: {
formatted: geocode.formatted_address,
long: $.map(geocode.address_components, function(v) {
return v.long_name;
}).join(", ")
},
rectangle: new Rectangle(area),
};
Ox.print("area", area)
return $.extend(location, {
marker: new Marker(location),
polygon: new Polygon(location)
});
}
function Marker(location) {
var listeners = {},
marker = new google.maps.Marker({
2010-07-24 19:27:39 +00:00
icon: icon("red"),
2010-07-24 01:32:08 +00:00
position: location.rectangle.center,
title: location.name.formatted
2010-07-24 19:27:39 +00:00
}),
selected = false;
2010-07-24 01:32:08 +00:00
function click() {
2010-07-24 19:27:39 +00:00
selected = !selected;
2010-07-24 01:32:08 +00:00
marker.setOptions({
2010-07-24 19:27:39 +00:00
icon: icon(selected ? "blue" : "red")
2010-07-24 01:32:08 +00:00
});
2010-07-24 19:27:39 +00:00
location.polygon[selected ? "add" : "remove"]();
}
function dblclick() {
click();
self.map.fitBounds(location.rectangle.bounds);
2010-07-24 01:32:08 +00:00
}
function icon(color) {
return "http://dev.pan.do:8000" + oxui.path + "png/ox.ui/marker" + Ox.toTitleCase(color) + ".png"
}
return {
add: function() {
marker.setMap(self.map);
2010-07-24 19:27:39 +00:00
listeners = {
click: google.maps.event.addListener(marker, "click", click),
dblclick: google.maps.event.addListener(marker, "dblclick", dblclick),
};
return this;
},
deselect: function() {
2010-07-24 01:32:08 +00:00
},
remove: function() {
marker.setMap(null);
2010-07-24 19:27:39 +00:00
$.each(listeners, function(i, listener) {
google.maps.event.removeListener(listener);
});
return this;
},
select: function() {
2010-07-24 01:32:08 +00:00
}
};
}
function Polygon(location) {
var listeners = {},
points = [
location.rectangle.latlng.sw,
location.rectangle.latlng.nw,
location.rectangle.latlng.ne,
location.rectangle.latlng.se,
location.rectangle.latlng.sw
],
polygon = new google.maps.Polygon({
paths: points
}),
selected = false;
2010-07-24 19:27:39 +00:00
setOptions();
function click() {
selected = !selected;
setOptions();
}
2010-07-24 01:32:08 +00:00
function setOptions() {
var color = selected ? "#8080FF" : "#FFFFFF";
polygon.setOptions({
clickable: true,
fillColor: color,
fillOpacity: selected ? 0.1 : 0,
strokeColor: color,
strokeOpacity: 1,
strokeWeight: 2
});
}
return {
add: function() {
polygon.setMap(self.map);
2010-07-24 19:27:39 +00:00
listeners.click = google.maps.event.addListener(polygon, "click", click);
return this;
2010-07-24 01:32:08 +00:00
},
deselect: function() {
selected = false;
setOptions();
},
remove: function() {
polygon.setMap(null);
google.maps.event.removeListener(listeners.click);
2010-07-24 19:27:39 +00:00
return this;
2010-07-24 01:32:08 +00:00
},
select: function() {
selected = true;
setOptions();
}
};
}
function Rectangle(area) {
var latlng = {
sw: new google.maps.LatLng(area[0][0], area[0][1]),
ne: new google.maps.LatLng(area[1][0], area[1][1])
},
bounds = new google.maps.LatLngBounds(latlng.sw, latlng.ne),
lat = {},
lng = {};
latlng.mc = bounds.getCenter();
$.each(latlng, function(k, v) {
lat[k] = v.lat();
lng[k] = v.lng();
});
$.extend(latlng, {
sc: new google.maps.LatLng(lat.sw, lng.mc),
2010-07-24 19:27:39 +00:00
se: new google.maps.LatLng(lat.sw, lng.ne),
mw: new google.maps.LatLng(lat.mc, lng.sw),
mw: new google.maps.LatLng(lat.mc, lng.ne),
nw: new google.maps.LatLng(lat.ne, lng.sw),
nc: new google.maps.LatLng(lat.ne, lng.mc),
2010-07-24 01:32:08 +00:00
});
return {
area: area,
bounds: bounds,
canContain: function(rectangle) {
var outerSpan = this.bounds.toSpan(),
innerSpan = rectangle.bounds.toSpan();
return outerSpan.lat() > innerSpan.lat() &&
outerSpan.lng() > innerSpan.lng();
},
center: latlng.mc,
contains: function(rectangle) {
return this.bounds.contains(rectangle.bounds.getSouthWest()) &&
this.bounds.contains(rectangle.bounds.getNorthEast());
},
latlng: latlng
};
}
self.onChange = function(key, value) {
if (key == "type") {
}
};
return that;
};
Ox.MapImage = function(options, self) {
/*
options:
height image height (px)
places array of either names (""), points ([0, 0]),
or objects ({name, point, highlight})
type map type ("hybrid", "roadmap", "satellite", "terrain")
width image width (px)
*/
var self = self || {},
that = new Ox.Element("img", self)
.defaults({
height: 360,
markerColorHighlight: "yellow",
markerColorNormal: "blue",
places: [],
type: "satellite",
width: 640
})
.options(options || {})
$.extend(self, {
markers: {
highlight: [],
normal: []
},
src: "http://maps.google.com/maps/api/staticmap?sensor=false" +
"&size=" + self.options.width + "x" + self.options.height +
"&maptype=" + self.options.type
});
if (self.options.places.length) {
$.each(self.options.places, function(i, place) {
if (Ox.isString(place)) {
self.markers.normal.push(place);
} else if (Ox.isArray(place)) {
self.markers.normal.push(place.join(","));
} else {
self.markers[place.highlight ? "highlight" : "normal"]
.push("point" in place ? place.point.join(",") : place.name)
}
});
$.each(self.markers, function(k, markers) {
if (markers.length) {
self.src += "&markers=icon:" + "http://dev.pan.do:8000" + oxui.path + "png/ox.ui/marker" +
Ox.toTitleCase(self.options["markerColor" + Ox.toTitleCase(k)]) + ".png|" +
markers.join("|")
}
});
} else {
self.src += "&center=0,0&zoom=2"
}
that.attr({
src: self.src
});
self.onChange = function(key, value) {
};
return that;
};
2010-01-07 20:21:07 +00:00
/*
============================================================================
2010-02-02 16:03:11 +00:00
Menus
============================================================================
*/
Ox.MainMenu = function(options, self) {
2010-02-07 15:01:22 +00:00
2010-02-19 10:24:02 +00:00
/* options:
* extras
* menus
* size
*/
2010-02-07 15:01:22 +00:00
var self = self || {},
that = new Ox.Bar({}, self)
2010-02-08 09:35:24 +00:00
.defaults({
2010-02-19 10:24:02 +00:00
extras: [],
2010-02-08 09:35:24 +00:00
menus: [],
size: "medium"
})
.options(options || {})
2010-02-19 10:24:02 +00:00
.addClass("OxMainMenu Ox" + Ox.toTitleCase(self.options.size)) // fixme: bar should accept small/medium/large ... like toolbar
2010-02-08 09:35:24 +00:00
.click(click)
.mousemove(mousemove);
2010-02-07 15:01:22 +00:00
2010-02-08 09:35:24 +00:00
self.focused = false;
self.selected = -1;
that.menus = [];
2010-02-09 05:43:36 +00:00
that.titles = [];
that.layer = $("<div>").addClass("OxLayer");
2010-02-08 09:35:24 +00:00
2010-02-19 10:57:19 +00:00
$.each(self.options.menus, function(position, menu) {
2010-02-08 09:35:24 +00:00
that.titles[position] = $("<div>")
.addClass("OxTitle")
.html(menu.title)
.data("position", position)
.appendTo(that.$element);
that.menus[position] = new Ox.Menu($.extend(menu, {
element: that.titles[position],
mainmenu: that,
size: self.options.size
}));
2010-02-09 05:43:36 +00:00
that.bindEvent("hide_" + that.menus[position].options("id"), onHideMenu);
2010-02-08 09:35:24 +00:00
});
2010-02-19 10:57:19 +00:00
if (self.options.extras.length) {
that.extras = $("<div>")
.addClass("OxExtras")
.appendTo(that.$element);
$.each(self.options.extras, function(position, extra) {
2010-02-20 08:29:03 +00:00
extra.css({
float: "left" // fixme: need class!
}).appendTo(that.extras);
2010-02-19 10:57:19 +00:00
});
}
2010-02-08 09:35:24 +00:00
function click(event) {
var $target = $(event.target),
2010-02-09 05:43:36 +00:00
position = typeof $target.data("position") != "undefined" ?
$target.data("position") : -1;
clickTitle(position);
}
function clickTitle(position) {
var selected = self.selected;
if (self.selected > -1) {
that.menus[self.selected].hideMenu();
}
if (position > -1) {
if (position != selected) {
self.focused = true;
self.selected = position;
that.titles[self.selected].addClass("OxSelected");
that.menus[self.selected].showMenu();
}
2010-02-08 09:35:24 +00:00
}
}
2010-07-07 12:36:12 +00:00
function getMenuById(id) {
var menu = null;
$.each(that.menus, function(i, v) {
if (v.options("id") == id) {
menu = v;
return false;
}
});
return menu;
}
2010-02-08 09:35:24 +00:00
function mousemove(event) {
var $target = $(event.target),
2010-02-09 05:43:36 +00:00
focused,
position = typeof $target.data("position") != "undefined" ?
$target.data("position") : -1;
if (self.focused && position != self.selected) {
if (position > -1) {
clickTitle(position);
} else {
focused = self.focused;
that.menus[self.selected].hideMenu();
self.focused = focused;
2010-02-08 10:17:00 +00:00
}
2010-02-08 09:35:24 +00:00
}
}
2010-02-09 05:43:36 +00:00
function onHideMenu() {
2010-02-09 12:20:23 +00:00
if (self.selected > -1) {
that.titles[self.selected].removeClass("OxSelected");
self.selected = -1;
}
2010-02-08 09:35:24 +00:00
self.focused = false;
}
self.onChange = function(key, value) {
};
2010-02-19 10:24:02 +00:00
that.addMenuAfter = function(id) {
2010-02-08 10:17:00 +00:00
};
2010-02-19 10:24:02 +00:00
that.addMenuBefore = function(id) {
2010-02-08 10:17:00 +00:00
};
2010-07-07 12:36:12 +00:00
that.checkItem = function(id) {
that.getItem(id).options({
checked: true
});
};
2010-02-10 16:37:26 +00:00
that.disableItem = function(id) {
2010-07-13 22:38:53 +00:00
that.getItem(id).options({
disabled: true
});
2010-02-10 16:37:26 +00:00
};
that.enableItem = function(id) {
2010-07-13 22:38:53 +00:00
that.getItem(id).options({
disabled: false
});
2010-02-10 16:37:26 +00:00
};
2010-02-19 16:13:22 +00:00
that.getItem = function(id) {
2010-07-07 12:36:12 +00:00
var ids = id.split("_"),
item;
if (ids.length == 1) {
$.each(that.menus, function(i, menu) {
item = menu.getItem(id);
return !item;
});
} else {
item = getMenuById(ids.shift()).getItem(ids.join("_"));
}
2010-02-19 16:13:22 +00:00
return item;
};
2010-02-08 10:17:00 +00:00
that.removeMenu = function() {
};
2010-02-08 09:35:24 +00:00
that.selectNextMenu = function() {
if (self.selected < self.options.menus.length - 1) {
clickTitle(self.selected + 1);
}
};
that.selectPreviousMenu = function() {
if (self.selected) {
clickTitle(self.selected - 1);
}
};
2010-07-07 12:36:12 +00:00
that.uncheckItem = function(id) {
2010-07-13 22:38:53 +00:00
that.getItem(id).options({
checked: false
});
2010-07-07 12:36:12 +00:00
};
2010-02-08 09:35:24 +00:00
return that;
};
2010-02-02 16:03:11 +00:00
Ox.Menu = function(options, self) {
2010-02-09 12:58:47 +00:00
/*
2010-02-10 15:49:57 +00:00
2010-02-09 12:58:47 +00:00
options:
element the element the menu is attached to
id the menu id
items array of menu items
mainmenu the main menu this menu is part of, if any
offset offset of the menu, in px
parent the supermenu, if any
selected the position of the selected item
2010-02-10 15:49:57 +00:00
side open to "bottom" or "right"
2010-02-09 12:58:47 +00:00
size "large", "medium" or "small"
2010-02-10 15:49:57 +00:00
2010-07-07 12:36:12 +00:00
methods:
2010-02-10 15:49:57 +00:00
events:
2010-02-09 12:58:47 +00:00
change_groupId {id, value} checked item of a group has changed
click_itemId item not belonging to a group was clicked
2010-02-18 14:24:17 +00:00
click_menuId {id, value} item not belonging to a group was clicked
2010-02-18 15:23:43 +00:00
deselect_menuId {id, value} item was deselected not needed, not implemented
2010-02-09 12:58:47 +00:00
hide_menuId menu was hidden
2010-02-18 15:23:43 +00:00
select_menuId {id, value} item was selected not needed, not implemented
2010-02-10 15:49:57 +00:00
2010-02-09 12:58:47 +00:00
*/
2010-02-02 16:03:11 +00:00
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: [],
2010-02-08 09:35:24 +00:00
mainmenu: null,
2010-02-02 16:03:11 +00:00
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-07 15:01:22 +00:00
)
.click(click)
.mouseenter(mouseenter)
.mouseleave(mouseleave)
.mousemove(mousemove),
2010-02-05 14:59:24 +00:00
itemHeight = self.options.size == "small" ? 12 : (self.options.size == "medium" ? 16 : 20),
2010-02-18 14:24:17 +00:00
// menuHeight,
2010-02-07 15:01:22 +00:00
scrollSpeed = 1,
2010-02-05 14:59:24 +00:00
$item; // fixme: used?
2010-02-07 15:01:22 +00:00
// fixme: attach all private vars to self?
2010-02-02 16:03:11 +00:00
self.keyboardEvents = {
key_up: selectPreviousItem,
key_down: selectNextItem,
key_left: selectSupermenu,
key_right: selectSubmenu,
key_escape: hideMenu,
key_enter: clickSelectedItem
};
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-18 07:27:32 +00:00
constructItems(self.options.items);
2010-02-02 16:03:11 +00:00
that.$scrollbars.down = constructScrollbar("down")
.appendTo(that.$element);
that.$bottom = $("<div>")
.addClass("OxBottom")
.appendTo(that.$element);
2010-02-09 05:43:36 +00:00
that.$layer = $("<div>")
.addClass(self.options.mainmenu ? "OxMainMenuLayer" : "OxLayer");
2010-02-02 16:03:11 +00:00
2010-02-05 09:13:03 +00:00
function click(event) {
2010-02-07 15:01:22 +00:00
var item,
2010-02-07 15:12:14 +00:00
position,
2010-02-07 15:01:22 +00:00
$target = $(event.target);
if ($target.is(".OxCell")) {
2010-02-07 15:12:14 +00:00
position = $target.parent().data("position");
item = that.items[position];
2010-02-07 15:01:22 +00:00
if (!item.options("disabled")) {
2010-02-07 15:12:14 +00:00
clickItem(position);
2010-02-09 12:20:23 +00:00
} else {
that.hideMenu();
2010-02-07 15:01:22 +00:00
}
2010-02-09 12:20:23 +00:00
} else {
that.hideMenu();
2010-02-05 09:13:03 +00:00
}
}
2010-02-07 15:12:14 +00:00
function clickItem(position) {
var item = that.items[position];
if (!item.options("items").length) {
2010-02-08 09:35:24 +00:00
if (that.options("parent")) {
Ox.print("t.o.p", that.options("parent"))
2010-02-08 09:35:24 +00:00
that.options("parent").hideMenu().triggerEvent("click");
}
2010-02-07 15:12:14 +00:00
if (item.options("checked") !== null && (!item.options("group") || !item.options("checked"))) {
item.options({
checked: !item.options("checked")
});
2010-02-09 12:20:23 +00:00
Ox.Event.trigger("change_" + item.options("group"), {
2010-02-09 11:50:29 +00:00
id: item.options("id"),
2010-02-07 15:12:14 +00:00
value: item.options("title")[0] // fixme: value or title?
});
2010-02-09 12:20:23 +00:00
} else {
2010-02-18 14:24:17 +00:00
Ox.Event.trigger("click_" + self.options.id, {
id: item.options("id"),
title: item.options("title")[0]
});
2010-02-09 12:20:23 +00:00
Ox.Event.trigger("click_" + item.options("id"));
2010-02-07 15:12:14 +00:00
}
if (item.options("title").length == 2) {
item.toggleTitle();
}
}
2010-02-09 12:20:23 +00:00
that.hideMenu();
2010-02-07 15:12:14 +00:00
}
function clickSelectedItem() {
2010-02-09 05:43:36 +00:00
// called on key.enter
2010-02-04 09:50:45 +00:00
if (self.options.selected > -1) {
2010-02-07 15:12:14 +00:00
clickItem(self.options.selected);
2010-02-05 05:20:13 +00:00
} else {
that.hideMenu();
2010-02-04 09:50:45 +00:00
}
}
2010-02-18 07:27:32 +00:00
function constructItems(items) {
that.items = [];
that.$content.empty();
2010-02-18 14:24:17 +00:00
scrollMenuUp();
2010-02-18 07:27:32 +00:00
$.each(items, function(i, item) {
var position;
if (item.id) {
that.items.push(new Ox.MenuItem($.extend(item, {
menu: that,
position: position = that.items.length
})).data("position", position).appendTo(that.$content)); // fixme: jquery bug when passing {position: position}? does not return the object?;
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,
mainmenu: self.options.mainmenu,
offset: {
left: 0,
top: -4
},
parent: that,
side: "right",
size: self.options.size,
});
}
} else {
that.$content.append(constructSpace());
that.$content.append(constructLine());
that.$content.append(constructSpace());
}
});
2010-02-18 14:24:17 +00:00
if (!that.is(":hidden")) {
that.hideMenu();
that.showMenu();
}
2010-02-18 07:27:32 +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));
}
function hideMenu() {
// called on key_escape
that.hideMenu();
}
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-07 15:01:22 +00:00
function mouseenter() {
that.gainFocus();
}
function mouseleave() {
if (self.options.selected > -1 && !that.items[self.options.selected].options("items").length) {
selectItem(-1);
}
}
function mousemove(event) {
var item,
position,
$target = $(event.target);
if ($target.is(".OxCell")) {
position = $target.parent().data("position");
item = that.items[position];
if (!item.options("disabled") && position != self.options.selected) {
selectItem(position);
}
} else {
mouseleave();
}
}
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
}
2010-02-05 17:37:15 +00:00
function scrollMenuUp() {
if (that.$scrollbars.up.is(":visible")) {
that.$content.css({
top: "0px"
});
that.$scrollbars.up.hide();
if (that.$scrollbars.down.is(":hidden")) {
that.$scrollbars.down.show();
} else {
that.$container.height(that.$container.height() + itemHeight);
}
}
}
2010-02-07 15:01:22 +00:00
function selectItem(position) {
var item;
if (self.options.selected > -1) {
2010-02-18 14:24:17 +00:00
item = that.items[self.options.selected]
item.removeClass("OxSelected");
2010-02-07 15:01:22 +00:00
}
if (position > -1) {
item = that.items[position];
$.each(that.submenus, function(id, submenu) {
if (!submenu.is(":hidden")) {
submenu.hideMenu();
return false;
}
});
item.options("items").length && that.submenus[item.options("id")].showMenu(); // fixme: do we want to switch to this style?
item.addClass("OxSelected");
}
2010-02-18 09:11:47 +00:00
self.options.selected = position;
2010-02-07 15:01:22 +00:00
}
2010-02-02 16:03:11 +00:00
function selectNextItem() {
2010-02-05 15:26:23 +00:00
var offset,
selected = self.options.selected;
Ox.print("sNI", selected)
2010-02-05 05:20:13 +00:00
if (!isLastEnabledItem()) {
2010-02-05 17:37:15 +00:00
if (selected == -1) {
scrollMenuUp();
} else {
2010-02-07 15:01:22 +00:00
that.items[selected].removeClass("OxSelected");
2010-02-04 09:50:45 +00:00
}
2010-02-05 05:20:13 +00:00
do {
selected++;
} while (that.items[selected].options("disabled"))
2010-02-07 15:01:22 +00:00
selectItem(selected);
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;
Ox.print("sPI", selected)
2010-02-05 17:37:15 +00:00
if (selected > - 1) {
if (!isFirstEnabledItem()) {
2010-02-07 15:01:22 +00:00
that.items[selected].removeClass("OxSelected");
2010-02-05 17:37:15 +00:00
do {
selected--;
} while (that.items[selected].options("disabled"))
2010-02-07 15:01:22 +00:00
selectItem(selected);
2010-02-05 15:26:23 +00:00
}
2010-02-05 17:37:15 +00:00
offset = that.items[selected].offset().top - that.$container.offset().top;
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-05 15:26:23 +00:00
}
}
2010-02-02 16:03:11 +00:00
}
2010-02-05 09:13:03 +00:00
function selectSubmenu() {
Ox.print("selectSubmenu", self.options.selected)
2010-02-05 17:37:15 +00:00
if (self.options.selected > -1) {
var submenu = that.submenus[that.items[self.options.selected].options("id")];
if (submenu && submenu.hasEnabledItems()) {
submenu.gainFocus();
submenu.selectFirstItem();
2010-02-08 09:35:24 +00:00
} else if (self.options.mainmenu) {
self.options.mainmenu.selectNextMenu();
}
} else if (self.options.mainmenu) {
self.options.mainmenu.selectNextMenu();
2010-02-05 09:13:03 +00:00
}
}
function selectSupermenu() {
Ox.print("selectSupermenu", self.options.selected)
2010-02-05 09:13:03 +00:00
if (self.options.parent) {
that.items[self.options.selected].trigger("mouseleave");
self.options.parent.gainFocus();
2010-02-08 09:35:24 +00:00
} else if (self.options.mainmenu) {
self.options.mainmenu.selectPreviousMenu();
2010-02-05 09:13:03 +00:00
}
}
self.onChange = function(key, value) {
2010-02-18 07:27:32 +00:00
if (key == "items") {
constructItems(value);
2010-02-18 09:11:47 +00:00
} else if (key == "selected") {
selectItem(value);
2010-02-18 07:27:32 +00:00
}
2010-02-05 09:13:03 +00:00
}
2010-02-20 03:42:03 +00:00
that.addItem = function(item, position) {
};
2010-02-19 16:13:22 +00:00
that.addItemAfter = function(item, id) {
2010-02-08 10:17:00 +00:00
};
2010-02-19 16:13:22 +00:00
that.addItemBefore = function(item, id) {
2010-02-08 10:17:00 +00:00
};
2010-07-07 12:36:12 +00:00
that.checkItem = function(id) {
that.getItem(id).options({
checked: true
});
};
2010-02-10 16:37:26 +00:00
that.getItem = function(id) {
2010-07-07 12:36:12 +00:00
var ids = id.split("_"),
item;
if (ids.length == 1) {
$.each(that.items, function(i, v) {
if (v.options("id") == id) {
item = v;
return false;
}
});
if (!item) {
$.each(that.submenus, function(k, submenu) {
item = submenu.getItem(id);
return !item;
});
2010-02-10 20:02:58 +00:00
}
2010-07-07 12:36:12 +00:00
} else {
item = that.submenus[ids.shift()].getItem(ids.join("_"));
}
2010-02-19 16:13:22 +00:00
return item;
2010-02-10 16:37:26 +00:00
};
2010-02-05 09:13:03 +00:00
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() {
if (that.is(":hidden")) {
return;
}
2010-02-04 08:02:23 +00:00
$.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-08 09:39:15 +00:00
selectItem(-1);
2010-02-05 17:37:15 +00:00
scrollMenuUp();
2010-02-18 14:24:17 +00:00
that.$scrollbars.up.is(":visible") && that.$scrollbars.up.hide();
that.$scrollbars.down.is(":visible") && that.$scrollbars.down.hide();
//that.$scrollbars.down.hide();
2010-02-05 15:42:52 +00:00
if (self.options.parent) {
self.options.element.removeClass("OxSelected");
}
2010-02-09 05:43:36 +00:00
that.hide()
.loseFocus()
.unbindEvent(self.keyboardEvents)
2010-02-09 05:43:36 +00:00
.triggerEvent("hide");
that.$layer.hide();
2010-02-05 09:13:03 +00:00
$document.unbind("click", click);
2010-02-08 09:35:24 +00:00
return that;
//that.triggerEvent("hide");
2010-02-05 09:13:03 +00:00
};
2010-02-08 10:17:00 +00:00
that.removeItem = function() {
};
2010-02-05 09:13:03 +00:00
that.selectFirstItem = function() {
selectNextItem();
2010-02-02 16:03:11 +00:00
};
that.showMenu = function() {
if (!that.is(":hidden")) {
return;
}
2010-02-09 05:43:36 +00:00
if (!self.options.parent && !that.$layer.parent().length) {
that.$layer.appendTo($body);
}
2010-02-04 08:02:23 +00:00
that.parent().length || that.appendTo($body);
2010-02-18 14:42:53 +00:00
that.css({
left: "-1000px",
top: "-1000px",
}).show();
2010-02-04 08:02:23 +00:00
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-18 14:42:53 +00:00
menuHeight = that.$content.outerHeight(); // fixme: why is outerHeight 0 when hidden?
2010-06-29 13:10:13 +00:00
menuMaxHeight = Math.floor($window.height() - top - 16);
2010-02-05 17:37:15 +00:00
if (self.options.parent) {
2010-02-18 14:24:17 +00:00
if (menuHeight > menuMaxHeight) {
top = Ox.limit(top - menuHeight + menuMaxHeight, self.options.parent.offset().top, top);
menuMaxHeight = Math.floor($window.height() - top - 16);
2010-02-05 17:37:15 +00:00
}
}
2010-02-18 14:42:53 +00:00
that.css({
left: left + "px",
top: top + "px"
});
2010-02-18 14:24:17 +00:00
if (menuHeight > menuMaxHeight) {
that.$container.height(menuMaxHeight - itemHeight - 8); // margin
2010-02-03 12:12:21 +00:00
that.$scrollbars.down.show();
2010-02-18 14:24:17 +00:00
} else {
that.$container.height(menuHeight);
2010-02-03 12:12:21 +00:00
}
2010-02-18 14:42:53 +00:00
!self.options.parent && that.gainFocus();
that.bindEvent(self.keyboardEvents);
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-08 09:35:24 +00:00
return that;
//that.triggerEvent("show");
2010-02-02 16:03:11 +00:00
};
2010-02-03 12:12:21 +00:00
that.toggleMenu = function() {
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-07 15:01:22 +00:00
id: Ox.toCamelCase(self.options.menu.options("id") + "/" + self.options.id)
2010-02-03 12:12:21 +00:00
})
2010-02-07 15:01:22 +00:00
.data("group", self.options.group); // fixme: why?
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) {
2010-02-08 09:45:48 +00:00
return oxui.symbols[modifier];
2010-02-03 12:12:21 +00:00
}).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-08 09:45:48 +00:00
oxui.symbols[self.options.keyboard.key] ||
self.options.keyboard.key.toUpperCase()
2010-02-03 12:12:21 +00:00
})
2010-02-05 05:20:13 +00:00
);
2010-02-03 12:12:21 +00:00
function parseKeyboard(str) {
2010-02-18 14:24:17 +00:00
var modifiers = str.split(" "),
2010-02-03 12:12:21 +00:00
key = modifiers.pop();
return {
modifiers: modifiers,
key: key
2010-07-05 17:01:42 +00:00
};
2010-02-03 12:12:21 +00:00
}
self.onChange = function(key, value) {
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") {
2010-07-13 22:38:53 +00:00
that.toggleClass("OxDisabled"); // fixme: this will only work if onChange is only invoked on actual change
2010-02-10 16:37:26 +00:00
} else if (key == "title") {
2010-07-24 01:32:08 +00:00
self.options.title = Ox.makeArray(value);
that.$title.html(self.options.title[0]);
2010-02-03 12:12:21 +00:00
}
}
2010-02-10 16:37:26 +00:00
that.toggle = function() {
// toggle id and title
};
2010-02-03 12:12:21 +00:00
that.toggleChecked = function() {
};
that.toggleDisabled = function() {
};
that.toggleTitle = function() {
2010-07-24 01:32:08 +00:00
Ox.print("s.o.t", self.options.title)
2010-02-03 12:12:21 +00:00
that.options({
2010-07-24 01:32:08 +00:00
title: self.options.title.reverse()
2010-02-10 16:37:26 +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({
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:
2010-07-17 08:46:27 +00:00
elements: [{ array of one, two or three elements
collapsible: false, collapsible or not (only for outer elements)
collapsed: false, collapsed or not (only for collapsible elements)
element: {}, OxElement (if any element is resizable or
collapsible, all OxElements must have an id)
resizable: false, resizable or not (only for outer elements)
resize: [], array of sizes (only for resizable elements,
first value is min, last value is max,
other values are "snappy" points in between)
size: 0 size in px (one element must have no size)
}],
orientation: "" "horizontal" or "vertical"
methods:
isCollapsed(id) element is collapsed or not
resize(id, size) resize element to size px
toggle(id) collapse or expand element
events:
resize
toggle
2010-01-07 20:21:07 +00:00
----------------------------------------------------------------------------
*/
Ox.SplitPanel = function(options, self) {
2010-07-06 18:28:58 +00:00
2010-01-07 20:21:07 +00:00
var self = self || {},
that = new Ox.Element({}, self) // fixme: Container
2010-01-07 20:21:07 +00:00
.defaults({
elements: [],
orientation: "horizontal"
})
.options(options || {})
2010-07-17 08:46:27 +00:00
.addClass("OxSplitPanel");
$.extend(self, {
dimensions: oxui.getDimensions(self.options.orientation),
edges: oxui.getEdges(self.options.orientation),
length: self.options.elements.length
});
2010-07-06 18:28:58 +00:00
that.$elements = [];
2010-01-07 20:21:07 +00:00
$.each(self.options.elements, function(i, v) {
2010-07-17 08:46:27 +00:00
self.options.elements[i] = $.extend({
collapsible: false,
collapsed: false,
resizable: false,
resize: [],
size: "auto"
}, v);
2010-07-06 18:28:58 +00:00
that.$elements[i] = v.element
2010-07-17 08:46:27 +00:00
.css(self.edges[2], 0)
.css(self.edges[3], 0);
2010-07-06 18:28:58 +00:00
});
2010-07-07 07:18:38 +00:00
setSizes();
2010-07-06 18:28:58 +00:00
$.each(self.options.elements, function(i, v) {
2010-01-07 20:21:07 +00:00
//that.append(element)
2010-07-17 08:46:27 +00:00
Ox.print("V: ", v)
that.$elements[i].appendTo(that); // fixme: that.$content
2010-07-06 18:28:58 +00:00
if (v.collapsible || v.resizable) {
Ox.print("v.size", v.size)
2010-07-17 08:46:27 +00:00
var $resizebar = new Ox.Resizebar({
2010-07-06 18:28:58 +00:00
collapsible: v.collapsible,
2010-07-17 08:46:27 +00:00
edge: self.edges[i == 0 ? 0 : 1],
2010-07-06 18:28:58 +00:00
elements: i < 2 ?
[that.$elements[0], that.$elements[1]] :
[that.$elements[1], that.$elements[2]],
2010-07-17 08:46:27 +00:00
id: v.element.options("id"),
2010-07-06 18:28:58 +00:00
orientation: self.options.orientation == "horizontal" ? "vertical" : "horizontal",
parent: that, // fixme: that.$content
2010-07-06 18:28:58 +00:00
resizable: v.resizable,
resize: v.resize,
size: v.size
})
2010-07-17 08:46:27 +00:00
.css(self.edges[i == 0 ? 0 : 1], v.size);
$resizebar[i == 0 ? "insertAfter" : "insertBefore"](that.$elements[i]);
2010-07-06 18:28:58 +00:00
}
2010-01-07 20:21:07 +00:00
});
2010-07-06 18:28:58 +00:00
2010-07-07 07:18:38 +00:00
function getPositionById(id) {
var position = -1;
$.each(self.options.elements, function(i, element) {
if (element.element.options("id") == id) {
2010-07-17 08:46:27 +00:00
position = i;
2010-07-07 07:18:38 +00:00
return false;
}
});
return position;
}
2010-07-06 18:28:58 +00:00
function getSize(element) {
2010-07-07 07:18:38 +00:00
return element.size + element.resizable;
2010-07-06 18:28:58 +00:00
}
2010-07-07 07:18:38 +00:00
function setSizes() {
$.each(self.options.elements, function(i, v) {
2010-07-17 08:46:27 +00:00
v.size != "auto" && that.$elements[i].css(self.dimensions[0], v.size + "px");
2010-07-07 07:18:38 +00:00
if (i == 0) {
2010-07-17 08:46:27 +00:00
that.$elements[i].css(self.edges[0], 0);
v.size != "auto" && that.$elements[i].css(
self.edges[1], (getSize(self.options.elements[1]) + (length == 3 ? getSize(self.options.elements[2]) : 0)) + "px"
2010-07-07 07:18:38 +00:00
);
} else if (i == 1) {
2010-07-17 08:46:27 +00:00
self.options.elements[0].size != "auto" && that.$elements[i].css(
self.edges[0], getSize(self.options.elements[0]) + "px"
2010-07-07 07:18:38 +00:00
);
2010-07-17 08:46:27 +00:00
(self.options.elements[0].size != "auto" || v.size != "auto") && that.$elements[i].css(
self.edges[1], (self.length == 3 ? getSize(self.options.elements[2]) : 0) + "px"
2010-07-07 07:18:38 +00:00
);
} else {
2010-07-17 08:46:27 +00:00
that.$elements[i].css(self.edges[1], 0);
v.size != "auto" && that.$elements[i].css(
self.edges[0], (getSize(self.options.elements[0]) + getSize(self.options.elements[1])) + "px"
2010-07-07 07:18:38 +00:00
);
}
});
}
2010-07-17 08:46:27 +00:00
that.isCollapsed = function(id) {
return self.options.elements[getPositionById(id)].collapsed;
};
2010-07-07 07:18:38 +00:00
that.resize = function(id, size) {
// one can pass pos instead of id
var pos = Ox.isNumber(id) ? id : getPositionById(id);
// Ox.print("pos", pos, self.options.elements, $.map(self.options.elements, function(v, i) { return v.element.options("id"); }))
2010-07-07 07:18:38 +00:00
self.options.elements[pos].size = size;
setSizes();
return that;
2010-07-07 07:18:38 +00:00
};
2010-07-17 08:46:27 +00:00
that.toggle = function(id) {
Ox.print("toggle", id);
/*
// something like this is needed to load in collapsed state
if (Ox.isUndefined(self.options.position)) {
self.options.position = parseInt(self.options.parent.css(self.options.edge)) +
(self.options.collapsed ? self.options.size : 0);
}
var size = self.options.position -
(self.options.collapsed ? 0 : self.options.size),
animate = {};
Ox.print("s.o.e", self.options.edge);
*/
var pos = getPositionById(id),
size = self.options.elements[pos].collapsed ? 0 : self.options.elements[pos].size,
animate = {};
animate[self.edges[pos == 0 ? 0 : 1]] = size;
self.options.parent.animate(animate, 200, function() {
var i = (self.options.edge == "left" || self.options.edge == "top") ? 1 : 0;
Ox.Event.trigger("resize_" + id, self.options.elements[i][self.dimensions[1]]());
self.options.elements[pos].collapsed = !self.options.elements[pos].collapsed;
});
};
2010-01-07 20:21:07 +00:00
return that;
2010-07-06 18:28:58 +00:00
2010-01-07 20:21:07 +00:00
};
2010-02-10 16:37:26 +00:00
Ox.TabPanel = function(options, self) {
};
2010-02-20 08:29:03 +00:00
/*
============================================================================
Requests
============================================================================
*/
2010-01-27 12:30:00 +00:00
2010-02-20 08:29:03 +00:00
/*
----------------------------------------------------------------------------
Ox.LoadingIcon
----------------------------------------------------------------------------
*/
2010-01-27 12:30:00 +00:00
2010-02-20 08:29:03 +00:00
Ox.LoadingIcon = function(options, self) {
var self = self || {},
that = new Ox.Element("img", self)
.defaults({
size: "medium"
})
.options(options || {})
.attr({
2010-07-05 07:09:34 +00:00
src: oxui.path + "/png/ox.ui." + Ox.theme() + "/loading.png" // fixme: oxui.themePath needed?
2010-02-20 08:29:03 +00:00
})
.addClass(
"OxLoadingIcon Ox" + Ox.toTitleCase(self.options.size)
);
self.deg = 0;
2010-07-01 23:51:08 +00:00
self.interval = 0;
self.isRunning = false;
function clear() {
clearInterval(self.interval);
self.deg = 0;
self.interval = 0;
update();
}
2010-02-20 08:29:03 +00:00
function update() {
that.css({
MozTransform: "rotate(" + self.deg + "deg)",
WebkitTransform: "rotate(" + self.deg + "deg)"
});
}
that.start = function() {
2010-07-01 23:51:08 +00:00
self.isRunning = true;
clear();
that.animate({
opacity: 1
}, 250);
self.interval = setInterval(function() {
self.deg = (self.deg + 30) % 360;
update();
}, 83);
2010-02-20 08:29:03 +00:00
};
that.stop = function() {
2010-07-01 23:51:08 +00:00
that.animate({
opacity: 0
}, 250, function() {
!self.isRunning && clear();
self.isRunning = false;
});
2010-02-20 08:29:03 +00:00
}
return that;
}
/*
----------------------------------------------------------------------------
Ox.Progressbar
----------------------------------------------------------------------------
*/
2010-01-27 12:30:00 +00:00
2010-07-24 01:32:08 +00:00
/*
============================================================================
Miscellaneous
============================================================================
*/
/*
----------------------------------------------------------------------------
Ox.Tooltip
----------------------------------------------------------------------------
*/
Ox.Tooltip = function(options, self) {
var self = self || {},
that = new Ox.Element()
.defaults({
text: ""
})
.options(options || {})
.addClass("OxTooltip")
.html(self.options.text);
self.onChange = function(key, value) {
if (key == "text") {
that.html(value);
}
};
that.hide = function() {
that.animate({
opacity: 0
}, 250, function() {
that.remove();
});
return that;
};
that.show = function(e) {
var left, top, width, height;
that.appendTo($body);
width = that.width();
height = that.height();
left = Ox.limit(e.clientX - width / 2, 0, $document.width() - width);
top = e.clientY > $document.height() - height - 16 ? e.clientY - 32 : e.clientY + 16;
that.css({
left: left + "px",
top: top + "px"
})
.animate({
opacity: 1
}, 250);
return that;
};
return that;
};
2010-01-27 12:30:00 +00:00
2010-07-13 22:38:53 +00:00
})();