From a6ed310087ac576c33a4f032e27bf7c12c247634 Mon Sep 17 00:00:00 2001 From: rolux Date: Thu, 5 May 2011 20:02:56 +0200 Subject: [PATCH] various documentation-related changes --- demos/listmap2/js/listmap.js | 6 +- demos/mouse/index.html | 2 +- demos/mouse/js/mouse.js | 6 +- docs/api.js | 2 +- docs/index.html | 7 +- source/Ox.UI/js/Calendar/Ox.Calendar.js | 30 +- source/Ox.UI/js/Core/Ox.Element.js | 150 +++- source/Ox.UI/js/Core/Ox.JQueryElement.js | 16 +- source/Ox.UI/js/Core/Ox.Keyboard.js | 89 +-- source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js | 17 +- source/Ox.UI/js/List/Ox.List.js | 47 +- source/Ox.UI/js/Map/Ox.Map.js | 84 +++ source/Ox.js | 725 ++++++++++++++----- 13 files changed, 880 insertions(+), 301 deletions(-) diff --git a/demos/listmap2/js/listmap.js b/demos/listmap2/js/listmap.js index fb97f652..412feffc 100644 --- a/demos/listmap2/js/listmap.js +++ b/demos/listmap2/js/listmap.js @@ -5,7 +5,7 @@ Ox.load('UI', { theme: 'modern' }, function() { - Ox.loadJSON('json/cities100000.json', function(data) { + Ox.getJSON('json/cities100000.json', function(data) { var listmap = new Ox.ListMap({ height: window.innerHeight, @@ -22,7 +22,7 @@ Ox.load('UI', { size = Math.sqrt(city.population * 100), latSize = size / Ox.EARTH_CIRCUMFERENCE * 360, lngSize = size * Ox.getDegreesPerMeter(city.latitude); - return Ox.extend({ + return { countryCode: city.country_code == 'XK' ? 'RS-KO' : city.country_code, editable: true, flag: city.country_code, @@ -38,7 +38,7 @@ Ox.load('UI', { west: city.longitude - lngSize / 2, north: city.latitude + latSize / 2, east: city.longitude + lngSize / 2 - }); + }; }), width: window.innerWidth }) diff --git a/demos/mouse/index.html b/demos/mouse/index.html index 3dfbdaa2..89908496 100644 --- a/demos/mouse/index.html +++ b/demos/mouse/index.html @@ -3,7 +3,7 @@ OxJS Mouse Events Demo - + diff --git a/demos/mouse/js/mouse.js b/demos/mouse/js/mouse.js index a007beb6..2eb4c03f 100644 --- a/demos/mouse/js/mouse.js +++ b/demos/mouse/js/mouse.js @@ -1,4 +1,6 @@ -Ox.load('UI', function() { +Ox.load('UI', { + debug: true +}, function() { var $target = Ox.Element() .css({ position: 'absolute', @@ -36,7 +38,7 @@ Ox.load('UI', function() { 'anyclick', 'singleclick', 'doubleclick', 'mouserepeat', 'dragstart', 'drag', 'dragpause', 'dragend' ].forEach(function(event) { - $target.bindEvent(event, function(foo, e) { + $target.bindEvent(event, function(e) { var date = new Date(); $('
') .html( diff --git a/docs/api.js b/docs/api.js index 82283587..030482e0 100644 --- a/docs/api.js +++ b/docs/api.js @@ -2,7 +2,7 @@ OxUI Documentation ***/ var app = {}; -$(function() { +Ox.load('UI', {debug: true}, function() { app.$body = $('body'); app.$document = $(document); app.$window = $(window); diff --git a/docs/index.html b/docs/index.html index ff67d375..f877ff95 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,11 +3,8 @@ oxjs API - - - - - + + diff --git a/source/Ox.UI/js/Calendar/Ox.Calendar.js b/source/Ox.UI/js/Calendar/Ox.Calendar.js index 48dfbc82..b3305904 100644 --- a/source/Ox.UI/js/Calendar/Ox.Calendar.js +++ b/source/Ox.UI/js/Calendar/Ox.Calendar.js @@ -1,4 +1,28 @@ // vim: et:ts=4:sw=4:sts=4:ft=js + +/*@ +Ox.Calendar Basic calendar object + () -> Calendar object + (options) -> Calendar object + (options, self) -> Calendar object + options Options object + date UTC Date on which the calendar is centered + dates <[o]|[]> Date objects to be displayed + end End of the event (UTC Date, as string) + name Name of the event + start Start of the event (UTC Date, as string) + type Type of the event (like "person") + height Height in px + range <[n]|[100, 5101]> Start and end year of the calendar + width Width in px + zoom Initial zoom level + self Shared private variable +@*/ + +// Fixme: switch to UTC +// Fixme: in options.dates, replace "stop" with "end" +// Fixme: create a variable-resolution date type (with end that is _inclusive_) + Ox.Calendar = function(options, self) { self = self || {}; @@ -6,9 +30,9 @@ Ox.Calendar = function(options, self) { .defaults({ date: new Date(), dates: [], - height: 512, - range: [100, 5101], - width: 512, + height: 256, + range: [1000, 3000], + width: 256, zoom: 8 }) .options(options || {}) diff --git a/source/Ox.UI/js/Core/Ox.Element.js b/source/Ox.UI/js/Core/Ox.Element.js index c8a879aa..00a2a47b 100644 --- a/source/Ox.UI/js/Core/Ox.Element.js +++ b/source/Ox.UI/js/Core/Ox.Element.js @@ -1,11 +1,67 @@ // vim: et:ts=4:sw=4:sts=4:ft=js // check out http://ejohn.org/apps/learn/#36 (-#38, making fns work w/o new) -Ox.Element = function() { +/*@ +Ox.Element Basic UI element object + # Usage -------------------------------------------------------------------- + ([options[, self]]) -> UI element + # Arguments ---------------------------------------------------------------- + options the options of the element + # Properties + element tagname or CSS selector + tooltip tooltip (not implemented) + options tagname or CSS selector + self shared private variable + # Properties --------------------------------------------------------------- + $element jQuery DOM object + bindEvent binds an event to a function, once + # Usage + (event, callback) -> this element + ({event: callback, ...}) -> this element + # Arguments + event event name + callback callback function + data event data + bindEventOnce binds an event to a function + defaults sets the default options + options sets the options + triggerEvent triggers an event + unbindEvent unbinds an event + # Events ------------------------------------------------------------------- + anyclick anyclick + fires on mouseup, but not on any subsequent mouseup within 250 ms + * <*> original event properties + doubleclick doubleclick + fires on the second mousedown within 250 ms + * <*> original event properties + drag drag + fires on mousemove after dragstart, stops firing on mouseup + clientDX horizontal drag delta in px + clientDY vertical drag delta in px + * <*> original event properties + dragend dragpause + Fires on mouseup after dragstart + clientDX horizontal drag delta in px + clientDY vertical drag delta in px + * <*> original event properties + dragpause dragpause + Fires once when the mouse doesn't move for 250 ms after drag + clientDX horizontal drag delta in px + clientDY vertical drag delta in px + * <*> original event properties + dragstart dragstart + fires when the mouse is down for 250 ms + * <*> original event properties + mouserepeat mouserepeat + fires every 50 ms after the mouse was down for 250 ms, stops firing on + mouseleave or mouseup + * <*> original event properties + singleclick singleclick + fires 250 ms after mouseup, if there was no subsequent mousedown + * <*> original event properties +@*/ - /*** - Basic element object - ***/ +Ox.Element = function() { /* tooltip option can be any of the following: @@ -137,7 +193,7 @@ Ox.Element = function() { that.triggerEvent('mouserepeat'); } function mouseup(e) { - // only trigger on firse mouseup + // only trigger on first mouseup if (!self.mouseup) { that.triggerEvent('anyclick', e); self.mouseup = true; @@ -173,19 +229,29 @@ Ox.Element = function() { that._self = self; // fixme: remove + /*@ + bindEvent Binds a function to an event + (event, callback) -> This element + ({event: callback, ...}) -> This element + callback Callback function + data event data (key/value pairs) + event Event name (can be namespaced, like "click.foo") + @*/ that.bindEvent = function() { - /*** - binds a function to an event triggered by this object - Usage - bindEvent(event, fn) - bindEvent({eventA: fnA, eventB: fnB, ...}) - ***/ Ox.forEach(Ox.makeObject(arguments), function(fn, event) { bind('bind', event, fn); }); return that; } + /*@ + bindEventOnce Binds a function to an event, once + (event, callback) -> This element + ({event: callback, ...}) -> This element + callback Callback function + data event data (key/value pairs) + event Event name (can be namespaced, like "click.foo") + @*/ that.bindEventOnce = function() { Ox.forEach(Ox.makeObject(arguments), function(fn, event) { bind('one', event, fn); @@ -193,6 +259,13 @@ Ox.Element = function() { return that; }; + /*@ + Sets the default options for an element object + ({key: value, ...}) -> + key the name of the default option + that the element object + value the value of the default option + @*/ that.defaults = function(defaults) { // sets the default options self.defaults = defaults; @@ -200,43 +273,54 @@ Ox.Element = function() { return that; }; + /*@ + Makes an element object gain focus + () -> that + that the element object + @*/ that.gainFocus = function() { - /*** - make this object gain focus - ***/ Ox.Focus.focus(that.id); return that; }; + /*@ + Returns true if an element object has focus + () -> hasFocus + hasFocus true if the element has focus + @*/ that.hasFocus = function() { - /*** - returns true if this object has focus - ***/ return Ox.Focus.focused() == that.id; }; + /*@ + Makes an element object lose focus + () -> that + that the element object + @*/ + that.loseFocus = function() { - /*** - make this object lose focus - ***/ Ox.Focus.blur(that.id); return that; }; + /*@ + .options() + Gets or sets the options of an element object + # Usage + () -> all options + (key) -> the value of option[key] + (key, value) -> this element + sets options[key] to value and calls self.setOption(key, value) + if the key/value pair was added or modified + ({key: value, ...}) -> this element + sets multiple options and calls self.setOption(key, value) + for every key/value pair that was added or modified + # Arguments + key the name of the option + value the value of the option + @*/ + that.options = function() { - /* - that.options() - returns self.options - that.options(key) - returns self.options.key - that.options(key, val) - sets self.options.key to val, calls self.setOption(key, val) - if the key has been added or its val has changed, returns that - that.options({keyA: valA, keyB: valB}) - sets self.options.keyA to valA and self.options.keyB to valB, - calls self.setOptions(key, val) for every key/value pair - that has been added or modified, returns that - */ return Ox.getset(self.options, arguments, self.setOption, that); }; diff --git a/source/Ox.UI/js/Core/Ox.JQueryElement.js b/source/Ox.UI/js/Core/Ox.JQueryElement.js index a80c0ecc..cd249b86 100644 --- a/source/Ox.UI/js/Core/Ox.JQueryElement.js +++ b/source/Ox.UI/js/Core/Ox.JQueryElement.js @@ -1,13 +1,20 @@ // vim: et:ts=4:sw=4:sts=4:ft=js -/*** -Basic jQuery element -***/ +/*@ +Ox.JQueryElement Wrapper for jQuery + # Usage + ($element) -> Wrapped jQuery DOM element + # Arguments + $element jQuery DOM Element +@*/ Ox.JQueryElement = function($element) { var that = this; + //@ Ox.JQueryElement.id Unique id that.id = Ox.uid(); + //@ Ox.JQueryElement.ox OxJS version that.ox = Ox.VERSION; + //@ Ox.JQueryElement.$element The jQuery DOM element that.$element = $element.data({ oxid: that.id }); @@ -15,6 +22,7 @@ Ox.JQueryElement = function($element) { return that; }; +// add all jQuery functions to the prototype of Ox.JQueryElement Ox.forEach($('
'), function(val, key) { if (Ox.isFunction(val)) { Ox.JQueryElement.prototype[key] = function() { @@ -31,7 +39,7 @@ Ox.forEach($('
'), function(val, key) { // if the $element of an ox object was returned // then return the ox object instead // so that we can do oxObj.jqFn().oxFn() - return ret.jquery && Ox.UI.elements[id = ret.data('oxid')] ? + return ret && ret.jquery && Ox.UI.elements[id = ret.data('oxid')] ? Ox.UI.elements[id] : ret; }; } diff --git a/source/Ox.UI/js/Core/Ox.Keyboard.js b/source/Ox.UI/js/Core/Ox.Keyboard.js index 65351cf9..144465f2 100644 --- a/source/Ox.UI/js/Core/Ox.Keyboard.js +++ b/source/Ox.UI/js/Core/Ox.Keyboard.js @@ -5,46 +5,7 @@ (function() { - var buffer = '', - // the dot notation ('0.numpad') makes the keyboard event ('key_0.numpad') - // namespaced, so that binding to 'key_0' will catch 'key_0.numpad' too - keyNames = { - 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', - // fixme: this is usually 91: window.left, 92: window.right, 93: select - 91: 'meta.left', 92: 'meta.right', 93: 'meta.right', - 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', 224: 'meta' - // see dojo, for ex. - }, - // meta comes last so that we can differentiate between - // alt_control_shift_meta.left and alt_control_shift_meta.right - modifierNames = { - altKey: 'alt', // Mac: option - ctrlKey: 'control', - shiftKey: 'shift', - metaKey: 'meta', // Mac: command - }, - resetTimeout, triggerTimeout; + var buffer = '', resetTimeout, triggerTimeout; /* Ox.UI.ready(function() { @@ -59,10 +20,10 @@ if ($element.length) { if ( ( - keyNames[event.keyCode] == 'up' && + Ox.KEYS[event.keyCode] == 'up' && $element[0].selectionStart + $element[0].selectionEnd == 0 ) || ( - keyNames[event.keyCode] == 'down' && + Ox.KEYS[event.keyCode] == 'down' && $element[0].selectionStart == $element.val().length && $element[0].selectionEnd == $element.val().length ) @@ -82,27 +43,41 @@ }); function keydown(event) { + var focused = Ox.Focus.focused(), key, - keyName = keyNames[event.keyCode] || '', + keyName = Ox.KEYS[event.keyCode] || '', + keyNames = keyName ? [keyName] : [], keyBasename = keyName.split('.')[0], - keys = keyName ? [keyName] : []; - Ox.forEach(modifierNames, function(v, k) { + ret = true; + + Ox.forEach(Ox.MODIFIER_KEYS, function(v, k) { // avoid pushing modifier twice if (event[k] && keyBasename != v) { - keys.splice(-1, 0, v); + keyNames.splice(-1, 0, v); } }); - key = keys.join('_'); - if (/^(shift_)?[a-z]$|^\d(\.numpad)?$|space/.test(key)) { + key = keyNames.join('_'); + if (focused !== null) { + Ox.UI.elements[focused].triggerEvent('key_' + key); + // prevent Chrome from going back in history, or scrolling + if ( + [ + 'backspace', 'down', 'left', 'right', 'space', 'up' + ].indexOf(keyBasename) > -1 && + !Ox.UI.elements[focused].hasClass('OxInput') + ) { + ret = false; + } + } + + if (/^[\w\d](\.numpad)?$|space/.test(key)) { // don't register leading spaces or trailing double spaces if (!(keyName == 'space' && (buffer == '' || / $/.test(buffer)))) { buffer += keyName == 'space' ? ' ' : keyBasename; - Ox.print('buffer', buffer) // clear the trigger timeout only if the key went into the buffer clearTimeout(triggerTimeout); triggerTimeout = setTimeout(function() { - Ox.print('buffer', buffer) focused !== null && Ox.UI.elements[focused].triggerEvent('keys', { keys: buffer }); @@ -114,16 +89,10 @@ resetTimeout = setTimeout(function() { buffer = ''; }, 1000); - if (focused !== null) { - Ox.UI.elements[focused].triggerEvent('key_' + key); - // prevent Chrome from going back in history, or scrolling - if ( - ['backspace', 'down', 'left', 'right', 'space', 'up'].indexOf(key) > -1 && - !Ox.UI.elements[focused].hasClass('OxInput') - ) { - return false; - } - } + + Ox.print(ret) + return ret; + } })(); diff --git a/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js b/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js index 67e2a669..f8739060 100644 --- a/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js +++ b/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js @@ -39,12 +39,11 @@ Ox.SyntaxHighlighter = function(options, self) { self.source = ''; self.tokens = Ox.tokenize(self.options.source); self.tokens.forEach(function(token, i) { - var classNames, tokenString; + var classNames; if ( !(self.options.stripComments && token.type == 'comment') ) { classNames = 'Ox' + Ox.toTitleCase(token.type); - tokenString = self.options.source.substr(self.cursor, token.length); if (token.type == 'whitespace') { if (isAfterLinebreak() && hasIrregularSpaces()) { classNames += ' OxLeading' @@ -53,7 +52,7 @@ Ox.SyntaxHighlighter = function(options, self) { } } self.source += '' + - encodeToken(tokenString, token.type) + ''; + encodeToken(token.source, token.type) + ''; } self.cursor += token.length; function isAfterLinebreak() { @@ -65,7 +64,7 @@ Ox.SyntaxHighlighter = function(options, self) { self.tokens[i + 1].type == 'linebreak'; } function hasIrregularSpaces() { - return tokenString.split('').reduce(function(prev, curr) { + return token.source.split('').reduce(function(prev, curr) { return prev + (curr == ' ' ? 1 : 0); }, 0) % self.options.tabLength; } @@ -108,24 +107,24 @@ Ox.SyntaxHighlighter = function(options, self) { .html(self.source) .appendTo(that); - function encodeToken(str, type) { + function encodeToken(source, type) { var linebreak = '
', tab = Ox.repeat(' ', self.options.tabLength); if (self.options.showLinebreaks) { if (type == 'linebreak') { - linebreak = '¶' + linebreak; + linebreak = '\u21A9' + linebreak; } else { - linebreak = '' + linebreak; + linebreak = '\u21A9' + linebreak; } } if (self.options.showTabs) { tab = '\u2192' + tab.substr(6) + ''; } - str = Ox.encodeHTML(str) + source = Ox.encodeHTML(source) .replace(/ /g, ' ') .replace(/\t/g, tab) .replace(/\n/g, linebreak); - return str; + return source; } self.setOption = function() { diff --git a/source/Ox.UI/js/List/Ox.List.js b/source/Ox.UI/js/List/Ox.List.js index cbe48e6b..8b20bdd6 100644 --- a/source/Ox.UI/js/List/Ox.List.js +++ b/source/Ox.UI/js/List/Ox.List.js @@ -1,4 +1,14 @@ // vim: et:ts=4:sw=4:sts=4:ft=js + +/*@ +Basic list object +(options) -> that +(options, self) -> that +options the list's options +self shared private variable +@*/ + + Ox.List = function(options, self) { /*** @@ -17,23 +27,26 @@ Ox.List = function(options, self) { var self = self || {}, that = new Ox.Container({}, self) .defaults({ - centered: false, - construct: null, - draggable: false, - format: [], - itemHeight: 16, - items: null, - itemWidth: 16, - keys: [], - max: -1, - min: 0, - orientation: 'vertical', - pageLength: 100, - selected: [], - sort: [], - sortable: false, - type: 'text', - unique: '' + centered: false, //@ if true, and orientation is 'horizontal', + //@ then keep the selected item centered + construct: null, //@ (data) returns the list item HTML + draggable: false, //@ true if the items can be reordered + format: [], //@ ??? + itemHeight: 16, //@ item height + items: null, //@ list items + //@ (data) returns {items, size, ...} + //@ (data, callback) returns [items] + itemWidth: 16, //@ item width + keys: [], //@ keys of the list items + max: -1, //@ max number of items that can be selected + min: 0, //@ min number of items that must be selected + orientation: 'vertical', //@ 'horizontal' or 'vertical' + pageLength: 100, //@ number of items per page + selected: [], //@ ids of the selected elements + sort: [], //@ + sortable: false, //@ + type: 'text', //@ + unique: '' //@ name of the key that acts as unique id }) .options(options || {}) .scroll(scroll); diff --git a/source/Ox.UI/js/Map/Ox.Map.js b/source/Ox.UI/js/Map/Ox.Map.js index 0c6b0408..02938071 100644 --- a/source/Ox.UI/js/Map/Ox.Map.js +++ b/source/Ox.UI/js/Map/Ox.Map.js @@ -1,5 +1,89 @@ // vim: et:ts=4:sw=4:sts=4:ft=js +/*@ +Ox.Map Basic map object + # DESCRIPTION -------------------------------------------------------------- + Ox.Map is a wrapper around the + Google + Maps API. + # USAGE -------------------------------------------------------------------- + () -> Map object + (options) -> Map object + (options, self) -> Map object + # ARGUMENTS ---------------------------------------------------------------- + options options + clickable If true, clicking on the map finds a place + editable If true, places are editable + findPlaceholder Placeholder text for the find input element + labels If true, show labels on the map + markers Maximum number of markers to be displayed + places <[o]|[]> Array of place objects + countryCode ISO 3166 country code + east Longitude of the eastern boundary in degrees + editable If true, the place is editable + geoname Geoname (like "Paris, Île-de-France, France") + lat Latitude in degrees + lng Longitude in degrees + markerColor CSS color of the place marker + markerSize size of the place marker in px + name Name (like "Paris") + north Latitude of the northern boundary in degrees + south Latitude of the southern boundary in degrees + type Type (like "city" or "country") + west Longitude of the western boundary in degrees + selected Id of the selected place + statusbar If true, the map has a statusbar + toolbar If true, the map has a toolbar + self Shared private variable + # EVENTS ------------------------------------------------------------------- + addplace Fires when a place has been added + place Place object + editplace Fires when a place has been edited + place Place object + geocode Fires when a google geocode request returns + latLng Query coordinates, or undefined + lat latitude + lng longitude + address Query string, or undefined + results <[o]> Google Maps geocode results + address_components <[o]> Address components + long_name Long name + short_name Short name + types <[s]> Types (like "country" or "political") + formatted_address Formatted address + geometry Geometry + bounds Bounds + northEast North-east corner + lat Latitude + lng Longitude + southWest South-west corner + lat Latitude + lng Longitude + location Location + lat Latitude + lng Longitude + location_type Location type (like "APPROXIMATE") + viewport Viewport + northEast North-east corner + lat Latitude + lng Longitude + southWest South-west corner + lat Latitude + lng Longitude + types <[s]> Types (like "country" or "political") + # EXAMPLES ----------------------------------------------------------------- + + > Ox.Map() === true + false + > Ox.Map() === false + false +@*/ + Ox.Map = function(options, self) { self = self || {}; diff --git a/source/Ox.js b/source/Ox.js index f25e1312..e36c0819 100644 --- a/source/Ox.js +++ b/source/Ox.js @@ -1,6 +1,16 @@ // vim: et:ts=4:sw=4:sts=4:ft=js // todo: check http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ +// also see https://github.com/tlrobinson/narwhal/blob/master/lib/util.js + + +/*@ +Ox The Ox object + See Ox.wrap for details. + (value) -> wrapped value + value <*> any value +@*/ + Ox = function(val) { return Ox.wrap(val); }; @@ -11,48 +21,77 @@ Constants ================================================================================ */ +//@ Ox.AMPM <[str]> ['AM', 'PM'] Ox.AMPM = ['AM', 'PM']; -//Ox.DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; +//@ Ox.DURATIONS <[str]> ['year', 'month', 'day', 'minute', 'second'] Ox.DURATIONS = ['year', 'month', 'day', 'minute', 'second']; +//@ Ox.EARTH_RADIUS Radius of the earth in meters Ox.EARTH_RADIUS = 6378137; +//@ Ox.EARTH_CIRCUMFERENCE Circumference of the earth in meters Ox.EARTH_CIRCUMFERENCE = Ox.EARTH_RADIUS * 2 * Math.PI; +//@ Ox.HTML_ENTITIES HTML entities for ... (FIXME) Ox.HTML_ENTITIES = { '"': '"', '&': '&', "'": ''', '<': '<', '>': '>' }; +//@ Ox.KEYS Names for key codes +// the dot notation ('0.numpad') allows for namespaced events ('key_0.numpad'), +// so that binding to 'key_0' will catch 'key0.numpad' too Ox.KEYS = { - SECTION: 0, BACKSPACE: 8, TAB: 9, CLEAR: 12, ENTER: 13, - SHIFT: 16, CONTROL: 17, OPTION: 18, PAUSE: 19, CAPSLOCK: 20, - ESCAPE: 27, SPACE: 32, PAGEUP: 33, PAGEDOWN: 34, END: 35, HOME: 36, - LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, INSERT: 45, DELETE: 46, HELP: 47, - 0: 48, 1: 49, 2: 50, 3: 51, 4: 52, 5: 53, 6: 54, 7: 55, 8: 56, 9: 57, - A: 65, B: 66, C: 67, D: 68, E: 69, F: 70, G: 71, H: 72, I: 73, J: 74, - K: 75, L: 76, M: 77, N: 78, O: 79, P: 80, Q: 81, R: 82, S: 83, T: 84, - U: 85, V: 86, W: 87, X: 88, Y: 89, Z: 90, - META_LEFT: 91, META_RIGHT: 92, SELECT: 93, - '0_NUMPAD': 96, '1_NUMPAD': 97, '2_NUMPAD': 98, '3_NUMPAD': 99, - '4_NUMPAD': 100, '5_NUMPAD': 101, '6_NUMPAD': 102, '7_NUMPAD': 103, - '8_NUMPAD': 104, '9_NUMPAD': 105, '*_NUMPAD': 106, '+_NUMPAD': 107, - '\n_NUMPAD': 108, '-_NUMPAD': 109, '._NUMPAD': 110, '/_NUMPAD': 111, - F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, - F8: 110, F9: 120, F10: 121, F11: 122, F12: 123, F13: 124, F14: 125, - F15: 126, F16: 127, NUMLOCK: 144, SCROLLLOCK: 145, - ';': 186, '=': 187, ',': 188, '-': 189, '.': 190, '/': 191, '`': 192, - '(': 219, '\\': 220, ')': 221, '\'': 222 -}; -Ox.MAP_TILE_SIZE = 256; + 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', + // fixme: this is usually 91: window.left, 92: window.right, 93: select + 91: 'meta.left', 92: 'meta.right', 93: 'meta.right', + 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', 224: 'meta' + // see dojo, for ex. +}, +Ox.MAP_TILE_SIZE = 256; // fixme: definitely not needed here +//@ Ox.MODIFIER_KEYS Names for modifier keys +// meta comes last so that one can differentiate between +// alt_control_shift_meta.left and alt_control_shift_meta.right +Ox.MODIFIER_KEYS = { + altKey: 'alt', // Mac: option + ctrlKey: 'control', + shiftKey: 'shift', + metaKey: 'meta', // Mac: command +} +//@ Ox.MONTHS <[str]> Names of months Ox.MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; +//@ Ox.SHORT_MONTHS <[str]> Short names of months Ox.SHORT_MONTHS = Ox.MONTHS.map(function(val) { return val.substr(0, 3); }); +//@ Ox.PATH Path of Ox.js Ox.PATH = Array.prototype.slice.apply( document.getElementsByTagName('script') ).filter(function(element) { return /Ox\.js$/.test(element.src); })[0].src.replace('Ox.js', ''); +//@ Ox.PREFIXES ['K', 'M', 'G', 'T', 'P'] Ox.PREFIXES = ['K', 'M', 'G', 'T', 'P']; +//@ Ox.SYMBOLS Unicode characters for symbols Ox.SYMBOLS = { DOLLAR: '\u0024', CENT: '\u00A2', POUND: '\u00A3', CURRENCY: '\u00A4', YEN: '\u00A5', @@ -78,15 +117,18 @@ Ox.SYMBOLS = { CLOSE: '\u2715', BALLOT: '\u2717', WINDOWS: '\u2756', EDIT: '\uF802', CLICK: '\uF803', APPLE: '\uF8FF' }; -// local timezone offset in milliseconds +//@ Ox.TYPES <[str]> list of types, as returned by Ox.type() Ox.TYPES = [ 'Arguments', 'Array', 'Boolean', 'Date', 'Element', 'Function', 'Infinity', 'NaN', 'Null', 'Number', 'Object', 'RegExp', 'String', 'Undefined' ]; +//@ Ox.VERSION OxJS version number Ox.VERSION = '0.1.2'; +//@ Ox.WEEKDAYS <[str]> Names of weekdays Ox.WEEKDAYS = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]; +//@ Ox.SHORT_WEEKDAYS <[str]> Short names of weekdays Ox.SHORT_WEEKDAYS = Ox.WEEKDAYS.map(function(val) { return val.substr(0, 3); }); @@ -97,36 +139,268 @@ Core functions ================================================================================ */ +/*@ +Ox.doc Generates documentation for annotated JavaScript + (source) Array of documentation objects + source JavaScript source code + > Ox.doc("//@ Ox.foo bar") + [{"name": "Ox.foo", "summary": "bar", "type": "string"}] +@*/ + +Ox.doc = (function() { + var re = { + item: /^(.+) <(.+)> (.+)$/, + multiline: /^\/\*\@.*?\n([\w\W]+)\n.*?\@\*\/$/, + script: /\n(\s* + > object.options("key", "val").options("key") + "val" + > object.options({foo: "foo", bar: "bar"}).options() + {"key": "val", "foo": "foo", "bar": "bar"} +@*/ + Ox.getset = function(obj, args, callback, context) { - /*** - Generic getter and setter function - - can be implemented like this: - - that.options = function() { - return Ox.getset(options, arguments, setOption(key, val), that); - } - - Ox.getset(obj, []) returns obj - Ox.getset(obj, [key]) returns obj.key - Ox.getset(obj, [key, val], callback, context) - Ox.getset(obj, [{key: val, ...}], callback, context) sets obj.key to val, - calls callback(key, val) - for each changed value, - returns context - (for chaining) - - >>> o = new function() { var o = {}, s = function() {}, t = this; t.o = function() { return Ox['getset'](o, arguments, s, t); }; return t; } - true - >>> Ox.getset({}, []) && o.o('key', 'val').o('key') - 'val' - >>> Ox.getset({}, []) && o.o({key: 'val', foo: 'bar'}).o().foo - 'bar' - >>> Ox.getset({}, []) && typeof o.o({foo: undefined}).o('foo') == 'undefined' - true - >>> delete o - true - ***/ var obj_ = Ox.clone(obj), ret; if (args.length == 0) { // getset([]) @@ -137,7 +411,6 @@ Ox.getset = function(obj, args, callback, context) { } else { // getset([key, val]) or getset([{key: val, ...}]) args = Ox.makeObject(args); - // args = Ox.makeObject(Ox.isObject(args[0]) ? args[0] : args); obj = Ox.extend(obj, args); Ox.forEach(args, function(val, key) { if (!obj_ || !Ox.isEqual(obj_[key], val)) { @@ -149,11 +422,20 @@ Ox.getset = function(obj, args, callback, context) { return ret; } +/*@ +Ox.load Loads a module + (module, callback) -> undefined + (module, options, callback) -> undefined + module Module name + options Module options + callback Callback function + success If true, the module has been loaded successfully +@*/ + Ox.load = function(module, options, callback) { - /*** - loads Ox modules - fixme: no way to load multiple modules - ***/ + // fixme: no way to load multiple modules + // problem: where do multiple options go? + // [{name: "", options: {}}, {name: "", options: {}}] isn't pretty callback = arguments[arguments.length - 1]; options = arguments.length == 3 ? arguments[1] : {}; Ox.loadFile(Ox.PATH + 'Ox.' + module + '/Ox.' + module + '.js', function() { @@ -161,16 +443,29 @@ Ox.load = function(module, options, callback) { }); }; +/*@ +Ox.loadFile Loads a file (image, script or stylesheet) + (file="script.js", callback) -> undefined + (file="stylesheet.css", callback) -> undefined + (file="image.png", callback) -> DOM element + file Local path or remote URL + callback Callback function +@*/ + Ox.loadFile = (function() { - /*** - loads stylesheets, scripts and images - ***/ + // fixme: this doesn't handle errors yet var cache = {}; return function (file, callback) { - var element, request, + var element, + request, type = file.split('.').pop(); + isImage = type != 'css' && type != 'js'; if (!cache[file]) { - if (type == 'css' || type == 'js') { + if (isImage) { + element = new Image(); + element.onload = addFileToCache; + element.src = file; + } else { if (!findFileInHead()) { element = document.createElement(type == 'css' ? 'link' : 'script'); element[type == 'css' ? 'href' : 'src'] = file; @@ -185,22 +480,19 @@ Ox.loadFile = (function() { } else { addFileToCache(); } - } else { - element = new Image(); - element.onload = addFileToCache; - element.src = file; } } else { callback(); } function addFileToCache() { - //type == 'svg' && Ox.print('addToCache', file) - if (type == 'css' || type == 'js') { - cache['file'] = true; - callback(); - } else { + if (isImage) { + // for an image, save the element itself, + // so that it remains in the browser cache cache['file'] = element; callback(element); + } else { + cache['file'] = true; + callback(); } } function findFileInHead() { @@ -227,25 +519,17 @@ Ox.loadFile = (function() { }; }()); -Ox.loadJSON = function(url, callback) { - var req = new XMLHttpRequest(); - req.open('GET', url, true); - req.onreadystatechange = function() { - if (req.readyState == 4) { - if (req.status == 200) { - callback(JSON.parse(req.responseText)); - } else { - throw new Error('URL ' + url + ', status ' + req.status); - } - } - }; - req.send(); -}; +/*@ +Ox.print Prints its arguments to the console + (arg, ...) -> String + The string contains the timestamp, the name of the caller function, and + any arguments, separated by spaces + arg <*> any value + > Ox.print("foo").substr(-3) + "foo" +@*/ Ox.print = function() { - /* - like console.log, but prepends timestamp and name of the caller function - */ if (window.console) { var args = Ox.makeArray(arguments), date = new Date(); @@ -255,27 +539,39 @@ Ox.print = function() { ); window.console.log.apply(window.console, args); } + return args.join(' '); }; -Ox.uid = (function() { - /*** - returns a unique id - >>> Ox.uid() != Ox.uid() +/*@ +Ox.uid Returns a unique id + () -> Unique id + > Ox.uid() != Ox.uid() true - ***/ +@*/ +Ox.uid = (function() { var uid = 0; return function() { return uid++; }; }()); +/*@ +Ox.wrap Wraps a value so that one can directly call any Ox function on it + Additionally, chain() allows for chaining, and value() returns the + original value. See examples for details. + (value) -> wrapped value + chain wrap the return value to allow chaining + value unwrap the value wrapped by chain() + value <*> any value + > Ox.wrap("foobar").repeat(2) + "foobarfoobar" + > Ox.wrap("foobar").chain().reverse().toTitleCase().value() + "Raboof" + > Ox.wrap("foobar").value() + "foobar" +@*/ + Ox.wrap = function(val, chained) { - /*** - >>> Ox.wrap('foobar').reverse() - 'raboof' - >>> Ox.wrap('foobar').chain().reverse().reverse().value() - 'foobar' - ***/ var wrapper = { chain: function() { wrapper.chained = true; @@ -845,6 +1141,7 @@ Ox.sum = function(obj) { }; Ox.toArray = function(obj) { + // fixme: can this be thrown out? /* >>> Ox.toArray('foo') ['foo'] @@ -1027,14 +1324,26 @@ Date functions ================================================================================ */ +/*@ +Ox.getDateInWeek Get the date that falls on a given weekday in the same week + # Usage + (date, weekday) -> Date + (date, weekday, utc) -> UTC Date + # Arguments + date Date + weekday 1-7 (Monday-Sunday) or name, full ("Monday") or short ("Sun") + utc if true, all dates are UTC + # Examples + > Ox.formatDate(Ox.getDateInWeek(new Date("January 1 2000"), "Sunday"), "%A, %B %e, %Y") + "Sunday, January 2, 2000" + > Ox.formatDate(Ox.getDateInWeek(new Date("Jan 1 2000"), "Fri"), "%A, %B %e, %Y") + "Friday, December 31, 1999" + > Ox.formatDate(Ox.getDateInWeek(new Date("1/1/2000"), 1), "%A, %B %e, %Y") + "Monday, December 27, 1999" +@*/ + Ox.getDateInWeek = function(date, weekday, utc) { /* - >>> Ox.formatDate(Ox.getDateInWeek(new Date("January 1 2000"), "Sunday"), "%A, %B %e, %Y") - "Sunday, January 2, 2000" - >>> Ox.formatDate(Ox.getDateInWeek(new Date("Jan 1 2000"), "Fri"), "%A, %B %e, %Y") - "Friday, December 31, 1999" - >>> Ox.formatDate(Ox.getDateInWeek(new Date("1/1/2000"), 1), "%A, %B %e, %Y") - "Monday, December 27, 1999" */ date = Ox.makeDate(date); Ox.print(date, Ox.getDate(date, utc), Ox.formatDate(date, '%u', utc), date) @@ -1241,6 +1550,19 @@ DOM functions ================================================================================ */ +/*@ +Ox.canvas Generic canvas object + Returns an object with the properties: canvas, + context, data and imageData. + # Usage -------------------------------------------------------------------- + Ox.canvas(width, height) -> canvas + Ox.canvas(image) -> canvas + # Arguments ---------------------------------------------------------------- + width Width in px + height Height in px + image Image object +@*/ + Ox.canvas = function() { // Ox.canvas(img) or Ox.canvas(width, height) var c = {}, isImage = arguments.length == 1, @@ -1257,6 +1579,11 @@ Ox.canvas = function() { return c; }; +/*@ +Ox.documentReady Calls a callback function once the DOM is ready + (callback) -> If true, the document was ready + callback Callback function +@*/ Ox.documentReady = (function() { var callbacks = []; document.onreadystatechange = function() { @@ -1270,42 +1597,72 @@ Ox.documentReady = (function() { }; return function(callback) { if (document.readyState == 'complete') { - //Ox.print('document is ready') callback(); + return true; } else { callbacks.push(callback); - //Ox.print('document is not ready', callbacks) + return false; } } }()); +/*@ +Ox.Element Generic HTML element, mimics jQuery + (str) -> Element object + str Tagname ('') or selector ('tagname', '.classname', '#id') + > Ox.element("
").addClass("red").addClass("red")[0].classname + "red" + > Ox.element("
").attr({id: "red"}).attr("id") + "red" + > Ox.element("
").css("color", "red").css("color") + "red" + > Ox.element("
").html("red").html() + "red" +@*/ Ox.element = function(str) { - /* - Generic HTML element, mimics jQuery - >>> Ox.element('div').attr({id: 'foo'}).attr('id') - 'foo' - >>> Ox.element('div').css('color', 'red').css('color') - 'red' - >>> Ox.element('div').html('foo').html() - 'foo' - */ return { + //@ 0 The DOM element itself 0: str[0] == '<' ? document.createElement(str.substr(1, str.length - 2)) : str[0] == '.' ? document.getElementsByClassName(str.substr(1))[0] : str[0] == '#' ? document.getElementById(str.substr(1)) : document.getElementsByTagName(str)[0], + /*@ + addClass Adds a class name + (className) -> This element + className Class name + @*/ addClass: function(str) { - this[0].className += (this[0].className ? ' ' : '') + str; + this[0].className = this[0].className ? Ox.unique( + (this[0].className + ' ' + str).split(' ') + ) : str; return this; }, + /*@ + append() Appends another element to this element + (element) -> This element + element Another element + @*/ append: function(element) { this[0].appendChild(element[0]); return this; }, + /*@ + appendTo appends this element object to another element object + (element) -> This element + element Another element + @*/ appendTo: function(element) { element[0].appendChild(this[0]); return this; }, + /*@ + attr Gets or sets an attribute + (key) -> Value + (key, value) -> This element + ({key, value}) -> This element + key Attribute name + value Attribute value + @*/ attr: function() { var ret, that = this; if (arguments.length == 1 && Ox.isString(arguments[0])) { @@ -1318,6 +1675,14 @@ Ox.element = function(str) { } return ret; }, + /*@ + css Gets or sets a CSS attribute + (key) -> Value + (key, value) -> This element + ({key, value}) -> This element + key Attribute name + value Attribute value + @*/ css: function() { var ret, that = this; if (arguments.length == 1 && Ox.isString(arguments[0])) { @@ -1330,6 +1695,12 @@ Ox.element = function(str) { } return ret; }, + /*@ + html Gets or sets the inner HTML + () -> The inner HTML + (html) -> This element + html The inner HTML + @*/ html: function(str) { var ret; if (Ox.isUndefined(str)) { @@ -1340,8 +1711,27 @@ Ox.element = function(str) { } return ret; }, - mousedown: function(fn) { - this[0].onmousedown = fn; + /*@ + mousedown Binds a function to the mousedown event + (callback) -> This element + callback Callback function + event The DOM event + @*/ + mousedown: function(callback) { + this[0].onmousedown = callback; + return this; + }, + /*@ + removeClass Removes a class name + (className) -> This element + className Class name + @*/ + removeClass: function(str) { + this[0].className = Ox.filter( + this[0].className.split(' '), function(className) { + return className != str; + } + ).join(' '); return this; } } @@ -1429,7 +1819,7 @@ Encoding functions >>> Ox.encodeBase64(32394) 'foo' */ - return btoa(Ox.encodeBase256(num)).replace(/=/g, ""); + return btoa(Ox.encodeBase256(num)).replace(/=/g, ''); } Ox.decodeBase64 = function(str) { @@ -1555,7 +1945,6 @@ Encoding functions // relies on dom, but shorter than using this: // http://www.w3.org/TR/html5/named-character-references.html return Ox.element('
').html(str)[0].childNodes[0].nodeValue; - //return $('
').html(str)[0].childNodes[0].nodeValue; }; Ox.encodePNG = function(img, str) { @@ -2334,9 +2723,10 @@ Ox.parseHTML = (function() { '<script>alert()</script>' */ var defaultTags = [ - 'a', 'b', 'blockquote', 'cite', 'code', 'del', - 'em', 'i', 'img', 'ins', 'li', 'ol', 'q', 'rtl', - 's', 'strong', 'sub', 'sup', 'ul', '[]' + 'a', 'b', 'blockquote', 'cite', 'code', + 'del', 'em', 'i', 'img', 'ins', + 'li', 'ol', 'q', 'rtl', 's', + 'strong', 'sub', 'sup', 'ul', '[]' ], parse = { a: { @@ -2687,6 +3077,7 @@ Ox.startsWith = function(str, sub) { // fixme: // !!(/^sub/(str)) is shorter than // Ox.startsWith(str, sub) anyway + // new RegExp('^' + sub).test(str) is longer though... */ return new RegExp('^' + sub).test(str); }; @@ -2983,7 +3374,7 @@ Ox.tokenize = (function() { } tokenize[type](); tokens.push({ - length: cursor - start, + source: source.substr(start, cursor - start), type: type, }); } @@ -3009,7 +3400,6 @@ Ox.tokenize = (function() { } else { prevToken = tokens[index]; prevString = source.substr(cursor - prevToken.length - offset, prevToken.length); - Ox.print('forward slash |', prevToken, prevToken.type, '"'+prevString+'"'); isRegExp = ( prevToken.type == 'keyword' && ['false', 'null', 'true'].indexOf(prevString) == -1 @@ -3098,16 +3488,16 @@ Ox.truncate = function(str, len, pad, pos) { Ox.words = function(str) { /* - >>> Ox.words('He\'s referring to the "ill-conceived" AOL/TimeWarner merger--didn\'t you know?') - ['he\'s', 'referring', 'to' , 'the' , 'ill-conceived' , 'aol', 'timewarner' , 'merger' , 'didn\'t', 'you', 'know'] + > Ox.words("The key/value pairs are read-only--aren't they?") + ["the", "key", "value", "pairs", "are", "read-only", "aren't", "they"] */ var arr = str.toLowerCase().split(/\b/), chr = "-'", len = arr.length, startsWithWord = !!/\w/(arr[0]); arr.forEach(function(v, i) { - // find single occurrences of chars in chr - // that are not at the beginning or end of str + // find single occurrences of "-" or "-" + // that are not at the beginning or end of the string // and join the surrounding words with them if ( i > 0 && i < len - 1 && @@ -3320,46 +3710,55 @@ Ox.isString = function(val) { return typeof val == 'string'; }; +/*@ +Ox.isUndefined Tests if a value is undefined + (value) -> If true, the value is undefined + value <*> any value + > Ox.isUndefined() + true +@*/ + Ox.isUndefined = function(val) { // fixme: void 0 is also nice - /* - >>> Ox.isUndefined() - true - */ return typeof val == 'undefined'; }; +/*@ +Ox.typeOf Returns the type of a value + (value) -> type + value <*> Any value + # Examples + > (function() { return Ox.typeOf(arguments); }()) + "arguments" + > Ox.typeOf([]) + "array" + > Ox.typeOf(false) + "boolean" + > Ox.typeOf(new Date()) + "date" + > Ox.typeOf(document.createElement()) + "element" + > Ox.typeOf(function() {}) + "function" + > Ox.typeOf(Infinity) + "infinity" + > Ox.typeOf(NaN) + "nan" + > Ox.typeOf(null) + "null" + > Ox.typeOf(0) + "number" + > Ox.typeOf({}) + "object" + > Ox.typeOf(/ /) + "regexp" + > Ox.typeOf('') + "string" + > Ox.typeOf() + "undefined" +@*/ + Ox.typeOf = function(val) { - /* - >>> (function() { return Ox.typeOf(arguments); }()) - 'arguments' - >>> Ox.typeOf([]) - 'array' - >>> Ox.typeOf(false) - 'boolean' - >>> Ox.typeOf(new Date()) - 'date' - >>> Ox.typeOf(document.createElement()) - 'element' - >>> Ox.typeOf(function() {}) - 'function' - >>> Ox.typeOf(Infinity) - 'infinity' - >>> Ox.typeOf(NaN) - 'nan' - >>> Ox.typeOf(null) - 'null' - >>> Ox.typeOf(0) - 'number' - >>> Ox.typeOf({}) - 'object' - >>> Ox.typeOf(/ /) - 'regexp' - >>> Ox.typeOf('') - 'string' - >>> Ox.typeOf() - 'undefined' - */ var ret; Ox.forEach(Ox.TYPES, function(type) { if (Ox['is' + type](val)) {