2010-01-07 20:21:07 +00:00
|
|
|
|
// todo: check http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
|
|
|
|
|
|
2011-01-23 04:59:16 +00:00
|
|
|
|
/*
|
|
|
|
|
Ox = function(val) {
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
if (!window.Ox) {
|
|
|
|
|
Ox = {
|
|
|
|
|
version: '0.1.2'
|
|
|
|
|
};
|
|
|
|
|
}
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Constants
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.AMPM = ['AM', 'PM'];
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
2010-11-28 15:06:47 +00:00
|
|
|
|
Ox.EARTH_RADIUS = 6378137;
|
|
|
|
|
Ox.EARTH_CIRCUMFERENCE = Ox.EARTH_RADIUS * 2 * Math.PI;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.HTML_ENTITIES = {'"': '"', '&': '&', "'": ''',
|
|
|
|
|
'<': '<', '>': '>'};
|
|
|
|
|
Ox.MONTHS = ['January', 'February', 'March', 'April', 'May', 'June',
|
|
|
|
|
'July', 'August', 'September', 'October', 'November', 'December'];
|
|
|
|
|
Ox.PREFIXES = ['K', 'M', 'G', 'T', 'P'];
|
|
|
|
|
Ox.WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
|
|
|
|
|
'Friday', 'Saturday', 'Sunday'];
|
2010-09-03 08:47:40 +00:00
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Core functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
2010-01-27 12:30:00 +00:00
|
|
|
|
Ox.getset = function(obj, args, callback, context) {
|
2011-01-23 04:59:16 +00:00
|
|
|
|
/***
|
|
|
|
|
Generic getter and setter function
|
|
|
|
|
|
2010-09-05 00:31:58 +00:00
|
|
|
|
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),
|
|
|
|
|
returns context
|
2011-01-23 04:59:16 +00:00
|
|
|
|
***/
|
2010-02-06 08:23:42 +00:00
|
|
|
|
var obj_ = obj,
|
2010-09-05 00:31:58 +00:00
|
|
|
|
args_ = {},
|
|
|
|
|
args = args || [],
|
|
|
|
|
callback = callback || {},
|
2010-01-27 12:30:00 +00:00
|
|
|
|
context = context || {},
|
|
|
|
|
length = args.length,
|
|
|
|
|
ret;
|
|
|
|
|
if (length == 0) {
|
|
|
|
|
// getset()
|
|
|
|
|
ret = obj;
|
2010-09-05 00:31:58 +00:00
|
|
|
|
} else if (length == 1 && Ox.isString(args[0])) {
|
2010-01-27 12:30:00 +00:00
|
|
|
|
// getset(str)
|
|
|
|
|
ret = obj[args[0]]
|
|
|
|
|
} else {
|
|
|
|
|
// getset(str, val) or getset({str: val, ...})
|
2010-09-05 00:31:58 +00:00
|
|
|
|
if (length == 1) {
|
|
|
|
|
args = args[0];
|
|
|
|
|
} else {
|
|
|
|
|
args_[args[0]] = args[1];
|
|
|
|
|
args = args_;
|
|
|
|
|
}
|
2010-01-27 12:30:00 +00:00
|
|
|
|
obj = $.extend(obj, args);
|
2010-02-06 08:23:42 +00:00
|
|
|
|
$.each(args, function(key, value) {
|
|
|
|
|
if (!obj_ || !obj_[key] || obj_[key] !== value) {
|
|
|
|
|
callback(key, value);
|
|
|
|
|
}
|
2010-01-27 12:30:00 +00:00
|
|
|
|
});
|
|
|
|
|
ret = context;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.print = function() {
|
|
|
|
|
/*
|
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
if (window.console) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var args = $.makeArray(arguments),
|
|
|
|
|
date = new Date;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
args.unshift(Ox.formatDate(date, '%H:%M:%S') + '.' +
|
2010-01-07 20:21:07 +00:00
|
|
|
|
(Ox.pad(+date % 1000, 3)));
|
2011-02-09 17:56:35 +00:00
|
|
|
|
window.console.log.apply(window.console, args);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.uid = (function() {
|
2010-09-03 08:47:40 +00:00
|
|
|
|
/***
|
2011-01-23 04:59:16 +00:00
|
|
|
|
returns a unique id
|
|
|
|
|
>>> Ox.uid() != Ox.uid()
|
|
|
|
|
true
|
2010-09-03 08:47:40 +00:00
|
|
|
|
***/
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var uid = 0;
|
|
|
|
|
return function() {
|
|
|
|
|
return uid++;
|
|
|
|
|
};
|
2011-02-09 17:56:35 +00:00
|
|
|
|
}());
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
|
|
|
|
Ox.user = function() {
|
2011-02-03 21:39:22 +00:00
|
|
|
|
// fixme: move to ox.ui
|
2010-01-07 20:21:07 +00:00
|
|
|
|
$.get("http://www.maxmind.com/app/locate_my_ip", function(data) {
|
|
|
|
|
var arr = data.split("tblProduct1"),
|
|
|
|
|
re = />(.+?)<\/td>\n<td class=output align="center">\n(.*?)\n/,
|
|
|
|
|
results = {};
|
|
|
|
|
arr.shift();
|
|
|
|
|
$.each(arr, function(i, v) {
|
|
|
|
|
var result = re(v);
|
|
|
|
|
results[result[1].replace(/Your |\*/, "")] = result[2];
|
|
|
|
|
});
|
2010-02-06 10:29:27 +00:00
|
|
|
|
Ox.print(results)
|
2010-01-07 20:21:07 +00:00
|
|
|
|
});
|
|
|
|
|
return {
|
|
|
|
|
document: {
|
|
|
|
|
referrer: document.referrer
|
|
|
|
|
},
|
|
|
|
|
history: {
|
|
|
|
|
length: history.length
|
|
|
|
|
},
|
|
|
|
|
navigator: navigator,
|
|
|
|
|
innerHeight: innerHeight,
|
|
|
|
|
innerWidth: innerWidth,
|
|
|
|
|
screen: screen,
|
|
|
|
|
outerHeight: outerHeight,
|
|
|
|
|
outerWidth: outerWidth
|
|
|
|
|
}
|
2010-07-13 22:38:53 +00:00
|
|
|
|
};
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Array and Object functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.avg = function(obj) {
|
2010-09-03 08:47:40 +00:00
|
|
|
|
/***
|
2011-01-23 04:59:16 +00:00
|
|
|
|
returns the average of an array's values, or an object's properties
|
2010-01-07 20:21:07 +00:00
|
|
|
|
>>> Ox.avg([-1, 0, 1])
|
|
|
|
|
0
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.avg({a: 1, b: 2, c: 3})
|
2010-01-07 20:21:07 +00:00
|
|
|
|
2
|
2010-09-03 08:47:40 +00:00
|
|
|
|
***/
|
2010-01-07 20:21:07 +00:00
|
|
|
|
return Ox.sum(obj) / Ox.length(obj);
|
|
|
|
|
};
|
|
|
|
|
|
2011-01-23 04:59:16 +00:00
|
|
|
|
Ox.clone = function(obj) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
*/
|
2011-01-23 04:59:16 +00:00
|
|
|
|
return Ox.isArray(obj) ? obj.slice() : Ox.extend({}, obj);
|
|
|
|
|
};
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.count = function(arr) {
|
|
|
|
|
/*
|
|
|
|
|
Ox.count(['foo', 'bar', 'foo']).foo
|
|
|
|
|
2
|
|
|
|
|
*/
|
|
|
|
|
var obj = {};
|
|
|
|
|
arr.forEach(function(v) {
|
|
|
|
|
obj[v] = (obj[v] || 0) + 1;
|
|
|
|
|
});
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.each = function(obj, fn) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
// fixme: deprecate!
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
|
|
|
|
Ox.each() works for arrays, objects and strings,
|
|
|
|
|
like $.each(), unlike [].forEach()
|
|
|
|
|
>>> Ox.each([0, 1, 2], function(i, v) {})
|
|
|
|
|
[0, 1, 2]
|
|
|
|
|
>>> Ox.each({a: 1, b: 2, c: 3}, function(k, v) {}).a
|
|
|
|
|
1
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.each('foo', function(i, v) {})
|
|
|
|
|
'foo'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
var i, isArray = Ox.isArray(obj);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
for (i in obj) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
i = isArray ? parseInt(i) : i;
|
2011-01-23 04:59:16 +00:00
|
|
|
|
// fixme: should be (v, k), like [].forEach()
|
2010-01-07 20:21:07 +00:00
|
|
|
|
if (fn(i, obj[i]) === false) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
|
|
|
|
|
2010-12-31 07:03:36 +00:00
|
|
|
|
Ox.equals = function(obj0, obj1) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.equals([1, 2, 3], [1, 2, 3])
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.equals({a: 1, b: [2, 3], c: {d: '4'}}, {a: 1, b: [2, 3], c: {d: '4'}})
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.equals(function() { return; }, function() { return; });
|
|
|
|
|
true
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
var ret = false;
|
2010-12-31 07:03:36 +00:00
|
|
|
|
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) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(obj0, function(v, i) {
|
2010-12-31 11:01:35 +00:00
|
|
|
|
ret = Ox.equals(v, obj1[i]);
|
2010-12-31 07:03:36 +00:00
|
|
|
|
return ret;
|
|
|
|
|
});
|
2011-01-23 04:59:16 +00:00
|
|
|
|
} else if (Ox.isDate(obj0)) {
|
|
|
|
|
ret = obj0.getTime() == obj1.getTime();
|
2010-12-31 07:03:36 +00:00
|
|
|
|
} else if (Ox.isObject(obj0)) {
|
|
|
|
|
ret = Ox.equals(Ox.keys(obj0), Ox.keys(obj1)) &&
|
|
|
|
|
Ox.equals(Ox.values(obj0), Ox.values(obj1));
|
2011-01-02 10:01:55 +00:00
|
|
|
|
} else if (Ox.isFunction(obj0)) {
|
|
|
|
|
ret = obj0.toString() == obj1.toString();
|
2010-12-31 07:03:36 +00:00
|
|
|
|
}
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.every = function(obj, fn) {
|
|
|
|
|
/*
|
2010-12-31 07:03:36 +00:00
|
|
|
|
Ox.every() works for arrays, objects and strings, unlike [].every()
|
2010-01-07 20:21:07 +00:00
|
|
|
|
>>> 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
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.every("foo", function(v) { return v == 'f'; })
|
2010-01-07 20:21:07 +00:00
|
|
|
|
false
|
2010-07-20 20:04:13 +00:00
|
|
|
|
>>> Ox.every([true, true, true])
|
|
|
|
|
true
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2010-07-20 20:04:13 +00:00
|
|
|
|
return Ox.filter(Ox.values(obj), fn || function(v) {
|
|
|
|
|
return v;
|
|
|
|
|
}).length == Ox.length(obj);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.extend = function() {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.extend({a: 1}, {b: 2}, {c: 3}).c
|
|
|
|
|
3
|
|
|
|
|
*/
|
|
|
|
|
var obj = {};
|
|
|
|
|
Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg, i) {
|
|
|
|
|
Ox.forEach(arg, function(val, key) {
|
|
|
|
|
obj[key] = val;
|
2011-01-23 04:59:16 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return obj;
|
2011-01-23 04:59:16 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.filter = function(arr, fn) {
|
|
|
|
|
/*
|
|
|
|
|
Ox.filter works for arrays and strings, like $.grep(), unlike [].filter()
|
|
|
|
|
>>> Ox.filter([2, 1, 0], function(v, i) { return v == i; })
|
|
|
|
|
[1]
|
|
|
|
|
>>> Ox.filter("210", function(v, i) { return v == i; })
|
|
|
|
|
[1]
|
|
|
|
|
*/
|
|
|
|
|
var i, len = arr.length, ret = [];
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (fn(arr[i], i)) {
|
|
|
|
|
ret.push(arr[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
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.find = function(arr, str) {
|
|
|
|
|
/*
|
2011-01-23 04:59:16 +00:00
|
|
|
|
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
|
2010-09-03 08:47:40 +00:00
|
|
|
|
>>> Ox.find(["foo", "bar", "foobar", "barfoo"], "foo")
|
|
|
|
|
[["foo", "foobar"], ["barfoo"]]
|
|
|
|
|
*/
|
|
|
|
|
var arrLowerCase = arr.map(function(v) {
|
|
|
|
|
return v.toLowerCase();
|
|
|
|
|
}),
|
|
|
|
|
ret = [[], []];
|
|
|
|
|
str && arrLowerCase.forEach(function(v, i) {
|
|
|
|
|
var index = v.indexOf(str.toLowerCase());
|
|
|
|
|
index > -1 && ret[index == 0 ? 0 : 1].push(arr[i]);
|
|
|
|
|
});
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach = function(obj, fn) {
|
|
|
|
|
/*
|
|
|
|
|
Ox.forEach() works for arrays, objects and strings,
|
|
|
|
|
like $.each(), unlike [].forEach()
|
|
|
|
|
The arguments of the iterator function are (value, key),
|
|
|
|
|
like [].forEach(), unlike $.each()
|
|
|
|
|
>>> Ox.forEach([0, 1, 2], function(v, i) {})
|
|
|
|
|
[0, 1, 2]
|
|
|
|
|
>>> Ox.forEach({a: 1, b: 2, c: 3}, function(v, k) {}).a
|
|
|
|
|
1
|
|
|
|
|
>>> Ox.forEach('foo', function(v, i) {})
|
|
|
|
|
'foo'
|
|
|
|
|
*/
|
|
|
|
|
var key, isArray = Ox.isArray(obj);
|
|
|
|
|
for (key in obj) {
|
|
|
|
|
key = isArray ? parseInt(key) : key;
|
|
|
|
|
if (fn(obj[key], key) === false) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
|
|
|
|
|
2010-07-05 16:52:12 +00:00
|
|
|
|
Ox.getObjectById = function(arr, id) {
|
2011-01-23 04:59:16 +00:00
|
|
|
|
/***
|
|
|
|
|
>>> Ox.getObjectById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo").title
|
|
|
|
|
"Foo"
|
|
|
|
|
***/
|
2010-07-05 16:52:12 +00:00
|
|
|
|
var ret = null;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(arr, function(v) {
|
2010-07-05 16:52:12 +00:00
|
|
|
|
if (v.id == id) {
|
|
|
|
|
ret = v;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.getPositionById = function(arr, id) {
|
2011-01-23 04:59:16 +00:00
|
|
|
|
/***
|
|
|
|
|
>>> Ox.getPositionById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "bar")
|
|
|
|
|
1
|
|
|
|
|
***/
|
2010-07-05 16:52:12 +00:00
|
|
|
|
var ret = -1;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(arr, function(v, i) {
|
2010-07-05 16:52:12 +00:00
|
|
|
|
if (v.id == id) {
|
|
|
|
|
ret = i;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.keys = function(obj) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.keys({a: 1, b: 2, c: 3})
|
2010-01-07 20:21:07 +00:00
|
|
|
|
["a", "b", "c"]
|
|
|
|
|
*/
|
|
|
|
|
var keys = [];
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(obj, function(v, k) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
keys.push(k);
|
|
|
|
|
});
|
|
|
|
|
return keys;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.length = function(obj) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.length({"a": 1, "b": 2, "c": 3})
|
|
|
|
|
3
|
|
|
|
|
*/
|
|
|
|
|
var length = 0;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(obj, function() {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
length++;
|
|
|
|
|
});
|
|
|
|
|
return length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.makeArray = function(arr) {
|
|
|
|
|
/*
|
|
|
|
|
like $.makeArray()
|
|
|
|
|
>>> Ox.makeArray("foo")
|
|
|
|
|
["foo"]
|
|
|
|
|
>>> Ox.makeArray(["foo"])
|
|
|
|
|
["foo"]
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> (function() { return Ox.makeArray(arguments); }("foo"))
|
2010-01-07 20:21:07 +00:00
|
|
|
|
["foo"]
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> (function() { return Ox.makeArray(arguments); }(["foo"]))
|
2010-01-07 20:21:07 +00:00
|
|
|
|
["foo"]
|
|
|
|
|
*/
|
2010-09-03 08:47:40 +00:00
|
|
|
|
// fixme: this doesn't work for numbers
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var ret = [], i = 0, len = arr.length;
|
|
|
|
|
if (Ox.isString(arr)) {
|
|
|
|
|
ret = [arr];
|
|
|
|
|
} else {
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
ret.push(arr[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.makeObject = function(arr) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.makeObject("foo", "bar").foo
|
|
|
|
|
"bar"
|
|
|
|
|
>>> Ox.makeObject({foo: "bar"}).foo
|
|
|
|
|
"bar"
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>/>> (function() { return Ox.makeObject(arguments); }("foo", "bar")).foo // fixme
|
2010-01-07 20:21:07 +00:00
|
|
|
|
"bar"
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>/>> (function() { return Ox.makeObject(arguments); }({foo: "bar"})).foo
|
2010-01-07 20:21:07 +00:00
|
|
|
|
"bar"
|
|
|
|
|
*/
|
|
|
|
|
var obj = {};
|
|
|
|
|
if (arguments.length == 1) {
|
|
|
|
|
obj = arguments[0];
|
|
|
|
|
} else {
|
|
|
|
|
obj[arguments[0]] = arguments[1];
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.map = function(arr, fn) {
|
|
|
|
|
/*
|
|
|
|
|
Ox.map() works for arrays and strings, like $.map(), unlike [].map()
|
|
|
|
|
>>> Ox.map([1, 1, 1], function(v, i) { return v == i; })
|
|
|
|
|
[false, true, false]
|
|
|
|
|
>>> Ox.map("111", function(v, i) { return v == i; })
|
|
|
|
|
[false, true, false]
|
|
|
|
|
>>> Ox.map(new Array(3), function(v, i) { return i; })
|
|
|
|
|
[0, 1, 2]
|
|
|
|
|
*/
|
2011-01-23 04:59:16 +00:00
|
|
|
|
// fixme: why not [].map.call(str, fn)?
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var i, len = arr.length, val, ret = [];
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if ((val = fn(arr[i], i)) !== null) {
|
|
|
|
|
ret.push(val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.max = function(obj) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.max([-1, 0, 1])
|
|
|
|
|
1
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.max({a: 1, b: 2, c: 3})
|
2010-01-07 20:21:07 +00:00
|
|
|
|
3
|
|
|
|
|
*/
|
|
|
|
|
return Math.max.apply(Math, Ox.values(obj));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.min = function(obj) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.min([-1, 0, 1])
|
|
|
|
|
-1
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.min({a: 1, b: 2, c: 3})
|
2010-01-07 20:21:07 +00:00
|
|
|
|
1
|
|
|
|
|
*/
|
|
|
|
|
return Math.min.apply(Math, Ox.values(obj));
|
|
|
|
|
};
|
|
|
|
|
|
2011-01-23 04:59:16 +00:00
|
|
|
|
Ox.merge = function(arr) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.merge(['foo'], ['bar'], ['baz'])
|
|
|
|
|
['foo', 'bar', 'baz']
|
|
|
|
|
*/
|
|
|
|
|
Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg) {
|
|
|
|
|
Ox.forEach(arg, function(val) {
|
2011-01-23 04:59:16 +00:00
|
|
|
|
arr.push(val);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return arr;
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.range = function(start, stop, step) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.range(3)
|
|
|
|
|
[0, 1, 2]
|
|
|
|
|
>>> Ox.range(3, 0)
|
|
|
|
|
[3, 2, 1]
|
|
|
|
|
>>> Ox.range(1, 2, 0.5)
|
|
|
|
|
[1, 1.5]
|
|
|
|
|
*/
|
|
|
|
|
stop = arguments.length > 1 ? stop : arguments[0];
|
|
|
|
|
start = arguments.length > 1 ? start : 0;
|
|
|
|
|
step = step || (start <= stop ? 1 : -1);
|
|
|
|
|
var range = [],
|
|
|
|
|
i;
|
|
|
|
|
for (i = start; step > 0 ? i < stop : i > stop; i += step) {
|
|
|
|
|
range.push(i);
|
|
|
|
|
}
|
|
|
|
|
return range;
|
|
|
|
|
};
|
|
|
|
|
|
2010-07-13 22:38:53 +00:00
|
|
|
|
Ox.serialize = function(obj) {
|
2010-09-03 08:47:40 +00:00
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.serialize({a: 1, b: 2, c: 3})
|
|
|
|
|
'a=1&b=2&c=3'
|
2010-09-03 08:47:40 +00:00
|
|
|
|
*/
|
2010-07-13 22:38:53 +00:00
|
|
|
|
var arr = [];
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(obj, function(val, key) {
|
|
|
|
|
val !== '' && arr.push(key + '=' + val);
|
2010-07-13 22:38:53 +00:00
|
|
|
|
});
|
2011-01-03 12:01:38 +00:00
|
|
|
|
return arr.join('&');
|
2010-07-13 22:38:53 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.setPropertyOnce = function(arr, str) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.setPropertyOnce([{selected: false}, {selected: false}])
|
|
|
|
|
0
|
|
|
|
|
>>> Ox.setPropertyOnce([{selected: true}, {selected: true}])
|
|
|
|
|
0
|
|
|
|
|
*/
|
2010-09-03 08:47:40 +00:00
|
|
|
|
var pos = -1;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(arr, function(v, i) {
|
2010-09-03 08:47:40 +00:00
|
|
|
|
if (pos == -1 && arr[i][str]) {
|
|
|
|
|
pos = i;
|
|
|
|
|
} else if (pos > -1 && arr[i][str]) {
|
|
|
|
|
delete arr[i][str];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (pos == -1) {
|
|
|
|
|
arr[0][str] = true;
|
|
|
|
|
pos = 0;
|
|
|
|
|
}
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.shuffle = function(arr) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.shuffle([1, 2, 3]).length
|
|
|
|
|
3
|
|
|
|
|
*/
|
|
|
|
|
var shuffle = arr;
|
|
|
|
|
return shuffle.sort(function() {
|
|
|
|
|
return Math.random() - 0.5;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.some = function(obj, fn) {
|
|
|
|
|
/*
|
2010-07-05 16:52:12 +00:00
|
|
|
|
Ox.some() works for arrays, objects and strings, unlike [].some()
|
2010-01-07 20:21:07 +00:00
|
|
|
|
>>> Ox.some([2, 1, 0], function(i, v) { return i == v; })
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.some({a: 1, b: 2, c: 3}, function(v) { return v == 1; })
|
|
|
|
|
true
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.some("foo", function(v) { return v == 'f'; })
|
2010-01-07 20:21:07 +00:00
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return Ox.filter(Ox.values(obj), fn).length > 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.sum = function(obj) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.sum([-1, 0, 1])
|
|
|
|
|
0
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.sum({a: 1, b: 2, c: 3})
|
2010-01-07 20:21:07 +00:00
|
|
|
|
6
|
|
|
|
|
*/
|
|
|
|
|
var sum = 0;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(obj, function(val) {
|
|
|
|
|
sum += val;
|
2010-01-07 20:21:07 +00:00
|
|
|
|
});
|
|
|
|
|
return sum;
|
|
|
|
|
};
|
|
|
|
|
|
2010-09-06 23:44:37 +00:00
|
|
|
|
Ox.unique = function(arr) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.unique([1, 2, 3, 1])
|
|
|
|
|
[1, 2, 3]
|
|
|
|
|
*/
|
|
|
|
|
var unique = [];
|
|
|
|
|
$.each(arr, function(i, v) {
|
|
|
|
|
unique.indexOf(v) == -1 && unique.push(v);
|
|
|
|
|
});
|
|
|
|
|
return unique;
|
|
|
|
|
};
|
|
|
|
|
|
2010-07-13 22:38:53 +00:00
|
|
|
|
Ox.unserialize = function(str) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.unserialize('a=1&b=2&c=3').c
|
|
|
|
|
'3'
|
|
|
|
|
*/
|
2010-07-13 22:38:53 +00:00
|
|
|
|
var arr, obj = {};
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(str.split('&'), function(val) {
|
|
|
|
|
arr = val.split('=');
|
2010-07-13 22:38:53 +00:00
|
|
|
|
obj[arr[0]] = arr[1];
|
|
|
|
|
});
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.values = function(obj) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.values({a: 1, b: 2, c: 3})
|
2010-01-07 20:21:07 +00:00
|
|
|
|
[1, 2, 3]
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.values([1, 2, 3])
|
2010-01-07 20:21:07 +00:00
|
|
|
|
[1, 2, 3]
|
|
|
|
|
*/
|
|
|
|
|
var values = [];
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(obj, function(val) {
|
|
|
|
|
values.push(val);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
});
|
|
|
|
|
return values;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.hsl = function(rgb) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.hsl([0, 0, 0])
|
|
|
|
|
[0, 0, 0]
|
|
|
|
|
>>> Ox.hsl([255, 255, 255])
|
|
|
|
|
[0, 0, 1]
|
|
|
|
|
>>> Ox.hsl([0, 255, 0])
|
|
|
|
|
[120, 1, 0.5]
|
|
|
|
|
*/
|
|
|
|
|
rgb = rgb.map(function(v) {
|
|
|
|
|
return v / 255;
|
|
|
|
|
});
|
|
|
|
|
var max = Ox.max(rgb),
|
|
|
|
|
min = Ox.min(rgb),
|
|
|
|
|
hsl = [0, 0, 0];
|
|
|
|
|
hsl[2] = 0.5 * (max + min);
|
|
|
|
|
if (max == min) {
|
|
|
|
|
hsl[0] = 0;
|
|
|
|
|
hsl[1] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (max == rgb[0]) {
|
|
|
|
|
hsl[0] = (60 * (rgb[1] - rgb[2]) / (max - min) + 360) % 360;
|
|
|
|
|
} else if (max == rgb[1]) {
|
|
|
|
|
hsl[0] = 60 * (rgb[2] - rgb[0]) / (max - min) + 120;
|
|
|
|
|
} else if (max == rgb[2]) {
|
|
|
|
|
hsl[0] = 60 * (rgb[0] - rgb[1]) / (max - min) + 240;
|
|
|
|
|
}
|
|
|
|
|
if (hsl[2] <= 0.5) {
|
|
|
|
|
hsl[1] = (max - min) / (2 * hsl[2]);
|
|
|
|
|
} else {
|
|
|
|
|
hsl[1] = (max - min) / (2 - 2 * hsl[2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return hsl;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.rgb = function(hsl) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.rgb([0, 0, 0])
|
|
|
|
|
[0, 0, 0]
|
|
|
|
|
>>> Ox.rgb([0, 0, 1])
|
|
|
|
|
[255, 255, 255]
|
|
|
|
|
>>> Ox.rgb([120, 1, 0.5])
|
|
|
|
|
[0, 255, 0]
|
|
|
|
|
*/
|
|
|
|
|
hsl[0] /= 360;
|
|
|
|
|
var rgb = [0, 0, 0],
|
|
|
|
|
v1, v2, v3;
|
|
|
|
|
if (hsl[1] == 0) {
|
|
|
|
|
rgb = [hsl[2], hsl[2], hsl[2]];
|
|
|
|
|
} else {
|
|
|
|
|
if (hsl[2] < 0.5) {
|
|
|
|
|
v2 = hsl[2] * (1 + hsl[1]);
|
|
|
|
|
} else {
|
|
|
|
|
v2 = hsl[1] + hsl[2] - (hsl[1] * hsl[2]);
|
|
|
|
|
}
|
|
|
|
|
v1 = 2 * hsl[2] - v2;
|
|
|
|
|
rgb.forEach(function(v, i) {
|
|
|
|
|
v3 = hsl[0] + (1 - i) * 1/3;
|
|
|
|
|
if (v3 < 0) {
|
|
|
|
|
v3++;
|
|
|
|
|
} else if (v3 > 1) {
|
|
|
|
|
v3--;
|
|
|
|
|
}
|
|
|
|
|
if (v3 < 1/6) {
|
|
|
|
|
rgb[i] = v1 + ((v2 - v1) * 6 * v3);
|
|
|
|
|
} else if (v3 < 0.5) {
|
|
|
|
|
rgb[i] = v2;
|
|
|
|
|
} else if (v3 < 2/3) {
|
|
|
|
|
rgb[i] = v1 + ((v2 - v1) * 6 * (2/3 - v3));
|
|
|
|
|
} else {
|
|
|
|
|
rgb[i] = v1;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return rgb.map(function(v) {
|
|
|
|
|
return v * 255;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Date functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.getDateInWeek = function(date, weekday) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
2010-09-03 08:47:40 +00:00
|
|
|
|
>>> 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"
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.print("getDateInWeek", date.toString(), weekday)
|
|
|
|
|
var date = date || new Date(),
|
|
|
|
|
sourceWeekday = Ox.formatDate(date, "%u");
|
|
|
|
|
targetWeekday = Ox.isNumber(weekday) ? weekday :
|
|
|
|
|
Ox.map(Ox.WEEKDAYS, function(v, i) {
|
|
|
|
|
return v.substr(0, 3) == weekday.substr(0, 3) ? i + 1 : null;
|
|
|
|
|
})[0];
|
|
|
|
|
date.setDate(date.getDate() - sourceWeekday + targetWeekday);
|
|
|
|
|
return date;
|
|
|
|
|
}
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.getDayOfTheYear = function(date) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.getDayOfTheYear(new Date("12/31/2004"))
|
|
|
|
|
366
|
|
|
|
|
*/
|
|
|
|
|
var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
|
|
|
return function(date) {
|
|
|
|
|
date = date || new Date();
|
|
|
|
|
var day = date.getDate(),
|
|
|
|
|
month = date.getMonth(),
|
|
|
|
|
i;
|
|
|
|
|
for (i = 0; i < month; i++) {
|
|
|
|
|
day += days[i];
|
|
|
|
|
}
|
|
|
|
|
if (month >= 2 && Ox.isLeapYear(date.getFullYear())) {
|
|
|
|
|
day++;
|
|
|
|
|
}
|
|
|
|
|
return day;
|
|
|
|
|
};
|
|
|
|
|
}();
|
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.getDaysInMonth = function(year, month) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.getDaysInMonth(2000, 2)
|
|
|
|
|
28
|
|
|
|
|
>>> Ox.getDaysInMonth("2002", "Feb")
|
|
|
|
|
28
|
|
|
|
|
>>> Ox.getDaysInMonth("2004", "February")
|
|
|
|
|
29
|
|
|
|
|
*/
|
|
|
|
|
Ox.print("getDaysInMonth", year, month)
|
|
|
|
|
var year = parseInt(year),
|
|
|
|
|
month = Ox.isNumber(month) ? month :
|
|
|
|
|
Ox.map(Ox.MONTHS, function(v, i) {
|
|
|
|
|
return v.substr(0, 3) == month.substr(0, 3) ? i + 1 : null;
|
|
|
|
|
})[0];
|
|
|
|
|
return Ox.DAYS[month - 1] + (month == 2 && Ox.isLeapYear(year));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.getFirstDayOfTheYear = function(date) {
|
|
|
|
|
/*
|
|
|
|
|
Decimal weekday of January 1 (0-6, Sunday as first day)
|
|
|
|
|
>>> Ox.getFirstDayOfTheYear(new Date("01/01/00"))
|
|
|
|
|
6
|
|
|
|
|
*/
|
|
|
|
|
var date_ = date ? new Date(date.valueOf()) : new Date();
|
|
|
|
|
date_.setMonth(0);
|
|
|
|
|
date_.setDate(1);
|
|
|
|
|
return date_.getDay();
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.getISODate = function(date) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.getISODate(new Date("01/01/2000"))
|
|
|
|
|
"2000-01-01T00:00:00Z"
|
|
|
|
|
*/
|
|
|
|
|
return Ox.formatDate(date || new Date(), '%FT%TZ');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.getISODay = function(date) {
|
|
|
|
|
/*
|
|
|
|
|
Decimal weekday (1-7, Monday as first day)
|
|
|
|
|
>>> Ox.getISODay(new Date("01/01/2000"))
|
|
|
|
|
6
|
|
|
|
|
>>> Ox.getISODay(new Date("01/02/2000"))
|
|
|
|
|
7
|
|
|
|
|
>>> Ox.getISODay(new Date("01/03/2000"))
|
|
|
|
|
1
|
|
|
|
|
*/
|
|
|
|
|
return (date || new Date()).getDay() || 7;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.getISOWeek = function(date) {
|
|
|
|
|
/*
|
|
|
|
|
see http://en.wikipedia.org/wiki/ISO_8601
|
|
|
|
|
>>> Ox.getISOWeek(new Date("01/01/2000"))
|
|
|
|
|
52
|
|
|
|
|
>>> Ox.getISOWeek(new Date("01/02/2000"))
|
|
|
|
|
52
|
|
|
|
|
>>> Ox.getISOWeek(new Date("01/03/2000"))
|
|
|
|
|
1
|
|
|
|
|
*/
|
|
|
|
|
date = date || new Date();
|
|
|
|
|
var date_ = new Date(date.valueOf());
|
|
|
|
|
// set date to Thursday of the same week
|
|
|
|
|
date_.setDate(date.getDate() - Ox.getISODay(date) + 4);
|
|
|
|
|
return Math.floor((Ox.getDayOfTheYear(date_) - 1) / 7) + 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.getISOYear = function(date) {
|
|
|
|
|
/*
|
|
|
|
|
see http://en.wikipedia.org/wiki/ISO_8601
|
|
|
|
|
>>> Ox.getISOYear(new Date("01/01/2000"))
|
|
|
|
|
1999
|
|
|
|
|
>>> Ox.getISOYear(new Date("01/02/2000"))
|
|
|
|
|
1999
|
|
|
|
|
>>> Ox.getISOYear(new Date("01/03/2000"))
|
|
|
|
|
2000
|
|
|
|
|
*/
|
|
|
|
|
date = date || new Date();
|
|
|
|
|
var date_ = new Date(date.valueOf());
|
|
|
|
|
// set date to Thursday of the same week
|
|
|
|
|
date_.setDate(date.getDate() - Ox.getISODay(date) + 4);
|
|
|
|
|
return date_.getFullYear();
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-27 12:30:00 +00:00
|
|
|
|
Ox.getTime = function() {
|
|
|
|
|
return +new Date();
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.getTimezoneOffsetString = function(date) {
|
|
|
|
|
/*
|
|
|
|
|
Time zone offset string (-1200 - +1200)
|
|
|
|
|
>>> Ox.getTimezoneOffsetString(new Date("01/01/2000"))
|
|
|
|
|
"+0100"
|
|
|
|
|
*/
|
|
|
|
|
var offset = (date || new 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) {
|
|
|
|
|
/*
|
|
|
|
|
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"))
|
|
|
|
|
1
|
|
|
|
|
>>> Ox.getWeek(new Date("01/03/2000"))
|
|
|
|
|
1
|
|
|
|
|
*/
|
|
|
|
|
date = date || new Date();
|
|
|
|
|
return Math.floor((Ox.getDayOfTheYear(date) +
|
|
|
|
|
Ox.getFirstDayOfTheYear(date) - 1) / 7);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isLeapYear = function(year) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isLeapYear(2000)
|
|
|
|
|
false
|
|
|
|
|
*/
|
|
|
|
|
return year % 4 == 0 && year % 400 != 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
DOM functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.canvas = function() {
|
|
|
|
|
// Ox.canvas(img) or Ox.canvas(width, height)
|
|
|
|
|
var c = {}, isImage = arguments.length == 1,
|
|
|
|
|
image = isImage ? arguments[0] : {
|
|
|
|
|
width: arguments[0], height: arguments[1]
|
|
|
|
|
};
|
2011-02-09 17:56:35 +00:00
|
|
|
|
c.context = (c.canvas = Ox.element('canvas').attr({
|
2010-01-07 20:21:07 +00:00
|
|
|
|
width: image.width, height: image.height
|
2011-02-09 17:56:35 +00:00
|
|
|
|
})[0]).getContext('2d');
|
2010-09-03 08:47:40 +00:00
|
|
|
|
isImage && c.context.drawImage(image, 0, 0);
|
2011-02-09 17:56:35 +00:00
|
|
|
|
c.data = (c.imageData = c.context.getImageData(
|
|
|
|
|
0, 0, image.width, image.height
|
|
|
|
|
)).data;
|
2010-01-07 20:21:07 +00:00
|
|
|
|
return c;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.element = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.element('div').attr({id: 'foo'}).attr('id')
|
|
|
|
|
'foo'
|
|
|
|
|
>>> Ox.element('div').html('foo').html()
|
|
|
|
|
'foo'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
return {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
0: str[0] == '#' ? document.getElementById(str.substr(1)) :
|
2010-01-07 20:21:07 +00:00
|
|
|
|
document.createElement(str),
|
|
|
|
|
attr: function() {
|
|
|
|
|
var args, ret, that = this;
|
|
|
|
|
if (arguments.length == 1 && Ox.isString(arguments[0])) {
|
|
|
|
|
ret = this[0].getAttribute(arguments[0]);
|
|
|
|
|
} else {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(Ox.makeObject.apply(this, arguments), function(v, k) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
that[0].setAttribute(k, v);
|
|
|
|
|
});
|
|
|
|
|
ret = this;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
},
|
|
|
|
|
html: function(str) {
|
|
|
|
|
var ret;
|
|
|
|
|
if (Ox.isUndefined(str)) {
|
|
|
|
|
ret = this[0].innerHTML;
|
|
|
|
|
} else {
|
|
|
|
|
this[0].innerHTML = str;
|
|
|
|
|
ret = this;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Encoding functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
var aliases = {'I': '1', 'L': '1', 'O': '0', 'U': 'V'},
|
|
|
|
|
digits = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
function cap(width, height) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
// returns maximum encoding capacity of an image
|
|
|
|
|
return parseInt(width * height * 3/8) - 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function seek(data, px) {
|
|
|
|
|
// returns this, or the next, opaque pixel
|
|
|
|
|
while (data[px * 4 + 3] < 255) {
|
|
|
|
|
if (++px * 4 == data.length) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
throwPNGError('de');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function xor(byte) {
|
|
|
|
|
// returns "1"-bits-in-byte % 2
|
|
|
|
|
var xor = 0;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.range(8).forEach(function(i) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
xor ^= byte >> i & 1;
|
|
|
|
|
});
|
|
|
|
|
return xor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function throwPNGError(str) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
throw new RangeError(
|
|
|
|
|
'PNG codec can\'t ' +
|
|
|
|
|
(str == 'en' ? 'encode data' : 'decode image')
|
|
|
|
|
);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function throwUTF8Error(byte, pos) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
throw new RangeError(
|
|
|
|
|
'UTF-8 codec can\'t decode byte 0x' +
|
|
|
|
|
byte.toString(16).toUpperCase() + ' at position ' + pos
|
|
|
|
|
);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.encodeBase32 = function(num) {
|
|
|
|
|
// see http://www.crockford.com/wrmg/base32.html
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.encodeBase32(15360)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
'F00'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
>>> Ox.encodeBase32(33819)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
'110V'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
return Ox.map(num.toString(32), function(char) {
|
|
|
|
|
return digits[parseInt(char, 32)];
|
2011-02-09 17:56:35 +00:00
|
|
|
|
}).join('');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodeBase32 = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeBase32('foo')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
15360
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeBase32('ilou')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
33819
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeBase32('?').toString()
|
|
|
|
|
'NaN'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
return parseInt($.map(str.toUpperCase(), function(char) {
|
|
|
|
|
var index = digits.indexOf(aliases[char] || char);
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return (index == -1 ? ' ' : index).toString(32);
|
|
|
|
|
}).join(''), 32);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.encodeBase64 = function(num) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.encodeBase64(32394)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
'foo'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
return btoa(Ox.encodeBase256(num)).replace(/=/g, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodeBase64 = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeBase64('foo')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
32394
|
|
|
|
|
*/
|
|
|
|
|
return Ox.decodeBase256(atob(str));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.encodeBase128 = function(num) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.encodeBase128(1685487)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
'foo'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
var str = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
while (num) {
|
|
|
|
|
str = Ox.char(num & 127) + str;
|
|
|
|
|
num >>= 7;
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodeBase128 = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeBase128('foo')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
1685487
|
|
|
|
|
*/
|
|
|
|
|
var num = 0, len = str.length;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(str, function(char, i) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
num += char.charCodeAt(0) << (len - i - 1) * 7;
|
|
|
|
|
});
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.encodeBase256 = function(num) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.encodeBase256(6713199)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
'foo'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
var str = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
while (num) {
|
|
|
|
|
str = Ox.char(num & 255) + str;
|
|
|
|
|
num >>= 8;
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodeBase256 = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeBase256('foo')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
6713199
|
|
|
|
|
*/
|
|
|
|
|
var num = 0, len = str.length;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(str, function(char, i) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
num += char.charCodeAt(0) << (len - i - 1) * 8;
|
|
|
|
|
});
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.encodeDeflate = function(str) {
|
|
|
|
|
// encodes string, using deflate
|
|
|
|
|
/*
|
|
|
|
|
in fact, the string is written to the rgb channels of a canvas element,
|
|
|
|
|
then the dataURL is decoded from base64, and some head and tail cut off
|
|
|
|
|
*/
|
|
|
|
|
str = Ox.encodeUTF8(str);
|
|
|
|
|
var len = str.length, c = Ox.canvas(Math.ceil((4 + len) / 3), 1), data;
|
|
|
|
|
str = Ox.pad(Ox.encodeBase256(len), 4, Ox.char(0)) + str +
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.repeat('\u00FF', (4 - len % 4) % 4); // simpler? Ox.pad()?
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/* fixme: why does map not work here?
|
|
|
|
|
c.data = $.map(c.data, function(v, i) {
|
|
|
|
|
return i % 4 < 3 ? str.charCodeAt(i - parseInt(i / 4)) : 255;
|
|
|
|
|
});
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < c.data.length; i += 1) {
|
|
|
|
|
c.data[i] = i % 4 < 3 ? str.charCodeAt(i - parseInt(i / 4)) : 255;
|
|
|
|
|
}
|
|
|
|
|
c.context.putImageData(c.imageData, 0, 0);
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.print(c.canvas.toDataURL())
|
|
|
|
|
data = atob(c.canvas.toDataURL().split(',')[1]);
|
|
|
|
|
Ox.print('data', data);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
return data.substr(8, data.length - 20);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodeDeflate = function(str) {
|
|
|
|
|
var image = new Image();
|
2011-02-09 17:56:35 +00:00
|
|
|
|
image.src = 'data:image/png;base64,' + btoa('\u0089PNG\r\n\u001A\n' +
|
|
|
|
|
str + Ox.repeat('\u0000', 4) + 'IEND\u00AEB`\u0082');
|
|
|
|
|
Ox.print(image.src);
|
|
|
|
|
while (!image.width) {} // block until image data is available
|
2010-01-07 20:21:07 +00:00
|
|
|
|
str = Ox.map(Ox.canvas(image).data, function(v, i) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return i % 4 < 3 ? Ox.char(v) : '';
|
|
|
|
|
}).join('');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
return Ox.decodeUTF8(str.substr(4, Ox.decodeBase256(str.substr(0, 4))));
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.encodeHTML = function(str) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.encodeHTML('\'<"&">\'')
|
|
|
|
|
''<"&">''
|
|
|
|
|
>>> Ox.encodeHTML('äbçdê')
|
|
|
|
|
'äbçdê'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return $.map(str, function(v) {
|
|
|
|
|
var code = v.charCodeAt(0);
|
|
|
|
|
return code < 128 ? (v in Ox.HTML_ENTITIES ? Ox.HTML_ENTITIES[v] : v) :
|
|
|
|
|
'&#x' + Ox.pad(code.toString(16).toUpperCase(), 4) + ';';
|
|
|
|
|
}).join('');
|
|
|
|
|
};
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
|
|
|
|
Ox.decodeHTML = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeHTML(''<"&">'')
|
|
|
|
|
'\'<"&">\''
|
|
|
|
|
>>> Ox.decodeHTML(''<"&">'')
|
|
|
|
|
'\'<"&">\''
|
|
|
|
|
>>> Ox.decodeHTML('äbçdê')
|
|
|
|
|
'äbçdê'
|
|
|
|
|
>>> Ox.decodeHTML('äbçdê')
|
|
|
|
|
'äbçdê'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
// relies on dom, but shorter than using this:
|
|
|
|
|
// http://www.w3.org/TR/html5/named-character-references.html
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return $('<div/>').html(str)[0].childNodes[0].nodeValue;
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
is encoded bitwise into the r/g/b bytes of all opaque pixels
|
|
|
|
|
by flipping, if necessary, the least significant bit, so that
|
|
|
|
|
(number of "1"-bits of the byte) % 2 is the bit of the string
|
|
|
|
|
wishlist:
|
|
|
|
|
- only use deflate if it actually shortens the message
|
|
|
|
|
- in deflate, strip and later re-insert the chunk types
|
|
|
|
|
- encode a decoy message into the least significant bit
|
|
|
|
|
(and flip the second least significant bit, if at all)
|
|
|
|
|
- write an extra png chunk containing some key
|
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
//str = Ox.encodeDeflate(str); currently broken
|
|
|
|
|
str = Ox.encodeUTF8(str);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var c = Ox.canvas(img), len = str.length, px = 0;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
if (len == 0 || len > cap(img.width, img.height)) {
|
|
|
|
|
throwPNGError('en')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
len = Ox.pad(Ox.encodeBase256(len), 4, Ox.char(0));
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.forEach(Ox.map(len + str, function(byte) {
|
|
|
|
|
return Ox.map(Ox.range(8), function(i) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
return byte.charCodeAt(0) >> 7 - i & 1;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
}).join('');
|
|
|
|
|
}).join(''), function(bit, i) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var index = parseInt((px = seek(c.data, px)) * 4 + i % 3),
|
|
|
|
|
byte = c.data[index];
|
|
|
|
|
c.data[index] = bit == xor(byte) ? byte :
|
|
|
|
|
byte & 254 | !(byte & 1);
|
|
|
|
|
px += i % 3 == 2;
|
|
|
|
|
});
|
|
|
|
|
c.context.putImageData(c.imageData, 0, 0);
|
|
|
|
|
return c.canvas.toDataURL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodePNG = function(img) {
|
|
|
|
|
// decodes image, returns string
|
2011-02-09 17:56:35 +00:00
|
|
|
|
var bits = '', data = Ox.canvas(img).data, flag = false, i = 0,
|
|
|
|
|
len = 4, max = cap(img.width, img.height), px = 0, str = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
do {
|
|
|
|
|
bits += xor(data[parseInt((px = seek(data, px)) * 4 + i % 3)]);
|
|
|
|
|
px += i % 3 == 2;
|
|
|
|
|
if (++i % 8 == 0) {
|
|
|
|
|
str += Ox.char(parseInt(bits, 2));
|
2011-02-09 17:56:35 +00:00
|
|
|
|
bits = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
len--;
|
|
|
|
|
if (len == 0 && !flag) {
|
|
|
|
|
len = Ox.decodeBase256(str);
|
2011-02-09 17:56:35 +00:00
|
|
|
|
if (len <= 0 || len > max) {
|
2010-02-06 10:29:27 +00:00
|
|
|
|
Ox.print(len);
|
2011-02-09 17:56:35 +00:00
|
|
|
|
throwPNGError('de');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
2011-02-09 17:56:35 +00:00
|
|
|
|
str = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
flag = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (len);
|
|
|
|
|
try {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
//return Ox.decodeDeflate(str); currently broken
|
|
|
|
|
return Ox.decodeUTF8(str);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
} catch(e) {
|
2010-02-06 10:29:27 +00:00
|
|
|
|
Ox.print(e.toString());
|
2011-02-09 17:56:35 +00:00
|
|
|
|
throwPNGError('de');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.encodeUTF8 = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
see http://en.wikipedia.org/wiki/UTF-8
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.encodeUTF8('foo')
|
|
|
|
|
'foo'
|
|
|
|
|
>>> Ox.encodeUTF8('¥€$')
|
|
|
|
|
'\u00C2\u00A5\u00E2\u0082\u00AC\u0024'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return $.map(Array.prototype.slice.call(str), function(chr) {
|
|
|
|
|
var code = chr.charCodeAt(0),
|
|
|
|
|
str = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
if (code < 128) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
str = chr;
|
2010-01-07 20:21:07 +00:00
|
|
|
|
} else if (code < 2048) {
|
|
|
|
|
str = String.fromCharCode(code >> 6 | 192) +
|
|
|
|
|
String.fromCharCode(code & 63 | 128);
|
|
|
|
|
} else {
|
|
|
|
|
str = String.fromCharCode(code >> 12 | 224) +
|
|
|
|
|
String.fromCharCode(code >> 6 & 63 | 128) +
|
|
|
|
|
String.fromCharCode(code & 63 | 128);
|
|
|
|
|
}
|
|
|
|
|
return str;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
}).join('');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.decodeUTF8 = function(str) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.decodeUTF8('foo')
|
|
|
|
|
'foo'
|
|
|
|
|
>>> Ox.decodeUTF8('\u00C2\u00A5\u00E2\u0082\u00AC\u0024')
|
|
|
|
|
'¥€$'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
|
|
|
|
var bytes = $.map(str, function(v) {
|
|
|
|
|
return v.charCodeAt(0);
|
|
|
|
|
}),
|
|
|
|
|
i = 0,
|
|
|
|
|
len = str.length,
|
2011-02-09 17:56:35 +00:00
|
|
|
|
str = '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
while (i < len) {
|
|
|
|
|
if (bytes[i] <= 128) {
|
|
|
|
|
str += String.fromCharCode(bytes[i]);
|
|
|
|
|
i++;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
} else if (
|
|
|
|
|
bytes[i] >= 192 && bytes[i] < 240 &&
|
|
|
|
|
i < len - (bytes[i] < 224 ? 1 : 2)
|
|
|
|
|
) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
if (bytes[i + 1] >= 128 && bytes[i + 1] < 192) {
|
|
|
|
|
if (bytes[i] < 224) {
|
|
|
|
|
str += String.fromCharCode((bytes[i] & 31) << 6 |
|
|
|
|
|
bytes[i + 1] & 63);
|
|
|
|
|
i += 2;
|
|
|
|
|
} else if (bytes[i + 2] >= 128 && bytes[i + 2] < 192) {
|
|
|
|
|
str += String.fromCharCode((bytes[i] & 15) << 12 |
|
|
|
|
|
(bytes[i + 1] & 63) << 6 | bytes[i + 2] & 63);
|
|
|
|
|
i += 3;
|
|
|
|
|
} else {
|
|
|
|
|
throwUTF8Error(bytes[i + 2], i + 2);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throwUTF8Error(bytes[i + 1], i + 1);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throwUTF8Error(bytes[i], i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Format functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
2011-01-24 04:08:19 +00:00
|
|
|
|
Ox.formatColor = function() {
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2011-01-06 06:10:46 +00:00
|
|
|
|
Ox.formatCurrency = function(num, str, dec) {
|
2011-01-30 03:54:06 +00:00
|
|
|
|
return str + Ox.formatNumber(num, dec);
|
2011-01-06 06:10:46 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.formatDate = function() {
|
|
|
|
|
/*
|
|
|
|
|
See http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/strftime.3.html
|
|
|
|
|
and http://en.wikipedia.org/wiki/ISO_8601
|
|
|
|
|
>>> _date = new Date("01/02/05 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"
|
|
|
|
|
*/
|
|
|
|
|
var ampm = ["AM", "PM"],
|
|
|
|
|
days = ["Monday", "Tuesday", "Wednesday", "Thursday",
|
|
|
|
|
"Friday", "Saturday", "Sunday"],
|
|
|
|
|
months = ["January", "February", "March", "April", "May", "June",
|
|
|
|
|
"July", "August", "September", "October", "November", "December"],
|
|
|
|
|
format = [
|
|
|
|
|
["%", function() {return "%{%}";}],
|
|
|
|
|
["c", function() {return "%x %X";}],
|
|
|
|
|
["X", function() {return "%r";}],
|
|
|
|
|
["x", function() {return "%D";}],
|
|
|
|
|
["D", function() {return "%m/%d/%y";}],
|
|
|
|
|
["F", function() {return "%Y-%m-%d";}],
|
|
|
|
|
["h", function() {return "%b";}],
|
|
|
|
|
["R", function() {return "%H:%M";}],
|
|
|
|
|
["r", function() {return "%I:%M:%S %p";}],
|
|
|
|
|
["T", function() {return "%H:%M:%S";}],
|
|
|
|
|
["v", function() {return "%e-%b-%Y";}],
|
|
|
|
|
["\\+", function() {return "%a %b %e %H:%M:%S %Z %Y";}],
|
|
|
|
|
["A", function(d) {return days[(d.getDay() + 6) % 7];}],
|
|
|
|
|
["a", function(d) {return days[(d.getDay() + 6) % 7].toString().substr(0, 3);}],
|
|
|
|
|
["B", function(d) {return months[d.getMonth()];}],
|
|
|
|
|
["b", function(d) {return months[d.getMonth()].toString().substr(0, 3);}],
|
|
|
|
|
["C", function(d) {return d.getFullYear().toString().substr(0, 2);}],
|
|
|
|
|
["d", function(d) {return Ox.pad(d.getDate(), 2);}],
|
|
|
|
|
["e", function(d) {return Ox.pad(d.getDate(), 2, " ");}],
|
|
|
|
|
["G", function(d) {return Ox.getISOYear(d);}],
|
|
|
|
|
["g", function(d) {return Ox.getISOYear(d).toString().substr(-2);}],
|
|
|
|
|
["H", function(d) {return Ox.pad(d.getHours(), 2);}],
|
|
|
|
|
["I", function(d) {return Ox.pad((d.getHours() + 11) % 12 + 1, 2);}],
|
|
|
|
|
["j", function(d) {return Ox.pad(Ox.getDayOfTheYear(d), 3);}],
|
|
|
|
|
["k", function(d) {return Ox.pad(d.getHours(), 2, " ");}],
|
|
|
|
|
["l", function(d) {return Ox.pad(((d.getHours() + 11) % 12 + 1), 2, " ");}],
|
|
|
|
|
["M", function(d) {return Ox.pad(d.getMinutes(), 2);}],
|
|
|
|
|
["m", function(d) {return Ox.pad((d.getMonth() + 1), 2);}],
|
|
|
|
|
["p", function(d) {return ampm[Math.floor(d.getHours() / 12)];}],
|
|
|
|
|
["Q", function(d) {return Math.floor(d.getMonth() / 4) + 1;}],
|
|
|
|
|
["S", function(d) {return Ox.pad(d.getSeconds(), 2);}],
|
|
|
|
|
["s", function(d) {return Math.floor(d.getTime() / 1000);}],
|
|
|
|
|
["U", function(d) {return Ox.pad(Ox.getWeek(d), 2);}],
|
|
|
|
|
["u", function(d) {return Ox.getISODay(d);}],
|
|
|
|
|
["V", function(d) {return Ox.pad(Ox.getISOWeek(d), 2);}],
|
|
|
|
|
["W", function(d) {return Ox.pad(Math.floor((Ox.getDayOfTheYear(d) +
|
|
|
|
|
(Ox.getFirstDayOfTheYear(d) || 7) - 2) / 7), 2);}],
|
|
|
|
|
["w", function(d) {return d.getDay();}],
|
|
|
|
|
["Y", function(d) {return d.getFullYear();}],
|
|
|
|
|
["y", function(d) {return d.getFullYear().toString().substr(-2);}],
|
|
|
|
|
["Z", function(d) {return d.toString().split("(")[1].replace(")", "");}],
|
|
|
|
|
["z", function(d) {return Ox.getTimezoneOffsetString(d);}],
|
|
|
|
|
["n", function() {return "\n";}],
|
|
|
|
|
["t", function() {return "\t";}],
|
|
|
|
|
["\\{%\\}", function() {return "%";}]
|
|
|
|
|
];
|
|
|
|
|
$.each(format, function(i, v) {
|
|
|
|
|
format[i][0] = new RegExp("%" + v[0] + "", "g");
|
|
|
|
|
});
|
|
|
|
|
return function(date, str) {
|
|
|
|
|
str = str || date;
|
|
|
|
|
date = arguments.length == 2 ? date : new Date();
|
2011-01-05 14:53:06 +00:00
|
|
|
|
var split;
|
|
|
|
|
if (typeof date == 'string') {
|
|
|
|
|
// support YYYY-MM-DD
|
|
|
|
|
split = date.substr(0, 10).split('-');
|
|
|
|
|
if (split.length == 3) {
|
|
|
|
|
date = [split[1], split[2], split[0]].join('/') + date.substr(10);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (Ox.isNumber(date) || Ox.isString(date)) {
|
|
|
|
|
date = new Date(date);
|
|
|
|
|
}
|
|
|
|
|
if (Ox.isDate(date) && date.toString() != 'Invalid Date') {
|
|
|
|
|
$.each(format, function(i, v) {
|
|
|
|
|
str = str.replace(v[0], v[1](date));
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
str = '';
|
|
|
|
|
}
|
2010-01-07 20:21:07 +00:00
|
|
|
|
return str;
|
|
|
|
|
};
|
|
|
|
|
}();
|
|
|
|
|
|
2010-07-01 15:06:04 +00:00
|
|
|
|
Ox.formatDuration = function(sec, dec, format) {
|
2010-07-01 12:26:32 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.formatDuration(123456.789, 3)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"1:10:17:36.789"
|
2010-07-01 12:26:32 +00:00
|
|
|
|
>>> Ox.formatDuration(12345.6789)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"03:25:46"
|
2010-07-01 12:26:32 +00:00
|
|
|
|
>>> Ox.formatDuration(12345.6789, true)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"0:03:25:46"
|
2010-07-01 12:26:32 +00:00
|
|
|
|
>>> Ox.formatDuration(3599.999, 3)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"00:59:59.999"
|
2010-07-01 12:26:32 +00:00
|
|
|
|
>>> Ox.formatDuration(3599.999)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"01:00:00"
|
2010-07-01 12:26:32 +00:00
|
|
|
|
*/
|
2010-07-01 15:06:04 +00:00
|
|
|
|
var format = arguments.length == 3 ? format : (Ox.isString(dec) ? dec : "short"),
|
|
|
|
|
dec = (arguments.length == 3 || Ox.isNumber(dec)) ? dec : 0,
|
2010-07-01 12:26:32 +00:00
|
|
|
|
sec = dec ? sec : Math.round(sec),
|
2010-07-01 15:06:04 +00:00
|
|
|
|
val = [
|
|
|
|
|
Math.floor(sec / 31536000),
|
|
|
|
|
Math.floor(sec % 31536000 / 86400),
|
|
|
|
|
Math.floor(sec % 86400 / 3600),
|
|
|
|
|
Math.floor(sec % 3600 / 60),
|
|
|
|
|
format == "short" ? Ox.formatNumber(sec % 60, dec) : sec % 60
|
|
|
|
|
],
|
|
|
|
|
str = {
|
|
|
|
|
medium: ["y", "d", "h", "m", "s"],
|
|
|
|
|
long: ["year", "day", "hour", "minute", "second"]
|
|
|
|
|
},
|
|
|
|
|
pad = [0, 3, 2, 2, dec ? dec + 3 : 2];
|
|
|
|
|
while (!val[0] && val.length > (format == "short" ? 3 : 1)) {
|
|
|
|
|
val.shift();
|
|
|
|
|
str.medium.shift();
|
|
|
|
|
str.long.shift();
|
|
|
|
|
pad.shift();
|
|
|
|
|
}
|
|
|
|
|
while (format != "short" && !val[val.length - 1] && val.length > 1) {
|
|
|
|
|
val.pop();
|
|
|
|
|
str.medium.pop();
|
|
|
|
|
str.long.pop();
|
|
|
|
|
}
|
|
|
|
|
return $.map(val, function(v, i) {
|
|
|
|
|
return format == "short" ? Ox.pad(v, pad[i]) :
|
|
|
|
|
v + (format == "long" ? " " : "") + str[format][i] +
|
|
|
|
|
(format == "long" && v != 1 ? "s" : "");
|
|
|
|
|
}).join(format == "short" ? ":" : " ");
|
2010-07-01 12:26:32 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.formatNumber = function(num, dec) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.formatNumber(123456789, 3)
|
|
|
|
|
"123,456,789.000"
|
|
|
|
|
>>> Ox.formatNumber(-2000000 / 3, 3)
|
|
|
|
|
"-666,666.667"
|
|
|
|
|
>>> Ox.formatNumber(666666.666)
|
|
|
|
|
"666,667"
|
|
|
|
|
*/
|
|
|
|
|
var str = Math.abs(num).toFixed(dec || 0),
|
2011-01-05 14:53:06 +00:00
|
|
|
|
spl = str.split('.'),
|
2010-01-07 20:21:07 +00:00
|
|
|
|
arr = [];
|
|
|
|
|
while (spl[0]) {
|
|
|
|
|
arr.unshift(spl[0].substr(-3));
|
|
|
|
|
spl[0] = spl[0].substr(0, spl[0].length - 3);
|
|
|
|
|
}
|
2011-01-05 14:53:06 +00:00
|
|
|
|
spl[0] = arr.join(',');
|
|
|
|
|
return (num < 0 ? '-' : '') + spl.join('.');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.formatPercent = function(num, total, dec) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.formatPercent(1, 1000, 2)
|
|
|
|
|
"0.10%"
|
|
|
|
|
*/
|
2011-01-05 14:53:06 +00:00
|
|
|
|
return Ox.formatNumber(num / total * 100, dec) + '%'
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-01 09:56:16 +00:00
|
|
|
|
Ox.formatResolution = function(arr, str) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.formatResolution([1920, 1080], 'px')
|
|
|
|
|
"1920 x 1080 px"
|
|
|
|
|
*/
|
|
|
|
|
return arr[0] + ' x ' + arr[1] + (str ? ' ' + str : '');
|
2011-02-01 09:56:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
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];
|
|
|
|
|
});
|
2011-01-05 14:53:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
Ox.formatValue = function(num, str, bin) {
|
2010-07-01 12:26:32 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.formatValue(0, "B")
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"0 KB"
|
2010-07-01 12:26:32 +00:00
|
|
|
|
>>> Ox.formatValue(123456789, "B")
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"123.5 MB"
|
|
|
|
|
>>> Ox.formatValue(1234567890, "B", true)
|
|
|
|
|
"1.15 GiB"
|
|
|
|
|
*/
|
|
|
|
|
var base = bin ? 1024 : 1000,
|
|
|
|
|
len = Ox.PREFIXES.length,
|
|
|
|
|
val;
|
|
|
|
|
Ox.forEach(Ox.PREFIXES, function(chr, i) {
|
|
|
|
|
if (num < Math.pow(base, i + 2) || i == len - 1) {
|
|
|
|
|
val = Ox.formatNumber(num / Math.pow(base, i + 1), i) +
|
|
|
|
|
' ' + chr + (bin ? 'i' : '') + str;
|
2010-07-01 12:26:32 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return val;
|
|
|
|
|
};
|
|
|
|
|
|
2011-01-24 04:08:19 +00:00
|
|
|
|
Ox.formatUnit = function(num, str) {
|
|
|
|
|
return num + ' ' + str;
|
|
|
|
|
};
|
|
|
|
|
|
2010-11-28 15:06:47 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Geo functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.getArea = function(point0, point1) {
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.getCenter = function(point0, point1) {
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.getDistance = function(point0, point1) {
|
|
|
|
|
point0 = point0.map(function(deg) {
|
|
|
|
|
return Ox.rad(deg);
|
|
|
|
|
});
|
|
|
|
|
point1 = point1.map(function(deg) {
|
|
|
|
|
return Ox.rad(deg);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.getMetersPerDegree = function(point) {
|
|
|
|
|
return Math.cos(point[0] * Math.PI / 180) * Ox.EARTH_CIRCUMFERENCE / 360;
|
|
|
|
|
};
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
HTML functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.parseEmailAddresses = function(html) {
|
|
|
|
|
return html.replace(
|
|
|
|
|
/\b([0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi,
|
|
|
|
|
'<a href="mailto:$1" title="mailto:$1">$1</a>'
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.parseHTML = (function() {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.parseHTML('http://foo.com, bar')
|
|
|
|
|
'<a href="http://foo.com" title="http://foo.com">foo.com</a>, bar'
|
|
|
|
|
>>> Ox.parseHTML('(see: www.foo.com)')
|
|
|
|
|
'(see: <a href="http://www.foo.com" title="http://www.foo.com">www.foo.com</a>)'
|
|
|
|
|
>>> Ox.parseHTML('foo@bar.com')
|
|
|
|
|
'<a href="mailto:foo@bar.com" title="mailto:foo@bar.com">foo@bar.com</a>'
|
|
|
|
|
>>> Ox.parseHTML('<a href="http://foo.com" onmouseover="alert()">foo</a>')
|
|
|
|
|
'<a href="http://foo.com" title="http://foo.com">foo</a>'
|
|
|
|
|
>>> Ox.parseHTML('<a href="javascript:alert()">foo</a>')
|
|
|
|
|
'<a href="javascript:alert()">foo</a>'
|
|
|
|
|
>>> Ox.parseHTML('[http://foo.com foo]')
|
|
|
|
|
'<a href="http://foo.com" title="http://foo.com">foo</a>'
|
|
|
|
|
>>> Ox.parseHTML('<rtl>foo</rtl>')
|
|
|
|
|
'<div style="direction: rtl">foo</div>'
|
|
|
|
|
>>> Ox.parseHTML('<script>alert()</script>')
|
|
|
|
|
'<script>alert()</script>'
|
|
|
|
|
*/
|
|
|
|
|
var defaultTags = [
|
|
|
|
|
'a', 'b', 'blockquote', 'cite', 'code', 'del',
|
|
|
|
|
'em', 'i', 'img', 'ins', 'li', 'ol', 'q', 'rtl',
|
|
|
|
|
's', 'strong', 'sub', 'sup', 'ul', '[]'
|
|
|
|
|
],
|
|
|
|
|
parse = {
|
|
|
|
|
a: {
|
|
|
|
|
'<a [^<>]*?href="(https?:\/\/.+?)".*?>': '<a href="{1}" title="{1}">',
|
|
|
|
|
'<\/a>': '</a>'
|
|
|
|
|
},
|
|
|
|
|
img: {
|
|
|
|
|
'<img [^<>]*?src="(https?:\/\/.+?)".*?>': '<img src="{1}">'
|
|
|
|
|
},
|
|
|
|
|
rtl: {
|
|
|
|
|
'<rtl>': '<div style="direction: rtl">',
|
|
|
|
|
'<\/rtl>': '</div>'
|
|
|
|
|
},
|
|
|
|
|
'*': function(tag) {
|
|
|
|
|
var ret = {};
|
|
|
|
|
ret['<(/?' + tag + ')>'] = '<{1}>';
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
tab = '\t';
|
|
|
|
|
|
|
|
|
|
return function(html, tags, wikilinks) {
|
|
|
|
|
var matches = [],
|
|
|
|
|
tags = tags || defaultTags;
|
|
|
|
|
html = Ox.clean(html);
|
|
|
|
|
if (tags.indexOf('[]') > -1) {
|
|
|
|
|
html = html.replace(/\[(https?:\/\/.+?) (.+?)\]/gi, '<a href="$1">$2</a>');
|
|
|
|
|
tags = tags.filter(function(tag) {
|
|
|
|
|
return tag != '[]';
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
tags.forEach(function(tag) {
|
|
|
|
|
var p = parse[tag] || parse['*'](tag);
|
|
|
|
|
Ox.forEach(p, function(replace, regexp) {
|
|
|
|
|
html = html.replace(new RegExp(regexp, 'gi'), function() {
|
|
|
|
|
matches.push(Ox.formatString(replace, arguments));
|
|
|
|
|
return tab + (matches.length - 1) + tab;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
html = Ox.encodeHTML(html);
|
|
|
|
|
html = Ox.parseURLs(html);
|
|
|
|
|
html = Ox.parseEmailAddresses(html);
|
|
|
|
|
matches.forEach(function(match, i) {
|
|
|
|
|
html = html.replace(new RegExp(tab + i + tab, 'gi'), match);
|
|
|
|
|
});
|
|
|
|
|
html = html.replace(/\n/g, '<br/>\n')
|
|
|
|
|
// close extra opening (and remove extra closing) tags
|
|
|
|
|
return $('<div>').html(html).html();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}());
|
|
|
|
|
|
|
|
|
|
Ox.parseURL = (function() {
|
|
|
|
|
// fixme: leak memory, like now, or create every time? ... benchmark??
|
|
|
|
|
var a = document.createElement('a'),
|
|
|
|
|
keys = ['hash', 'host', 'hostname', 'origin',
|
|
|
|
|
'pathname', 'port', 'protocol', 'search'];
|
|
|
|
|
return function(str) {
|
|
|
|
|
var ret = {};
|
|
|
|
|
a.href = str;
|
|
|
|
|
keys.forEach(function(key) {
|
|
|
|
|
ret[key] = a[key];
|
|
|
|
|
});
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
}());
|
|
|
|
|
|
|
|
|
|
Ox.parseURLs = function(html) {
|
|
|
|
|
return html.replace(
|
|
|
|
|
/\b((https?:\/\/|www\.).+?)([\.,:;!\?\)\]]*?(\s|$))/gi,
|
|
|
|
|
function(str, url, pre, end) {
|
|
|
|
|
url = (pre == 'www.' ? 'http://' : '' ) + url;
|
|
|
|
|
return Ox.formatString(
|
|
|
|
|
'<a href="{url}" title="{url}">{host}</a>{end}',
|
|
|
|
|
{
|
|
|
|
|
end: end,
|
|
|
|
|
host: Ox.parseURL(url).hostname,
|
|
|
|
|
url: url
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Math functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.asinh = function(x) {
|
|
|
|
|
/*
|
|
|
|
|
fixme: no test
|
|
|
|
|
*/
|
|
|
|
|
return Math.log(x + Math.sqrt(x * x + 1));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.deg = function(rad) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.deg(2 * Math.PI)
|
|
|
|
|
360
|
|
|
|
|
*/
|
|
|
|
|
return rad * 180 / Math.PI;
|
|
|
|
|
};
|
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.divideInt = function(num, by) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.divideInt(100, 3)
|
|
|
|
|
[33, 33, 34]
|
|
|
|
|
>>> Ox.divideInt(100, 6)
|
|
|
|
|
[16, 16, 17, 17, 17, 17]
|
|
|
|
|
*/
|
|
|
|
|
var arr = [],
|
|
|
|
|
div = parseInt(num / by),
|
|
|
|
|
mod = num % by,
|
|
|
|
|
i;
|
|
|
|
|
for (i = 0; i < by; i++) {
|
|
|
|
|
arr[i] = div + (i > by - 1 - mod);
|
|
|
|
|
}
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.limit = function(num, min, max) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.limit(1, 2, 3)
|
|
|
|
|
2
|
|
|
|
|
>>> Ox.limit(2, 1)
|
|
|
|
|
1
|
|
|
|
|
*/
|
|
|
|
|
var len = arguments.length;
|
|
|
|
|
max = arguments[len - 1];
|
|
|
|
|
min = len == 3 ? min : 0;
|
|
|
|
|
return Math.min(Math.max(num, min), max);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.log = function(x, base) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.log(100, 10)
|
|
|
|
|
2
|
|
|
|
|
>>> Ox.log(Math.E)
|
|
|
|
|
1
|
|
|
|
|
*/
|
|
|
|
|
return Math.log(x) / Math.log(base || Math.E);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.rad = function(deg) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.rad(360)
|
|
|
|
|
2 * Math.PI
|
|
|
|
|
*/
|
|
|
|
|
return deg * Math.PI / 180;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.random = function() {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.random(3) in {0: 0, 1: 0, 2: 0, 3: 0}
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.random(1, 2) in {1: 0, 2: 0}
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
var len = arguments.length,
|
|
|
|
|
min = len == 1 ? 0 : arguments[0],
|
|
|
|
|
max = arguments[len - 1];
|
|
|
|
|
return min + parseInt(Math.random() * (max - min + 1));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.round = function(num, dec) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.round(2 / 3, 6)
|
|
|
|
|
0.666667
|
|
|
|
|
>>> Ox.round(1 / 2, 3)
|
|
|
|
|
0.5
|
|
|
|
|
*/
|
|
|
|
|
var pow = Math.pow(10, dec || 0);
|
|
|
|
|
return Math.round(num * pow) / pow;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.sinh = function(x) {
|
|
|
|
|
/*
|
|
|
|
|
fixme: no test
|
|
|
|
|
*/
|
|
|
|
|
return (Math.exp(x) - Math.exp(-x)) / 2;
|
|
|
|
|
};
|
|
|
|
|
|
2011-01-15 06:09:22 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
RegExp functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.regexp = {
|
|
|
|
|
'accents': '¨´`ˆ˜',
|
|
|
|
|
'letters': 'a-z¨´`ˆ˜äåáà âãæçëéèèñïÃìîöóòôõøœßúùûÿ'
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
String functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.basename = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
fixme: this should go into Path functions
|
|
|
|
|
>>> Ox.basename("foo/bar/foo.bar")
|
|
|
|
|
"foo.bar"
|
|
|
|
|
>>> Ox.basename("foo.bar")
|
|
|
|
|
"foo.bar"
|
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return str.replace(/^.*[\/\\]/g, '');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.char = String.fromCharCode;
|
|
|
|
|
|
|
|
|
|
Ox.clean = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.clean("foo bar")
|
|
|
|
|
"foo bar"
|
|
|
|
|
>>> Ox.clean(" foo bar ")
|
|
|
|
|
"foo bar"
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.clean(" foo \n bar ")
|
|
|
|
|
"foo\nbar"
|
2010-01-07 20:21:07 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return Ox.map(str.split('\n'), function(str) {
|
|
|
|
|
return Ox.trim(str.replace(/\s+/g, ' '));
|
|
|
|
|
}).join('\n');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-09-03 08:47:40 +00:00
|
|
|
|
Ox.contains = function(str, chr) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.contains("foo", "bar")
|
|
|
|
|
false
|
|
|
|
|
>>> Ox.contains("foobar", "bar")
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return str.indexOf(chr) > -1;
|
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.endsWith = function(str, sub) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.endsWith("foobar", "bar")
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return str.substr(-sub.length) === sub;
|
|
|
|
|
};
|
|
|
|
|
|
2010-09-17 22:10:07 +00:00
|
|
|
|
Ox.highlight = function(txt, str) {
|
|
|
|
|
// fixme: move to ox.ui
|
|
|
|
|
return str ? txt.replace(
|
|
|
|
|
new RegExp('(' + str + ')', 'ig'),
|
|
|
|
|
'<span class="OxHighlight">$1</span>'
|
|
|
|
|
) : txt;
|
2010-12-26 20:16:35 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isValidEmail = function(str) {
|
2011-02-09 17:56:35 +00:00
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isValidEmail("foo@bar.com")
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.isValidEmail("foo.bar@foobar.co.uk")
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.isValidEmail("foo@bar")
|
|
|
|
|
false
|
|
|
|
|
*/
|
2010-12-26 20:16:35 +00:00
|
|
|
|
return !!/^[0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6}$/i(str);
|
2010-09-17 22:10:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.pad = function(str, len, pad, pos) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.pad(1, 2)
|
|
|
|
|
"01"
|
|
|
|
|
>>> Ox.pad("abc", 6, ".", "right")
|
|
|
|
|
"abc..."
|
|
|
|
|
>>> Ox.pad("foobar", 3, ".", "right")
|
|
|
|
|
"foo"
|
|
|
|
|
>>> Ox.pad("abc", 6, "123456", "right")
|
|
|
|
|
"abc123"
|
|
|
|
|
>>> Ox.pad("abc", 6, "123456", "left")
|
|
|
|
|
"456abc"
|
|
|
|
|
*/
|
|
|
|
|
str = str.toString().substr(0, len);
|
|
|
|
|
pad = Ox.repeat(pad || "0", len - str.length);
|
|
|
|
|
pos = pos || "left";
|
|
|
|
|
str = pos == "left" ? pad + str : str + pad;
|
2011-02-09 17:56:35 +00:00
|
|
|
|
str = pos == "left" ?
|
|
|
|
|
str.substr(str.length - len, str.length) :
|
2010-01-07 20:21:07 +00:00
|
|
|
|
str.substr(0, len);
|
|
|
|
|
return str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.repeat = function(str, num) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.repeat(1, 3)
|
|
|
|
|
"111"
|
|
|
|
|
>>> Ox.repeat("foo", 3)
|
|
|
|
|
"foofoofoo"
|
|
|
|
|
*/
|
2011-01-23 04:59:16 +00:00
|
|
|
|
return num >= 1 ? new Array(num + 1).join(str.toString()) : '';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.reverse = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
Ox.reverse("foo")
|
|
|
|
|
oof
|
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return str.split('').reverse().join('');
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.startsWith = function(str, sub) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.startsWith("foobar", "foo")
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return str.substr(0, sub.length) === sub;
|
|
|
|
|
};
|
|
|
|
|
|
2010-02-18 17:45:37 +00:00
|
|
|
|
Ox.stripTags = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.stripTags("f<span>o</span>o")
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"foo"
|
2010-02-18 17:45:37 +00:00
|
|
|
|
*/
|
2011-02-09 17:56:35 +00:00
|
|
|
|
return str.replace(/(<.*?>)/gi, '');
|
2010-02-18 17:45:37 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.toCamelCase = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.toCamelCase("foo-bar-baz")
|
|
|
|
|
"fooBarBaz"
|
|
|
|
|
>>> Ox.toCamelCase("foo/bar/baz")
|
|
|
|
|
"fooBarBaz"
|
|
|
|
|
>>> Ox.toCamelCase("foo_bar_baz")
|
|
|
|
|
"fooBarBaz"
|
|
|
|
|
*/
|
|
|
|
|
return str.replace(/[\-_\/][a-z]/g, function(str) {
|
|
|
|
|
return str[1].toUpperCase();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.toDashes = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.toDashes("fooBarBaz")
|
|
|
|
|
"foo-bar-baz"
|
|
|
|
|
*/
|
|
|
|
|
return str.replace(/[A-Z]/g, function(str) {
|
|
|
|
|
return '-' + str.toLowerCase();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.toSlashes = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.toSlashes("fooBarBaz")
|
|
|
|
|
"foo/bar/baz"
|
|
|
|
|
*/
|
|
|
|
|
return str.replace(/[A-Z]/g, function(str) {
|
|
|
|
|
return '/' + str.toLowerCase();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.toTitleCase = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.toTitleCase("foo")
|
|
|
|
|
"Foo"
|
|
|
|
|
>>> Ox.toTitleCase("Apple releases iPhone, IBM stock plummets")
|
|
|
|
|
"Apple Releases iPhone, IBM Stock Plummets"
|
|
|
|
|
*/
|
2011-01-02 10:01:55 +00:00
|
|
|
|
return $.map(str.split(' '), function(v) {
|
2010-01-07 20:21:07 +00:00
|
|
|
|
var sub = v.substr(1),
|
|
|
|
|
low = sub.toLowerCase();
|
|
|
|
|
if (sub == low) {
|
|
|
|
|
v = v.substr(0, 1).toUpperCase() + low;
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}).join(" ");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.toUnderscores = function(str) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.toUnderscores("fooBarBaz")
|
|
|
|
|
"foo_bar_baz"
|
|
|
|
|
*/
|
|
|
|
|
return str.replace(/[A-Z]/g, function(str) {
|
|
|
|
|
return '_' + str.toLowerCase();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.trim = function(str) { // is in jQuery
|
|
|
|
|
/*
|
|
|
|
|
Ox.trim(" foo ")
|
|
|
|
|
"foo"
|
|
|
|
|
*/
|
|
|
|
|
return str.replace(/^\s+|\s+$/g, "");
|
2010-07-05 07:09:34 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.truncate = function(str, len, pad, pos) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.truncate("anticonstitutionellement", 16, "...", "center")
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"anticon...lement"
|
2010-07-05 07:09:34 +00:00
|
|
|
|
*/
|
|
|
|
|
var pad = pad || {},
|
|
|
|
|
pos = pos || "right",
|
|
|
|
|
strlen = str.length,
|
|
|
|
|
padlen = pad.length,
|
|
|
|
|
left, right;
|
|
|
|
|
if (strlen > len) {
|
|
|
|
|
if (pos == "left") {
|
|
|
|
|
str = pad + str.substr(padlen + strlen - len);
|
|
|
|
|
} else if (pos == "center") {
|
|
|
|
|
left = Math.ceil((len - padlen) / 2);
|
|
|
|
|
right = Math.floor((len - padlen) / 2);
|
|
|
|
|
str = str.substr(0, left) + pad + str.substr(-right);
|
|
|
|
|
} else if (pos == "right") {
|
|
|
|
|
str = str.substr(0, len - padlen) + pad;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
};
|
|
|
|
|
|
2011-02-09 17:56:35 +00:00
|
|
|
|
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"
|
|
|
|
|
*/
|
|
|
|
|
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
|
|
|
|
|
// and join the surrounding words with them
|
|
|
|
|
if (
|
|
|
|
|
i > 0 && i < len - 1 &&
|
|
|
|
|
v.length == 1 && chr.indexOf(v) > -1
|
|
|
|
|
) {
|
|
|
|
|
arr[i + 1] = arr[i - 1] + arr[i] + arr[i + 1];
|
|
|
|
|
arr[i - 1] = arr[i] = '';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// remove elements that have been emptied above
|
|
|
|
|
arr = arr.filter(function(v) {
|
|
|
|
|
return v.length;
|
|
|
|
|
});
|
|
|
|
|
// return words, not spaces or punctuation
|
|
|
|
|
return arr.filter(function(v, i) {
|
|
|
|
|
return i % 2 == !startsWithWord;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-05 07:09:34 +00:00
|
|
|
|
Ox.wordwrap = function(str, len, sep, bal, spa) {
|
|
|
|
|
/*
|
2011-02-09 17:56:35 +00:00
|
|
|
|
>>> Ox.wordwrap("Anticonstitutionellement, Paris s'eveille", 25, "<br/>")
|
|
|
|
|
"Anticonstitutionellement, <br/>Paris s'eveille"
|
2010-07-05 07:09:34 +00:00
|
|
|
|
>>> Ox.wordwrap("Anticonstitutionellement, Paris s'eveille", 16, "<br/>")
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"Anticonstitution<br/>ellement, Paris <br/>s'eveille"
|
2010-07-05 07:09:34 +00:00
|
|
|
|
>>> Ox.wordwrap("These are short words", 16, "<br/>", true)
|
2011-02-09 17:56:35 +00:00
|
|
|
|
"These are <br/>short words"
|
2010-07-05 07:09:34 +00:00
|
|
|
|
*/
|
2010-09-11 08:59:40 +00:00
|
|
|
|
var str = str === null ? '' : str.toString(),
|
2010-09-08 16:35:34 +00:00
|
|
|
|
len = len || 80,
|
2010-07-05 07:09:34 +00:00
|
|
|
|
sep = sep || "<br/>",
|
|
|
|
|
bal = bal || false,
|
2010-09-06 23:44:37 +00:00
|
|
|
|
spa = Ox.isUndefined(spa) ? true : spa,
|
2010-07-05 07:09:34 +00:00
|
|
|
|
words = str.split(" "),
|
|
|
|
|
lines;
|
|
|
|
|
if (bal) {
|
|
|
|
|
// balance lines: test if same number of lines
|
|
|
|
|
// can be achieved with a shorter line length
|
|
|
|
|
lines = Ox.wordwrap(str, len, sep, false).split(sep);
|
|
|
|
|
if (lines.length > 1) {
|
|
|
|
|
// test shorter line, unless
|
|
|
|
|
// that means cutting a word
|
|
|
|
|
var max = Ox.max($.map(words, function(word) {
|
|
|
|
|
return word.length;
|
|
|
|
|
}));
|
|
|
|
|
while (len > max) {
|
|
|
|
|
len--;
|
|
|
|
|
if (Ox.wordwrap(str, len, sep, false).split(sep).length > lines.length) {
|
|
|
|
|
len++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lines = [""];
|
|
|
|
|
$.each(words, function(i, word) {
|
|
|
|
|
if ((lines[lines.length - 1] + word + " ").length <= len + 1) {
|
|
|
|
|
// word fits in current line
|
|
|
|
|
lines[lines.length - 1] += word + " ";
|
|
|
|
|
} else {
|
|
|
|
|
if (word.length <= len) {
|
|
|
|
|
// word fits in next line
|
|
|
|
|
lines.push(word + " ");
|
|
|
|
|
} else {
|
|
|
|
|
// word is longer than line
|
|
|
|
|
var chr = len - lines[lines.length - 1].length;
|
|
|
|
|
lines[lines.length - 1] += word.substr(0, chr);
|
|
|
|
|
for (var pos = chr; pos < word.length; pos += len) {
|
|
|
|
|
lines.push(word.substr(pos, len));
|
|
|
|
|
}
|
|
|
|
|
lines[lines.length - 1] += " ";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (!spa) {
|
|
|
|
|
lines = $.map(lines, function(line) {
|
|
|
|
|
return Ox.trim(line);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return Ox.trim(lines.join(sep));
|
|
|
|
|
};
|
2010-01-07 20:21:07 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================================================================================
|
|
|
|
|
Type functions
|
|
|
|
|
================================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Ox.isArray = function(val) { // is in jQuery
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isArray([])
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return val instanceof Array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ox.isBoolean = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isBoolean(false)
|
|
|
|
|
true
|
|
|
|
|
*/
|
2010-12-31 11:01:35 +00:00
|
|
|
|
return typeof val == 'boolean';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isDate = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isDate(new Date())
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return val instanceof Date;
|
|
|
|
|
};
|
|
|
|
|
|
2011-01-23 04:59:16 +00:00
|
|
|
|
Ox.isElement = function(val) {
|
|
|
|
|
return !!(val && val.nodeType == 1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.isFunction = function(val) { // is in jQuery
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isFunction(function() {})
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.isFunction(/ /)
|
|
|
|
|
false
|
|
|
|
|
*/
|
2010-12-31 11:01:35 +00:00
|
|
|
|
return typeof val == 'function' && !Ox.isRegExp(val);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
2011-01-23 04:59:16 +00:00
|
|
|
|
Ox.isNaN = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isNaN(NaN)
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return val !== val;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 20:21:07 +00:00
|
|
|
|
Ox.isNull = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isNull(null)
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return val === null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isNumber = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isNumber(0)
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.isNumber(Infinity)
|
|
|
|
|
false
|
|
|
|
|
>>> Ox.isNumber(NaN)
|
|
|
|
|
false
|
|
|
|
|
*/
|
2010-12-31 11:01:35 +00:00
|
|
|
|
return typeof val == 'number' && isFinite(val);
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isObject = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isObject({})
|
|
|
|
|
true
|
|
|
|
|
>>> Ox.isObject([])
|
|
|
|
|
false
|
|
|
|
|
>>> Ox.isObject(new Date())
|
|
|
|
|
false
|
|
|
|
|
>>> Ox.isObject(null)
|
|
|
|
|
false
|
|
|
|
|
*/
|
2010-12-31 11:01:35 +00:00
|
|
|
|
return typeof val == 'object' && !$.isArray(val) &&
|
2010-01-07 20:21:07 +00:00
|
|
|
|
!Ox.isDate(val) && !Ox.isNull(val);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isRegExp = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isRegExp(/ /)
|
|
|
|
|
true
|
|
|
|
|
*/
|
|
|
|
|
return val instanceof RegExp;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isString = function(val) {
|
|
|
|
|
/*
|
2010-12-31 11:01:35 +00:00
|
|
|
|
>>> Ox.isString('')
|
2010-01-07 20:21:07 +00:00
|
|
|
|
true
|
|
|
|
|
*/
|
2010-12-31 11:01:35 +00:00
|
|
|
|
return typeof val == 'string';
|
2010-01-07 20:21:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ox.isUndefined = function(val) {
|
|
|
|
|
/*
|
|
|
|
|
>>> Ox.isUndefined()
|
|
|
|
|
true
|
|
|
|
|
*/
|
2010-12-31 11:01:35 +00:00
|
|
|
|
return typeof val == 'undefined';
|
2010-11-25 11:47:42 +00:00
|
|
|
|
};
|