3376 lines
116 KiB
JavaScript
3376 lines
116 KiB
JavaScript
/*
|
|
################################################################################
|
|
ox.ui.js
|
|
|
|
requires
|
|
jquery-1.4.js
|
|
ox.js
|
|
################################################################################
|
|
*/
|
|
|
|
// also see test.js, in demos ...
|
|
|
|
(function() {
|
|
|
|
var oxui = {
|
|
defaultTheme: "classic",
|
|
elements: {},
|
|
getDimensions: function(orientation) {
|
|
return orientation == "horizontal" ?
|
|
["width", "height"] : ["height", "width"];
|
|
},
|
|
getEdges: function(orientation) {
|
|
return orientation == "horizontal" ?
|
|
["left", "right", "top", "bottom"] :
|
|
["top", "bottom", "left", "right"];
|
|
},
|
|
getBarSize: function(size) {
|
|
var sizes = {
|
|
small: 20,
|
|
medium: 24,
|
|
large: 28,
|
|
};
|
|
return sizes[size];
|
|
},
|
|
jQueryFunctions: function() {
|
|
var functions = [],
|
|
$element = $("<div>");
|
|
//delete $element.length;
|
|
Ox.each($element, function(k, v) {
|
|
if (typeof v == "function") {
|
|
functions.push(k);
|
|
}
|
|
});
|
|
return functions.sort();
|
|
}(),
|
|
path: $("script[src*=ox.ui.js]").attr("src")
|
|
.replace("js/ox.ui.js", ""),
|
|
symbols: { // fixme: make lowercase
|
|
alt: "\u2325",
|
|
apple: "\uF8FF",
|
|
arrow_down: "\u2193",
|
|
arrow_left: "\u2190",
|
|
arrow_right: "\u2192",
|
|
arrow_up: "\u2191",
|
|
backspace: "\u232B",
|
|
backup: "\u2707",
|
|
ballot: "\u2717",
|
|
black_star: "\u2605",
|
|
burn: "\u2622",
|
|
caps_lock: "\u21EA",
|
|
check: "\u2713",
|
|
clear: "\u2327",
|
|
click: "\uF803",
|
|
close: "\u2715",
|
|
command: "\u2318",
|
|
control: "\u2303",
|
|
cut: "\u2702",
|
|
"delete": "\u2326",
|
|
diamond: "\u25C6",
|
|
edit: "\uF802",
|
|
eject: "\u23CF",
|
|
escape: "\u238B",
|
|
end: "\u2198",
|
|
enter: "\u2324",
|
|
fly: "\u2708",
|
|
gear: "\u2699",
|
|
home: "\u2196",
|
|
info: "\u24D8",
|
|
navigate: "\u2388",
|
|
option: "\u2387",
|
|
page_up: "\u21DE",
|
|
page_down: "\u21DF",
|
|
redo: "\u21BA",
|
|
"return": "\u21A9",
|
|
select: "\u21D5",
|
|
shift: "\u21E7",
|
|
sound: "\u266B",
|
|
space: "\u2423",
|
|
tab: "\u21E5",
|
|
trash: "\u267A",
|
|
triangle_down: "\u25BC",
|
|
triangle_left: "\u25C0",
|
|
triangle_right: "\u25BA",
|
|
triangle_up: "\u25B2",
|
|
undo: "\u21BB",
|
|
voltage: "\u26A1",
|
|
warning: "\u26A0",
|
|
white_star: "\u2606"
|
|
}
|
|
},
|
|
$window, $document, $body;
|
|
|
|
$(function() {
|
|
$window = $(window),
|
|
$document = $(document),
|
|
$body = $("body");
|
|
Ox.theme(oxui.defaultTheme);
|
|
});
|
|
|
|
/*
|
|
============================================================================
|
|
Application
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.App
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.App = function() {
|
|
/*
|
|
options:
|
|
requestTimeout
|
|
requestType
|
|
requestURL
|
|
*/
|
|
return function(options) {
|
|
|
|
options = options || {};
|
|
var self = {},
|
|
that = this;
|
|
|
|
self.options = $.extend({
|
|
requestTimeout: oxui.requestTimeout,
|
|
requestType: oxui.requestType,
|
|
requestURL: oxui.requestURL
|
|
}, options);
|
|
|
|
self.change = function() {
|
|
|
|
};
|
|
|
|
that.launch = function() {
|
|
$.ajaxSetup({
|
|
timeout: self.options.requestTimeout,
|
|
type: self.options.requestType,
|
|
url: self.options.requestURL
|
|
});
|
|
};
|
|
|
|
that.options = function() {
|
|
return Ox.getset(self.options, Array.slice.call(arguments), self.change, that);
|
|
};
|
|
|
|
that.request = function(action, data, callback) {
|
|
if (arguments.length == 2) {
|
|
callback = data;
|
|
data = {};
|
|
}
|
|
return Ox.Request.send({
|
|
url: self.options.requestURL,
|
|
data: {
|
|
action: action,
|
|
data: JSON.stringify(data)
|
|
},
|
|
callback: callback
|
|
});
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Event
|
|
----------------------------------------------------------------------------
|
|
|
|
naming convention for event/trigger
|
|
verb.id.namespace, i.e. verb.sourceId.targetId (?)
|
|
...
|
|
bind("keydown.shift+dot.numpad", function() {
|
|
// ...
|
|
})
|
|
keyboard handler then would:
|
|
$.each(stack, function(i, v) {
|
|
elements[v].trigger("keydown.shift+0.numpad");
|
|
});
|
|
and the element would implement
|
|
this.trigger(event, data) {
|
|
|
|
}
|
|
...
|
|
keyboard handler also triggers keydown.buffer
|
|
*/
|
|
|
|
// use dom elements / jquery instead
|
|
|
|
|
|
Ox.Event = function() {
|
|
var keyboardEvents = {};
|
|
$eventHandler = $("<div>");
|
|
function isKeyboardEvent(event) {
|
|
return event.substr(0, 4) == "key_";
|
|
}
|
|
return {
|
|
bind: function(id, event, callback) {
|
|
if (isKeyboardEvent(event)) {
|
|
keyboardEvents[id] = keyboardEvents[id] || {};
|
|
keyboardEvents[id][event] = callback;
|
|
}
|
|
if (!isKeyboardEvent(event) || Ox.Focus.focused() == id) {
|
|
$eventHandler.bind(event, callback);
|
|
}
|
|
},
|
|
bindKeyboard: function(id) {
|
|
$.each(keyboardEvents[id] || [], function(event, callback) {
|
|
Ox.Event.bind(id, event, callback);
|
|
});
|
|
},
|
|
trigger: function(event, data) {
|
|
Ox.print("trigger", event, data || {});
|
|
$eventHandler.trigger(event, data || {});
|
|
},
|
|
unbind: function(id, event, callback) {
|
|
if (isKeyboardEvent(event)) {
|
|
$.each(keyboardEvents[id] || [], function(e, callback) {
|
|
if (e == event) {
|
|
delete keyboardEvents[id][e];
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
$eventHandler.unbind(event, callback);
|
|
},
|
|
unbindKeyboard: function(id) {
|
|
$.each(keyboardEvents[id] || [], function(event, callback) {
|
|
$eventHandler.unbind(event, callback);
|
|
});
|
|
}
|
|
}
|
|
}();
|
|
|
|
Ox.Event_ = function() {
|
|
var events = {};
|
|
return {
|
|
// make these bind, trigger, unbind
|
|
publish: function(event, data) {
|
|
Ox.print("publish", event, data);
|
|
if (events[event]) {
|
|
$.each(events[event], function(i, v) {
|
|
setTimeout(function() {
|
|
v(data);
|
|
}, 0);
|
|
});
|
|
}
|
|
},
|
|
subscribe: function(event, callback) {
|
|
Ox.print("subscribe", event, callback);
|
|
if (events[event]) {
|
|
events[event].push(callback);
|
|
} else {
|
|
events[event] = [callback];
|
|
}
|
|
},
|
|
unsubscribe: function(event, callback) {
|
|
Ox.print("unsubscribe", event, callback);
|
|
$.each(events[event], function(i, v) {
|
|
if (Ox.startsWith(callback.toString(), v.toString())) {
|
|
events[event].splice(i, 1);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Focus
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Focus = function() {
|
|
var stack = [];
|
|
return {
|
|
focus: function(id) {
|
|
var index = stack.indexOf(id);
|
|
if (stack.length) {
|
|
Ox.Event.unbindKeyboard(stack[stack.length - 1])
|
|
}
|
|
if (index > -1) {
|
|
stack.splice(index, 1);
|
|
}
|
|
stack.push(id);
|
|
Ox.Event.bindKeyboard(id);
|
|
Ox.print("focus", stack);
|
|
},
|
|
focused: function() {
|
|
return stack[stack.length - 1];
|
|
},
|
|
blur: function(id) {
|
|
if (stack.indexOf(id) > -1) {
|
|
stack.splice(stack.length - 2, 0, stack.pop());
|
|
}
|
|
Ox.Event.unbindKeyboard(id);
|
|
Ox.Event.bindKeyboard(stack[stack.length - 1]);
|
|
Ox.print("blur", stack);
|
|
}
|
|
};
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.History
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Keyboard
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
(function() {
|
|
|
|
var buffer = "",
|
|
bufferTime = 0,
|
|
bufferTimeout = 1000,
|
|
keyNames = function() {
|
|
return {
|
|
0: "section",
|
|
8: "backspace",
|
|
9: "tab",
|
|
12: "clear",
|
|
13: "enter",
|
|
16: "shift",
|
|
17: "control",
|
|
18: "alt",
|
|
20: "capslock",
|
|
27: "escape",
|
|
32: "space",
|
|
33: "pageup",
|
|
34: "pagedown",
|
|
35: "end",
|
|
36: "home",
|
|
37: "left",
|
|
38: "up",
|
|
39: "right",
|
|
40: "down",
|
|
45: "insert",
|
|
46: "delete",
|
|
47: "help",
|
|
48: "0",
|
|
49: "1",
|
|
50: "2",
|
|
51: "3",
|
|
52: "4",
|
|
53: "5",
|
|
54: "6",
|
|
55: "7",
|
|
56: "8",
|
|
57: "9",
|
|
65: "a",
|
|
66: "b",
|
|
67: "c",
|
|
68: "d",
|
|
69: "e",
|
|
70: "f",
|
|
71: "g",
|
|
72: "h",
|
|
73: "i",
|
|
74: "j",
|
|
75: "k",
|
|
76: "l",
|
|
77: "m",
|
|
78: "n",
|
|
79: "o",
|
|
80: "p",
|
|
81: "q",
|
|
82: "r",
|
|
83: "s",
|
|
84: "t",
|
|
85: "u",
|
|
86: "v",
|
|
87: "w",
|
|
88: "x",
|
|
89: "y",
|
|
90: "z",
|
|
91: "meta.left",
|
|
92: "meta.right",
|
|
93: "select",
|
|
96: "0.numpad",
|
|
97: "1.numpad",
|
|
98: "2.numpad",
|
|
99: "3.numpad",
|
|
100: "4.numpad",
|
|
101: "5.numpad",
|
|
102: "6.numpad",
|
|
103: "7.numpad",
|
|
104: "8.numpad",
|
|
105: "9.numpad",
|
|
106: "asterisk.numpad",
|
|
107: "plus.numpad",
|
|
109: "minus.numpad",
|
|
108: "enter.numpad",
|
|
110: "dot.numpad",
|
|
111: "slash.numpad",
|
|
112: "f1",
|
|
113: "f2",
|
|
114: "f3",
|
|
115: "f4",
|
|
116: "f5",
|
|
117: "f6",
|
|
118: "f7",
|
|
119: "f8",
|
|
120: "f9",
|
|
121: "f10",
|
|
122: "f11",
|
|
123: "f12",
|
|
124: "f13",
|
|
125: "f14",
|
|
126: "f15",
|
|
127: "f16",
|
|
144: "numlock",
|
|
145: "scrolllock",
|
|
186: "semicolon",
|
|
187: "equal",
|
|
188: "comma",
|
|
189: "minus",
|
|
190: "dot",
|
|
191: "slash",
|
|
192: "backtick",
|
|
219: "openbracket",
|
|
220: "backslash",
|
|
221: "closebracket",
|
|
222: "quote"
|
|
// see dojo, for ex.
|
|
};
|
|
}(),
|
|
modifierNames = {
|
|
altKey: "alt", // mac: option
|
|
ctrlKey: "control",
|
|
metaKey: "meta", // mac: command
|
|
shiftKey: "shift"
|
|
};
|
|
|
|
$(function() {
|
|
// fixme: how to do this better?
|
|
// in firefox on mac, keypress doesn't fire for up/down
|
|
// if the cursor is at the start/end of an input element
|
|
// on linux, it doesn't seem to fire if the input element has focus
|
|
if ($.browser.mozilla) {
|
|
$document.keypress(keypress);
|
|
$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);
|
|
}
|
|
});
|
|
function keypress(event) {
|
|
var key,
|
|
keys = [],
|
|
//ret = true,
|
|
time;
|
|
$.each(modifierNames, function(k, v) {
|
|
if (event[k]) {
|
|
keys.push(v);
|
|
}
|
|
});
|
|
// avoid pushing modifier twice
|
|
if (keyNames[event.keyCode] && keys.indexOf(keyNames[event.keyCode]) == -1) {
|
|
keys.push(keyNames[event.keyCode]);
|
|
}
|
|
key = keys.join(".");
|
|
if (key.match(/^[\w\d-]$|SPACE/)) {
|
|
time = Ox.getTime();
|
|
if (time - bufferTime > bufferTimeout) {
|
|
buffer = "";
|
|
}
|
|
buffer += key == "SPACE" ? " " : key;
|
|
bufferTime = time;
|
|
}
|
|
Ox.Event.trigger("key_" + key);
|
|
//return false;
|
|
/*
|
|
$.each(stack, function(i, v) {
|
|
// fixme: we dont get the return value!
|
|
ret = Ox.event.trigger(keyboard + Ox.toCamelCase(key) + "." + v);
|
|
return ret;
|
|
});
|
|
*/
|
|
}
|
|
|
|
})();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Mouse (??)
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Request
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Request = function() {
|
|
|
|
var cache = {},
|
|
pending = {},
|
|
requests = {},
|
|
self = {
|
|
options: {
|
|
timeout: 15000,
|
|
type: "POST",
|
|
url: "api"
|
|
}
|
|
};
|
|
|
|
return {
|
|
|
|
cancel: function() {
|
|
var index;
|
|
if (arguments.length == 0) {
|
|
requests = {};
|
|
} else if (Ox.isFunction(arguments[0])) {
|
|
// cancel with function
|
|
$.each(requests, function(id, req) {
|
|
if (arguments[0](req)) {
|
|
delete requests[id];
|
|
}
|
|
})
|
|
} else {
|
|
// cancel by id
|
|
delete requests[arguments[0]]
|
|
}
|
|
},
|
|
|
|
emptyCache: function() {
|
|
cache = {};
|
|
},
|
|
|
|
options: function(options) {
|
|
return Ox.getset(self.options, options, $.noop(), this);
|
|
},
|
|
|
|
send: function(options) {
|
|
|
|
options = $.extend({
|
|
age: -1,
|
|
callback: function() {},
|
|
id: Ox.uid(),
|
|
timeout: self.options.timeout,
|
|
type: self.options.type,
|
|
url: self.options.url
|
|
}, options);
|
|
|
|
var req = JSON.stringify({
|
|
url: options.url,
|
|
data: options.data
|
|
});
|
|
|
|
function callback(data) {
|
|
delete requests[options.id];
|
|
options.callback(data);
|
|
}
|
|
|
|
function debug(request) {
|
|
var $iframe = $("<iframe>")
|
|
.css({ // fixme: should go into a class
|
|
width: 768,
|
|
height: 384
|
|
}),
|
|
$dialog = new Ox.Dialog({
|
|
title: "Application Error",
|
|
buttons: [
|
|
{
|
|
value: "Close",
|
|
click: function() {
|
|
$dialog.close();
|
|
}
|
|
}
|
|
],
|
|
width: 800,
|
|
height: 400
|
|
})
|
|
.append($iframe)
|
|
.open(),
|
|
iframe = $iframe[0].contentDocument || $iframe[0].contentWindow.document;
|
|
iframe.open();
|
|
iframe.write(request.responseText);
|
|
iframe.close();
|
|
}
|
|
|
|
function error(request, status, error) {
|
|
var data;
|
|
if (arguments.length == 1) {
|
|
data = arguments[0]
|
|
} else {
|
|
try {
|
|
data = JSON.parse(request.responseText);
|
|
} catch (err) {
|
|
data = {
|
|
status: {
|
|
code: request.status,
|
|
text: request.statusText
|
|
}
|
|
};
|
|
}
|
|
}
|
|
if (data.status.code < 500) {
|
|
callback(data);
|
|
} else {
|
|
var $dialog = new Ox.Dialog({
|
|
title: "Application Error",
|
|
buttons: [
|
|
{
|
|
value: "Details",
|
|
click: function() {
|
|
$dialog.close(function() {
|
|
debug(request);
|
|
});
|
|
}
|
|
},
|
|
{
|
|
value: "Close",
|
|
click: function() {
|
|
$dialog.close(function() {
|
|
callback(data);
|
|
});
|
|
}
|
|
}
|
|
],
|
|
width: 400,
|
|
height: 100
|
|
})
|
|
.append("Sorry, we have encountered an application error while handling your request. To help us find out what went wrong, you may want to report this error to an administrator. Otherwise, please try again later.")
|
|
.open();
|
|
// fixme: change this to Send / Don't Send
|
|
Ox.print({
|
|
request: request,
|
|
status: status,
|
|
error: error
|
|
});
|
|
}
|
|
pending[options.id] = false;
|
|
}
|
|
|
|
function success(data) {
|
|
pending[options.id] = false;
|
|
try {
|
|
data = JSON.parse(data);
|
|
} catch (err) {
|
|
error({
|
|
status: {
|
|
code: 500,
|
|
text: "Internal Server Error"
|
|
},
|
|
data: {}
|
|
});
|
|
return;
|
|
}
|
|
cache[req] = {
|
|
data: data,
|
|
time: Ox.getTime()
|
|
};
|
|
callback(data);
|
|
}
|
|
|
|
if (pending[options.id]) {
|
|
setTimeout(function() {
|
|
Ox.Request.send(options);
|
|
}, 0);
|
|
} else {
|
|
requests[options.id] = {
|
|
url: options.url,
|
|
data: options.data
|
|
};
|
|
if (cache[req] && (options.age == -1 || options.age > Ox.getTime() - cache[req].time)) {
|
|
setTimeout(function() {
|
|
callback(cache[req].data);
|
|
}, 0);
|
|
} else {
|
|
pending[options.id] = true;
|
|
$.ajax({
|
|
data: options.data,
|
|
error: error,
|
|
success: success,
|
|
timeout: options.timeout,
|
|
type: options.type,
|
|
url: options.url
|
|
});
|
|
}
|
|
}
|
|
return options.id;
|
|
}
|
|
|
|
};
|
|
}();
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.URL
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
============================================================================
|
|
Core
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Container
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
// fixme: wouldn't it be better to let the elements be,
|
|
// rather then $element, $content, and potentially others,
|
|
// 0, 1, 2, etc, so that append would append 0, and appendTo
|
|
// would append (length - 1)?
|
|
Ox.Container = function() {
|
|
var that = new Ox.Element()
|
|
.addClass("OxContainer");
|
|
that.$content = new Ox.Element()
|
|
.addClass("OxContent")
|
|
.appendTo(that);
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Element
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
// check out http://ejohn.org/apps/learn/#36 (-#38, making fns work w/o new)
|
|
|
|
Ox.Element = function() {
|
|
|
|
var elements = {};
|
|
|
|
return function(options, self) {
|
|
|
|
// construct
|
|
options = options || {};
|
|
self = self || {};
|
|
var that = this;
|
|
|
|
// init
|
|
(function() {
|
|
// allow for Ox.Widget("tagname", self)
|
|
if (typeof options == "string") {
|
|
options = {
|
|
element: options
|
|
};
|
|
}
|
|
that.ox = Ox.version;
|
|
that.id = Ox.uid();
|
|
that.$element = $("<" + (options.element || "div") + "/>", {
|
|
data: {
|
|
ox: that.id
|
|
}
|
|
});
|
|
elements[that.id] = that;
|
|
wrapjQuery();
|
|
})();
|
|
|
|
// private
|
|
function wrapjQuery() {
|
|
$.each(oxui.jQueryFunctions, function(i, fn) {
|
|
that[fn] = function() {
|
|
var args = arguments,
|
|
length = args.length,
|
|
id, ret;
|
|
$.each(args, function(i, arg) {
|
|
// if an ox object was passed
|
|
// then pass its $element instead
|
|
// so we can do oxObj.jqFn(oxObj)
|
|
if (arg.ox) {
|
|
args[i] = arg.$element;
|
|
}
|
|
/*
|
|
if (arg.ox) { // fixme: or is this too much magic?
|
|
if (fn == "appendTo" && arg.$content) {
|
|
args[i] = arg.$content
|
|
} else {
|
|
args[i] = arg.$element;
|
|
}
|
|
}
|
|
*/
|
|
});
|
|
/*
|
|
if (fn == "html" && that.$content) { // fixme: or is this too much magic?
|
|
$element = that.$content;
|
|
} else {
|
|
$element = that.$element;
|
|
}
|
|
*/
|
|
// why does this not work?
|
|
// ret = that.$element[v].apply(this, arguments);
|
|
if (length == 0) {
|
|
ret = that.$element[fn]();
|
|
} else if (length == 1) {
|
|
ret = that.$element[fn](args[0]);
|
|
} else if (length == 2) {
|
|
ret = that.$element[fn](args[0], args[1]);
|
|
} else if (length == 3) {
|
|
ret = that.$element[fn](args[0], args[1], args[2]);
|
|
} else if (length == 4) {
|
|
ret = that.$element[fn](args[0], args[1], args[2], args[3]);
|
|
}
|
|
if (fn == "data") {
|
|
// Ox.print("data ret", ret, $(ret))
|
|
}
|
|
// if the $element of an ox object was returned
|
|
// then return the ox object instead
|
|
// so we can do oxObj.jqFn().oxFn()
|
|
return ret.jquery && elements[id = ret.data("ox")] ?
|
|
elements[id] : ret;
|
|
}
|
|
});
|
|
}
|
|
|
|
// shared
|
|
self.onChange = function() {
|
|
// self.onChange(key, value)
|
|
// is called when an option changes
|
|
// (to be implemented by widget)
|
|
};
|
|
|
|
// public
|
|
that.bindEvent = function() {
|
|
// fixme: shouldn't this work the other way around,
|
|
// and bind a function to an event triggered by this widget?
|
|
/*
|
|
bindEvent(event, fn) or bindEvent({event0: fn0, event1: fn1, ...})
|
|
*/
|
|
if (arguments.length == 1) {
|
|
$.each(arguments[0], function(event, fn) {
|
|
Ox.Event.bind(that.id, event, fn);
|
|
});
|
|
} else {
|
|
Ox.Event.bind(that.id, arguments[0], arguments[1]);
|
|
}
|
|
return that;
|
|
};
|
|
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({...})
|
|
return that;
|
|
};
|
|
that.gainFocus = function() {
|
|
Ox.Focus.focus(that.id);
|
|
return that;
|
|
};
|
|
that.hasFocus = function() {
|
|
return Ox.Focus.focused() == that.id;
|
|
};
|
|
that.loseFocus = function() {
|
|
Ox.Focus.blur(that.id);
|
|
return that;
|
|
};
|
|
that.options = function() { // fixme: use Ox.getset
|
|
/*
|
|
that.options() returns self.options
|
|
that.options("foo") returns self.options.foo
|
|
that.options("foo", x) sets self.options.foo,
|
|
returns that
|
|
that.options({foo: x, bar: y}) sets self.options.foo
|
|
and self.options.bar,
|
|
returns that
|
|
*/
|
|
var length = arguments.length,
|
|
// args, options, ret;
|
|
args, ret;
|
|
if (length == 0) {
|
|
// options()
|
|
ret = self.options;
|
|
} else if (length == 1 && typeof arguments[0] == "string") {
|
|
// options(str)
|
|
ret = self.options[arguments[0]]
|
|
} else {
|
|
// options (str, val) or options({str: val, ...})
|
|
// translate (str, val) to ({str: val})
|
|
args = Ox.makeObject.apply(that, arguments);
|
|
/*
|
|
options = self.options;
|
|
*/
|
|
// if options have not been set, extend defaults,
|
|
// otherwise, extend options
|
|
self.options = $.extend(self.options || self.defaults, args);
|
|
$.each(args, function(key, value) {
|
|
self.onChange(key, value);
|
|
/*
|
|
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");
|
|
}
|
|
*/
|
|
});
|
|
ret = that;
|
|
}
|
|
return ret;
|
|
};
|
|
that.remove = function() {
|
|
that.$element.remove();
|
|
delete elements[that.ox];
|
|
return that;
|
|
};
|
|
that.triggerEvent = function() {
|
|
/*
|
|
triggerEvent(event, fn) or triggerEvent({event0: fn0, event1: fn1, ...})
|
|
*/
|
|
if (Ox.isObject(arguments[0])) {
|
|
$.each(arguments[0], function(event, fn) {
|
|
Ox.Event.trigger(event + "_" + self.options.id, fn);
|
|
});
|
|
} else {
|
|
Ox.Event.trigger(arguments[0] + "_" + self.options.id, arguments[1] || {});
|
|
}
|
|
return that;
|
|
};
|
|
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;
|
|
};
|
|
|
|
// return
|
|
return that;
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
Ox._Element = function(element) {
|
|
var that = this;
|
|
that.def = {};
|
|
that.opt = {};
|
|
that.ox = Ox.version;
|
|
that.id = Ox.uid();
|
|
//Ox.print("that.id", that.id)
|
|
that.$element = $("<" + (element || "div") + "/>")
|
|
//.addClass("OxElement")
|
|
.data("ox", that.id);
|
|
oxui.elements[that.id] = that;
|
|
// Ox.print("oxui.elements", oxui.elements)
|
|
//function setOption() {};
|
|
that.setOption = function() {};
|
|
/*
|
|
*/
|
|
that.destroy = function() {
|
|
that.$element.remove();
|
|
delete oxui.elements[that.ox];
|
|
}
|
|
/*
|
|
*/
|
|
that.disable = function() {
|
|
|
|
}
|
|
/*
|
|
*/
|
|
that.enable = function() {
|
|
|
|
}
|
|
/*
|
|
*/
|
|
///*
|
|
that.defaults = function() {
|
|
var length = arguments.length,
|
|
ret;
|
|
if (length == 0) {
|
|
ret = that.def
|
|
} else if (length == 1 && typeof arguments[0] == "string") {
|
|
ret = that.def[arguments[0]];
|
|
} else {
|
|
// translate ("key", "value") to {"key": "value"}
|
|
that.def = $.extend(
|
|
that.def, Ox.makeObject.apply(that, arguments)
|
|
);
|
|
ret = that;
|
|
}
|
|
return ret;
|
|
}
|
|
//*/
|
|
/*
|
|
Ox.Element.options()
|
|
get options
|
|
Ox.Element.options("foo")
|
|
get options.foo
|
|
Ox.Element.options("foo", 0)
|
|
set options.foo
|
|
Ox.Element.options({foo: 0, bar: 1})
|
|
set options.foo and options.bar
|
|
*/
|
|
///*
|
|
that.options = function() {
|
|
var length = arguments.length,
|
|
args, ret;
|
|
if (length == 0) {
|
|
//Ox.print("getting all options", options);
|
|
ret = that.opt;
|
|
} else if (length == 1 && typeof arguments[0] == "string") {
|
|
//Ox.print("getting one option", options, arguments[0], options[arguments[0]]);
|
|
ret = that.opt[arguments[0]];
|
|
} else {
|
|
// translate ("key", "value") to {"key": "value"}
|
|
args = Ox.makeObject.apply(that, arguments);
|
|
// if options have been set then extend options,
|
|
// otherwise extend defaults
|
|
that.opt = $.extend(Ox.length(that.opt) ?
|
|
that.opt : that.def, args);
|
|
// that.trigger("OxElement" + that.id + "SetOptions", args);
|
|
$.each(args, function(k, v) {
|
|
that.setOption(k, v);
|
|
//Ox.print("triggering", "OxElement" + that.id + "SetOption", {k: v})
|
|
//that.trigger("OxElement" + that.id + "SetOption", {k: v});
|
|
})
|
|
ret = that;
|
|
}
|
|
return ret;
|
|
}
|
|
// should become self.publish
|
|
that.publish = function(event, data) {
|
|
Ox.Event.publish(event + that.id, data);
|
|
return that;
|
|
}
|
|
that.subscribe = function(event, callback) {
|
|
Ox.Event.subscribe(event, callback);
|
|
return that;
|
|
}
|
|
//that.setOptions = function() {};
|
|
//*/
|
|
// wrap jquery functions
|
|
// so we can do oxObj.jqFn()
|
|
$.each(oxui.jqueryFunctions, function(i, v) {
|
|
that[v] = function() {
|
|
var args = arguments,
|
|
length = args.length,
|
|
$element, id, ret;
|
|
$.each(args, function(i, v) {
|
|
// if an oxui object was passed
|
|
// then pass its $element instead
|
|
// so we can do jqObj.append(oxObj)
|
|
if (v.ox) {
|
|
args[i] = v.$element;
|
|
}
|
|
});
|
|
if (v == "html" && that.$content) {
|
|
$element = that.$content;
|
|
} else {
|
|
$element = that.$element;
|
|
}
|
|
// why does this not work?
|
|
// ret = that.$element[v].apply(this, arguments);
|
|
// maybe because we pass this, and not that.$element[v] ... ?
|
|
// ret = that.$element[v].apply(that.$element[v], arguments);
|
|
// doesn't work either ...
|
|
if (length == 0) {
|
|
ret = $element[v]();
|
|
} else if (length == 1) {
|
|
ret = $element[v](args[0]);
|
|
} else if (length == 2) {
|
|
ret = $element[v](args[0], args[1]);
|
|
} else if (length == 3) {
|
|
ret = $element[v](args[0], args[1], args[2]);
|
|
} else if (length == 4) {
|
|
ret = $element[v](args[0], args[1], args[2], args[3]);
|
|
}
|
|
// if the $element of an oxui object was returned
|
|
// then return the oxui object instead
|
|
// so we can do oxObj.jqFn().oxFn()
|
|
//Ox.print("v", v, "arguments", arguments)
|
|
if (ret.jquery) {
|
|
//Ox.print("ret", ret, "ret.data('id')", ret.data("ox"))
|
|
}
|
|
return ret.jquery && oxui.elements[id = ret.data("ox")] ?
|
|
oxui.elements[id] : ret;
|
|
}
|
|
});
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.theme()
|
|
get theme
|
|
Ox.theme("foo")
|
|
set theme to "foo"
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.theme = function() {
|
|
var length = arguments.length,
|
|
classes = $body.attr("class").split(" "),
|
|
arg, theme;
|
|
$.each(classes, function(i, v) {
|
|
if (Ox.startsWith(v, "OxTheme")) {
|
|
theme = v.replace("OxTheme", "").toLowerCase();
|
|
if (length == 1) {
|
|
$body.removeClass(v);
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
if (length == 1) {
|
|
arg = arguments[0]
|
|
$body.addClass("OxTheme" + Ox.toTitleCase(arg));
|
|
if (theme) {
|
|
$("input[type=image]").each(function() {
|
|
var $this = $(this);
|
|
$this.attr({
|
|
src: $this.attr("src").replace(
|
|
"/ox.ui." + theme + "/", "/ox.ui." + arg + "/"
|
|
)
|
|
});
|
|
});
|
|
$(".OxLoadingIcon").each(function() {
|
|
var $this = $(this);
|
|
$this.attr({
|
|
src: $this.attr("src").replace(
|
|
"/ox.ui." + theme + "/", "/ox.ui." + arg + "/"
|
|
)
|
|
});
|
|
})
|
|
}
|
|
}
|
|
return theme;
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Bars
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.Bar = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
orientation: "horizontal",
|
|
size: "medium" // can be int
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxBar Ox" + Ox.toTitleCase(self.options.orientation)),
|
|
dimensions = oxui.getDimensions(self.options.orientation);
|
|
self.options.size = Ox.isString(self.options.size) ?
|
|
oxui.getBarSize(self.options.size) : self.options.size;
|
|
that.css(dimensions[0], "100%")
|
|
.css(dimensions[1], self.options.size + "px");
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Tabbar
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Tabbar = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Bar({
|
|
size: 20
|
|
}, self)
|
|
.defaults({
|
|
selected: 0,
|
|
tabs: []
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxTabbar");
|
|
|
|
Ox.ButtonGroup({
|
|
buttons: self.options.tabs,
|
|
group: true,
|
|
selectable: true,
|
|
selected: self.options.selected,
|
|
size: "medium",
|
|
style: "tab",
|
|
}).appendTo(that);
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
// fixme: no need for this
|
|
Ox.Toolbar = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Bar({
|
|
size: oxui.getBarSize(options.size)
|
|
}, self);
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Ox.Dialog
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.Dialog = function(options, self) {
|
|
|
|
// fixme: dialog should be derived from a generic draggable
|
|
var self = self || {},
|
|
that = new Ox.Element("div", self)
|
|
.defaults({
|
|
title: "",
|
|
buttons: [],
|
|
height: 128,
|
|
minHeight: 128,
|
|
minWidth: 192,
|
|
width: 384
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxDialog")
|
|
.css({
|
|
//left: (($document.width() - self.options.width) / 2) + "px",
|
|
//top: (($document.height() - self.options.height - 80) / 2) + "px",
|
|
width: self.options.width + "px",
|
|
height: (self.options.height + 80) + "px"
|
|
});
|
|
|
|
if (!Ox.isArray(self.options.buttons[0])) {
|
|
self.options.buttons = [[], self.options.buttons];
|
|
}
|
|
|
|
that.$titlebar = new Ox.Bar({
|
|
size: "medium"
|
|
})
|
|
.addClass("OxTitleBar")
|
|
//.html(self.options.title)
|
|
.mousedown(drag)
|
|
.appendTo(that);
|
|
that.$title = new Ox.Element()
|
|
.addClass("OxTitle")
|
|
.html(self.options.title)
|
|
.appendTo(that.$titlebar);
|
|
that.$content = new Ox.Container()
|
|
.addClass("OxContent")
|
|
.css({
|
|
height: self.options.height + "px"
|
|
})
|
|
.appendTo(that);
|
|
that.$buttonsbar = new Ox.Bar({})
|
|
.addClass("OxButtonsBar")
|
|
.appendTo(that);
|
|
that.$buttons = [];
|
|
$.each(self.options.buttons[0], function(i, button) {
|
|
that.$buttons[i] = new Ox.Button({
|
|
size: "medium",
|
|
value: button.value
|
|
})
|
|
.addClass("OxLeft")
|
|
.click(button.click) // fixme: rather use event?
|
|
.appendTo(that.$buttonsbar);
|
|
});
|
|
that.$resize = new Ox.Element()
|
|
.addClass("OxResize")
|
|
.mousedown(resize)
|
|
.appendTo(that.$buttonsbar);
|
|
$.each(self.options.buttons[1].reverse(), function(i, button) {
|
|
that.$buttons[that.$buttons.length] = new Ox.Button({
|
|
size: "medium",
|
|
value: button.value
|
|
})
|
|
.addClass("OxRight")
|
|
.click(button.click) // fixme: rather use event?
|
|
.appendTo(that.$buttonsbar);
|
|
});
|
|
that.$buttons[0].focus();
|
|
that.$layer = new Ox.Element()
|
|
.addClass("OxLayer");
|
|
|
|
function drag(event) {
|
|
var documentWidth = $document.width(),
|
|
documentHeight = $document.height(),
|
|
offset = that.offset(),
|
|
x = event.clientX,
|
|
y = event.clientY;
|
|
$window.mousemove(function(event) {
|
|
that.css({
|
|
margin: 0
|
|
});
|
|
$("*").css({
|
|
WebkitUserSelect: "none"
|
|
});
|
|
var left = Ox.limit(
|
|
offset.left - x + event.clientX,
|
|
24 - self.options.width, documentWidth - 24
|
|
),
|
|
top = Ox.limit(
|
|
offset.top - y + event.clientY,
|
|
24, documentHeight - 24
|
|
);
|
|
that.css({
|
|
left: left + "px",
|
|
top: top + "px"
|
|
});
|
|
});
|
|
$window.one("mouseup", function() {
|
|
$window.unbind("mousemove");
|
|
$("*").css({
|
|
WebkitUserSelect: "auto"
|
|
});
|
|
});
|
|
|
|
}
|
|
|
|
function resize(event) {
|
|
var contentHeight = that.$content.height(),
|
|
documentWidth = $document.width(),
|
|
documentHeight = $document.height(),
|
|
elementWidth = that.width(),
|
|
elementHeight = that.height(),
|
|
x = event.clientX,
|
|
y = event.clientY;
|
|
$window.mousemove(function(event) {
|
|
that.css({
|
|
margin: 0
|
|
});
|
|
var width = Ox.limit(
|
|
elementWidth - x + event.clientX,
|
|
self.options.minWidth, documentWidth
|
|
),
|
|
height = Ox.limit(
|
|
elementHeight - y + event.clientY,
|
|
self.options.minHeight, documentHeight
|
|
);
|
|
that.width(width);
|
|
that.height(height);
|
|
that.$content.height(height - 80);
|
|
});
|
|
$window.one("mouseup", function() {
|
|
$window.unbind("mousemove");
|
|
});
|
|
}
|
|
|
|
self.onChange = function(key, value) {
|
|
if (key == "title") {
|
|
that.$title.html(value);
|
|
}
|
|
}
|
|
|
|
that.append = function($element) {
|
|
that.$content.append($element);
|
|
return that;
|
|
}
|
|
|
|
that.close = function(callback) {
|
|
callback = callback || function() {};
|
|
that.animate({
|
|
opacity: 0
|
|
}, 200, function() {
|
|
that.remove();
|
|
that.$layer.remove();
|
|
callback();
|
|
});
|
|
return that;
|
|
}
|
|
|
|
that.disable = function() {
|
|
// to be used on submit of form, like login
|
|
that.$layer.addClass("OxFront");
|
|
};
|
|
|
|
that.enable = function() {
|
|
that.$layer.removeClass("OxFront");
|
|
}
|
|
|
|
that.open = function() {
|
|
Ox.print("opening...")
|
|
that.$layer.appendTo($body);
|
|
Ox.print("opening...")
|
|
that.css({
|
|
opacity: 0
|
|
}).appendTo(that.$layer).animate({
|
|
opacity: 1
|
|
}, 200);
|
|
return that;
|
|
}
|
|
|
|
return that;
|
|
|
|
}
|
|
|
|
/*
|
|
============================================================================
|
|
Forms
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.Form = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element("div", self)
|
|
.defaults({
|
|
items: []
|
|
})
|
|
.options(options || {}); // fixme: the || {} can be done once, in the options function
|
|
|
|
$.each(self.options.items, function(i, item) {
|
|
|
|
});
|
|
|
|
that.values = function() {
|
|
var values = {};
|
|
if (arguments.length == 0) {
|
|
$.each(self.options.items, function(i, item) {
|
|
values[item.id] = item.val();
|
|
});
|
|
return values;
|
|
} else {
|
|
$.each(arguments[0], function(key, value) {
|
|
|
|
});
|
|
return that;
|
|
}
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
Ox.FormItem = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element("", self)
|
|
.defaults({
|
|
error: "",
|
|
regexp: / /,
|
|
size: "medium",
|
|
type: "text"
|
|
})
|
|
.options(options || {});
|
|
|
|
that.$input = new OxInput();
|
|
|
|
return that;
|
|
|
|
}
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Button
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Button = function(options, self) {
|
|
/*
|
|
events:
|
|
click non-selectable button was clicked
|
|
deselect selectable button was deselected
|
|
select selectable button was selected
|
|
*/
|
|
var self = self || {},
|
|
that = new Ox.Element("input", self)
|
|
.defaults({
|
|
disabled: false,
|
|
group: null,
|
|
id: "",
|
|
selectable: false,
|
|
selected: false,
|
|
size: "medium",
|
|
style: "default", // can be default, symbol or tab
|
|
type: "text",
|
|
value: "",
|
|
values: []
|
|
})
|
|
.options($.extend(options, {
|
|
value: $.isArray(options.value) ?
|
|
options.value[0] : options.value,
|
|
values: $.makeArray(options.value)
|
|
}))
|
|
.attr({
|
|
disabled: self.options.disabled ? "disabled" : "",
|
|
type: self.options.type == "text" ? "button" : "image"
|
|
})
|
|
.addClass("OxButton Ox" + Ox.toTitleCase(self.options.size) +
|
|
(self.options.style ? " Ox" + Ox.toTitleCase(self.options.style) : "") +
|
|
(self.options.disabled ? " OxDisabled": "") +
|
|
(self.options.selected ? " OxSelected": ""))
|
|
.mousedown(mousedown)
|
|
.click(click);
|
|
//Ox.print(self.options.value, self.options.disabled)
|
|
/*
|
|
that.bind("OxElement" + that.id + "SetOptions", function(e, data) {
|
|
if (typeof data.selected != "undefined") {
|
|
if (data.selected != that.hasClass("OxSelected")) {
|
|
that.toggleClass("OxSelected");
|
|
}
|
|
}
|
|
if (typeof data.value != "undefined") {
|
|
if (self.options.type == "image") {
|
|
that.attr({
|
|
src: oxui.path + "png/" + Ox.theme() +
|
|
"/button" + Ox.toTitleCase(options.value) + ".png"
|
|
});
|
|
} else {
|
|
that.val(self.options.value);
|
|
}
|
|
}
|
|
})
|
|
*/
|
|
function mousedown(e) {
|
|
if (self.options.type == "image" && $.browser.safari) {
|
|
// keep image from being draggable
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
function click() {
|
|
if (!self.options.selectable) {
|
|
that.triggerEvent("click");
|
|
} else if (!self.options.group || !self.options.selected) {
|
|
if (self.options.group) {
|
|
that.triggerEvent("select");
|
|
} else {
|
|
that.toggleSelected();
|
|
}
|
|
}
|
|
if (self.options.values.length == 2) {
|
|
Ox.print("2 values")
|
|
that.options({
|
|
value: self.options.value == self.options.values[0] ?
|
|
self.options.values[1] : self.options.values[0]
|
|
});
|
|
}
|
|
//self.options.click();
|
|
}
|
|
self.onChange = function(key, value) {
|
|
//Ox.print("setOption", option, value)
|
|
Ox.print("OxButton onChange", key, value)
|
|
if (key == "selected") {
|
|
if (value != that.hasClass("OxSelected")) { // fixme: neccessary?
|
|
that.toggleClass("OxSelected");
|
|
}
|
|
that.triggerEvent("change");
|
|
} else if (key == "value") {
|
|
Ox.print("OxButton onChange value", value)
|
|
if (self.options.type == "image") {
|
|
that.attr({
|
|
src: oxui.path + "png/ox.ui." + Ox.theme() +
|
|
"/button" + Ox.toTitleCase(value) + ".png"
|
|
});
|
|
} else {
|
|
that.val(value);
|
|
}
|
|
}
|
|
}
|
|
that.toggleDisabled = function() {
|
|
that.options({
|
|
enabled: !self.options.disabled
|
|
});
|
|
}
|
|
that.toggleSelected = function() {
|
|
that.options({
|
|
selected: !self.options.selected
|
|
});
|
|
}
|
|
that.options("value", self.options.value);
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.ButtonGroup
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.ButtonGroup = function(options, self) {
|
|
|
|
/*
|
|
events:
|
|
change {id, value} selection within a group changed
|
|
*/
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
buttons: [],
|
|
group: false,
|
|
selectable: false,
|
|
selected: -1,
|
|
size: "medium",
|
|
style: "",
|
|
type: "text",
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxButtonGroup");
|
|
self.position = {};
|
|
|
|
that.$buttons = [];
|
|
$.each(self.options.buttons, function(position, button) {
|
|
that.$buttons[position] = Ox.Button({
|
|
disabled: button.disabled,
|
|
group: self.options.group ? that : null,
|
|
id: button.id,
|
|
selectable: self.options.selectable,
|
|
selected: position == self.options.selected,
|
|
size: self.options.size,
|
|
style: self.options.style,
|
|
type: self.options.type,
|
|
value: button.value
|
|
}).appendTo(that);
|
|
self.position[that.$buttons.id] = position;
|
|
that.bindEvent("select_" + that.$buttons[position].options("id"), function() {
|
|
selectButton(position);
|
|
});
|
|
});
|
|
|
|
function onChange(event, data) {
|
|
console.log("event", event, "data", data)
|
|
var id = event.split("_")[1];
|
|
Ox.print("OK")
|
|
if (self.options.selected > -1) {
|
|
that.$buttons[self.options.selected].toggleSelected();
|
|
}
|
|
self.options.selected = self.position[id];
|
|
that.triggerEvent("change", {
|
|
value: id
|
|
});
|
|
}
|
|
|
|
function selectButton(position) {
|
|
that.$buttons[self.options.selected].toggleSelected();
|
|
self.options.selected = position;
|
|
that.$buttons[self.options.selected].toggleSelected();
|
|
};
|
|
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Input
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Input = function(options, self) {
|
|
|
|
/* options:
|
|
* autocomplete function, or array of values, or dict with array of values per label or placeholder
|
|
* clear boolean, clear button, or not
|
|
* highlight boolean, highlight value in autocomplete menu, or not
|
|
* id
|
|
* label string or array (select) -- label and placeholder are mutually exclusive
|
|
* labelWidth integer (px)
|
|
* placeholder string or array (select) -- label and placeholder are mutually exclusive
|
|
* selected integer, selected label or placeholder
|
|
* size "large", "medium" or "small"
|
|
* type "text", "password", "textarea", etc.
|
|
*/
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element("div", self)
|
|
.defaults({
|
|
autocomplete: null,
|
|
clear: false,
|
|
highlight: false,
|
|
id: "",
|
|
label: "",
|
|
labelWidth: 0,
|
|
placeholder: "",
|
|
selected: 0,
|
|
size: "medium",
|
|
type: "text"
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxInput Ox" + Ox.toTitleCase(self.options.size)),
|
|
autocomplete;
|
|
|
|
if (self.options.label) {
|
|
self.options.label = Ox.makeArray(self.options.label);
|
|
self.option = self.options.label[self.options.selected];
|
|
self.items = self.options.label;
|
|
} else if (self.options.placeholder) {
|
|
self.options.placeholder = Ox.makeArray(self.options.placeholder);
|
|
self.option = self.options.placeholder[self.options.selected];
|
|
self.items = self.options.placeholder;
|
|
}
|
|
if (Ox.isArray(self.options.autocomplete)) {
|
|
autocomplete = self.options.autocomplete;
|
|
self.options.autocomplete = {};
|
|
self.options.autocomplete[self.placeholder] = autocomplete;
|
|
}
|
|
|
|
if (self.options.label) {
|
|
that.$label = new Ox.Element()
|
|
.addClass("OxLabel")
|
|
.width(self.options.labelWidth)
|
|
.html(self.options.label[0])
|
|
.appendTo(that);
|
|
}
|
|
if (self.options.label.length > 1 || self.options.placeholder.length > 1) {
|
|
that.$label && that.$label.click(select);
|
|
that.$select = new Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: "select"
|
|
})
|
|
.click(select)
|
|
.appendTo(that);
|
|
self.selectId = self.options.id + "_placeholder";
|
|
self.selectMenu = new Ox.Menu({
|
|
element: that,
|
|
id: self.selectId,
|
|
items: $.map(self.items, function(title, position) {
|
|
return {
|
|
checked: position == self.options.selected,
|
|
id: title.toLowerCase(),
|
|
group: self.selectId, // fixme: same id, works here, but should be different
|
|
title: title
|
|
};
|
|
}),
|
|
offset: {
|
|
left: 4,
|
|
top: 0
|
|
}
|
|
});
|
|
that.bindEvent("change_" + self.selectId, change);
|
|
}
|
|
|
|
that.$input = new Ox.Element(
|
|
self.options.type == "textarea" ? "textarea" : "input", self
|
|
)
|
|
.attr({
|
|
type: self.options.type == "textarea" ? null : self.options.type
|
|
})
|
|
.addClass(
|
|
"OxInput Ox" + Ox.toTitleCase(self.options.size) +
|
|
" OxPlaceholder"
|
|
)
|
|
.focus(focus)
|
|
.blur(blur)
|
|
.change(change)
|
|
.appendTo(that);
|
|
|
|
self.options.placeholder && that.$input.val(self.option);
|
|
|
|
if (self.options.clear) {
|
|
that.$clear = new Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: "clear"
|
|
})
|
|
.click(clear)
|
|
.appendTo(that);
|
|
}
|
|
|
|
if (options.autocomplete) {
|
|
that.$input.attr({
|
|
autocomplete: "off"
|
|
});
|
|
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({
|
|
element: that.$input,
|
|
id: self.autocompleteId,
|
|
offset: {
|
|
left: 4,
|
|
top: 0
|
|
},
|
|
size: self.options.size
|
|
});
|
|
that.bindEvent("click_" + self.autocompleteId, onClick);
|
|
}
|
|
|
|
that.bindEvent({
|
|
key_enter: submit,
|
|
key_escape: cancel
|
|
});
|
|
|
|
function autocomplete(value, callback) {
|
|
var value = value.toLowerCase(),
|
|
items = [];
|
|
if (value === "") {
|
|
// items = self.options.autocomplete[self.placeholder];
|
|
} else {
|
|
$.each(self.options.autocomplete[self.option], function(i, item) {
|
|
if (item.toLowerCase().indexOf(value) > -1) {
|
|
items.push(item);
|
|
}
|
|
});
|
|
}
|
|
callback(items);
|
|
}
|
|
|
|
function blur() {
|
|
that.loseFocus();
|
|
if (self.options.placeholder && that.$input.val() === "") {
|
|
that.$input.addClass("OxPlaceholder").val(self.option);
|
|
}
|
|
if (self.options.autocomplete) {
|
|
$document.unbind("keydown", keypress);
|
|
$document.unbind("keypress", keypress);
|
|
}
|
|
}
|
|
|
|
function call() {
|
|
var value = that.$input.val();
|
|
if (self.options.autocomplete) {
|
|
//Ox.print("###", self.option, value, callback)
|
|
Ox.isFunction(self.options.autocomplete) ? (
|
|
self.option ?
|
|
self.options.autocomplete(self.option, value, callback) :
|
|
self.options.autocomplete(value, callback)
|
|
) : autocomplete(value, callback);
|
|
}
|
|
}
|
|
|
|
function callback(items) {
|
|
var selected = items.length == 1 ? 0 : -1,
|
|
value = that.$input.val().toLowerCase();
|
|
if (items.length) {
|
|
items = $.map(items, function(title, position) {
|
|
if (value == Ox.stripTags(title.toLowerCase())) {
|
|
selected = position;
|
|
}
|
|
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
|
|
};
|
|
});
|
|
self.selectMenu.hideMenu();
|
|
self.autocompleteMenu.options({
|
|
items: items,
|
|
selected: selected
|
|
}).showMenu();
|
|
} else {
|
|
self.autocompleteMenu.hideMenu();
|
|
}
|
|
}
|
|
|
|
function cancel() {
|
|
that.$input.blur();
|
|
}
|
|
|
|
function change(event, data) {
|
|
self.option = data.value; // fixme: could be "title" as well
|
|
if (self.options.label) {
|
|
that.$label.html(self.option);
|
|
that.$input.focus();
|
|
call();
|
|
} else {
|
|
if (that.$input.is(".OxPlaceholder")) {
|
|
that.$input.val(self.option);
|
|
//that.$input.focus();
|
|
} else {
|
|
that.$input.focus();
|
|
call();
|
|
}
|
|
}
|
|
}
|
|
|
|
function clear() {
|
|
that.$input.val("").focus();
|
|
//call();
|
|
}
|
|
|
|
function focus() {
|
|
that.gainFocus();
|
|
if (that.$input.is(".OxPlaceholder")) {
|
|
that.$input.val("").removeClass("OxPlaceholder");
|
|
}
|
|
if (self.options.autocomplete) {
|
|
// fixme: different in webkit and firefox (?), see keyboard handler, need generic function
|
|
$document.bind("keydown", keypress);
|
|
$document.bind("keypress", keypress);
|
|
Ox.isFunction(self.options.autocomplete) ?
|
|
self.options.autocomplete(that.$input.val(), callback) :
|
|
autocomplete(that.$input.val(), callback);
|
|
}
|
|
}
|
|
|
|
function keypress(event) {
|
|
if (event.keyCode != 13) {
|
|
setTimeout(function() {
|
|
var value = that.$input.val();
|
|
if (value != self.value) {
|
|
self.value = value;
|
|
call();
|
|
}
|
|
}, 25);
|
|
}
|
|
}
|
|
|
|
function onClick(event, data) {
|
|
Ox.print("onClick", data)
|
|
that.$input.focus().val(Ox.stripTags(data.title));
|
|
self.autocompleteMenu.hideMenu();
|
|
submit();
|
|
}
|
|
|
|
function select() {
|
|
self.selectMenu.showMenu();
|
|
}
|
|
|
|
function selection() {
|
|
// fixme: not used!
|
|
var start, end;
|
|
if (arguments.length == 0) {
|
|
return [self.element.selectionStart, self.element.selectionEnd];
|
|
} else {
|
|
start = arguments[0];
|
|
end = arguments[1] || start;
|
|
self.element.setSelectionRange(start, end);
|
|
}
|
|
}
|
|
|
|
function submit() {
|
|
that.$input.trigger("blur");
|
|
that.triggerEvent("submit", that.$input.val());
|
|
}
|
|
|
|
that.width = function(value) {
|
|
that.$element.width(value);
|
|
that.$input.width(value - 2 -
|
|
(self.options.labelWidth ? self.options.labelWidth + 34 : 0) -
|
|
(self.options.placeholder.length > 1 ? 26 : 0) -
|
|
(self.options.clear ? 15 : 0));
|
|
// fixme: the values above are all weird guesswork
|
|
return that;
|
|
}
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Range
|
|
|
|
options:
|
|
animate boolean if true, animate thumb
|
|
arrows boolean if true, show arrows
|
|
arrowImages array arrow symbols, like ["minus", "plus"]
|
|
arrowStep number step when clicking arrows
|
|
max number maximum value
|
|
min number minimum value
|
|
orientation string "horizontal" or "vertical"
|
|
step number step between values
|
|
size number width or height, in px
|
|
thumbSize number minimum width or height of thumb, in px
|
|
thumbValue boolean if true, display value on thumb
|
|
trackImages string or array one or multiple track background image URLs
|
|
trackStep number 0 (scroll here) or step when clicking track
|
|
value number initial value
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Range = function(options, self) {
|
|
|
|
/*
|
|
init
|
|
*/
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
animate: false,
|
|
arrows: false,
|
|
arrowImages: ["previous", "next"],
|
|
arrowStep: 1,
|
|
max: 100,
|
|
min: 0,
|
|
orientation: "horizontal",
|
|
step: 1,
|
|
size: 128,
|
|
thumbSize: 16,
|
|
thumbValue: false,
|
|
trackImages: [],
|
|
trackStep: 0,
|
|
value: 0
|
|
})
|
|
.options($.extend(options, {
|
|
arrowStep: options.arrowStep ?
|
|
options.arrowStep : options.step,
|
|
trackImages: $.makeArray(options.trackImages || [])
|
|
}))
|
|
.addClass("OxRange");
|
|
|
|
// fixme: self. ... ?
|
|
var trackImages = self.options.trackImages.length,
|
|
values = (self.options.max - self.options.min + self.options.step) /
|
|
self.options.step;
|
|
|
|
/*
|
|
construct
|
|
*/
|
|
that.$element
|
|
.css({
|
|
width: self.options.size + "px"
|
|
});
|
|
if (self.options.arrows) {
|
|
var $arrowDec = Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: self.options.arrowImages[0]
|
|
})
|
|
.addClass("OxArrow")
|
|
.mousedown(mousedownArrow)
|
|
.click(clickArrowDec)
|
|
.appendTo(that.$element);
|
|
}
|
|
var $track = new Ox.Element()
|
|
.addClass("OxTrack")
|
|
.mousedown(clickTrack)
|
|
.appendTo(that.$element); // fixme: make that work
|
|
|
|
if (trackImages) {
|
|
var width = parseFloat(screen.width / trackImages),
|
|
$image = $("<canvas/>")
|
|
.attr({
|
|
width: width * trackImages,
|
|
height: 14
|
|
})
|
|
.addClass("OxImage")
|
|
.appendTo($track.$element), // fixme: make that work
|
|
c = $image[0].getContext('2d');
|
|
c.mozImageSmoothingEnabled = false; // we may want to remove this later
|
|
$.each(self.options.trackImages, function(i, v) {
|
|
//Ox.print(v)
|
|
$("<img/>")
|
|
.attr({
|
|
src: v
|
|
})
|
|
.load(function() {
|
|
c.drawImage(this, i * width, 0, width, 14);
|
|
});
|
|
});
|
|
}
|
|
var $thumb = Ox.Button({})
|
|
.addClass("OxThumb")
|
|
.appendTo($track);
|
|
if (self.options.arrows) {
|
|
var $arrowInc = Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: self.options.arrowImages[1]
|
|
})
|
|
.addClass("OxArrow")
|
|
.mousedown(mousedownArrow)
|
|
.click(clickArrowInc)
|
|
.appendTo(that.$element);
|
|
}
|
|
var rangeWidth, trackWidth, imageWidth, thumbWidth;
|
|
setWidth(self.options.size);
|
|
|
|
/*
|
|
private functions
|
|
*/
|
|
|
|
function clickArrowDec() {
|
|
that.removeClass("OxActive");
|
|
setValue(self.options.value - self.options.arrowStep, 200)
|
|
}
|
|
function clickArrowInc() {
|
|
that.removeClass("OxActive");
|
|
setValue(self.options.value + self.options.arrowStep, 200);
|
|
}
|
|
function clickTrack(e) {
|
|
Ox.Focus.focus();
|
|
var left = $track.offset().left,
|
|
offset = $(e.target).hasClass("OxThumb") ?
|
|
e.clientX - $thumb.offset().left - thumbWidth / 2 - 2 : 0;
|
|
function val(e) {
|
|
return getVal(e.clientX - left - offset);
|
|
}
|
|
setValue(val(e), 200);
|
|
$window.mousemove(function(e) {
|
|
setValue(val(e));
|
|
});
|
|
$window.one("mouseup", function() {
|
|
$window.unbind("mousemove");
|
|
});
|
|
}
|
|
function getPx(val) {
|
|
var pxPerVal = (trackWidth - thumbWidth - 2) /
|
|
(self.options.max - self.options.min);
|
|
return Math.ceil((val - self.options.min) * pxPerVal + 1);
|
|
}
|
|
function getVal(px) {
|
|
var px = trackWidth / values >= 16 ? px : px - 8,
|
|
valPerPx = (self.options.max - self.options.min) /
|
|
(trackWidth - thumbWidth);
|
|
return Ox.limit(self.options.min +
|
|
Math.floor(px * valPerPx / self.options.step) * self.options.step,
|
|
self.options.min, self.options.max);
|
|
}
|
|
function mousedownArrow() {
|
|
that.addClass("OxActive");
|
|
}
|
|
function setThumb(animate) {
|
|
var animate = typeof animate != "undefined" ? animate : 0;
|
|
$thumb.animate({
|
|
marginLeft: (getPx(self.options.value) - 2) + "px",
|
|
width: thumbWidth + "px"
|
|
}, self.options.animate ? animate : 0, function() {
|
|
if (self.options.thumbValue) {
|
|
$thumb.options({
|
|
value: self.options.value
|
|
});
|
|
}
|
|
});
|
|
}
|
|
function setValue(val, animate) {
|
|
val = Ox.limit(val, self.options.min, self.options.max);
|
|
if (val != self.options.value) {
|
|
that.options({
|
|
value: val
|
|
});
|
|
setThumb(animate);
|
|
//Ox.print("triggering OxRange" + that.id + "Change")
|
|
that.triggerEvent("change", { value: val });
|
|
}
|
|
}
|
|
function setWidth(width) {
|
|
trackWidth = width - self.options.arrows * 32;
|
|
thumbWidth = Math.max(trackWidth / values - 2, self.options.thumbSize - 2);
|
|
that.$element.css({
|
|
width: (width - 2) + "px"
|
|
});
|
|
$track.css({
|
|
width: (trackWidth - 2) + "px"
|
|
});
|
|
if (trackImages) {
|
|
$image.css({
|
|
width: (trackWidth - 2) + "px"
|
|
});
|
|
}
|
|
$thumb.css({
|
|
width: (thumbWidth - 2) + "px",
|
|
padding: 0
|
|
});
|
|
setThumb();
|
|
}
|
|
|
|
/*
|
|
shared functions
|
|
*/
|
|
|
|
self.onChange = function(option, value) {
|
|
|
|
}
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Select
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Select = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element("div", self) // fixme: do we use "div", or {}, or "", by default?
|
|
.defaults({
|
|
id: "",
|
|
items: [],
|
|
size: "medium"
|
|
})
|
|
.options(options)
|
|
.addClass("OxSelect Ox" + Ox.toTitleCase(self.options.size));
|
|
self.buttonId = self.options.id + "_button"
|
|
self.groupId = self.options.id + "_group"
|
|
self.menuId = self.options.id + "_menu",
|
|
|
|
$.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) {
|
|
self.selected = i;
|
|
}
|
|
});
|
|
|
|
that.$button = new Ox.Button($.extend(self.options, {
|
|
id: self.buttonId,
|
|
type: "text", // fixme: this shouldn't be necessary
|
|
value: self.options.items[self.selected].title
|
|
}), {})
|
|
.click(clickButton)
|
|
.appendTo(that);
|
|
|
|
that.$symbol = $("<div>", {
|
|
"class": "OxSymbol",
|
|
html: oxui.symbols.select
|
|
})
|
|
.click(function() {
|
|
that.$button.trigger("click");
|
|
})
|
|
.appendTo(that.$element);
|
|
|
|
that.$menu = new Ox.Menu({
|
|
element: that.$button,
|
|
id: self.menuId,
|
|
items: self.options.items,
|
|
offset: {
|
|
left: 8,
|
|
top: 0
|
|
},
|
|
side: "bottom",
|
|
size: self.options.size
|
|
});
|
|
|
|
that.bindEvent("change_" + self.groupId, clickMenu);
|
|
|
|
function clickButton() {
|
|
that.$menu.toggleMenu();
|
|
}
|
|
|
|
function clickMenu(event, data) {
|
|
Ox.print("clickMenu", event, data)
|
|
that.$button.options({
|
|
value: data.value
|
|
});
|
|
that.triggerEvent("change", data.value);
|
|
}
|
|
|
|
self.onChange = function(key, value) {
|
|
|
|
};
|
|
|
|
that.width = function(val) {
|
|
// fixme: silly hack, and won't work for css()
|
|
that.$element.width(val + 16);
|
|
that.$button.width(val);
|
|
that.$symbol.width(val);
|
|
return that;
|
|
};
|
|
|
|
return that;
|
|
|
|
}
|
|
|
|
/*
|
|
============================================================================
|
|
Lists
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.List = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Container({}, self);
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
Ox.ListItem = function(options, self) {
|
|
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Menus
|
|
============================================================================
|
|
*/
|
|
|
|
Ox.MainMenu = function(options, self) {
|
|
|
|
/* options:
|
|
* extras
|
|
* menus
|
|
* size
|
|
*/
|
|
|
|
var self = self || {},
|
|
that = new Ox.Bar({}, self)
|
|
.defaults({
|
|
extras: [],
|
|
menus: [],
|
|
size: "medium"
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxMainMenu Ox" + Ox.toTitleCase(self.options.size)) // fixme: bar should accept small/medium/large ... like toolbar
|
|
.click(click)
|
|
.mousemove(mousemove);
|
|
|
|
self.focused = false;
|
|
self.selected = -1;
|
|
that.menus = [];
|
|
that.titles = [];
|
|
that.layer = $("<div>").addClass("OxLayer");
|
|
|
|
$.each(self.options.menus, function(position, menu) {
|
|
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
|
|
}));
|
|
that.bindEvent("hide_" + that.menus[position].options("id"), onHideMenu);
|
|
});
|
|
|
|
Ox.print(self.options)
|
|
if (self.options.extras.length) {
|
|
that.extras = $("<div>")
|
|
.addClass("OxExtras")
|
|
.appendTo(that.$element);
|
|
$.each(self.options.extras, function(position, extra) {
|
|
extra.css({
|
|
float: "left" // fixme: need class!
|
|
}).appendTo(that.extras);
|
|
});
|
|
}
|
|
|
|
function click(event) {
|
|
var $target = $(event.target),
|
|
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) {
|
|
Ox.print("position", position, "self.selected", self.selected)
|
|
if (position != selected) {
|
|
self.focused = true;
|
|
self.selected = position;
|
|
Ox.print("position", position, "setting self.selected", self.selected)
|
|
that.titles[self.selected].addClass("OxSelected");
|
|
that.menus[self.selected].showMenu();
|
|
}
|
|
}
|
|
}
|
|
|
|
function mousemove(event) {
|
|
var $target = $(event.target),
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
function onHideMenu() {
|
|
Ox.print("hideMenu self.selected", self.selected)
|
|
if (self.selected > -1) {
|
|
that.titles[self.selected].removeClass("OxSelected");
|
|
self.selected = -1;
|
|
}
|
|
self.focused = false;
|
|
}
|
|
|
|
self.onChange = function(key, value) {
|
|
|
|
};
|
|
|
|
that.addMenuAfter = function(id) {
|
|
|
|
};
|
|
|
|
that.addMenuBefore = function(id) {
|
|
|
|
};
|
|
|
|
that.disableItem = function(id) {
|
|
|
|
};
|
|
|
|
that.enableItem = function(id) {
|
|
|
|
};
|
|
|
|
that.getItem = function(id) {
|
|
var item;
|
|
$.each(that.menus, function(i, menu) {
|
|
item = menu.getItem(id);
|
|
return !item;
|
|
});
|
|
return item;
|
|
};
|
|
|
|
that.removeMenu = function() {
|
|
|
|
};
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
Ox.Menu = function(options, self) {
|
|
|
|
/*
|
|
|
|
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
|
|
side open to "bottom" or "right"
|
|
size "large", "medium" or "small"
|
|
|
|
events:
|
|
change_groupId {id, value} checked item of a group has changed
|
|
click_itemId item not belonging to a group was clicked
|
|
click_menuId {id, value} item not belonging to a group was clicked
|
|
deselect_menuId {id, value} item was deselected not needed, not implemented
|
|
hide_menuId menu was hidden
|
|
select_menuId {id, value} item was selected not needed, not implemented
|
|
|
|
*/
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
element: null,
|
|
id: "",
|
|
items: [],
|
|
mainmenu: null,
|
|
offset: {
|
|
left: 0,
|
|
top: 0
|
|
},
|
|
parent: null,
|
|
selected: -1,
|
|
side: "bottom",
|
|
size: "medium",
|
|
})
|
|
.options(options)
|
|
.addClass(
|
|
"OxMenu Ox" + Ox.toTitleCase(self.options.side) +
|
|
" Ox" + Ox.toTitleCase(self.options.size)
|
|
)
|
|
.click(click)
|
|
.mouseenter(mouseenter)
|
|
.mouseleave(mouseleave)
|
|
.mousemove(mousemove),
|
|
itemHeight = self.options.size == "small" ? 12 : (self.options.size == "medium" ? 16 : 20),
|
|
// menuHeight,
|
|
scrollSpeed = 1,
|
|
$item; // fixme: used?
|
|
// fixme: attach all private vars to self?
|
|
|
|
// construct
|
|
that.items = [];
|
|
that.submenus = {};
|
|
that.$scrollbars = [];
|
|
that.$top = $("<div>")
|
|
.addClass("OxTop")
|
|
.appendTo(that.$element);
|
|
that.$scrollbars.up = constructScrollbar("up")
|
|
.appendTo(that.$element);
|
|
that.$container = $("<div>")
|
|
.addClass("OxContainer")
|
|
.appendTo(that.$element);
|
|
that.$content = $("<table>")
|
|
.addClass("OxContent")
|
|
.appendTo(that.$container);
|
|
constructItems(self.options.items);
|
|
that.$scrollbars.down = constructScrollbar("down")
|
|
.appendTo(that.$element);
|
|
that.$bottom = $("<div>")
|
|
.addClass("OxBottom")
|
|
.appendTo(that.$element);
|
|
that.$layer = $("<div>")
|
|
.addClass(self.options.mainmenu ? "OxMainMenuLayer" : "OxLayer");
|
|
|
|
function click(event) {
|
|
var item,
|
|
position,
|
|
$target = $(event.target);
|
|
if ($target.is(".OxCell")) {
|
|
position = $target.parent().data("position");
|
|
item = that.items[position];
|
|
if (!item.options("disabled")) {
|
|
clickItem(position);
|
|
} else {
|
|
that.hideMenu();
|
|
}
|
|
} else {
|
|
that.hideMenu();
|
|
}
|
|
}
|
|
|
|
function clickItem(position) {
|
|
var item = that.items[position];
|
|
Ox.print("clickItem", position, item.options("items").length)
|
|
if (!item.options("items").length) {
|
|
if (that.options("parent")) {
|
|
that.options("parent").hideMenu().triggerEvent("click");
|
|
}
|
|
if (item.options("checked") !== null && (!item.options("group") || !item.options("checked"))) {
|
|
item.options({
|
|
checked: !item.options("checked")
|
|
});
|
|
Ox.Event.trigger("change_" + item.options("group"), {
|
|
id: item.options("id"),
|
|
value: item.options("title")[0] // fixme: value or title?
|
|
});
|
|
} else {
|
|
Ox.Event.trigger("click_" + self.options.id, {
|
|
id: item.options("id"),
|
|
title: item.options("title")[0]
|
|
});
|
|
Ox.Event.trigger("click_" + item.options("id"));
|
|
}
|
|
if (item.options("title").length == 2) {
|
|
item.toggleTitle();
|
|
}
|
|
}
|
|
that.hideMenu();
|
|
}
|
|
|
|
function clickSelectedItem() {
|
|
// called on key.enter
|
|
if (self.options.selected > -1) {
|
|
clickItem(self.options.selected);
|
|
} else {
|
|
that.hideMenu();
|
|
}
|
|
}
|
|
|
|
function constructItems(items) {
|
|
that.items = [];
|
|
that.$content.empty();
|
|
scrollMenuUp();
|
|
$.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());
|
|
}
|
|
});
|
|
if (!that.is(":hidden")) {
|
|
Ox.print("hide&show")
|
|
that.hideMenu();
|
|
that.showMenu();
|
|
}
|
|
}
|
|
|
|
function constructLine() {
|
|
return $("<tr>").append(
|
|
$("<td>", {
|
|
"class": "OxLine",
|
|
colspan: 5
|
|
})
|
|
);
|
|
}
|
|
|
|
function constructScrollbar(direction) {
|
|
var interval,
|
|
speed = direction == "up" ? -1 : 1;
|
|
return $("<div/>", {
|
|
"class": "OxScrollbar Ox" + Ox.toTitleCase(direction),
|
|
html: oxui.symbols["triangle_" + direction],
|
|
click: function() { // fixme: do we need to listen to click event?
|
|
return false;
|
|
},
|
|
mousedown: function() {
|
|
scrollSpeed = 2;
|
|
return false;
|
|
},
|
|
mouseenter: function() {
|
|
var $otherScrollbar = that.$scrollbars[direction == "up" ? "down" : "up"];
|
|
$(this).addClass("OxSelected");
|
|
if ($otherScrollbar.is(":hidden")) {
|
|
$otherScrollbar.show();
|
|
that.$container.height(that.$container.height() - itemHeight);
|
|
if (direction == "down") {
|
|
that.$content.css({
|
|
top: -itemHeight + "px"
|
|
});
|
|
}
|
|
}
|
|
scrollMenu(speed);
|
|
interval = setInterval(function() {
|
|
scrollMenu(speed);
|
|
}, 100);
|
|
},
|
|
mouseleave: function() {
|
|
$(this).removeClass("OxSelected");
|
|
clearInterval(interval);
|
|
},
|
|
mouseup: function() {
|
|
scrollSpeed = 1;
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
function constructSpace() {
|
|
return $("<tr>").append(
|
|
$("<td>", {
|
|
"class": "OxSpace",
|
|
colspan: 5
|
|
})
|
|
);
|
|
}
|
|
|
|
function getElement(id) {
|
|
// fixme: needed?
|
|
return $("#" + Ox.toCamelCase(options.id + "/" + id));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
function scrollMenu(speed) {
|
|
var containerHeight = that.$container.height(),
|
|
contentHeight = that.$content.height(),
|
|
top = parseInt(that.$content.css("top")) || 0,
|
|
min = containerHeight - contentHeight + itemHeight,
|
|
max = 0;
|
|
top += speed * scrollSpeed * -itemHeight;
|
|
if (top <= min) {
|
|
top = min;
|
|
that.$scrollbars.down.hide().trigger("mouseleave");
|
|
that.$container.height(containerHeight + itemHeight);
|
|
that.items[that.items.length - 1].trigger("mouseover");
|
|
} else if (top >= max - itemHeight) {
|
|
top = max;
|
|
that.$scrollbars.up.hide().trigger("mouseleave");
|
|
that.$container.height(containerHeight + itemHeight);
|
|
that.items[0].trigger("mouseover");
|
|
}
|
|
that.$content.css({
|
|
top: top + "px"
|
|
});
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
function selectItem(position) {
|
|
var item;
|
|
if (self.options.selected > -1) {
|
|
item = that.items[self.options.selected]
|
|
item.removeClass("OxSelected");
|
|
}
|
|
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");
|
|
}
|
|
self.options.selected = position;
|
|
}
|
|
|
|
function selectNextItem() {
|
|
var offset,
|
|
selected = self.options.selected;
|
|
if (!isLastEnabledItem()) {
|
|
if (selected == -1) {
|
|
scrollMenuUp();
|
|
} else {
|
|
that.items[selected].removeClass("OxSelected");
|
|
}
|
|
do {
|
|
selected++;
|
|
} while (that.items[selected].options("disabled"))
|
|
selectItem(selected);
|
|
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"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function selectPreviousItem() {
|
|
var offset,
|
|
selected = self.options.selected;
|
|
if (selected > - 1) {
|
|
if (!isFirstEnabledItem()) {
|
|
that.items[selected].removeClass("OxSelected");
|
|
do {
|
|
selected--;
|
|
} while (that.items[selected].options("disabled"))
|
|
selectItem(selected);
|
|
}
|
|
offset = that.items[selected].offset().top - that.$container.offset().top;
|
|
Ox.print(offset);
|
|
if (offset < 0) {
|
|
if (that.$scrollbars.down.is(":hidden")) {
|
|
that.$scrollbars.down.show();
|
|
that.$container.height(that.$container.height() - itemHeight);
|
|
}
|
|
if (selected == 0) {
|
|
that.$scrollbars.up.hide();
|
|
that.$container.height(that.$container.height() + itemHeight);
|
|
}
|
|
that.$content.css({
|
|
top: ((parseInt(that.$content.css("top")) || 0) - offset) + "px"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function selectSubmenu() {
|
|
if (self.options.selected > -1) {
|
|
var submenu = that.submenus[that.items[self.options.selected].options("id")];
|
|
if (submenu && submenu.hasEnabledItems()) {
|
|
submenu.gainFocus();
|
|
submenu.selectFirstItem();
|
|
} else if (self.options.mainmenu) {
|
|
self.options.mainmenu.selectNextMenu();
|
|
}
|
|
} else if (self.options.mainmenu) {
|
|
self.options.mainmenu.selectNextMenu();
|
|
}
|
|
}
|
|
|
|
function selectSupermenu() {
|
|
if (self.options.parent) {
|
|
that.items[self.options.selected].trigger("mouseleave");
|
|
self.options.parent.gainFocus();
|
|
} else if (self.options.mainmenu) {
|
|
Ox.print("previousMenu")
|
|
self.options.mainmenu.selectPreviousMenu();
|
|
}
|
|
}
|
|
|
|
self.onChange = function(key, value) {
|
|
if (key == "items") {
|
|
constructItems(value);
|
|
} else if (key == "selected") {
|
|
selectItem(value);
|
|
}
|
|
}
|
|
|
|
that.addItem = function(item, position) {
|
|
|
|
};
|
|
|
|
that.addItemAfter = function(item, id) {
|
|
|
|
};
|
|
|
|
that.addItemBefore = function(item, id) {
|
|
|
|
};
|
|
|
|
that.getItem = function(id) {
|
|
var item;
|
|
$.each(this.items, function(i, v) {
|
|
if (v.options("id") == id) {
|
|
item = v;
|
|
return false;
|
|
}
|
|
});
|
|
return item;
|
|
};
|
|
|
|
that.hasEnabledItems = function() {
|
|
var ret = false;
|
|
$.each(that.items, function(i, item) {
|
|
if (!item.options("disabled")) {
|
|
return ret = true;
|
|
}
|
|
});
|
|
return ret;
|
|
};
|
|
|
|
that.hideMenu = function() {
|
|
Ox.print("hideMenu")
|
|
$.each(that.submenus, function(i, submenu) {
|
|
if (submenu.is(":visible")) {
|
|
submenu.hideMenu();
|
|
return false;
|
|
}
|
|
});
|
|
selectItem(-1);
|
|
scrollMenuUp();
|
|
that.$scrollbars.up.is(":visible") && that.$scrollbars.up.hide();
|
|
that.$scrollbars.down.is(":visible") && that.$scrollbars.down.hide();
|
|
//that.$scrollbars.down.hide();
|
|
if (self.options.parent) {
|
|
self.options.element.removeClass("OxSelected");
|
|
}
|
|
that.hide()
|
|
.loseFocus()
|
|
.unbindEvent({
|
|
key_up: selectPreviousItem,
|
|
key_down: selectNextItem,
|
|
key_left: selectSupermenu,
|
|
key_right: selectSubmenu,
|
|
key_escape: that.hideMenu,
|
|
key_enter: clickItem
|
|
})
|
|
.triggerEvent("hide");
|
|
that.$layer.hide();
|
|
$document.unbind("click", click);
|
|
return that;
|
|
//that.triggerEvent("hide");
|
|
};
|
|
|
|
that.removeItem = function() {
|
|
|
|
};
|
|
|
|
that.selectFirstItem = function() {
|
|
selectNextItem();
|
|
};
|
|
|
|
that.showMenu = function() {
|
|
Ox.print("showMenu");
|
|
if (!self.options.parent && !that.$layer.parent().length) {
|
|
that.$layer.appendTo($body);
|
|
}
|
|
that.parent().length || that.appendTo($body);
|
|
that.css({
|
|
left: "-1000px",
|
|
top: "-1000px",
|
|
}).show();
|
|
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),
|
|
menuHeight = that.$content.outerHeight(); // fixme: why is outerHeight 0 when hidden?
|
|
menuMaxHeight = Math.floor($window.height() - top - 16),
|
|
Ox.print("menuHeight", menuHeight, "menuMaxHeight", menuMaxHeight, that.items.length);
|
|
if (self.options.parent) {
|
|
if (menuHeight > menuMaxHeight) {
|
|
top = Ox.limit(top - menuHeight + menuMaxHeight, self.options.parent.offset().top, top);
|
|
menuMaxHeight = Math.floor($window.height() - top - 16);
|
|
}
|
|
}
|
|
that.css({
|
|
left: left + "px",
|
|
top: top + "px"
|
|
});
|
|
if (menuHeight > menuMaxHeight) {
|
|
that.$container.height(menuMaxHeight - itemHeight - 8); // margin
|
|
that.$scrollbars.down.show();
|
|
} else {
|
|
that.$container.height(menuHeight);
|
|
}
|
|
!self.options.parent && that.gainFocus();
|
|
that.bindEvent({
|
|
key_up: selectPreviousItem,
|
|
key_down: selectNextItem,
|
|
key_left: selectSupermenu,
|
|
key_right: selectSubmenu,
|
|
key_escape: that.hideMenu,
|
|
key_enter: clickSelectedItem
|
|
});
|
|
setTimeout(function() {
|
|
$document.bind("click", click);
|
|
}, 100);
|
|
return that;
|
|
//that.triggerEvent("show");
|
|
};
|
|
|
|
that.toggleMenu = function() {
|
|
Ox.print("toggleMenu")
|
|
that.is(":hidden") ? that.showMenu() : that.hideMenu();
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
Ox.MenuItem = function(options, self) {
|
|
|
|
var self = self || {},
|
|
that = new Ox.Element("tr", self)
|
|
.defaults({
|
|
bind: [],
|
|
checked: null,
|
|
disabled: false,
|
|
group: "",
|
|
icon: "",
|
|
id: "",
|
|
items: [],
|
|
keyboard: "",
|
|
menu: null, // fixme: is passing the menu to 100s of menu items really memory-neutral?
|
|
position: 0,
|
|
title: [],
|
|
})
|
|
.options($.extend(options, {
|
|
keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard),
|
|
title: Ox.makeArray(options.title || self.defaults.title)
|
|
}))
|
|
.addClass("OxItem" + (self.options.disabled ? " OxDisabled" : ""))
|
|
.attr({
|
|
id: Ox.toCamelCase(self.options.menu.options("id") + "/" + self.options.id)
|
|
})
|
|
.data("group", self.options.group); // fixme: why?
|
|
|
|
// construct
|
|
that.append(
|
|
that.$status = $("<td>", {
|
|
"class": "OxCell OxStatus",
|
|
html: self.options.checked ? oxui.symbols.check : ""
|
|
})
|
|
)
|
|
.append(
|
|
that.$icon = $("<td>", {
|
|
"class": "OxCell OxIcon"
|
|
})
|
|
.append(self.options.icon ?
|
|
$("<img>", {
|
|
src: self.options.icon
|
|
}) : null
|
|
)
|
|
)
|
|
.append(
|
|
that.$title = $("<td>", {
|
|
"class": "OxCell OxTitle",
|
|
html: self.options.title[0]
|
|
})
|
|
)
|
|
.append(
|
|
$("<td>", {
|
|
"class": "OxCell OxModifiers",
|
|
html: $.map(self.options.keyboard.modifiers, function(modifier) {
|
|
return oxui.symbols[modifier];
|
|
}).join("")
|
|
})
|
|
)
|
|
.append(
|
|
$("<td>", {
|
|
"class": "OxCell Ox" + (self.options.items.length ? "Submenu" : "Key"),
|
|
html: self.options.items.length ? oxui.symbols.triangle_right :
|
|
oxui.symbols[self.options.keyboard.key] ||
|
|
self.options.keyboard.key.toUpperCase()
|
|
})
|
|
);
|
|
|
|
function parseKeyboard(str) {
|
|
var modifiers = str.split(" "),
|
|
key = modifiers.pop();
|
|
return {
|
|
modifiers: modifiers,
|
|
key: key
|
|
}
|
|
}
|
|
|
|
self.onChange = function(key, value) {
|
|
Ox.print("MenuItem", self.options.id, "onChange", key, value);
|
|
if (key == "checked") {
|
|
if (value && self.options.group) {
|
|
$.each(self.options.menu.items, function(i, item) {
|
|
if (
|
|
item.options("id") != self.options.id &&
|
|
item.options("group") == self.options.group &&
|
|
item.options("checked")
|
|
) {
|
|
item.options({
|
|
checked: false
|
|
});
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
that.$status.html(value ? oxui.symbols.check : "")
|
|
} else if (key == "disabled") {
|
|
that.toggleClass("disabled"); // fixme: this will only work if onChange is only invoked on actual change
|
|
} else if (key == "title") {
|
|
|
|
}
|
|
}
|
|
|
|
that.toggle = function() {
|
|
// toggle id and title
|
|
};
|
|
|
|
that.toggleChecked = function() {
|
|
|
|
};
|
|
|
|
that.toggleDisabled = function() {
|
|
|
|
};
|
|
|
|
that.toggleTitle = function() {
|
|
that.options({
|
|
title: that.$title.html() == self.options.title[0] ?
|
|
self.options.title[1] : self.options.title[0]
|
|
});
|
|
};
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Panels
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.CollapsePanel
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.CollapsePanel = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Panel({}, self)
|
|
.defaults({
|
|
collapsed: false,
|
|
size: 20,
|
|
title: ""
|
|
})
|
|
.options(options)
|
|
.addClass("OxCollapsePanel"),
|
|
value = self.options.collapsed ?
|
|
["expand", "collapsed"] : ["collapse", "expand"],
|
|
$titlebar = new Ox.Bar({
|
|
orientation: "horizontal",
|
|
size: self.options.size,
|
|
})
|
|
.dblclick(dblclickTitlebar)
|
|
.appendTo(that),
|
|
$switch = new Ox.Button({
|
|
style: "symbol",
|
|
type: "image",
|
|
value: value,
|
|
})
|
|
.click(toggleCollapsed)
|
|
.appendTo($titlebar),
|
|
$title = new Ox.Element()
|
|
.addClass("OxTitle")
|
|
.html(self.options.title/*.toUpperCase()*/)
|
|
.appendTo($titlebar);
|
|
that.$content = new Ox.Element()
|
|
.addClass("OxContent")
|
|
.appendTo(that);
|
|
// fixme: doesn't work, content still empty
|
|
// need to hide it if collapsed
|
|
if (self.options.collapsed) {
|
|
that.$content.css({
|
|
marginTop: -that.$content.height() + "px"
|
|
});
|
|
}
|
|
function dblclickTitlebar(e) {
|
|
if (!$(e.target).hasClass("OxButton")) {
|
|
toggleCollapsed();
|
|
}
|
|
}
|
|
function toggleCollapsed() {
|
|
that.options({
|
|
collapsed: !self.options.collapsed
|
|
});
|
|
var top = self.options.collapsed ?
|
|
-that.$content.height() : 0;
|
|
that.$content.animate({
|
|
marginTop: top + "px"
|
|
}, 200);
|
|
}
|
|
self.onChange = function(option, value) {
|
|
if (option == "collapsed") {
|
|
$switch.options({
|
|
value: value ? "expand" : "collapse"
|
|
});
|
|
} else if (option == "title") {
|
|
$title.html(self.options.title);
|
|
}
|
|
};
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Panel
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.Panel = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.addClass("OxPanel");
|
|
return that;
|
|
};
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.SplitPanel
|
|
options:
|
|
orientation: "" "horizontal" or "vertical"
|
|
elements: [{
|
|
element, Ox Element
|
|
size: 0, size in px
|
|
resizable: false resizable or not
|
|
}]
|
|
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.SplitPanel = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element({}, self)
|
|
.defaults({
|
|
elements: [],
|
|
orientation: "horizontal"
|
|
})
|
|
.options(options || {})
|
|
.addClass("OxSplitPanel"),
|
|
length = self.options.elements.length,
|
|
dimensions = oxui.getDimensions(self.options.orientation),
|
|
edges = oxui.getEdges(self.options.orientation);
|
|
$.each(self.options.elements, function(i, v) {
|
|
Ox.print("v", v);
|
|
var element = v.element
|
|
.css({
|
|
position: "absolute" // fixme: this can go into a class
|
|
})
|
|
.css(edges[2], 0)
|
|
.css(edges[3], 0);
|
|
if (v.size != undefined) {
|
|
element.css(dimensions[0], v.size + "px");
|
|
}
|
|
if (i == 0) {
|
|
element.css(edges[0], 0);
|
|
if (v.size == undefined) {
|
|
element.css(
|
|
edges[1],
|
|
(self.options.elements[1].size + (length == 3 ? self.options.elements[2].size : 0)) + "px"
|
|
);
|
|
}
|
|
} else if (i == 1) {
|
|
if (self.options.elements[0].size != undefined) {
|
|
element.css(edges[0], self.options.elements[0].size + "px");
|
|
}
|
|
if (self.options.elements[0].size == undefined || v.size == undefined) {
|
|
element.css(
|
|
edges[1],
|
|
(length == 3 ? self.options.elements[2].size : 0) + "px"
|
|
);
|
|
}
|
|
} else {
|
|
element.css(edges[1], 0);
|
|
if (v.size == undefined) {
|
|
element.css(
|
|
edges[0],
|
|
(self.options.elements[0].size + self.options.elements[1].size) + "px"
|
|
);
|
|
}
|
|
}
|
|
element.appendTo(that);
|
|
//that.append(element)
|
|
});
|
|
return that;
|
|
};
|
|
|
|
Ox.TabPanel = function(options, self) {
|
|
|
|
};
|
|
|
|
/*
|
|
============================================================================
|
|
Requests
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.LoadingIcon
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Ox.LoadingIcon = function(options, self) {
|
|
var self = self || {},
|
|
that = new Ox.Element("img", self)
|
|
.defaults({
|
|
size: "medium"
|
|
})
|
|
.options(options || {})
|
|
.attr({
|
|
src: oxui.path + "/png/ox.ui." + Ox.theme() + "/loading.png"
|
|
})
|
|
.addClass(
|
|
"OxLoadingIcon Ox" + Ox.toTitleCase(self.options.size)
|
|
);
|
|
self.count = 0;
|
|
self.deg = 0;
|
|
function update() {
|
|
that.css({
|
|
MozTransform: "rotate(" + self.deg + "deg)",
|
|
WebkitTransform: "rotate(" + self.deg + "deg)"
|
|
});
|
|
}
|
|
that.start = function() {
|
|
self.deg = 0;
|
|
self.count++;
|
|
if (self.count == 1) {
|
|
that.animate({
|
|
opacity: 1
|
|
}, 250);
|
|
self.interval = setInterval(function() {
|
|
self.deg = (self.deg + 30) % 360;
|
|
update();
|
|
}, 83);
|
|
}
|
|
};
|
|
that.stop = function() {
|
|
self.count--;
|
|
if (self.count == 0) {
|
|
that.animate({
|
|
opacity: 0
|
|
}, 250, function() {
|
|
clearTimeout(self.interval);
|
|
self.deg = 0;
|
|
});
|
|
}
|
|
}
|
|
return that;
|
|
}
|
|
|
|
/*
|
|
----------------------------------------------------------------------------
|
|
Ox.Progressbar
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
})(); |