forked from 0x2620/oxjs
various documentation-related changes
This commit is contained in:
parent
b6fdf0c28b
commit
a6ed310087
13 changed files with 880 additions and 301 deletions
725
source/Ox.js
725
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 <f> The Ox object
|
||||
See Ox.wrap for details.
|
||||
(value) -> <o> 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 <number> Radius of the earth in meters
|
||||
Ox.EARTH_RADIUS = 6378137;
|
||||
//@ Ox.EARTH_CIRCUMFERENCE <num> Circumference of the earth in meters
|
||||
Ox.EARTH_CIRCUMFERENCE = Ox.EARTH_RADIUS * 2 * Math.PI;
|
||||
//@ Ox.HTML_ENTITIES <object> HTML entities for ... (FIXME)
|
||||
Ox.HTML_ENTITIES = {
|
||||
'"': '"', '&': '&', "'": ''', '<': '<', '>': '>'
|
||||
};
|
||||
//@ Ox.KEYS <object> 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 <obj> 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 <str> 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 <arr> ['K', 'M', 'G', 'T', 'P']
|
||||
Ox.PREFIXES = ['K', 'M', 'G', 'T', 'P'];
|
||||
//@ Ox.SYMBOLS <obj> 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 <str> 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 <f> Generates documentation for annotated JavaScript
|
||||
(source) <a> Array of documentation objects
|
||||
source <s> JavaScript source code
|
||||
> Ox.doc("//@ Ox.foo <s> bar")
|
||||
[{"name": "Ox.foo", "summary": "bar", "type": "string"}]
|
||||
@*/
|
||||
|
||||
Ox.doc = (function() {
|
||||
var re = {
|
||||
item: /^(.+) <(.+)> (.+)$/,
|
||||
multiline: /^\/\*\@.*?\n([\w\W]+)\n.*?\@\*\/$/,
|
||||
script: /\n(\s*<script>s*\n[\w\W]+\n\s*<\/script>s*)/g,
|
||||
singleline: /^\/\/@\s*(.*?)\s*$/,
|
||||
test: /\n(\s*> .+\n.+?)/g,
|
||||
usage: /\(.*?\)/
|
||||
},
|
||||
types = {
|
||||
b: 'boolean', d: 'date', e: 'element',
|
||||
f: 'function', n: 'number', o: 'object',
|
||||
r: 'regexp', s: 'string', u: 'undefined',
|
||||
'*': 'any', '!': 'event'
|
||||
}
|
||||
return function(source) {
|
||||
var blocks = Ox.map(Ox.tokenize(source), function(token) {
|
||||
// filter out tokens that are not comments
|
||||
// or don't match the doc comment pattern
|
||||
var match;
|
||||
return token.type == 'comment' && (match =
|
||||
re.multiline(token.source) || re.singleline(token.source)
|
||||
) ? match[1] : null;
|
||||
}),
|
||||
items = [];
|
||||
blocks.forEach(function(block) {
|
||||
var item, lastItem,
|
||||
lines = block
|
||||
.replace(re.script, encodeLinebreaks)
|
||||
.replace(re.test, encodeLinebreaks)
|
||||
.split('\n');
|
||||
// create a tree and parse its root node
|
||||
item = parseNode(parseTree(lines));
|
||||
if (/^[A-Z]/.test(item.name)) {
|
||||
items.push(item);
|
||||
} else {
|
||||
lastItem = items[items.length - 1];
|
||||
lastItem.properties = lastItem.properties || [];
|
||||
lastItem.properties.push(item);
|
||||
}
|
||||
});
|
||||
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 <string|'<a href="...">foo</a>'> summary
|
||||
// from a line of description with tags, like
|
||||
// some <a href="...">description</a> 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 (/^<script>/.test(line)) {
|
||||
item.examples = [parseScript(line)];
|
||||
} else if (/^>/.test(line)) {
|
||||
item.examples = item.examples || [];
|
||||
item.examples.push(parseTest(line));
|
||||
} else if ((subitem = parseItem(line))) {
|
||||
if (/^\(/.test(subitem.name)) {
|
||||
item.usage = item.usage || [];
|
||||
item.usage.push(parseNode(node));
|
||||
} else if (subitem.types[0] == 'event') {
|
||||
item.events = item.events || [];
|
||||
item.events.push(parseNode(node));
|
||||
} else {
|
||||
key = item.types[0] == 'function' ?
|
||||
'arguments' : 'properties'
|
||||
item[key] = item[key] || [];
|
||||
item[key].push(parseNode(node));
|
||||
}
|
||||
} else {
|
||||
item.description = item.description ?
|
||||
item.description + ' ' + line : line
|
||||
}
|
||||
}
|
||||
});
|
||||
return item;
|
||||
}
|
||||
function parseScript(str) {
|
||||
// remove script tags and extra indentation
|
||||
var lines = decodeLinebreaks(str).split('\n'),
|
||||
indent = getIndent(lines[1]);
|
||||
return {
|
||||
statement: Ox.map(lines, function(line, i) {
|
||||
return i && i < lines.length - 1 ?
|
||||
line.substr(indent) : null;
|
||||
}).join('\n')
|
||||
};
|
||||
}
|
||||
function parseTest(str) {
|
||||
var lines = decodeLinebreaks(str).split('\n');
|
||||
return {
|
||||
statement: lines[0].substr(2),
|
||||
result: JSON.parse(lines[1].trim())
|
||||
};
|
||||
}
|
||||
function parseTree(lines) {
|
||||
// parses indented lines into a tree structure, like
|
||||
// {line: "...", nodes: [{line: "...", nodes: [...]}]}
|
||||
var branches = [],
|
||||
indent,
|
||||
node = {
|
||||
// chop the root line
|
||||
line: lines.shift().trim()
|
||||
};
|
||||
if (lines.length) {
|
||||
indent = getIndent(lines[0]);
|
||||
lines.forEach(function(line) {
|
||||
if (getIndent(line) == indent) {
|
||||
// line is a child,
|
||||
// make it the root line of a new branch
|
||||
branches.push([line]);
|
||||
} else {
|
||||
// line is a descendant of the last child,
|
||||
// add it to the last branch
|
||||
branches[branches.length - 1].push(line);
|
||||
}
|
||||
});
|
||||
node.nodes = branches.map(function(lines) {
|
||||
return parseTree(lines);
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
function parseType(str) {
|
||||
// returns {types: [""]}
|
||||
// or {types: [""], default: ""}
|
||||
// or {types: [""], parent: ""}
|
||||
var isArray,
|
||||
ret = {types: []},
|
||||
split,
|
||||
type;
|
||||
// only split by ':' if there is no default string value
|
||||
if ('\'"'.indexOf(str.substr(-2, 1)) == -1) {
|
||||
split = str.split(':');
|
||||
str = split[0];
|
||||
if (split.length == 2) {
|
||||
ret.parent = split[1];
|
||||
}
|
||||
}
|
||||
str.split('|').forEach(function(str) {
|
||||
var unwrapped = unwrap(str);
|
||||
if (unwrapped in types) {
|
||||
ret.types.push(wrap(types[unwrapped]))
|
||||
} else if (
|
||||
(type = Ox.filter(Ox.values(types), function(type) {
|
||||
return Ox.startsWith(type, unwrapped);
|
||||
})).length
|
||||
) {
|
||||
ret.types.push(wrap(type[0]))
|
||||
} else {
|
||||
ret.default = str;
|
||||
}
|
||||
});
|
||||
function unwrap(str) {
|
||||
return (isArray = /^\[.+\]$/.test(str)) ?
|
||||
str = str.substr(1, str.length - 2) : str;
|
||||
}
|
||||
function wrap(str) {
|
||||
return isArray ? 'array[' + str + 's]' : str;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return items;
|
||||
};
|
||||
}())
|
||||
|
||||
Ox.get = function(url, callback) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
callback(req.responseText);
|
||||
} else {
|
||||
throw new Error('URL ' + url + ', status ' + req.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
req.send();
|
||||
};
|
||||
|
||||
Ox.getJSON = function(url, callback) {
|
||||
Ox.get(url, function(data) {
|
||||
callback(JSON.parse(data));
|
||||
});
|
||||
}
|
||||
|
||||
/*@
|
||||
Ox.getset <f> Generic getter and setter function
|
||||
See examples for details.
|
||||
# Usage --------------------------------------------------------------------
|
||||
Ox.getset(options, args=[]) -> <o> all options
|
||||
Ox.getset(options, args=[key]) -> <*> options[key]
|
||||
Ox.getset(options, args=[key, value], callback, context) -> <f|o> 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) -> <f|o> context
|
||||
sets multiple options and calls fn(key, value)
|
||||
for every key/value pair that was added or modified
|
||||
# Arguments ----------------------------------------------------------------
|
||||
options <obj> Options object (key/value pairs)
|
||||
args <[*]> The arguments "array" of the caller function
|
||||
callback <fun> Callback function
|
||||
The callback is called for every key/value pair that was added or
|
||||
modified.
|
||||
key <s> Key
|
||||
value <*> Value
|
||||
context <obj> The parent object of the caller function (for chaining)
|
||||
# Examples -----------------------------------------------------------------
|
||||
<script>
|
||||
var object = new function() {
|
||||
var options = {},
|
||||
setOption = function(key, value) {},
|
||||
that = this;
|
||||
that.options = function() {
|
||||
return Ox.getset(options, arguments, setOption, that);
|
||||
}
|
||||
return that;
|
||||
};
|
||||
</script>
|
||||
> 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 <f> Loads a module
|
||||
(module, callback) -> <u> undefined
|
||||
(module, options, callback) -> <u> undefined
|
||||
module <s> Module name
|
||||
options <o> Module options
|
||||
callback <f> Callback function
|
||||
success <b> 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 <f> Loads a file (image, script or stylesheet)
|
||||
(file="script.js", callback) -> <u> undefined
|
||||
(file="stylesheet.css", callback) -> <u> undefined
|
||||
(file="image.png", callback) -> <e> DOM element
|
||||
file <s> Local path or remote URL
|
||||
callback <f> 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 <f> Prints its arguments to the console
|
||||
(arg, ...) -> <s> 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 <f> Returns a unique id
|
||||
() -> <n> Unique id
|
||||
> Ox.uid() != Ox.uid()
|
||||
true
|
||||
***/
|
||||
@*/
|
||||
Ox.uid = (function() {
|
||||
var uid = 0;
|
||||
return function() {
|
||||
return uid++;
|
||||
};
|
||||
}());
|
||||
|
||||
/*@
|
||||
Ox.wrap <f> 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) -> <o> wrapped value
|
||||
chain <f> wrap the return value to allow chaining
|
||||
value <f> 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 <f> Get the date that falls on a given weekday in the same week
|
||||
# Usage
|
||||
(date, weekday) -> <dat> Date
|
||||
(date, weekday, utc) -> <dat> UTC Date
|
||||
# Arguments
|
||||
date <d> Date
|
||||
weekday <n|s> 1-7 (Monday-Sunday) or name, full ("Monday") or short ("Sun")
|
||||
utc <b> 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 <function> Generic canvas object
|
||||
Returns an object with the properties: <code>canvas</code>,
|
||||
<code>context</code>, <code>data</code> and <code>imageData</code>.
|
||||
# Usage --------------------------------------------------------------------
|
||||
Ox.canvas(width, height) -> <object> canvas
|
||||
Ox.canvas(image) -> <object> canvas
|
||||
# Arguments ----------------------------------------------------------------
|
||||
width <n> Width in px
|
||||
height <n> Height in px
|
||||
image <e> 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 <function> Calls a callback function once the DOM is ready
|
||||
(callback) -> <boolean> If true, the document was ready
|
||||
callback <function> 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 <f> Generic HTML element, mimics jQuery
|
||||
(str) -> <o> Element object
|
||||
str <s> Tagname ('<tagname>') or selector ('tagname', '.classname', '#id')
|
||||
> Ox.element("<div>").addClass("red").addClass("red")[0].classname
|
||||
"red"
|
||||
> Ox.element("<div>").attr({id: "red"}).attr("id")
|
||||
"red"
|
||||
> Ox.element("<div>").css("color", "red").css("color")
|
||||
"red"
|
||||
> Ox.element("<div>").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 <e> 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 <f> Adds a class name
|
||||
(className) -> <o> This element
|
||||
className <s> 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() <f> Appends another element to this element
|
||||
(element) -> <o> This element
|
||||
element <o> Another element
|
||||
@*/
|
||||
append: function(element) {
|
||||
this[0].appendChild(element[0]);
|
||||
return this;
|
||||
},
|
||||
/*@
|
||||
appendTo <f> appends this element object to another element object
|
||||
(element) -> <o> This element
|
||||
element <o> Another element
|
||||
@*/
|
||||
appendTo: function(element) {
|
||||
element[0].appendChild(this[0]);
|
||||
return this;
|
||||
},
|
||||
/*@
|
||||
attr <f> Gets or sets an attribute
|
||||
(key) -> <s> Value
|
||||
(key, value) -> <o> This element
|
||||
({key, value}) -> <o> This element
|
||||
key <str> Attribute name
|
||||
value <str> 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 <f> Gets or sets a CSS attribute
|
||||
(key) -> <s> Value
|
||||
(key, value) -> <o> This element
|
||||
({key, value}) -> <o> This element
|
||||
key <str> Attribute name
|
||||
value <str> 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 <f> Gets or sets the inner HTML
|
||||
() -> <s> The inner HTML
|
||||
(html) -> <o> This element
|
||||
html <s> 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 <f> Binds a function to the mousedown event
|
||||
(callback) -> <o> This element
|
||||
callback <f> Callback function
|
||||
event <o> The DOM event
|
||||
@*/
|
||||
mousedown: function(callback) {
|
||||
this[0].onmousedown = callback;
|
||||
return this;
|
||||
},
|
||||
/*@
|
||||
removeClass <f> Removes a class name
|
||||
(className) -> <o> This element
|
||||
className <s> 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('<div>').html(str)[0].childNodes[0].nodeValue;
|
||||
//return $('<div/>').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 <f> Tests if a value is undefined
|
||||
(value) -> <b> 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 <f> Returns the type of a value
|
||||
(value) -> <s> 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)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue