')
.css({paddingLeft: ((level * 32) + 'px')})
.html(
- '
' + item.name + ' ' +
+ '' + (name || item.name) + ' ' +
'<' + item.types.join('> or <') + '> ' +
+ (item.default ? 'default: ' + item.default + ' ' : '') +
Ox.parseHTML(item.summary)
)
];
@@ -89,7 +88,6 @@ Ox.DocPage = function(options, self) {
.html(
'> ' +
Ox.encodeHTML(example.statement)
- //example.statement
.replace(/ /g, ' ')
.replace(/\n/g, '
\n ') +
''
@@ -120,12 +118,11 @@ Ox.DocPage = function(options, self) {
);
} else {
item[section].forEach(function(v) {
- if (section == 'usage') {
- v.name = item.name + v.name + ' returns
';
- }
+ var name = section == 'usage' ?
+ item.name + v.name + ' returns
' : null;
$elements = Ox.merge(
$elements,
- Ox.map(getItem(v, level + 1), function($element) {
+ Ox.map(getItem(v, level + 1, name), function($element) {
return $element.addClass(className);
})
);
diff --git a/source/Ox.UI/js/Core/Ox.DocPanel.js b/source/Ox.UI/js/Core/Ox.DocPanel.js
new file mode 100644
index 00000000..5ff597ca
--- /dev/null
+++ b/source/Ox.UI/js/Core/Ox.DocPanel.js
@@ -0,0 +1,132 @@
+/*@
+Ox.DocPanel Documentation Panel
+@*/
+
+Ox.DocPanel = function(options, self) {
+
+ self = self || {};
+ var that = Ox.Element({}, self)
+ .defaults({
+ collapsible: true,
+ files: [],
+ getModule: function(item) {
+ return item.file.replace(self.options.path, '');
+ },
+ getSection: function(item) {
+ return item.section;
+ },
+ path: '',
+ resizable: true,
+ resize: [128, 256, 384],
+ size: 256
+ })
+ .options(options || {});
+
+ self.$list = Ox.Element();
+ self.$page = Ox.Element();
+
+ that.$element = Ox.SplitPanel({
+ elements: [
+ {
+ collapsible: self.options.collapsible,
+ element: self.$list,
+ resizable: self.options.resizable,
+ resize: self.options.resize,
+ size: self.options.size
+ },
+ {
+ element: self.$page
+ }
+ ],
+ orientation: 'horizontal'
+ });
+
+ loadList(function(docItems) {
+ self.items = docItems;
+ });
+
+ function loadList(callback) {
+ var counter = 0,
+ length = self.options.files.length;
+ docItems = [];
+ self.options.files.forEach(function(file) {
+ Ox.doc(self.options.path + file, function(fileItems) {
+ docItems = Ox.merge(docItems, fileItems);
+ if (++counter == length) {
+ makeTree(docItems);
+ callback(docItems);
+ }
+ });
+ });
+ function makeTree(docItems) {
+ var treeItems = [];
+ docItems.forEach(function(docItem) {
+ var moduleIndex, sectionIndex;
+ docItem.module = self.options.getModule(docItem);
+ moduleIndex = Ox.getPositionById(treeItems, '_' + docItem.module);
+ if (moduleIndex == -1) {
+ treeItems.push({
+ id: '_' + docItem.module,
+ items: [],
+ title: docItem.module
+ });
+ moduleIndex = treeItems.length - 1;
+ }
+ docItem.section = self.options.getSection(docItem);
+ if (docItem.section) {
+ sectionIndex = Ox.getPositionById(
+ treeItems[moduleIndex].items, '_' + docItem.section
+ );
+ if (sectionIndex == -1) {
+ treeItems[moduleIndex].items.push({
+ id: '_' + docItem.section,
+ items: [],
+ title: docItem.section
+ });
+ sectionIndex = treeItems[moduleIndex].items.length - 1;
+ }
+ }
+ (
+ docItem.section ?
+ treeItems[moduleIndex].items[sectionIndex] :
+ treeItems[moduleIndex]
+ ).items.push({
+ id: docItem.name,
+ title: docItem.name
+ });
+ });
+ self.$list = Ox.TreeList({
+ items: treeItems,
+ width: self.options.width
+ })
+ .bindEvent({
+ select: selectItem
+ });
+ that.$element.replaceElement(0, self.$list);
+ }
+ }
+
+ function getItemByName(name) {
+ var item = {};
+ Ox.forEach(self.items, function(v) {
+ if (v.name == name) {
+ item = v;
+ return false;
+ }
+ });
+ return item;
+ }
+
+ function selectItem(data) {
+ var selected = data.ids[0];
+ if (selected[0] != '_') {
+ self.$page = Ox.DocPage({
+ item: getItemByName(selected)
+ });
+ that.$element.replaceElement(1, self.$page);
+ }
+ }
+
+ return that;
+
+};
\ No newline at end of file
diff --git a/source/Ox.UI/js/Core/Ox.Theme.js b/source/Ox.UI/js/Core/Ox.Theme.js
index a04e3aaa..31b228f4 100644
--- a/source/Ox.UI/js/Core/Ox.Theme.js
+++ b/source/Ox.UI/js/Core/Ox.Theme.js
@@ -22,7 +22,6 @@ Ox.Theme = function(theme) {
return false;
}
});
- Ox.print('getTheme', theme)
return theme;
}
diff --git a/source/Ox.UI/js/List/Ox.TreeList.js b/source/Ox.UI/js/List/Ox.TreeList.js
index 6a270679..d5920b8d 100644
--- a/source/Ox.UI/js/List/Ox.TreeList.js
+++ b/source/Ox.UI/js/List/Ox.TreeList.js
@@ -156,7 +156,7 @@ Ox.TreeList = function(options, self) {
}
function toggleItem(item, expanded) {
- var $img, $item, pos;
+ var $img, pos;
item.expanded = expanded;
$.each(that.$element.find('.OxItem'), function(i, v) {
var $item = $(v);
@@ -166,12 +166,23 @@ Ox.TreeList = function(options, self) {
return false;
}
});
- Ox.print('i.e', item.expanded)
+ Ox.print('i.e', item.expanded, $img, $img.attr('src'));
+ // FIXME: why does this not work??
+ ///*
$img.attr({
src: Ox.UI.getImagePath(
'symbol' + (item.expanded ? 'Down' : 'Right') + '.svg'
)
});
+ //*/
+ /*
+ Ox.print($img.attr('src'))
+ $img.attr({
+ src: $img.attr('src') == Ox.UI.getImagePath('symbolDown.svg') ?
+ Ox.UI.getImagePath('symbolRight.svg') :
+ Ox.UI.getImagePath('symbolDown.svg')
+ });
+ */
item.expanded ?
that.$element.addItems(pos + 1, parseItems(item.items, item.level + 1)) :
that.$element.removeItems(pos + 1, parseItems(item.items, item.level + 1).length);
diff --git a/source/Ox.js b/source/Ox.js
index a5e182e5..e440933d 100644
--- a/source/Ox.js
+++ b/source/Ox.js
@@ -1,10 +1,11 @@
// vim: et:ts=4:sw=4:sts=4:ft=js
-// OxJS (c) 2007-2011 Ox2620, dual-licensed (GPL/MIT), see oxjs.org for details
+// OxJS (c) 2011 Ox2620, dual-licensed GPL/MIT, see http://oxjs.org for details
// 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
+//@ Core -----------------------------------------------------------------------
/*@
Ox The Ox object
@@ -17,214 +18,6 @@ Ox = function(val) {
return Ox.wrap(val);
};
-/*
-================================================================================
-Constants
-================================================================================
-*/
-
-//@ Ox.AMPM <[str]> ['AM', 'PM']
-Ox.AMPM = ['AM', 'PM'];
-//@ Ox.DURATIONS <[str]> ['year', 'month', 'day', 'minute', 'second']
-Ox.DURATIONS = ['year', 'month', 'day', 'minute', 'second'];
-//@ Ox.EARTH_RADIUS Radius of the earth in meters
-// see http://en.wikipedia.org/wiki/WGS-84
-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
+ > Ox.compact([null,,1,,2,,3])
+ [1, 2, 3]
@*/
-Ox.avg = function(obj) {
- return Ox.sum(obj) / Ox.len(obj);
-};
-
-Ox.clone = function(obj) {
- /***
- returns a copy of an array or object
- >>> (function() { a = ['val']; b = Ox.clone(a); a[0] = null; return b[0]; }())
- 'val'
- >>> (function() { a = {key: 'val'}; b = Ox.clone(a); a.key = null; return b.key; }())
- 'val'
- ***/
- return Ox.isArray(obj) ? obj.slice() : Ox.extend({}, obj);
-};
Ox.compact = function(arr) {
/***
returns an array without null or undefined values
- >>> Ox.compact([null,,1,,2,,3])
- [1, 2, 3]
***/
return Ox.map(arr, function(val) {
return Ox.isUndefined(val) ? null : val;
});
};
-Ox.count = function(arr) {
- /***
- >>> Ox.count(['foo', 'bar', 'foo']).foo
- 2
- ***/
- var obj = {};
+/*@
+ Ox.flatten
Flattens an array
+ > Ox.flatten([1, [2, [3], 4], 5])
+ [1, 2, 3, 4, 5]
+@*/
+Ox.flatten = function(arr) {
+ // fixme: can this work for objects too?
+ var ret = [];
arr.forEach(function(v) {
+ if (Ox.isArray(v)) {
+ Ox.flatten(v).forEach(function(v) {
+ ret.push(v);
+ });
+ } else {
+ ret.push(v);
+ }
+ });
+ return ret;
+};
+
+/*@
+Ox.merge Merges an array with one or more other arrays
+ > Ox.merge(['foo'], ['foo', 'bar'], ['bar'])
+ ['foo', 'foo', 'bar', 'bar']
+@*/
+Ox.merge = function(arr) {
+ Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg) {
+ Ox.forEach(arg, function(val) {
+ arr.push(val);
+ });
+ });
+ return arr;
+};
+
+/*@
+Ox.unique Returns an array without duplicate values
+ > Ox.unique([1, 2, 3, 2, 1])
+ [1, 2, 3]
+@*/
+
+Ox.unique = function(arr) {
+ var unique = [];
+ Ox.forEach(arr, function(val) {
+ unique.indexOf(val) == -1 && unique.push(val);
+ });
+ return unique;
+};
+
+/*@
+Ox.zip Zips an array of arrays
+ > Ox.zip([[0, 1], [2, 3], [4, 5]])
+ [[0, 2, 4], [1, 3, 5]]
+ > Ox.zip([0, 1, 2], [3, 4, 5])
+ [[0, 3], [1, 4], [2, 5]]
+@*/
+Ox.zip = function() {
+ var args = arguments.length == 1 ? arguments[0] : Ox.makeArray(arguments),
+ arr = [];
+ args[0].forEach(function(v, i) {
+ arr[i] = [];
+ args.forEach(function(v_, i_) {
+ arr[i].push(v_[i]);
+ });
+ });
+ return arr;
+};
+
+//@ Collections ----------------------------------------------------------------
+
+/*@
+Ox.avg Returns the average of an array's values, or an object's properties
+ (collection) -> Average value
+ collection <[n]|o> Array or object with numerical values
+ > Ox.avg([-1, 0, 1])
+ 0
+ > Ox.avg({a: 1, b: 2, c: 3})
+ 2
+@*/
+
+Ox.avg = function(obj) {
+ return Ox.sum(obj) / Ox.len(obj);
+};
+
+/*@
+Ox.clone Returns a (shallow) copy or an object or array
+ > (function() { a = ['val']; b = Ox.clone(a); a[0] = null; return b[0]; }())
+ 'val'
+ > (function() { a = {key: 'val'}; b = Ox.clone(a); a.key = null; return b.key; }())
+ 'val'
+@*/
+
+Ox.clone = function(obj) {
+ return Ox.isArray(obj) ? obj.slice() : Ox.extend({}, obj);
+};
+
+/*@
+Ox.count Counts the occurences of values in an array, object or string
+ > Ox.count(['f', 'o', 'o'])
+ {f: 1, o: 2}
+ > Ox.count({a: 'f', b: 'o', c: 'o'})
+ {f: 1, o: 2}
+ > Ox.count('foo')
+ {f: 1, o: 2}
+@*/
+Ox.count = function(arr) {
+ var obj = {};
+ Ox.forEach(arr, function(v) {
obj[v] = (obj[v] || 0) + 1;
});
return obj;
};
+//@ Ox.each (deprecated)
Ox.each = function(obj, fn) {
// fixme: deprecate!
/*
@@ -476,47 +267,38 @@ Ox.each = function(obj, fn) {
return obj;
};
+/*@
+Ox.every Returns true if a condition holds for every element of a collection
+ Unlike [].every(), Ox.every() works for arrays,
+ objects and strings.
+ > Ox.every([0, 1, 2], function(v, i) { return i == v; })
+ true
+ > Ox.every({a: 1, b: 2, c: 3}, function(v) { return v == 1; })
+ false
+ > Ox.every("foo", function(v) { return v == 'f'; })
+ false
+ > Ox.every([true, true, true])
+ true
+@*/
Ox.every = function(obj, fn) {
- /*
- Ox.every() works for arrays, objects and strings, unlike [].every()
- >>> Ox.every([0, 1, 2], function(v, i) { return i == v; })
- true
- >>> Ox.every({a: 1, b: 2, c: 3}, function(v) { return v == 1; })
- false
- >>> Ox.every("foo", function(v) { return v == 'f'; })
- false
- >>> Ox.every([true, true, true])
- true
- */
return Ox.filter(Ox.values(obj), fn || function(v) {
return v;
}).length == Ox.len(obj);
};
-Ox.extend = function() {
- /*
- >>> Ox.extend({a: 1, b: 1, c: 1}, {b: 2, c: 2}, {c: 3}).c
- {"a":1,"b":2,"c":3}
- */
- var obj = arguments[0];
- Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg, i) {
- Ox.forEach(arg, function(val, key) {
- obj[key] = val;
- });
- });
- return obj;
-};
+/*@
+Ox.filter Filters a collection by a given condition
+ Unlike [].filter(), Ox.filter() works for arrays,
+ objects and strings.
+ > Ox.filter([2, 1, 0], function(v, i) { return v == i; })
+ [1]
+ > Ox.keys(Ox.filter({a: 'c', b: 'b', c: 'a'}, function(v, k) { return v == k; }))
+ ['b']
+ > Ox.filter(' foo bar ', function(v) { return v != ' '; })
+ 'foobar'
+@*/
Ox.filter = function(obj, fn) {
- /***
- Ox.filter works for arrays, objects and strings, unlike [].filter()
- >>> Ox.filter([2, 1, 0], function(v, i) { return v == i; })
- [1]
- >>> Ox.keys(Ox.filter({a: 'c', b: 'b', c: 'a'}, function(v, k) { return v == k; }))
- ["b"]
- >>> Ox.filter(' foo bar ', function(v) { return v != ' '; })
- "foobar"
- ***/
var type = Ox.typeOf(obj),
ret = type == 'array' ? [] : type == 'object' ? {} : '';
Ox.forEach(obj, function(v, k) {
@@ -533,14 +315,17 @@ Ox.filter = function(obj, fn) {
return ret;
};
+/*@
+Ox.find Returns array elements that match a string, leading matches first
+ > Ox.find(['foo', 'bar', 'foobar', 'barfoo'], 'foo')
+ [['foo", 'foobar'], ['barfoo']]
+@*/
Ox.find = function(arr, str) {
/*
returns an array with two arrays as elements:
an array of elements of arr that begin with str,
and an array of elements of arr that contain,
but do not begin with str
- >>> Ox.find(["foo", "bar", "foobar", "barfoo"], "foo")
- [["foo", "foobar"], ["barfoo"]]
*/
var arrLowerCase = arr.map(function(v) {
return v.toLowerCase();
@@ -553,23 +338,6 @@ Ox.find = function(arr, str) {
return ret;
};
-Ox.flatten = function(arr) {
- /*
- >>> Ox.flatten([1, [2, [3], 4], 5])
- [1, 2, 3, 4, 5]
- */
- var ret = [];
- arr.forEach(function(v) {
- if (Ox.isArray(v)) {
- Ox.flatten(v).forEach(function(v) {
- ret.push(v);
- });
- } else {
- ret.push(v);
- }
- });
- return ret;
-}
/*@
Ox.forEach forEach loop
@@ -604,6 +372,10 @@ Ox.forEach = function(obj, fn) {
return obj;
};
+/*@
+Ox.getObjectById Returns an array element with a given id
+@*/
+// fixme: shouldn't this be getElementById() ?
Ox.getObjectById = function(arr, id) {
/***
>>> Ox.getObjectById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo").title
@@ -619,6 +391,10 @@ Ox.getObjectById = function(arr, id) {
return ret;
};
+/*@
+Ox.getPositionById Returns the index of an array element with a given id
+@*/
+// fixme: shouldn't this be getIndexById() ?
Ox.getPositionById = function(arr, id) {
/***
>>> Ox.getPositionById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "bar")
@@ -634,67 +410,101 @@ Ox.getPositionById = function(arr, id) {
return ret;
};
+// fixme: and what about getElementBy() and getIndexBy() ?
+
+/*@
+Ox.getset Generic getter and setter function
+ See examples for details.
+ # Usage --------------------------------------------------------------------
+ Ox.getset(options, args=[]) -> all options
+ Ox.getset(options, args=[key]) -> <*> options[key]
+ Ox.getset(options, args=[key, value], callback, context) -> context
+ sets options[key] to value and calls fn(key, value)
+ if the key/value pair was added or modified
+ Ox.getset(options, args=[{key: value}], callback, context) -> context
+ sets multiple options and calls fn(key, value)
+ for every key/value pair that was added or modified
+ # Arguments ----------------------------------------------------------------
+ options Options object (key/value pairs)
+ args The arguments "array" of the caller function
+ callback Callback function
+ The callback is called for every key/value pair that was added or
+ modified.
+ key Key
+ value <*> Value
+ context The parent object of the caller function (for chaining)
+ # Examples -----------------------------------------------------------------
+
+ > Ox.test.object.options("key", "val").options("key")
+ "val"
+ > Ox.test.object.options({foo: "foo", bar: "bar"}).options()
+ {"key": "val", "foo": "foo", "bar": "bar"}
+@*/
+
+Ox.getset = function(obj, args, callback, context) {
+ var obj_ = Ox.clone(obj), ret;
+ if (args.length == 0) {
+ // getset([])
+ ret = obj;
+ } else if (args.length == 1 && !Ox.isObject(args[0])) {
+ // getset([key])
+ ret = obj[args[0]];
+ } else {
+ // getset([key, val]) or getset([{key: val, ...}])
+ args = Ox.makeObject(args);
+ obj = Ox.extend(obj, args);
+ Ox.forEach(args, function(val, key) {
+ if (!obj_ || !Ox.isEqual(obj_[key], val)) {
+ callback && callback(key, val);
+ }
+ });
+ ret = context;
+ }
+ return ret;
+}
+
+/*@
+Ox.isEmpty Returns true if an array, object or string is empty
+ > Ox.isEmpty([])
+ true
+ > Ox.isEmpty({})
+ true
+ > Ox.isEmpty('')
+ true
+@*/
Ox.isEmpty = function(val) {
return Ox.len(val) == 0;
};
-Ox.isEqual = function(obj0, obj1) {
- /*
- >>> Ox.isEqual(false, false)
- true
- >>> Ox.isEqual(0, 0)
- true
- >>> Ox.isEqual(NaN, NaN)
- false
- >>> Ox.isEqual('', '')
- true
- >>> Ox.isEqual([1, 2, 3], [1, 2, 3])
- true
- >>> Ox.isEqual({a: 1, b: [2, 3], c: {d: '4'}}, {a: 1, b: [2, 3], c: {d: '4'}})
- true
- >>> Ox.isEqual({a: 1, b: 2, c: 3}, {c: 3, b: 2, a: 1})
- true // FIXME: is false
- >>> Ox.isEqual(function(arg) { return arg; }, function(arg) { return arg; })
- true
- >>> Ox.isEqual(function(foo) { return foo; }, function(bar) { return bar; })
- false
- */
- var ret = false;
- if (obj0 === obj1) {
- ret = true;
- } else if (typeof(obj0) == typeof(obj1)) {
- if (obj0 == obj1) {
- ret = true;
- } else if (Ox.isArray(obj0) && obj0.length == obj1.length) {
- ret = true;
- Ox.forEach(obj0, function(v, i) {
- ret = Ox.isEqual(v, obj1[i]);
- return ret;
- });
- } else if (Ox.isDate(obj0)) {
- ret = obj0.getTime() == obj1.getTime();
- } else if (Ox.isObject(obj0)) {
- ret = Ox.isEqual(Ox.keys(obj0), Ox.keys(obj1)) &&
- Ox.isEqual(Ox.values(obj0), Ox.values(obj1));
- } else if (Ox.isFunction(obj0)) {
- ret = obj0.toString() == obj1.toString();
- }
- }
- return ret;
-};
+/*@
+Ox.keys Returns the keys of an array, object or string
+ Unlike Object.keys(), Ox.keys() works for arrays,
+ objects and strings.
+ > Ox.keys([1, 2, 3])
+ [0, 1, 2]
+ > Ox.keys([1,,3])
+ [0, 2]
+ > Ox.keys([,])
+ [0]
+ > Ox.keys({a: 1, b: 2, c: 3})
+ ['a', 'b', 'c']
+ > Ox.keys('abc')
+ [0, 1, 2]
+@*/
+
+// fixme: is this really needed? arrays... ok... but strings??
Ox.keys = function(obj) {
- /*
- works for arrays, objects and strings, unlike Object.keys()
- >>> Ox.keys([1, 2, 3])
- [0, 1, 2]
- >>> Ox.keys({a: 1, b: 2, c: 3})
- ["a", "b", "c"]
- >>> Ox.keys('abc')
- [0, 1, 2]
- >>> Ox.keys([,])
- [0]
- */
var keys = [];
Ox.forEach(obj, function(v, k) {
keys.push(k);
@@ -702,13 +512,19 @@ Ox.keys = function(obj) {
return keys.sort();
};
-Ox.last = function(arr, val) {
- /***
- >>> Ox.last([1, 2, 3])
+/*@
+Ox.last Gets or sets the last element of an array
+ Unlike foobarbaz[foobarbaz.length - 1],
+ Ox.last(foobarbaz) is short.
+ > Ox.test.array = [1, 2, 3]
+ > Ox.last(Ox.test.array)
3
- >>> Ox.last([1, 2, 3], 4)
+ > Ox.last(Ox.test.array, 4)
[1, 2, 4]
- ***/
+ > Ox.test.array
+ [1, 2, 4]
+@*/
+Ox.last = function(arr, val) {
var ret;
if (arguments.length == 1) {
ret = arr[arr.length - 1];
@@ -719,19 +535,23 @@ Ox.last = function(arr, val) {
return ret;
};
-Ox.len = function(obj) {
- /*
- >>> Ox.len([1, 2, 3])
+/*@
+Ox.len Returns the length of an array, function, object or string
+ Not to be confused with Ox.length, which is the
+ length property of the Ox function
+ (1 Ox.len([1, 2, 3])
3
- >>> Ox.len({a: 1, b: 2, c: 3})
- 3
- >>> Ox.len('abc')
- 3
- >>> Ox.len(function(x, y) { return x + y; })
- 2
- >>> Ox.len([,])
+ > Ox.len([,])
1
- */
+ > Ox.len({a: 1, b: 2, c: 3})
+ 3
+ > Ox.len(function(x, y, z) { return x + y + z; })
+ 3
+ > Ox.len('abc')
+ 3
+@*/
+Ox.len = function(obj) {
return Ox.isObject(obj) ? Ox.values(obj).length : obj.length;
};
@@ -791,17 +611,20 @@ Ox.makeArray = function(obj) {
return Array.prototype.slice.call(obj);
}
+/*@
+Ox.makeObject Takes an array and returns an object
+ Ox.makeObject is a helper for functions with two alternative
+ signatures like ('key', 'val') and ({key: 'val'}).
+ > (function() { return Ox.makeObject(arguments); }({foo: 1, bar: 2}))
+ {foo: 1, bar: 2}
+ > (function() { return Ox.makeObject(arguments); }('foo', 1))
+ {foo: 1}
+ > (function() { return Ox.makeObject(arguments); }('foo'))
+ {}
+ > (function() { return Ox.makeObject(arguments); }())
+ {}
+@*/
Ox.makeObject = function(obj) {
- /*
- >>> (function() { return Ox.makeObject(arguments); }({foo: 'bar'})).foo
- 'bar'
- >>> (function() { return Ox.makeObject(arguments); }('foo', 'bar')).foo
- 'bar'
- >>> (function() { return Ox.makeObject(arguments); }('foo')).foo
- undefined
- >>> (function() { return Ox.makeObject(arguments); }()).foo
- undefined
- */
var ret = {};
if (Ox.isObject(obj[0])) {
// ({foo: 'bar'})
@@ -813,19 +636,24 @@ Ox.makeObject = function(obj) {
return ret;
};
-Ox.map = function(obj, fn) {
- /*
- Ox.map() works for arrays, objects and strings,
- unlike [].map()
- >>> Ox.map([1, 1, 1], function(v, i) { return v == i; })
- [false, true, false]
- >>> Ox.map({a: 'a', b: 'a', c: 'a'}, function(v, k) { return v == k; }).a
- true
- >>> Ox.map("111", function(v, i) { return v == i; })
- [false, true, false]
- >>> Ox.map([,], function(v, i) { return i; })
+/*
+Ox.map Transforms the values of an array, object or string
+ Unlike [].map(), Ox.map() works for arrays,
+ objects and strings. Returning null from the iterator
+ function will remove the element from the collection.
+ > Ox.map([0, 0, 0], function(v, i) { return v == i; })
+ [true, false, false]
+ > Ox.map({a: 'a', b: 'a', c: 'a'}, function(v, k) { return v == k; })
+ {a: true, b: false, c: false}
+ > Ox.map("000", function(v, i) { return v == i; })
+ [true, false, false]
+ > Ox.map([0, 1, 2, 4], function(v, i) { return v ? i == v : null; })
+ [true, true, false]
+ > Ox.map([,], function(v, i) { return i; })
[0]
- */
+*/
+
+Ox.map = function(obj, fn) {
// fixme: return null to filter out is a bit esoteric
var isObject = Ox.isObject(obj),
ret = isObject ? {} : [];
@@ -837,39 +665,32 @@ Ox.map = function(obj, fn) {
return ret;
};
-Ox.max = function(obj) {
- /*
- >>> Ox.max([-1, 0, 1])
- 1
- >>> Ox.max({a: 1, b: 2, c: 3})
+/*@
+Ox.max Returns the maximum value of a collection
+ > Ox.max([1, 2, 3])
3
- */
+ > Ox.max({a: 1, b: 2, c: 3})
+ 3
+ > Ox.max('123')
+ 3
+@*/
+Ox.max = function(obj) {
return Math.max.apply(Math, Ox.values(obj));
};
-Ox.min = function(obj) {
- /*
- >>> Ox.min([-1, 0, 1])
- -1
- >>> Ox.min({a: 1, b: 2, c: 3})
+/*@
+Ox.min Returns the minimum value of a collection
+ > Ox.min([1, 2, 3])
1
- */
+ > Ox.min({a: 1, b: 2, c: 3})
+ 1
+ > Ox.min('123')
+ 1
+@*/
+Ox.min = function(obj) {
return Math.min.apply(Math, Ox.values(obj));
};
-Ox.merge = function(arr) {
- /*
- >>> Ox.merge(['foo'], ['bar'], ['baz'])
- ['foo', 'bar', 'baz']
- */
- Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg) {
- Ox.forEach(arg, function(val) {
- arr.push(val);
- });
- });
- return arr;
-};
-
/*@
Ox.range Python-style range
(stop) -> <[n]> range
@@ -1032,18 +853,6 @@ Ox.toArray = function(obj) {
return arr;
};
-Ox.unique = function(arr) {
- /*
- >>> Ox.unique([1, 2, 3, 1])
- [1, 2, 3]
- */
- var unique = [];
- Ox.forEach(arr, function(val) {
- unique.indexOf(val) == -1 && unique.push(val);
- });
- return unique;
-};
-
Ox.unserialize = function(str) {
/*
>>> Ox.unserialize('a=1&b=2&c=3').c
@@ -1087,29 +896,7 @@ Ox.walk = function(obj, fn) {
});
};
-Ox.zip = function() {
- /*
- >>> Ox.zip([[0, 1], [2, 3], [4, 5]])
- [[0, 2, 4], [1, 3, 5]]
- >>> Ox.zip([0, 1, 2], [3, 4, 5])
- [[0, 3], [1, 4], [2, 5]]
- */
- var args = arguments.length == 1 ? arguments[0] : Ox.makeArray(arguments),
- arr = [];
- args[0].forEach(function(v, i) {
- arr[i] = [];
- args.forEach(function(v_, i_) {
- arr[i].push(v_[i]);
- });
- });
- return arr;
-};
-
-/*
-================================================================================
-Color functions
-================================================================================
-*/
+//@ Color ----------------------------------------------------------------------
/*@
Ox.hsl Takes RGB values and returns HSL values
@@ -1198,11 +985,125 @@ Ox.rgb = function(hsl) {
});
};
-/*
-================================================================================
-Date functions
-================================================================================
-*/
+//@ Constants ------------------------------------------------------------------
+
+//@ Ox.AMPM <[str]> ['AM', 'PM']
+Ox.AMPM = ['AM', 'PM'];
+//@ Ox.DURATIONS <[str]> ['year', 'month', 'day', 'minute', 'second']
+Ox.DURATIONS = ['year', 'month', 'day', 'minute', 'second'];
+//@ Ox.EARTH_RADIUS Radius of the earth in meters
+// see http://en.wikipedia.org/wiki/WGS-84
+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 both 'key_0' and 'key_0.numpad'.
+Ox.KEYS = {
+ 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 <[str]> ['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',
+ BULLET: '\u2022', ELLIPSIS: '\u2026', PERMILLE: '\u2030',
+ COLON: '\u20A1', CRUZEIRO: '\u20A2', FRANC: '\u20A3', LIRA: '\u20A4',
+ NAIRA: '\u20A6', PESETA: '\u20A7', WON: '\u20A9', SHEQEL: '\u20AA',
+ DONG: '\u20AB', EURO: '\u20AC', KIP: '\u20AD', TUGRIK: '\u20AE',
+ DRACHMA: '\u20AF', PESO: '\u20B1', GUARANI: '\u20B2', AUSTRAL: '\u20B3',
+ HRYVNIA: '\u20B4', CEDI: '\u20B5', TENGE: '\u20B8', RUPEE: '\u20B9',
+ CELSIUS: '\u2103', FAHRENHEIT: '\u2109', POUNDS: '\u2114', OUNCE: '\u2125',
+ OHM: '\u2126', KELVIN: '\u212A', ANGSTROM: '\u212B', INFO: '\u2139',
+ LEFT: '\u2190', UP: '\u2191', RIGHT: '\u2192', DOWN: '\u2193',
+ HOME: '\u2196', END: '\u2198', RETURN: '\u21A9',
+ REDO: '\u21BA', UNDO: '\u21BB', PAGEUP: '\u21DE', PAGEDOWN: '\u21DF',
+ CAPSLOCK: '\u21EA', TAB: '\u21E5', SHIFT: '\u21E7', INFINITY: '\u221E',
+ CONTROL: '\u2303', COMMAND: '\u2318', ENTER: '\u2324', ALT: '\u2325',
+ DELETE: '\u2326', CLEAR:'\u2327',BACKSPACE: '\u232B', OPTION: '\u2387',
+ NAVIGATE: '\u2388', ESCAPE: '\u238B', EJECT: '\u23CF',
+ SPACE: '\u2423', DIAMOND: '\u25C6',
+ STAR: '\u2605', SOUND: '\u266B', TRASH: '\u267A', FLAG: '\u2691',
+ ANCHOR: '\u2693', GEAR: '\u2699', ATOM: '\u269B', WARNING: '\u26A0',
+ CUT: '\u2702', BACKUP: '\u2707', FLY: '\u2708', CHECK: '\u2713',
+ CLOSE: '\u2715', BALLOT: '\u2717', WINDOWS: '\u2756',
+ EDIT: '\uF802', CLICK: '\uF803', APPLE: '\uF8FF'
+};
+//@ 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);
+});
+
+//@ Date -----------------------------------------------------------------------
+
+//@ Ox.getDate Get the day of a date, optionally UTC
/*@
Ox.getDateInWeek Get the date that falls on a given weekday in the same week
@@ -1221,7 +1122,7 @@ Ox.getDateInWeek Get the date that falls on a given weekday in the same week
> Ox.formatDate(Ox.getDateInWeek(new Date("1/1/2000"), 1), "%A, %B %e, %Y")
"Monday, December 27, 1999"
@*/
-
+// fixme: why is this Monday first? shouldn't it then be "getDateInISOWeek"??
Ox.getDateInWeek = function(date, weekday, utc) {
/*
*/
@@ -1236,6 +1137,8 @@ Ox.getDateInWeek = function(date, weekday, utc) {
return Ox.setDate(date, Ox.getDate(date, utc) - sourceWeekday + targetWeekday, utc);
}
+//@ Ox.getDay Get the weekday of a date, optionally UTC
+
/*@
Ox.getDayOfTheYear Get the day of the year for a given date
# Usage
@@ -1262,14 +1165,17 @@ Ox.getDayOfTheYear = function(date, utc) {
})) + Ox.getDate(date, utc);
};
+/*@
+Ox.getDaysInMonth Get the number of days in a given month
+ > Ox.getDaysInMonth(2000, 2)
+ 29
+ > Ox.getDaysInMonth("2002", "Feb")
+ 28
+ > Ox.getDaysInMonth(new Date('01/01/2004'), "February")
+ 29
+@*/
Ox.getDaysInMonth = function(year, month, utc) {
/*
- >>> Ox.getDaysInMonth(2000, 2)
- 29
- >>> Ox.getDaysInMonth("2002", "Feb")
- 28
- >>> Ox.getDaysInMonth(new Date('01/01/2004'), "February")
- 29
*/
year = Ox.makeYear(year);
month = Ox.isNumber(month) ? month :
@@ -1279,61 +1185,71 @@ Ox.getDaysInMonth = function(year, month, utc) {
return new Date(year, month, 0).getDate();
}
-Ox.getDaysInYear = function(year, utc) {
- /*
- >>> Ox.getDaysInYear(1900)
+/*
+Ox.getDaysInYear Get the number of days in a given year
+ > Ox.getDaysInYear(1900)
365
- >>> Ox.getDaysInYear('2000')
+ > Ox.getDaysInYear('2000')
366
- >>> Ox.getDaysInYear(new Date('01/01/2004'))
+ > Ox.getDaysInYear(new Date('01/01/2004'))
366
- */
+*/
+Ox.getDaysInYear = function(year, utc) {
return 365 + Ox.isLeapYear(Ox.makeYear(year, utc));
};
-Ox.getFirstDayOfTheYear = function(date, utc) {
- /*
- Decimal weekday of January 1 (0-6, Sunday as first day)
- >>> Ox.getFirstDayOfTheYear(new Date("01/01/2000"))
+/*@
+Ox.getFirstDayOfTheYear Get the weekday of the first day of a given year
+ Returns the decimal weekday of January 1 (0-6, Sunday as first day)
+ > Ox.getFirstDayOfTheYear(new Date('01/01/2000'))
6
- */
+@*/
+Ox.getFirstDayOfTheYear = function(date, utc) {
date = Ox.makeDate(date);
date = Ox.setMonth(date, 0, utc);
date = Ox.setDate(date, 1, utc);
return Ox.getDay(date, utc)
};
+//@ Ox.getFullYear Get the year of a date, optionally UTC
+
+//@ Ox.getHours Get the hours of a date, optionally UTC
+
+/*@
+Ox.getISODate Get the ISO date string for a given date
+ > Ox.getISODate(new Date('01/01/2000'))
+ '2000-01-01T00:00:00Z'
+@*/
Ox.getISODate = function(date, utc) {
- /*
- >>> Ox.getISODate(new Date("01/01/2000"))
- "2000-01-01T00:00:00Z"
- */
return Ox.formatDate(Ox.makeDate(date), '%FT%TZ', utc);
};
-Ox.getISODay = function(date, utc) {
- /*
- Decimal weekday (1-7, Monday as first day)
- >>> Ox.getISODay(new Date("01/01/2000"))
+/*@
+Ox.getISODay Get the ISO weekday of a given date
+ Returns the decimal weekday (1-7, Monday as first day)
+ > Ox.getISODay(new Date('01/01/2000'))
6
- >>> Ox.getISODay(new Date("01/02/2000"))
+ > Ox.getISODay(new Date('01/02/2000'))
7
- >>> Ox.getISODay(new Date("01/03/2000"))
+ > Ox.getISODay(new Date('01/03/2000'))
1
- */
+@*/
+Ox.getISODay = function(date, utc) {
return Ox.getDay(Ox.makeDate(date), utc) || 7;
};
-Ox.getISOWeek = function(date, utc) {
- /*
- see http://en.wikipedia.org/wiki/ISO_8601
- >>> Ox.getISOWeek(new Date("01/01/2000"))
+/*@
+Ox.getISOWeek Get the ISO week of a given date
+ See ISO 8601
+ > Ox.getISOWeek(new Date('01/01/2000'))
52
- >>> Ox.getISOWeek(new Date("01/02/2000"))
+ > Ox.getISOWeek(new Date('01/02/2000'))
52
- >>> Ox.getISOWeek(new Date("01/03/2000"))
+ > Ox.getISOWeek(new Date('01/03/2000'))
1
- */
+@*/
+
+Ox.getISOWeek = function(date, utc) {
date = Ox.makeDate(date);
// set date to Thursday of the same week
return Math.floor((Ox.getDayOfTheYear(Ox.setDate(
@@ -1341,16 +1257,18 @@ Ox.getISOWeek = function(date, utc) {
), utc) - 1) / 7) + 1;
};
-Ox.getISOYear = function(date, utc) {
- /*
- see http://en.wikipedia.org/wiki/ISO_8601
- >>> Ox.getISOYear(new Date("01/01/2000"))
+/*@
+Ox.getISOYear Get the ISO year of a given date
+ See ISO 8601
+ > Ox.getISOYear(new Date("01/01/2000"))
1999
- >>> Ox.getISOYear(new Date("01/02/2000"))
+ > Ox.getISOYear(new Date("01/02/2000"))
1999
- >>> Ox.getISOYear(new Date("01/03/2000"))
+ > Ox.getISOYear(new Date("01/03/2000"))
2000
- */
+@*/
+
+Ox.getISOYear = function(date, utc) {
date = Ox.makeDate(date);
// set date to Thursday of the same week
return Ox.getFullYear(Ox.setDate(
@@ -1358,64 +1276,103 @@ Ox.getISOYear = function(date, utc) {
));
};
+//@ Ox.getMilliseconds Get the milliseconds of a date
+//@ Ox.getMinutes Get the minutes of a date, optionally UTC
+//@ Ox.getMonth Get the month of a date, optionally UTC
+//@ Ox.getSeconds Get the seconds of a date
+
+//@ Ox.getTime Alias for +new Date() (deprecated)
Ox.getTime = function() {
// fixme: needed?
return +new Date();
-}
+};
+/*@
+Ox.getTimezoneOffset Get the local time zone offset in milliseconds
+@*/
Ox.getTimezoneOffset = function() {
return new Date().getTimezoneOffset() * 60000;
-}
+};
-Ox.getTimezoneOffsetString = function(date) {
- /*
- Time zone offset string ('-1200' - '+1200')
- >>> Ox.getTimezoneOffsetString(new Date('01/01/2000')).length
+/*@
+Ox.getTimezoneOffsetString Get the local time zone offset as a string
+ Returns a time zone offset string (from around '-1200' to around '+1200').
+ > Ox.getTimezoneOffsetString(new Date('01/01/2000')).length
5
- */
+@*/
+Ox.getTimezoneOffsetString = function(date) {
var offset = (Ox.makeDate(date)).getTimezoneOffset();
return (offset < 0 ? '+' : '-') +
Ox.pad(Math.floor(Math.abs(offset) / 60), 2) +
Ox.pad(Math.abs(offset) % 60, 2);
};
-Ox.getWeek = function(date, utc) {
- /*
- Week of the year (0-53, Sunday as first day)
- >>> Ox.getWeek(new Date("01/01/2000"))
+/*@
+Ox.getWeek Get the week of a given day
+ Returns the week of the year (0-53, Sunday as first day)
+ > Ox.getWeek(new Date('01/01/2000'))
0
- >>> Ox.getWeek(new Date("01/02/2000"))
+ > Ox.getWeek(new Date('01/02/2000'))
1
- >>> Ox.getWeek(new Date("01/03/2000"))
+ > Ox.getWeek(new Date('01/03/2000'))
1
- */
+@*/
+Ox.getWeek = function(date, utc) {
date = Ox.makeDate(date);
return Math.floor((Ox.getDayOfTheYear(date, utc) +
Ox.getFirstDayOfTheYear(date, utc) - 1) / 7);
};
-Ox.isLeapYear = function(year, utc) {
- /*
- >>> Ox.isLeapYear(1900)
+/*@
+Ox.isLeapYear Returns true if a given year is a leap year
+ > Ox.isLeapYear(1900)
false
- >>> Ox.isLeapYear('2000')
+ > Ox.isLeapYear('2000')
true
- >>> Ox.isLeapYear(new Date('01/01/2004'))
+ > Ox.isLeapYear(new Date('01/01/2004'))
true
- */
+@*/
+Ox.isLeapYear = function(year, utc) {
year = Ox.makeYear(year, utc);
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
};
+/*@
+Ox.makeDate Takes a date, number or string, returns a date
+ > Ox.formatDate(Ox.makeDate(new Date('01/01/1970')), '%M/%D/%Y')
+ '01/01/1970'
+ > Ox.formatDate(Ox.makeDate(0), '%M/%D/%Y')
+ '01/01/1970'
+ > Ox.formatDate(Ox.makeDate('01/01/1970'), '%M/%D/%Y')
+ '01/01/1970'
+@*/
Ox.makeDate = function(date) {
return Ox.isDate(date) ? date :
Ox.isUndefined(date) ? new Date() : new Date(date);
};
+/*@
+Ox.makeYear Takes a date, number or string, returns a year
+ > Ox.makeYear(new Date('01/01/1970'))
+ 1970
+ > Ox.makeYear(1970)
+ 1970
+ > Ox.makeYear('1970')
+ 1970
+@*/
Ox.makeYear = function(date, utc) {
return Ox.isDate(date) ? Ox.getFullYear(date, utc) : parseInt(date);
};
+//@ Ox.setDate Set the day of a date, optionally UTC
+//@ Ox.setDay Set the weekday of a date, optionally UTC
+//@ Ox.setFullYear Set the year of a date, optionally UTC
+//@ Ox.setHours Set the hours of a date, optionally UTC
+//@ Ox.setMilliseconds Set the milliseconds of a date
+//@ Ox.setMinutes Set the minutes of a date, optionally UTC
+//@ Ox.setMonth Set the month of a date, optionally UTC
+//@ Ox.setSeconds Set the seconds of a date
+
[
'FullYear', 'Month', 'Date', 'Day',
'Hours', 'Minutes', 'Seconds', 'Milliseconds'
@@ -1433,11 +1390,7 @@ Ox.makeYear = function(date, utc) {
}
});
-/*
-================================================================================
-DOM functions
-================================================================================
-*/
+//@ DOM ------------------------------------------------------------------------
/*@
Ox.canvas Generic canvas object
@@ -1625,11 +1578,7 @@ Ox.element = function(str) {
}
};
-/*
-================================================================================
-Encoding functions
-================================================================================
-*/
+//@ Encoding -------------------------------------------------------------------
(function() {
@@ -1674,55 +1623,61 @@ Encoding functions
);
}
- Ox.encodeBase32 = function(num) {
- // see http://www.crockford.com/wrmg/base32.html
- /*
- >>> Ox.encodeBase32(15360)
+ /*@
+ Ox.encodeBase32 Encode a number as base32
+ See Base 32.
+ > Ox.encodeBase32(15360)
'F00'
- >>> Ox.encodeBase32(33819)
+ > Ox.encodeBase32(33819)
'110V'
- */
+ @*/
+ Ox.encodeBase32 = function(num) {
return Ox.map(num.toString(32), function(char) {
return digits[parseInt(char, 32)];
}).join('');
}
- Ox.decodeBase32 = function(str) {
- /*
- >>> Ox.decodeBase32('foo')
+ /*@
+ Ox.decodeBase32 Decodes a base32-encoded number
+ See Base 32.
+ > Ox.decodeBase32('foo')
15360
- >>> Ox.decodeBase32('ilou')
+ > Ox.decodeBase32('ILOU')
33819
- >>> Ox.decodeBase32('?').toString()
+ > Ox.decodeBase32('?').toString()
'NaN'
- */
+ */
+ Ox.decodeBase32 = function(str) {
return parseInt(Ox.map(str.toUpperCase(), function(char) {
var index = digits.indexOf(aliases[char] || char);
return (index == -1 ? ' ' : index).toString(32);
}).join(''), 32);
}
- Ox.encodeBase64 = function(num) {
- /*
- >>> Ox.encodeBase64(32394)
+ /*@
+ Ox.encodeBase64 Encode a number as base64
+ > Ox.encodeBase64(32394)
'foo'
- */
+ @*/
+ Ox.encodeBase64 = function(num) {
return btoa(Ox.encodeBase256(num)).replace(/=/g, '');
}
- Ox.decodeBase64 = function(str) {
- /*
- >>> Ox.decodeBase64('foo')
+ /*@
+ Ox.decodeBase64 Decodes a base64-encoded number
+ > Ox.decodeBase64('foo')
32394
- */
+ @*/
+ Ox.decodeBase64 = function(str) {
return Ox.decodeBase256(atob(str));
}
- Ox.encodeBase128 = function(num) {
- /*
- >>> Ox.encodeBase128(1685487)
+ /*@
+ Ox.encodeBase128 Encode a number as base128
+ > Ox.encodeBase128(1685487)
'foo'
- */
+ @*/
+ Ox.encodeBase128 = function(num) {
var str = '';
while (num) {
str = Ox.char(num & 127) + str;
@@ -1731,11 +1686,12 @@ Encoding functions
return str;
}
- Ox.decodeBase128 = function(str) {
- /*
- >>> Ox.decodeBase128('foo')
+ /*@
+ Ox.decodeBase128 Decode a base128-encoded number
+ > Ox.decodeBase128('foo')
1685487
- */
+ @*/
+ Ox.decodeBase128 = function(str) {
var num = 0, len = str.length;
Ox.forEach(str, function(char, i) {
num += char.charCodeAt(0) << (len - i - 1) * 7;
@@ -1743,11 +1699,12 @@ Encoding functions
return num;
}
- Ox.encodeBase256 = function(num) {
- /*
- >>> Ox.encodeBase256(6713199)
+ /*@
+ Ox.encodeBase256 Encode a number as base256
+ > Ox.encodeBase256(6713199)
'foo'
- */
+ @*/
+ Ox.encodeBase256 = function(num) {
var str = '';
while (num) {
str = Ox.char(num & 255) + str;
@@ -1756,11 +1713,12 @@ Encoding functions
return str;
}
- Ox.decodeBase256 = function(str) {
- /*
- >>> Ox.decodeBase256('foo')
+ /*@
+ Ox.decodeBase256 Decode a base256-encoded number
+ > Ox.decodeBase256('foo')
6713199
- */
+ @*/
+ Ox.decodeBase256 = function(str) {
var num = 0, len = str.length;
Ox.forEach(str, function(char, i) {
num += char.charCodeAt(0) << (len - i - 1) * 8;
@@ -1768,6 +1726,7 @@ Encoding functions
return num;
}
+ //@ Ox.encodeDeflate (undocumented)
Ox.encodeDeflate = function(str) {
// encodes string, using deflate
/*
@@ -1793,6 +1752,7 @@ Encoding functions
return data.substr(8, data.length - 20);
}
+ //@ Ox.decodeDeflate (undocumented)
Ox.decodeDeflate = function(str) {
var image = new Image();
image.src = 'data:image/png;base64,' + btoa('\u0089PNG\r\n\u001A\n' +
@@ -1805,13 +1765,14 @@ Encoding functions
return Ox.decodeUTF8(str.substr(4, Ox.decodeBase256(str.substr(0, 4))));
}
- Ox.encodeHTML = function(str) {
- /*
- >>> Ox.encodeHTML('\'<"&">\'')
+ /*@
+ Ox.encodeHTML HTML-encodes a string
+ > Ox.encodeHTML('\'<"&">\'')
''<"&">''
- >>> Ox.encodeHTML('äbçdê')
+ > Ox.encodeHTML('äbçdê')
'äbçdê'
- */
+ @*/
+ Ox.encodeHTML = function(str) {
return Ox.map(str, function(v) {
var code = v.charCodeAt(0);
return code < 128 ? (v in Ox.HTML_ENTITIES ? Ox.HTML_ENTITIES[v] : v) :
@@ -1819,24 +1780,25 @@ Encoding functions
}).join('');
};
+ /*@
+ Ox.decodeHTML Decodes an HTML-encoded string
+ > Ox.decodeHTML(''<"&">'')
+ '\'<"&">\''
+ > Ox.decodeHTML(''<"&">'')
+ '\'<"&">\''
+ > Ox.decodeHTML('äbçdê')
+ 'äbçdê'
+ > Ox.decodeHTML('äbçdê')
+ 'äbçdê'
+ @*/
Ox.decodeHTML = function(str) {
- /*
- >>> Ox.decodeHTML(''<"&">'')
- '\'<"&">\''
- >>> Ox.decodeHTML(''<"&">'')
- '\'<"&">\''
- >>> Ox.decodeHTML('äbçdê')
- 'äbçdê'
- >>> Ox.decodeHTML('äbçdê')
- 'äbçdê'
- */
// 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;
};
+ //@ Ox.encodePNG
Encodes a string into an image, returns a new image URL
Ox.encodePNG = function(img, str) {
- // encodes string into image, returns new image url
/*
the message is compressed with deflate (by proxy of canvas),
then the string (four bytes length) + (length bytes message)
@@ -1872,8 +1834,8 @@ Encoding functions
return c.canvas.toDataURL();
}
+ //@ Ox.decodePNG Decodes an image, returns a string
Ox.decodePNG = function(img) {
- // decodes image, returns string
var bits = '', data = Ox.canvas(img).data, flag = false, i = 0,
len = 4, max = cap(img.width, img.height), px = 0, str = '';
do {
@@ -1990,126 +1952,129 @@ Format functions
================================================================================
*/
+/*@
+Ox.formatArea Formats a number of meters as square kilometers
+ > Ox.formatArea(1000000)
+ '1 km\u00B2'
+@*/
+
Ox.formatArea = function(num, dec) {
return Ox.formatNumber(Ox.round(num / 1000000, dec)) + ' km\u00B2';
}
+/*@
+Ox.formatColor (not implemented)
+@*/
Ox.formatColor = function() {
};
-Ox.formatCurrency = function(num, str, dec) {
- /*
- >>> Ox.formatCurrency(1000, '$', 2)
+/*@
+Ox.formatCurrency Formats a number with a currency symbol
+ > Ox.formatCurrency(1000, '$', 2)
'$1,000.00'
- */
+@*/
+
+Ox.formatCurrency = function(num, str, dec) {
return str + Ox.formatNumber(num, dec);
};
+/*@
+Ox.formatDate Formats a date according to a format string
+ See
+ strftime
+ and ISO 8601.
+ > Ox.test.date = new Date('2005-01-02 00:03:04')
+ > Ox.formatDate(Ox.test.date, '%A') // Full weekday
+ 'Sunday'
+ > Ox.formatDate(Ox.test.date, '%a') // Abbreviated weekday
+ 'Sun'
+ > Ox.formatDate(Ox.test.date, '%B') // Full month
+ 'January'
+ > Ox.formatDate(Ox.test.date, '%b') // Abbreviated month
+ 'Jan'
+ > Ox.formatDate(Ox.test.date, '%C') // Century
+ '20'
+ > Ox.formatDate(Ox.test.date, '%c') // US time and date
+ '01/02/05 12:03:04 AM'
+ > Ox.formatDate(Ox.test.date, '%D') // US date
+ '01/02/05'
+ > Ox.formatDate(Ox.test.date, '%d') // Zero-padded day of the month
+ '02'
+ > Ox.formatDate(Ox.test.date, '%e') // Space-padded day of the month
+ ' 2'
+ > Ox.formatDate(Ox.test.date, '%F') // Date
+ '2005-01-02'
+ > Ox.formatDate(Ox.test.date, '%G') // Full ISO-8601 year
+ '2004'
+ > Ox.formatDate(Ox.test.date, '%g') // Abbreviated ISO-8601 year
+ '04'
+ > Ox.formatDate(Ox.test.date, '%H') // Zero-padded hour (24-hour clock)
+ '00'
+ > Ox.formatDate(Ox.test.date, '%h') // Abbreviated month
+ 'Jan'
+ > Ox.formatDate(Ox.test.date, '%I') // Zero-padded hour (12-hour clock)
+ '12'
+ > Ox.formatDate(Ox.test.date, '%j') // Zero-padded day of the year
+ '002'
+ > Ox.formatDate(Ox.test.date, '%k') // Space-padded hour (24-hour clock)
+ ' 0'
+ > Ox.formatDate(Ox.test.date, '%l') // Space-padded hour (12-hour clock)
+ '12'
+ > Ox.formatDate(Ox.test.date, '%M') // Zero-padded minute
+ '03'
+ > Ox.formatDate(Ox.test.date, '%m') // Zero-padded month
+ '01'
+ > Ox.formatDate(Ox.test.date, '%n') // Newline
+ '\n'
+ > Ox.formatDate(Ox.test.date, '%p') // AM or PM
+ 'AM'
+ > Ox.formatDate(Ox.test.date, '%Q') // Quarter of the year
+ '1'
+ > Ox.formatDate(Ox.test.date, '%R') // Zero-padded hour and minute
+ '00:03'
+ > Ox.formatDate(Ox.test.date, '%r') // US time
+ '12:03:04 AM'
+ > Ox.formatDate(Ox.test.date, '%S') // Zero-padded second
+ '04'
+ > Ox.formatDate(Ox.test.date, '%s', true) // Number of seconds since the Epoch
+ '1104620584'
+ > Ox.formatDate(Ox.test.date, '%T') // Time
+ '00:03:04'
+ > Ox.formatDate(Ox.test.date, '%t') // Tab
+ '\t'
+ > Ox.formatDate(Ox.test.date, '%U') // Zero-padded week of the year (00-53, Sunday as first day)
+ '01'
+ > Ox.formatDate(Ox.test.date, '%u') // Decimal weekday (1-7, Monday as first day)
+ '7'
+ > Ox.formatDate(Ox.test.date, '%V') // Zero-padded ISO-8601 week of the year
+ '53'
+ > Ox.formatDate(Ox.test.date, '%v') // Formatted date
+ ' 2-Jan-2005'
+ > Ox.formatDate(Ox.test.date, '%W') // Zero-padded week of the year (00-53, Monday as first day)
+ '00'
+ > Ox.formatDate(Ox.test.date, '%w') // Decimal weekday (0-6, Sunday as first day)
+ '0'
+ > Ox.formatDate(Ox.test.date, '%X') // US time
+ '12:03:04 AM'
+ > Ox.formatDate(Ox.test.date, '%x') // US date
+ '01/02/05'
+ > Ox.formatDate(Ox.test.date, '%Y') // Full year
+ '2005'
+ > Ox.formatDate(Ox.test.date, '%y') // Abbreviated year
+ '05'
+ > Ox.formatDate(Ox.test.date, '%Z', true) // Time zone name
+ 'UTC'
+ > Ox.formatDate(Ox.test.date, '%z', true) // Time zone offset
+ '+0000'
+ > Ox.formatDate(Ox.test.date, '%+', true) // Formatted date and time
+ 'Sun Jan 2 00:03:04 CET 2005'
+ > Ox.formatDate(Ox.test.date, '%%')
+ '%'
+@*/
+
Ox.formatDate = function(date, str, utc) {
// fixme: date and utc are optional, date can be date, number or string
-
- /*
- See http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/strftime.3.html
- and http://en.wikipedia.org/wiki/ISO_8601
- >>> _date = new Date("2005-01-02 00:03:04")
- "Sun Jan 02 2005 00:03:04 GMT+0100 (CET)"
- >>> Ox.formatDate(_date, "%A") // Full weekday
- "Sunday"
- >>> Ox.formatDate(_date, "%a") // Abbreviated weekday
- "Sun"
- >>> Ox.formatDate(_date, "%B") // Full month
- "January"
- >>> Ox.formatDate(_date, "%b") // Abbreviated month
- "Jan"
- >>> Ox.formatDate(_date, "%C") // Century
- "20"
- >>> Ox.formatDate(_date, "%c") // US time and date
- "01/02/05 12:03:04 AM"
- >>> Ox.formatDate(_date, "%D") // US date
- "01/02/05"
- >>> Ox.formatDate(_date, "%d") // Zero-padded day of the month
- "02"
- >>> Ox.formatDate(_date, "%e") // Space-padded day of the month
- " 2"
- >>> Ox.formatDate(_date, "%F") // Date
- "2005-01-02"
- >>> Ox.formatDate(_date, "%G") // Full ISO-8601 year
- "2004"
- >>> Ox.formatDate(_date, "%g") // Abbreviated ISO-8601 year
- "04"
- >>> Ox.formatDate(_date, "%H") // Zero-padded hour (24-hour clock)
- "00"
- >>> Ox.formatDate(_date, "%h") // Abbreviated month
- "Jan"
- >>> Ox.formatDate(_date, "%I") // Zero-padded hour (12-hour clock)
- "12"
- >>> Ox.formatDate(_date, "%j") // Zero-padded day of the year
- "002"
- >>> Ox.formatDate(_date, "%k") // Space-padded hour (24-hour clock)
- " 0"
- >>> Ox.formatDate(_date, "%l") // Space-padded hour (12-hour clock)
- "12"
- >>> Ox.formatDate(_date, "%M") // Zero-padded minute
- "03"
- >>> Ox.formatDate(_date, "%m") // Zero-padded month
- "01"
- >>> Ox.formatDate(_date, "%n") // Newline
- "\n"
- >>> Ox.formatDate(_date, "%p") // AM or PM
- "AM"
- >>> Ox.formatDate(_date, "%Q") // Quarter of the year
- "1"
- >>> Ox.formatDate(_date, "%R") // Zero-padded hour and minute
- "00:03"
- >>> Ox.formatDate(_date, "%r") // US time
- "12:03:04 AM"
- >>> Ox.formatDate(_date, "%S") // Zero-padded second
- "04"
- >/> Ox.formatDate(_date, "%s") // Number of seconds since the Epoch
- "1104620584"
- >>> Ox.formatDate(_date, "%T") // Time
- "00:03:04"
- >>> Ox.formatDate(_date, "%t") // Tab
- "\t"
- >>> Ox.formatDate(_date, "%U") // Zero-padded week of the year (00-53, Sunday as first day)
- "01"
- >>> Ox.formatDate(_date, "%u") // Decimal weekday (1-7, Monday as first day)
- "7"
- >>> Ox.formatDate(_date, "%V") // Zero-padded ISO-8601 week of the year
- "53"
- >>> Ox.formatDate(_date, "%v") // Formatted date
- " 2-Jan-2005"
- >>> Ox.formatDate(_date, "%W") // Zero-padded week of the year (00-53, Monday as first day)
- "00"
- >>> Ox.formatDate(_date, "%w") // Decimal weekday (0-6, Sunday as first day)
- "0"
- >>> Ox.formatDate(_date, "%X") // US time
- "12:03:04 AM"
- >>> Ox.formatDate(_date, "%x") // US date
- "01/02/05"
- >>> Ox.formatDate(_date, "%Y") // Full year
- "2005"
- >>> Ox.formatDate(_date, "%y") // Abbreviated year
- "05"
- >/> Ox.formatDate(_date, "%Z") // Time zone name
- "CET"
- >/> Ox.formatDate(_date, "%z") // Time zone offset
- "+0100"
- >/> Ox.formatDate(_date, "%+") // Formatted date and time
- "Sun Jan 2 00:03:04 CET 2005"
- >>> Ox.formatDate(_date, "%%")
- "%"
- >>> delete _date
- true
- >>> Ox.formatDate(new Date("01/01/2000"), "%W")
- "00"
- >>> Ox.formatDate(new Date("01/02/2000"), "%W")
- "00"
- >>> Ox.formatDate(new Date("01/03/2000"), "%W")
- "01"
- */
-
date = Ox.makeDate(date);
var format = [
['%', function() {return '%{%}';}],
@@ -2167,19 +2132,20 @@ Ox.formatDate = function(date, str, utc) {
return str;
};
-Ox.formatDuration = function(sec, dec, format) {
- /*
- >>> Ox.formatDuration(123456.789, 3)
+/*@
+Ox.formatDuration Formats a duration as a string
+ > Ox.formatDuration(123456.789, 3)
"1:10:17:36.789"
- >>> Ox.formatDuration(12345.6789)
+ > Ox.formatDuration(12345.6789)
"03:25:46"
- >>> Ox.formatDuration(12345.6789, true)
+ > Ox.formatDuration(12345.6789, true)
"0:03:25:46"
- >>> Ox.formatDuration(3599.999, 3)
+ > Ox.formatDuration(3599.999, 3)
"00:59:59.999"
- >>> Ox.formatDuration(3599.999)
+ > Ox.formatDuration(3599.999)
"01:00:00"
- */
+@*/
+Ox.formatDuration = function(sec, dec, format) {
var format = arguments.length == 3 ? format : (Ox.isString(dec) ? dec : "short"),
dec = (arguments.length == 3 || Ox.isNumber(dec)) ? dec : 0,
sec = dec ? sec : Math.round(sec),
@@ -2213,15 +2179,17 @@ Ox.formatDuration = function(sec, dec, format) {
}).join(format == "short" ? ":" : " ");
};
-Ox.formatNumber = function(num, dec) {
- /*
- >>> Ox.formatNumber(123456789, 3)
+/*@
+Ox.formatNumber Formats a number with thousands separators
+ > Ox.formatNumber(123456789, 3)
"123,456,789.000"
- >>> Ox.formatNumber(-2000000 / 3, 3)
+ > Ox.formatNumber(-2000000 / 3, 3)
"-666,666.667"
- >>> Ox.formatNumber(666666.666)
+ > Ox.formatNumber(666666.666)
"666,667"
- */
+@*/
+Ox.formatNumber = function(num, dec) {
+ // fixme: specify decimal and thousands separators
var str = Math.abs(num).toFixed(dec || 0),
spl = str.split('.'),
arr = [];
@@ -2233,23 +2201,24 @@ Ox.formatNumber = function(num, dec) {
return (num < 0 ? '-' : '') + spl.join('.');
};
-Ox.formatOrdinal = function(num) {
- /*
- >>> Ox.formatOrdinal(1)
+/*@
+Ox.formatOrdinal Formats a number as an ordinal
+ > Ox.formatOrdinal(1)
"1st"
- >>> Ox.formatOrdinal(2)
+ > Ox.formatOrdinal(2)
"2nd"
- >>> Ox.formatOrdinal(3)
+ > Ox.formatOrdinal(3)
"3rd"
- >>> Ox.formatOrdinal(4)
+ > Ox.formatOrdinal(4)
"4th"
- >>> Ox.formatOrdinal(11)
+ > Ox.formatOrdinal(11)
"11th"
- >>> Ox.formatOrdinal(12)
+ > Ox.formatOrdinal(12)
"12th"
- >>> Ox.formatOrdinal(13)
+ > Ox.formatOrdinal(13)
"13th"
- */
+@*/
+Ox.formatOrdinal = function(num) {
var str = num.toString(),
end = str[str.length - 1],
ten = str.length > 1 && str[str.length - 2] == '1';
@@ -2265,43 +2234,50 @@ Ox.formatOrdinal = function(num) {
return str;
};
-Ox.formatPercent = function(num, total, dec) {
- /*
- >>> Ox.formatPercent(1, 1000, 2)
+/*@
+Ox.formatPercent Formats the relation of two numbers as a percentage
+ > Ox.formatPercent(1, 1000, 2)
"0.10%"
- */
+@*/
+Ox.formatPercent = function(num, total, dec) {
return Ox.formatNumber(num / total * 100, dec) + '%'
};
-Ox.formatResolution = function(arr, str) {
- /*
- >>> Ox.formatResolution([1920, 1080], 'px')
+/*@
+Ox.formatResolution Formats two values as a resolution
+ > Ox.formatResolution([1920, 1080], 'px')
"1920 x 1080 px"
- */
+@*/
+// fixme: should be formatDimensions
+Ox.formatResolution = function(arr, str) {
return arr[0] + ' x ' + arr[1] + (str ? ' ' + str : '');
}
+/*@
+Ox.formatString Basic string formatting
+ > Ox.formatString('{0}{1}', ['foo', 'bar'])
+ foobar'
+ > Ox.formatString('{a}{b}', {a: 'foo', b: 'bar'})
+ 'foobar'
+@*/
+
Ox.formatString = function (str, obj) {
- /*
- >>> Ox.formatString('{0}{1}', ['foo', 'bar'])
- "foobar"
- >>> Ox.formatString('{a}{b}', {a: 'foo', b: 'bar'})
- "foobar"
- */
return str.replace(/\{([^}]+)\}/g, function(str, match) {
return obj[match];
});
}
-Ox.formatValue = function(num, str, bin) {
- /*
- >>> Ox.formatValue(0, "B")
+/*@
+Ox.formatValue Formats a numerical value
+ > Ox.formatValue(0, "B")
"0 KB"
- >>> Ox.formatValue(123456789, "B")
+ > Ox.formatValue(123456789, "B")
"123.5 MB"
- >>> Ox.formatValue(1234567890, "B", true)
+ > Ox.formatValue(1234567890, "B", true)
"1.15 GiB"
- */
+@*/
+// fixme: is this the best name?
+Ox.formatValue = function(num, str, bin) {
var base = bin ? 1024 : 1000,
len = Ox.PREFIXES.length,
val;
@@ -2315,18 +2291,20 @@ Ox.formatValue = function(num, str, bin) {
return val;
};
+/*@
+Ox.formatUnit Formats a number with a unit
+@*/
Ox.formatUnit = function(num, str) {
return num + ' ' + str;
};
-/*
-================================================================================
-Geo functions
-================================================================================
-*/
+//* Geo ------------------------------------------------------------------------
(function() {
+ // fixme: make all this work with different types of "points"
+ // i.e. {lat, lng}, [lat, lng]
+
function rad(point) {
return {
lat: Ox.rad(point.lat),
@@ -2334,10 +2312,16 @@ Geo functions
};
}
+ /*@
+ Ox.crossesDateline Returns true if a given rectangle crosses the dateline
+ @*/
Ox.crossesDateline = function(point0, point1) {
return point0.lng > point1.lng;
}
+ /*@
+ Ox.getArea Returns the area in square meters of a given rectancle
+ @*/
Ox.getArea = function(point0, point1) {
/*
area of a ring between two latitudes:
@@ -2361,11 +2345,12 @@ Geo functions
Math.abs(point0.lng - point1.lng);
};
- Ox.getBearing = function(point0, point1) {
- /*
- >>> Ox.getBearing({lat: -45, lng: 0}, {lat: 45, lng: 0})
+ /*@
+ Ox.getBearing Returns the bearing from one point to another
+ > Ox.getBearing({lat: -45, lng: 0}, {lat: 45, lng: 0})
0
- */
+ @*/
+ Ox.getBearing = function(point0, point1) {
var point0 = rad(point0),
point1 = rad(point1),
x = Math.cos(point0.lat) * Math.sin(point1.lat) -
@@ -2376,11 +2361,12 @@ Geo functions
return (Ox.deg(Math.atan2(y, x)) + 360) % 360;
};
+ /*@
+ Ox.getCenter Returns the center of a recangle on a spehre
+ > Ox.getCenter({lat: -45, lng: -90}, {lat: 45, lng: 90})
+ {lat: 0, lng: 0}
+ @*/
Ox.getCenter = function(point0, point1) {
- /*
- >>> Ox.values(Ox.getCenter({lat: -45, lng: -90}, {lat: 45, lng: 90}))
- [0, 0]
- */
var point0 = rad(point0),
point1 = rad(point1),
x = Math.cos(point1.lat) *
@@ -2399,20 +2385,21 @@ Geo functions
return {lat: lat, lng: lng};
};
+ /*@
+ Ox.getDegreesPerMeter Returns degrees per meter at a given latitude
+ > 360 / Ox.getDegreesPerMeter(0)
+ Ox.EARTH_CIRCUMFERENCE
+ @*/
Ox.getDegreesPerMeter = function(lat) {
- /***
- return degrees per meter at a given latitude
- >>> Ox.EARTH_CIRCUMFERENCE == 360 / Ox.getDegreesPerMeter(0)
- true
- ***/
return 360 / Ox.EARTH_CIRCUMFERENCE / Math.cos(lat * Math.PI / 180);
};
+ /*@
+ Ox.getDistance Returns the distance in meters between two points
+ > Ox.getDistance({lat: -45, lng: -90}, {lat: 45, lng: 90}) * 2
+ Ox.EARTH_CIRCUMFERENCE
+ @*/
Ox.getDistance = function(point0, point1) {
- /*
- >>> Ox.EARTH_CIRCUMFERENCE == Ox.getDistance({lat: -45, lng: -90}, {lat: 45, lng: 90}) * 2
- true
- */
var point0 = rad(point0),
point1 = rad(point1);
return Math.acos(
@@ -2422,11 +2409,12 @@ Geo functions
) * Ox.EARTH_RADIUS;
};
+ /*@
+ Ox.getLatLngByXY Returns lat/lng for a given x/y on a 1x1 mercator projection
+ > Ox.values(Ox.getLatLngByXY({x: 0.5, y: 0.5}))
+ {lat: 0, lng: 0}
+ @*/
Ox.getLatLngByXY = function(xy) {
- /*
- >>> Ox.values(Ox.getLatLngByXY({x: 0.5, y: 0.5}))
- [0, 0]
- */
function getVal(val) {
return (val - 0.5) * 2 * Math.PI;
}
@@ -2436,20 +2424,21 @@ Geo functions
}
};
+ /*@
+ Ox.getMetersPerDegree Returns meters per degree at a given latitude
+ > Ox.getMetersPerDegree(0) * 360
+ Ox.EARTH_CIRCUMFERENCE
+ @*/
Ox.getMetersPerDegree = function(lat) {
- /***
- returns meters per degree at a given latitude
- >>> Ox.EARTH_CIRCUMFERENCE == Ox.getMetersPerDegree(0) * 360
- true
- ***/
return Math.cos(lat * Math.PI / 180) * Ox.EARTH_CIRCUMFERENCE / 360;
};
+ /*@
+ Ox.getXYByLatLng Returns x/y on a 1x1 mercator projection for a given lat/lng
+ > Ox.getXYByLatLng({lat: 0, lng: 0})
+ {x: 0.5, y: 0.5}
+ @*/
Ox.getXYByLatLng = function(latlng) {
- /*
- >>> Ox.values(Ox.getXYByLatLng({lat: 0, lng: 0}))
- [0.5, 0.5]
- */
function getVal(val) {
return (val / (2 * Math.PI) + 0.5)
}
@@ -2461,6 +2450,7 @@ Geo functions
}());
+//@ Ox.Line (undocumented)
Ox.Line = function(point0, point1) {
var self = {
@@ -2519,6 +2509,7 @@ Ox.Line = function(point0, point1) {
};
+//@ Ox.Point (undocumented)
Ox.Point = function(lat, lng) {
var self = {lat: lat, lng: lng},
@@ -2552,6 +2543,7 @@ Ox.Point = function(lat, lng) {
};
+//@ Ox.Rectangle (undocumented)
Ox.Rectangle = function(point0, point1) {
var self = {
@@ -2588,13 +2580,12 @@ Ox.Rectangle = function(point0, point1) {
};
+//@ HTML -----------------------------------------------------------------------
-/*
-================================================================================
-HTML functions
-================================================================================
-*/
-
+/*@
+Ox.parseEmailAddresses Takes HTML and turns e-mail addresses into links
+@*/
+// fixme: no tests
Ox.parseEmailAddresses = function(html) {
return html.replace(
/\b([0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi,
@@ -2602,25 +2593,26 @@ Ox.parseEmailAddresses = function(html) {
);
};
-Ox.parseHTML = (function() {
- /*
- >>> Ox.parseHTML('http://foo.com, bar')
+/*@
+Ox.parseHTML Takes HTML from an untrusted source and returns something sane
+ > Ox.parseHTML('http://foo.com, bar')
'foo.com, bar'
- >>> Ox.parseHTML('(see: www.foo.com)')
+ > Ox.parseHTML('(see: www.foo.com)')
'(see: www.foo.com)'
- >>> Ox.parseHTML('foo@bar.com')
+ > Ox.parseHTML('foo@bar.com')
'foo@bar.com'
- >>> Ox.parseHTML('foo')
+ > Ox.parseHTML('foo')
'foo'
- >>> Ox.parseHTML('foo')
+ > Ox.parseHTML('foo')
'<a href="javascript:alert()">foo</a>'
- >>> Ox.parseHTML('[http://foo.com foo]')
+ > Ox.parseHTML('[http://foo.com foo]')
'foo'
- >>> Ox.parseHTML('foo')
+ > Ox.parseHTML('foo')
'foo
'
- >>> Ox.parseHTML('')
- '<script>alert()</script>'
- */
+ > Ox.parseHTML('')
+ '<script>alert()</script>'
+@*/
+Ox.parseHTML = (function() {
var defaultTags = [
'a', 'b', 'blockquote', 'cite', 'code',
'del', 'em', 'i', 'img', 'ins',
@@ -2681,6 +2673,28 @@ Ox.parseHTML = (function() {
}());
+/*@
+Ox.parseURL Takes a URL, returns its components
+ (url) -> URL components
+ url URL
+ > Ox.test.object = Ox.parseURL('http://www.foo.com:8080/bar/index.html?a=0&b=1#c')
+ > Ox.test.object.hash
+ '#c'
+ > Ox.test.object.host
+ 'www.foo.com:8080'
+ > Ox.test.object.hostname
+ 'www.foo.com'
+ > Ox.test.object.origin
+ 'http://www.foo.com:8080'
+ > Ox.test.object.pathname
+ '/bar/index.html'
+ > Ox.test.object.port
+ '8080'
+ > Ox.test.object.protocol
+ 'http:'
+ > Ox.test.object.search
+ '?a=0&b=1'
+@*/
Ox.parseURL = (function() {
// fixme: leak memory, like now, or create every time? ... benchmark??
var a = document.createElement('a'),
@@ -2696,6 +2710,11 @@ Ox.parseURL = (function() {
};
}());
+/*@
+Ox.parseURLs Takes HTML and turns URLs into links
+@*/
+// fixme: is parseURLs the right name?
+// fixme: no tests
Ox.parseURLs = function(html) {
return html.replace(
/\b((https?:\/\/|www\.).+?)([\.,:;!\?\)\]]*?(\s|$))/gi,
@@ -2713,18 +2732,44 @@ Ox.parseURLs = function(html) {
);
};
-/*
-================================================================================
-JavaScript functions
-================================================================================
-*/
+//@ JavaScript -----------------------------------------------------------------
/*@
Ox.doc Generates documentation for annotated JavaScript
+ (file, callback) -> undefined
+ file JavaScript file
+ callback Callback function
+ doc <[o]> Array of doc objects
+ arguments <[o]|u> Arguments (array of doc objects)
+ Present if the type of the item is
+ "function".
+ description Multi-line description with optional markup
+ See Ox.parseHTML for details
+ events <[o]|u> Events (array of doc objects)
+ Present if the item fires any events
+ file File name
+ line Line number
+ name Name of the item
+ properties <[o]|u> Properties (array of doc objects)
+ Present if the type of the item is
+ "event", "function"
+ or "object".
+ section Section in the file
+ source <[o]> Source code (array of tokens)
+ length Length of the token
+ offset Offset of the token
+ type Type of the token
+ See Ox.tokenize for list of types
+ summary One-line summary
+ usage <[o]> Usage (array of doc objects)
+ Present if the type of the item is
+ "function".
+ type Type of the item
+
(source) Array of documentation objects
source JavaScript source code
- > Ox.doc("//@ Ox.foo just some string")
- [{"name": "Ox.foo", "summary": "just some string", "type": "string"}]
+ # > Ox.doc("//@ Ox.foo just some string")
+ # [{"name": "Ox.foo", "summary": "just some string", "type": "string"}]
@*/
Ox.doc = (function() {
@@ -2741,224 +2786,242 @@ Ox.doc = (function() {
e: 'element', f: 'function', n: 'number',
o: 'object', r: 'regexp', s: 'string',
u: 'undefined', '*': 'any', '!': 'event'
- }
- return function(source) {
- var blocks = [],
- items = [],
- tokens = [];
- Ox.tokenize(source).forEach(function(token) {
- var match;
- token.source = source.substr(token.offset, token.length);
- if (token.type == 'comment' && (match =
- re.multiline(token.source) || re.singleline(token.source)
- )) {
- blocks.push(match[1]);
- tokens.push([]);
- } else if (tokens.length) {
- tokens[tokens.length - 1].push(token);
+ };
+ function decodeLinebreaks(match, submatch) {
+ return (submatch || match).replace(/\u21A9/g, '\n');
+ }
+ function encodeLinebreaks(match, submatch) {
+ return '\n' + (submatch || match).replace(/\n/g, '\u21A9');
+ }
+ function getIndent(str) {
+ var indent = -1;
+ while (str[++indent] == ' ') {}
+ return indent;
+ }
+ function parseItem(str) {
+ var matches = re.item(str);
+ // to tell a variable with default value, like
+ // name foo'> summary
+ // from a line of description with tags, like
+ // some description text
+ // we need to check if there is either no forward slash
+ // or if the second last char is a single or double quote
+ return matches && (
+ matches[2].indexOf('/') == -1 ||
+ '\'"'.indexOf(matches[2].substr(-2, 1)) > -1
+ ) ? Ox.extend({
+ name: parseName(matches[1].trim()),
+ summary: matches[3].trim()
+ }, parseType(matches[2])) : null;
+ }
+ function parseName(str) {
+ var matches = re.usage(str);
+ return matches ? matches[0] : str;
+ }
+ function parseNode(node) {
+ var item = parseItem(node.line), subitem;
+ Ox.print(node, node.line, 'item', item);
+ node.nodes && node.nodes.forEach(function(node) {
+ var key, line = node.line, subitem;
+ if (!/^#/.test(node.line)) {
+ if (/^