/* ################################################################################ ox.ui.js requires jquery-1.4.js ox.js ################################################################################ */ // also see test.js, in demos ... (function() { var oxui = { defaultTheme: "classic", elements: {}, getDimensions: function(orientation) { return orientation == "horizontal" ? ["width", "height"] : ["height", "width"]; }, getEdges: function(orientation) { return orientation == "horizontal" ? ["left", "right", "top", "bottom"] : ["top", "bottom", "left", "right"]; }, getBarSize: function(size) { var sizes = { xsmall: 16, small: 24, medium: 28, large: 32, xlarge: 40 }; return sizes[size]; }, jQueryFunctions: function() { var functions = [], $element = $("
"); //delete $element.length; Ox.each($element, function(k, v) { if (typeof v == "function") { functions.push(k); } }); return functions.sort(); }(), path: $("script[src*=ox.ui.js]").attr("src") .replace("js/ox.ui.js", ""), stack: [] }, $window, $document, $body; $(function() { $window = $(window), $document = $(document), $body = $("body"); Ox.theme(oxui.defaultTheme); }) /* ============================================================================ Application ============================================================================ */ /* ---------------------------------------------------------------------------- Ox.App ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- Ox.Cache ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- 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 events = {}; return { // make these bind, trigger, unbind publish: function(event, data) { console.log("publish", event, data); if (events[event]) { $.each(events[event], function(i, v) { setTimeout(function() { v(data); }, 0); }); } }, subscribe: function(event, callback) { console.log("subscribe", event, callback); if (events[event]) { events[event].push(callback); } else { events[event] = [callback]; } }, unsubscribe: function(event, callback) { console.log("unsubscribe", event, callback); $.each(events[event], function(i, v) { if (Ox.startsWith(callback.toString(), v.toString())) { events[event].splice(i, 1); } }); } }; }(); /* ---------------------------------------------------------------------------- Ox.Focus ---------------------------------------------------------------------------- */ Ox.Focus = function() { var stack = []; return { focus: function(id) { var index = stack.indexOf(id); if (index > -1) { oxui.stack.splice(i, 1); } oxui.stack.push(id); }, blur: function(id) { oxui.stack.pop(); } }; }(); /* ---------------------------------------------------------------------------- Ox.History ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- Ox.Keyboard ---------------------------------------------------------------------------- */ (function() { var buffer = "", bufferTime = 0, bufferTimeout = 1000, keyNames = function() { return { 0: "section", 8: "backspace", 9: "tab", 12: "clear", 13: "enter", 16: "shift", 17: "control", 18: "alt", 20: "capslock", 27: "escape", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "delete", 47: "help", 48: "0", 49: "1", 50: "2", 51: "3", 52: "4", 53: "5", 54: "6", 55: "7", 56: "8", 57: "9", 65: "A", 66: "B", 67: "C", 68: "D", 69: "E", 70: "F", 71: "G", 72: "H", 73: "I", 74: "J", 75: "K", 76: "L", 77: "M", 78: "N", 79: "O", 80: "P", 81: "Q", 82: "R", 83: "S", 84: "T", 85: "U", 86: "V", 87: "W", 88: "X", 89: "Y", 90: "Z", 91: "meta.left", 92: "meta.right", 93: "select", 96: "0.numpad", 97: "1.numpad", 98: "2.numpad", 99: "3.numpad", 100: "4.numpad", 101: "5.numpad", 102: "6.numpad", 103: "7.numpad", 104: "8.numpad", 105: "9.numpad", 106: "asterisk.numpad", 107: "plus.numpad", 109: "minus.numpad", 108: "enter.numpad", 110: "dot.numpad", 111: "slash.numpad", 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 120: "f9", 121: "f10", 122: "f11", 123: "f12", 124: "f13", 125: "f14", 126: "f15", 127: "f16", 144: "numlock", 145: "scrolllock", 186: "semicolon", 187: "equal", 188: "comma", 189: "minus", 190: "dot", 191: "slash", 192: "backtick", 219: "openbracket", 220: "backslash", 221: "closebracket", 222: "quote" // see dojo, for ex. }; }(), modifierNames = { altKey: "alt", // mac: option ctrlKey: "control", metaKey: "meta", // mac: command shiftKey: "shift" }; return function() { document.keydown(keydown); function keydown(e) { var key = [], ret = true, time; $.each(modifierNames, function(k, v) { if (e[k]) { key.push(v); } }); // avoid pushing modifier twice if (keyNames[e.keyCode] && keys.indexOf(keyNames[e.keyCode]) == -1) { key.push(keyNames[e.keyCode]); } key = key.join(" "); if (key.match(/^[\w\d-]$|SPACE/)) { time = Ox.time(); if (time - bufferTime > bufferTimeout) { buffer = ""; } buffer += key == "SPACE" ? " " : key; bufferTime = time; } $.each(stack, function(i, v) { // fixme: we dont get the return value! ret = Ox.event.publish(keyboard + Ox.toCamelCase(key) + "." + v); return ret; }); } }; })(); /* ---------------------------------------------------------------------------- Ox.Mouse (??) ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- Ox.URL ---------------------------------------------------------------------------- */ /* ============================================================================ Core ============================================================================ */ /* ---------------------------------------------------------------------------- Ox.Container ---------------------------------------------------------------------------- */ // fixme: wouldn't it be better to let the elements be, // rather then $element, $content, and potentially others, // 0, 1, 2, etc, so that append would append 0, and appendTo // would append (length - 1)? Ox.Container = function() { var that = new Ox.Element() .addClass("OxContainer"); that.$content = new Ox.Element() .addClass("OxContent") .appendTo(that); return that; } /* ---------------------------------------------------------------------------- Ox.Element ---------------------------------------------------------------------------- */ // check out http://ejohn.org/apps/learn/#36 (-#38, making fns work w/o new) Ox.Element = function() { var elements = {}; return function(options, self) { // construct options = options || {}; self = self || {}; var that = this; // init (function() { // allow for Ox.Widget("tagname", self) if (typeof options == "string") { options = { element: options }; } that.ox = Ox.version; that.id = Ox.uid(); that.$element = $("<" + (options.element || "div") + "/>", { data: { ox: that.id } }); elements[that.id] = that; wrapjQuery(); })(); // private function wrapjQuery() { $.each(oxui.jQueryFunctions, function(i, v) { that[v] = function() { var args = arguments, length = args.length, id, ret; $.each(args, function(i, v) { // if an ox object was passed // then pass its $element instead // so we can do oxObj.jqFn(oxObj) if (v.ox) { args[i] = v.$element; } }); // why does this not work? // ret = that.$element[v].apply(this, arguments); if (length == 0) { ret = that.$element[v](); } else if (length == 1) { ret = that.$element[v](args[0]); } else if (length == 2) { ret = that.$element[v](args[0], args[1]); } else if (length == 3) { ret = that.$element[v](args[0], args[1], args[2]); } else if (length == 4) { ret = that.$element[v](args[0], args[1], args[2], args[3]); } // if the $element of an ox object was returned // then return the ox object instead // so we can do oxObj.jqFn().oxFn() return ret.jquery && elements[id = ret.data("ox")] ? elements[id] : ret; } }); } // shared self.onChange = function() { // self.onChange(option, value) // is called when an option changes // (to be implemented by widget) }; // public that.defaults = function(defaults) { /* that.defaults({foo: x}) sets self.defaults */ self.defaults = defaults; return that; } that.gain = function() { Ox.Focus.gain(that.id); } that.lose = function() { Ox.Focus.lose(that.id); } that.options = function() { /* that.options() returns self.options that.options("foo") returns self.options.foo that.options("foo", x) sets self.options.foo, returns that that.options({foo: x, bar: y}) sets self.options.foo and self.options.bar, returns that */ var length = arguments.length, args, ret; if (length == 0) { // options() ret = self.options; } else if (length == 1 && typeof arguments[0] == "string") { // options(str) ret = self.options[arguments[0]] } else { // options (str, val) or options({str: val, ...}) // translate (str, val) to ({str: val}) args = Ox.makeObject.apply(that, arguments); // if options have not been set, extend defaults, // otherwise, extend options self.options = $.extend( self.options || self.defaults, args); $.each(args, function(k, v) { self.onChange(k, v); }); ret = that; } return ret; } that.publish = function() { arguments[0] = arguments[0] + "." + that.id; Ox.Event.publish.apply(that, arguments); // or, maybe better: $(".OxWidget").trigger.apply(that, arguments); return that; } that.remove = function() { that.$element.remove(); delete elements[that.ox]; } that.subscribe = function() { Ox.Event.subscribe.apply(that, arguments); // or that.$element.bind.apply(that, arguments); return that; } that.unsubscribe = function() { Ox.Event.unsubscribe.apply(that, arguments); return that; } // return return that; } }(); Ox._Element = function(element) { var that = this; that.def = {}; that.opt = {}; that.ox = Ox.version; that.id = Ox.uid(); //console.log("that.id", that.id) that.$element = $("<" + (element || "div") + "/>") //.addClass("OxElement") .data("ox", that.id); oxui.elements[that.id] = that; // console.log("oxui.elements", oxui.elements) //function setOption() {}; that.setOption = function() {}; /* */ that.destroy = function() { that.$element.remove(); delete oxui.elements[that.ox]; } /* */ that.disable = function() { } /* */ that.enable = function() { } /* */ ///* that.defaults = function() { var length = arguments.length, ret; if (length == 0) { ret = that.def } else if (length == 1 && typeof arguments[0] == "string") { ret = that.def[arguments[0]]; } else { // translate ("key", "value") to {"key": "value"} that.def = $.extend( that.def, Ox.makeObject.apply(that, arguments) ); ret = that; } return ret; } //*/ /* Ox.Element.options() get options Ox.Element.options("foo") get options.foo Ox.Element.options("foo", 0) set options.foo Ox.Element.options({foo: 0, bar: 1}) set options.foo and options.bar */ ///* that.options = function() { var length = arguments.length, args, ret; if (length == 0) { //console.log("getting all options", options); ret = that.opt; } else if (length == 1 && typeof arguments[0] == "string") { //console.log("getting one option", options, arguments[0], options[arguments[0]]); ret = that.opt[arguments[0]]; } else { // translate ("key", "value") to {"key": "value"} args = Ox.makeObject.apply(that, arguments); // if options have been set then extend options, // otherwise extend defaults that.opt = $.extend(Ox.length(that.opt) ? that.opt : that.def, args); // that.trigger("OxElement" + that.id + "SetOptions", args); $.each(args, function(k, v) { that.setOption(k, v); //console.log("triggering", "OxElement" + that.id + "SetOption", {k: v}) //that.trigger("OxElement" + that.id + "SetOption", {k: v}); }) ret = that; } return ret; } // should become self.publish that.publish = function(event, data) { Ox.Event.publish(event + that.id, data); return that; } that.subscribe = function(event, callback) { Ox.Event.subscribe(event, callback); return that; } //that.setOptions = function() {}; //*/ // wrap jquery functions // so we can do oxObj.jqFn() $.each(oxui.jqueryFunctions, function(i, v) { that[v] = function() { var args = arguments, length = args.length, $element, id, ret; $.each(args, function(i, v) { // if an oxui object was passed // then pass its $element instead // so we can do jqObj.append(oxObj) if (v.ox) { args[i] = v.$element; } }); if (v == "html" && that.$content) { $element = that.$content; } else { $element = that.$element; } // why does this not work? // ret = that.$element[v].apply(this, arguments); // maybe because we pass this, and not that.$element[v] ... ? // ret = that.$element[v].apply(that.$element[v], arguments); // doesn't work either ... if (length == 0) { ret = $element[v](); } else if (length == 1) { ret = $element[v](args[0]); } else if (length == 2) { ret = $element[v](args[0], args[1]); } else if (length == 3) { ret = $element[v](args[0], args[1], args[2]); } else if (length == 4) { ret = $element[v](args[0], args[1], args[2], args[3]); } // if the $element of an oxui object was returned // then return the oxui object instead // so we can do oxObj.jqFn().oxFn() //console.log("v", v, "arguments", arguments) if (ret.jquery) { //console.log("ret", ret, "ret.data('id')", ret.data("ox")) } return ret.jquery && oxui.elements[id = ret.data("ox")] ? oxui.elements[id] : ret; } }); return that; }; /* ---------------------------------------------------------------------------- Ox.theme() get theme Ox.theme("foo") set theme to "foo" ---------------------------------------------------------------------------- */ Ox.theme = function() { var length = arguments.length, classes = $body.attr("class").split(" "), arg, theme; $.each(classes, function(i, v) { if (Ox.startsWith(v, "OxTheme")) { theme = v.replace("OxTheme", "").toLowerCase(); if (length == 1) { $body.removeClass(v); } return false; } }); if (length == 1) { arg = arguments[0] $body.addClass("OxTheme" + Ox.toTitleCase(arg)); if (theme) { $("input[type=image]").each(function() { var $this = $(this); $this.attr({ src: $this.attr("src").replace( "/ox.ui." + theme + "/", "/ox.ui." + arg + "/" ) }); }); } } return theme; }; /* ============================================================================ Bars ============================================================================ */ Ox.Bar = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) .defaults({ orientation: "horizontal", size: 16 }) .options(options || {}), dimensions = oxui.getDimensions(self.options.orientation); that.addClass("OxBar Ox" + Ox.toTitleCase(self.options.orientation)) .css(dimensions[0], "100%") .css(dimensions[1], self.options.size + "px"); return that; }; /* ---------------------------------------------------------------------------- Ox.Tabbar ---------------------------------------------------------------------------- */ Ox.Tabbar = function(options, self) { var self = self || {}, that = new Ox.Bar({ size: 20 }, self) .defaults({ selected: 0, values: [] }) .options(options || {}) .addClass("OxTabbar"); (function() { Ox.ButtonGroup({ selectable: true, selected: self.options.selected, size: "small", style: "tab", values: self.options.values }).appendTo(that); })(); return that; }; Ox.Toolbar = function(options, self) { var self = self || {}, that = new Ox.Bar({ size: oxui.getBarSize(options.size) }, self); return that; }; /* ============================================================================ Forms ============================================================================ */ /* ---------------------------------------------------------------------------- Ox.Button ---------------------------------------------------------------------------- */ Ox.Button = function(options, self) { var self = self || {}, that = new Ox.Element("input", self) .defaults({ buttonId: null, disabled: false, groupId: null, selectable: false, selected: false, size: "small", style: "", // can be symbol or tab type: "text", value: "", values: [] }) .options($.extend(options, { value: $.isArray(options.value) ? options.value[0] : options.value, values: $.makeArray(options.value) })); that.attr({ disabled: self.options.disabled ? "disabled" : "", type: self.options.type == "text" ? "button" : "image" }) .addClass("OxButton Ox" + Ox.toTitleCase(self.options.size) + (self.options.style ? " Ox" + Ox.toTitleCase(self.options.style) : "") + (self.options.disabled ? " OxDisabled": "") + (self.options.selected ? " OxSelected": "")) .mousedown(mousedown) .click(click); //console.log(self.options.value, self.options.disabled) /* that.bind("OxElement" + that.id + "SetOptions", function(e, data) { if (typeof data.selected != "undefined") { if (data.selected != that.hasClass("OxSelected")) { that.toggleClass("OxSelected"); } } if (typeof data.value != "undefined") { if (self.options.type == "image") { that.attr({ src: oxui.path + "png/" + Ox.theme() + "/button" + Ox.toTitleCase(options.value) + ".png" }); } else { that.val(self.options.value); } } }) */ function mousedown(e) { if (self.options.type == "image" && $.browser.safari) { // keep image from being draggable e.preventDefault(); } } function click() { if (self.options.selectable && !(self.options.groupId !== null && self.options.selected)) { that.toggleSelected(); } if (self.options.values.length == 2) { console.log("2 values") that.options({ value: self.options.value == self.options.values[0] ? self.options.values[1] : self.options.values[0] }); } } self.onChange = function(option, value) { //console.log("setOption", option, value) if (option == "selected") { if (value != that.hasClass("OxSelected")) { that.toggleClass("OxSelected"); } } if (option == "value") { if (self.options.type == "image") { that.attr({ src: oxui.path + "png/ox.ui." + Ox.theme() + "/button" + Ox.toTitleCase(value) + ".png" }); } else { that.val(value); } } } that.toggleSelected = function() { that.options({ selected: !self.options.selected }); that.trigger("OxButtonToggle", self.options); } that.options("value", self.options.value); return that; }; /* ---------------------------------------------------------------------------- Ox.ButtonGroup ---------------------------------------------------------------------------- */ Ox.ButtonGroup = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) .defaults({ groupId: Ox.uid(), selectable: false, selected: -1, size: "small", style: "", type: "text", values: [] }) .options(options || {}) .addClass("OxButtonGroup"); (function() { self.$buttons = []; $.each(self.options.values, function(i, v) { self.$buttons[i] = Ox.Button({ buttonId: i, groupId: self.options.groupId, selectable: self.options.selectable, selected: i == self.options.selected, size: self.options.size, style: self.options.style, type: self.options.type, value: v }).appendTo(that); }); that.$element.bind("OxButtonToggle", function(e, data) { console.log("Data", data, self.options) if (data.groupId = self.options.groupId) { if (data.selected) { if (self.options.selected > -1) { self.$buttons[self.options.selected].toggleSelected(); } self.options.selected = data.buttonId; } } }); })(); return that; }; /* ---------------------------------------------------------------------------- Ox.Input ---------------------------------------------------------------------------- */ Ox.Input = function(options, self) { var self = self || {}, that = new Ox.Element("input", self) .defaults({ placeholder: "", size: "small", type: "text" }) .options(options || {}); that.attr({ type: self.options.type, placeholder: self.options.placeholder }) .addClass("OxInput Ox" + Ox.toTitleCase(self.options.size) + " OxPlaceholder") //.change(change) .focus(focus) .blur(blur); /* doesn't work yet function change() { console.log("change", that.val(), that.hasClass("OxPlaceholder")) if ((that.val() !== "") != that.hasClass("OxPlaceholder")) { that.toggleClass("OxPlaceholder"); } } */ function focus() { console.log("focus", that.val(), that.attr("class")) if (that.hasClass("OxPlaceholder")) { that.val("").removeClass("OxPlaceholder"); } } function blur() { console.log("blur", that.val(), that.attr("class")) if (that.val() === "") { that.addClass("OxPlaceholder").val(that.attr("placeholder")); } } return that; }; /* ---------------------------------------------------------------------------- Ox.Range options: animate boolean if true, animate thumb arrows boolean if true, show arrows arrowImages array arrow symbols, like ["minus", "plus"] arrowStep number step when clicking arrows max number maximum value min number minimum value orientation string "horizontal" or "vertical" step number step between values size number width or height, in px thumbSize number minimum width or height of thumb, in px thumbValue boolean if true, display value on thumb trackImages string or array one or multiple track background image URLs trackStep number 0 (scroll here) or step when clicking track value number initial value ---------------------------------------------------------------------------- */ Ox.Range = function(options, self) { /* init */ var self = self || {}, that = new Ox.Element({}, self) .defaults({ animate: false, arrows: false, arrowImages: ["previous", "next"], arrowStep: 1, max: 100, min: 0, orientation: "horizontal", step: 1, size: 128, thumbSize: 16, thumbValue: false, trackImages: [], trackStep: 0, value: 0 }) .options($.extend(options, { arrowStep: options.arrowStep ? options.arrowStep : options.step, trackImages: $.makeArray(options.trackImages || []) })) .addClass("OxRange"); // fixme: self. ... ? var trackImages = self.options.trackImages.length, values = (self.options.max - self.options.min + self.options.step) / self.options.step; /* construct */ that.$element .css({ width: self.options.size + "px" }); if (self.options.arrows) { var $arrowDec = Ox.Button({ style: "symbol", type: "image", value: self.options.arrowImages[0] }) .addClass("OxArrow") .mousedown(mousedownArrow) .click(clickArrowDec) .appendTo(that.$element); } var $track = new Ox.Element() .addClass("OxTrack") .mousedown(clickTrack) .appendTo(that.$element); // fixme: make that work if (trackImages) { var width = parseFloat(screen.width / trackImages), $image = $("") .attr({ width: width * trackImages, height: 14 }) .addClass("OxImage") .appendTo($track.$element), // fixme: make that work c = $image[0].getContext('2d'); c.mozImageSmoothingEnabled = false; // we may want to remove this later $.each(self.options.trackImages, function(i, v) { //console.log(v) $("") .attr({ src: v }) .load(function() { c.drawImage(this, i * width, 0, width, 14); }); }); } var $thumb = Ox.Button({}) .addClass("OxThumb") .appendTo($track); if (self.options.arrows) { var $arrowInc = Ox.Button({ style: "symbol", type: "image", value: self.options.arrowImages[1] }) .addClass("OxArrow") .mousedown(mousedownArrow) .click(clickArrowInc) .appendTo(that.$element); } var rangeWidth, trackWidth, imageWidth, thumbWidth; setWidth(self.options.size); /* private functions */ function clickArrowDec() { that.removeClass("OxActive"); setValue(self.options.value - self.options.arrowStep, 200) } function clickArrowInc() { that.removeClass("OxActive"); setValue(self.options.value + self.options.arrowStep, 200); } function clickTrack(e) { Ox.Focus.focus(); var left = $track.offset().left, offset = $(e.target).hasClass("OxThumb") ? e.clientX - $thumb.offset().left - thumbWidth / 2 - 2 : 0; function val(e) { return getVal(e.clientX - left - offset); } setValue(val(e), 200); $window.mousemove(function(e) { setValue(val(e)); }); $window.one("mouseup", function() { $window.unbind("mousemove"); }); } function getPx(val) { var pxPerVal = (trackWidth - thumbWidth - 2) / (self.options.max - self.options.min); return Math.ceil((val - self.options.min) * pxPerVal + 1); } function getVal(px) { var px = trackWidth / values >= 16 ? px : px - 8, valPerPx = (self.options.max - self.options.min) / (trackWidth - thumbWidth); return Ox.limit(self.options.min + Math.floor(px * valPerPx / self.options.step) * self.options.step, self.options.min, self.options.max); } function mousedownArrow() { that.addClass("OxActive"); } function setThumb(animate) { var animate = typeof animate != "undefined" ? animate : 0; $thumb.animate({ marginLeft: (getPx(self.options.value) - 2) + "px", width: thumbWidth + "px" }, self.options.animate ? animate : 0, function() { if (self.options.thumbValue) { $thumb.options({ value: self.options.value }); } }); } function setValue(val, animate) { val = Ox.limit(val, self.options.min, self.options.max); if (val != self.options.value) { that.options({ value: val }); setThumb(animate); //console.log("triggering OxRange" + that.id + "Change") that.publish("change", { value: val }); } } function setWidth(width) { trackWidth = width - self.options.arrows * 32; thumbWidth = Math.max(trackWidth / values - 2, self.options.thumbSize - 2); that.$element.css({ width: (width - 2) + "px" }); $track.css({ width: (trackWidth - 2) + "px" }); if (trackImages) { $image.css({ width: (trackWidth - 2) + "px" }); } $thumb.css({ width: (thumbWidth - 2) + "px", padding: 0 }); setThumb(); } /* shared functions */ self.onChange = function(option, value) { } return that; }; /* ---------------------------------------------------------------------------- Ox.Dialog ---------------------------------------------------------------------------- */ Ox.Dialog = function(options) { var options = $.extend({ title: "", buttons: [], width: 256, height: 128 }, options), that = new Ox.Element() .addClass("OxDialog") .css({ left: (($(document).width() - options.width) / 2) + "px", top: (($(document).height() - options.height - 48) / 2) + "px", width: options.width + "px", height: (options.height + 48) + "px" }); that.$titlebar = new Ox.Element() .addClass("OxTitleBar") .html(options.title) .mousedown(function(e) { var offset = that.offset(), //maxLeft = $(document).width() - that.width(), //maxTop = $(document).height() - that.height(), x = e.clientX, y = e.clientY, documentWidth = $(document).width(); documentHeight = $(document).height(); $(window).mousemove(function(e) { var left = Ox.constrain(offset.left - x + e.clientX, 24 - options.width, documentWidth - 24), top = Ox.constrain(offset.top - y + e.clientY, -24 - options.height, documentHeight - 24); that.css({ left: left + "px", top: top + "px" }); }); $(window).one("mouseup", function() { $(window).unbind("mousemove"); }); }) .appendTo(that); that.$content = new Ox.Container() .addClass("OxContent") .css({ height: options.height + "px" }) .appendTo(that); that.$buttonsbar = new Ox.Element() .addClass("OxButtonsBar") .appendTo(that); //that.$buttons = []; $.each(options.buttons, function(i, v) { v.appendTo(that.$buttonsbar); }); options.buttons[0].focus(); that.$layer = $(".OxLayer"); // fixme: lazy loading of layer is fine, but save in var, dont look up that.append = function($element) { that.$content.append($element); return that; } that.close = function() { that.animate({ opacity: 0 }, 200, function() { that.remove(); that.$layer.remove(); }) } that.open = function() { if (!that.$layer.length) { that.$layer = new Ox.Element() .addClass("OxLayer") .appendTo($("body")); } that.css({ opacity: 0 }).appendTo(that.$layer).animate({ opacity: 1 }, 200); return that; } return that; } /* ============================================================================ Panels ============================================================================ */ /* ---------------------------------------------------------------------------- Ox.CollapsePanel ---------------------------------------------------------------------------- */ Ox.CollapsePanel = function(options, self) { var self = self || {}, that = new Ox.Panel({}, self) .defaults({ collapsed: false, size: 20, title: "" }) .options(options) .addClass("OxCollapsePanel"), value = self.options.collapsed ? ["expand", "collapsed"] : ["collapse", "expand"], $titlebar = new Ox.Bar({ orientation: "horizontal", size: self.options.size, }) .dblclick(dblclickTitlebar) .appendTo(that), $switch = new Ox.Button({ size: "small", style: "symbol", type: "image", value: value, }) .click(toggleCollapsed) .appendTo($titlebar), $title = new Ox.Element() .addClass("OxTitle") .html(self.options.title/*.toUpperCase()*/) .appendTo($titlebar); that.$content = new Ox.Element() .addClass("OxContent") .appendTo(that); // fixme: doesn't work, content still empty // need to hide it if collapsed if (self.options.collapsed) { that.$content.css({ marginTop: -that.$content.height() + "px" }); } function dblclickTitlebar(e) { if (!$(e.target).hasClass("OxButton")) { toggleCollapsed(); } } function toggleCollapsed() { that.options({ collapsed: !self.options.collapsed }); var top = self.options.collapsed ? -that.$content.height() : 0; that.$content.animate({ marginTop: top + "px" }, 200); } self.onChange = function(option, value) { if (option == "collapsed") { $switch.options({ value: value ? "expand" : "collapse" }); } else if (option == "title") { $title.html(self.options.title); } }; return that; }; /* ---------------------------------------------------------------------------- Ox.Panel ---------------------------------------------------------------------------- */ Ox.Panel = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) .addClass("OxPanel"); return that; }; /* ---------------------------------------------------------------------------- Ox.SplitPanel options: orientation: "" "horizontal" or "vertical" elements: [{ element, Ox Element size: 0, size in px resizable: false resizable or not }] ---------------------------------------------------------------------------- */ Ox.SplitPanel = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) .defaults({ elements: [], orientation: "horizontal" }) .options(options || {}) .addClass("OxSplitPanel"), length = self.options.elements.length, dimensions = oxui.getDimensions(self.options.orientation), edges = oxui.getEdges(self.options.orientation); $.each(self.options.elements, function(i, v) { var element = v.element .css({ position: "absolute" // fixme: this can go into a class }) .css(edges[2], 0) .css(edges[3], 0); if (v.size != undefined) { element.css(dimensions[0], v.size + "px"); } if (i == 0) { element.css(edges[0], 0); if (v.size == undefined) { element.css( edges[1], (self.options.elements[1].size + (length == 3 ? self.options.elements[2].size : 0)) + "px" ); } } else if (i == 1) { if (self.options.elements[0].size != undefined) { element.css(edges[0], self.options.elements[0].size + "px"); } if (self.options.elements[0].size == undefined || v.size == undefined) { element.css( edges[1], (length == 3 ? self.options.elements[2].size : 0) + "px" ); } } else { element.css(edges[1], 0); if (v.size == undefined) { element.css( edges[0], (self.options.elements[0].size + self.options.elements[1].size) + "px" ); } } element.appendTo(that); //that.append(element) }); return that; }; })();