From d7fb9e3dad08e516d512721b817d583be63d9bce Mon Sep 17 00:00:00 2001 From: rlx <0x0073@0x2620.org> Date: Wed, 9 Feb 2011 17:56:35 +0000 Subject: [PATCH] updating ox.js --- build/css/ox.ui.css | 11 + build/css/ox.ui.modern.css | 3 +- build/js/ox.js | 634 ++++++++++++++++++++++++++----------- build/js/ox.ui.js | 242 ++++++++++---- tests/png.html | 80 +++-- tests/tests.js | 80 ++--- 6 files changed, 715 insertions(+), 335 deletions(-) diff --git a/build/css/ox.ui.css b/build/css/ox.ui.css index b3c4c5b9..1912e56c 100644 --- a/build/css/ox.ui.css +++ b/build/css/ox.ui.css @@ -295,6 +295,10 @@ textarea { -moz-border-radius: 8px; -webkit-border-radius: 8px; } +textarea.OxSquare { + -moz-border-radius: 0; + -webkit-border-radius: 0; +} /* -------------------------------------------------------------------------------- OxButton @@ -1296,6 +1300,13 @@ Video .OxAnnotation:last-child { border-width: 0; } +.OxAnnotation.OxEdit { + padding: 0; +} +.OxAnnotation textarea { + padding: 4px; + border: 0; +} .OxVideoEditor { overflow-x: hidden; diff --git a/build/css/ox.ui.modern.css b/build/css/ox.ui.modern.css index 84aeb8b2..4a70fbb4 100644 --- a/build/css/ox.ui.modern.css +++ b/build/css/ox.ui.modern.css @@ -69,9 +69,10 @@ Forms */ -.OxThemeModern .OxButton, .OxThemeModern input.OxCheckbox, .OxThemeModern input.OxInput, +.OxThemeModern textarea, +.OxThemeModern .OxButton, .OxThemeModern .OxLabel, .OxThemeModern .OxTrack { //border: 1px solid rgb(80, 80, 80); diff --git a/build/js/ox.js b/build/js/ox.js index eec35506..f821c350 100644 --- a/build/js/ox.js +++ b/build/js/ox.js @@ -5,9 +5,11 @@ Ox = function(val) { }; */ -Ox = { - version: '0.1.2' -}; +if (!window.Ox) { + Ox = { + version: '0.1.2' + }; +} /* ================================================================================ @@ -15,14 +17,17 @@ Constants ================================================================================ */ -Ox.AMPM = ["AM", "PM"]; +Ox.AMPM = ['AM', 'PM']; Ox.DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; Ox.EARTH_RADIUS = 6378137; Ox.EARTH_CIRCUMFERENCE = Ox.EARTH_RADIUS * 2 * Math.PI; -Ox.MONTHS = ["January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December"]; -Ox.WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday", "Sunday"]; +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']; /* ================================================================================ @@ -76,16 +81,16 @@ Ox.getset = function(obj, args, callback, context) { Ox.print = function() { /* */ - if (typeof console != "undefined") { + if (window.console) { var args = $.makeArray(arguments), date = new Date; - args.unshift(Ox.formatDate(date, "%H:%M:%S") + "." + + args.unshift(Ox.formatDate(date, '%H:%M:%S') + '.' + (Ox.pad(+date % 1000, 3))); - console.log.apply(console, args); + window.console.log.apply(window.console, args); } } -Ox.uid = function() { +Ox.uid = (function() { /*** returns a unique id >>> Ox.uid() != Ox.uid() @@ -95,7 +100,7 @@ Ox.uid = function() { return function() { return uid++; }; -}(); +}()); Ox.user = function() { // fixme: move to ox.ui @@ -137,17 +142,32 @@ Ox.avg = function(obj) { returns the average of an array's values, or an object's properties >>> Ox.avg([-1, 0, 1]) 0 - >>> Ox.avg({"a": 1, "b": 2, "c": 3}) + >>> Ox.avg({a: 1, b: 2, c: 3}) 2 ***/ return Ox.sum(obj) / Ox.length(obj); }; Ox.clone = function(obj) { + /* + */ return Ox.isArray(obj) ? obj.slice() : Ox.extend({}, obj); }; +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; +}; + Ox.each = function(obj, fn) { + // fixme: deprecate! /* Ox.each() works for arrays, objects and strings, like $.each(), unlike [].forEach() @@ -155,11 +175,12 @@ Ox.each = function(obj, fn) { [0, 1, 2] >>> Ox.each({a: 1, b: 2, c: 3}, function(k, v) {}).a 1 - >>> Ox.each("foo", function(i, v) {}) - "foo" + >>> Ox.each('foo', function(i, v) {}) + 'foo' */ - var i; + var i, isArray = Ox.isArray(obj); for (i in obj) { + i = isArray ? parseInt(i) : i; // fixme: should be (v, k), like [].forEach() if (fn(i, obj[i]) === false) { break; @@ -170,7 +191,12 @@ Ox.each = function(obj, fn) { Ox.equals = function(obj0, obj1) { /* - ... core? type? + >>> 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 */ var ret = false; if (obj0 === obj1) { @@ -179,7 +205,7 @@ Ox.equals = function(obj0, obj1) { if (obj0 == obj1) { ret = true; } else if (Ox.isArray(obj0) && obj0.length == obj1.length) { - Ox.each(obj0, function(i, v) { + Ox.forEach(obj0, function(v, i) { ret = Ox.equals(v, obj1[i]); return ret; }); @@ -192,7 +218,6 @@ Ox.equals = function(obj0, obj1) { ret = obj0.toString() == obj1.toString(); } } - Ox.print('Ox.equals', obj0, obj1, ret) return ret; } @@ -203,7 +228,7 @@ Ox.every = function(obj, fn) { true >>> Ox.every({a: 1, b: 2, c: 3}, function(v) { return v == 1; }) false - >>> Ox.every("foo", function(v) { return v == "f"; }) + >>> Ox.every("foo", function(v) { return v == 'f'; }) false >>> Ox.every([true, true, true]) true @@ -213,13 +238,18 @@ Ox.every = function(obj, fn) { }).length == Ox.length(obj); }; -Ox.extend = function(obj) { - Ox.each(Array.prototype.slice.call(arguments, 1), function(i, arg) { - Ox.each(arg, function(key, val) { - obj0[key] = val; +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; }); }); - return obj0; + return obj; }; Ox.filter = function(arr, fn) { @@ -277,13 +307,36 @@ Ox.find = function(arr, str) { return ret; } +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; +}; + Ox.getObjectById = function(arr, id) { /*** >>> Ox.getObjectById([{id: "foo", title: "Foo"}, {id: "bar", title: "Bar"}], "foo").title "Foo" ***/ var ret = null; - Ox.each(arr, function(i, v) { + Ox.forEach(arr, function(v) { if (v.id == id) { ret = v; return false; @@ -298,7 +351,7 @@ Ox.getPositionById = function(arr, id) { 1 ***/ var ret = -1; - Ox.each(arr, function(i, v) { + Ox.forEach(arr, function(v, i) { if (v.id == id) { ret = i; return false; @@ -309,11 +362,11 @@ Ox.getPositionById = function(arr, id) { Ox.keys = function(obj) { /* - >>> Ox.keys({"a": 1, "b": 2, "c": 3}) + >>> Ox.keys({a: 1, b: 2, c: 3}) ["a", "b", "c"] */ var keys = []; - Ox.each(obj, function(k) { + Ox.forEach(obj, function(v, k) { keys.push(k); }); return keys; @@ -325,7 +378,7 @@ Ox.length = function(obj) { 3 */ var length = 0; - Ox.each(obj, function() { + Ox.forEach(obj, function() { length++; }); return length; @@ -338,9 +391,9 @@ Ox.makeArray = function(arr) { ["foo"] >>> Ox.makeArray(["foo"]) ["foo"] - >>> (function() { return Ox.makeArray(arguments); })("foo") + >>> (function() { return Ox.makeArray(arguments); }("foo")) ["foo"] - >>> (function() { return Ox.makeArray(arguments); })(["foo"]) + >>> (function() { return Ox.makeArray(arguments); }(["foo"])) ["foo"] */ // fixme: this doesn't work for numbers @@ -361,9 +414,9 @@ Ox.makeObject = function(arr) { "bar" >>> Ox.makeObject({foo: "bar"}).foo "bar" - >/>> (function() { return Ox.makeObject(arguments); })("foo", "bar").foo // fixme + >/>> (function() { return Ox.makeObject(arguments); }("foo", "bar")).foo // fixme "bar" - >/>> (function() { return Ox.makeObject(arguments); })({foo: "bar"}).foo + >/>> (function() { return Ox.makeObject(arguments); }({foo: "bar"})).foo "bar" */ var obj = {}; @@ -399,7 +452,7 @@ Ox.max = function(obj) { /* >>> Ox.max([-1, 0, 1]) 1 - >>> Ox.max({"a": 1, "b": 2, "c": 3}) + >>> Ox.max({a: 1, b: 2, c: 3}) 3 */ return Math.max.apply(Math, Ox.values(obj)); @@ -409,15 +462,19 @@ Ox.min = function(obj) { /* >>> Ox.min([-1, 0, 1]) -1 - >>> Ox.min({"a": 1, "b": 2, "c": 3}) + >>> Ox.min({a: 1, b: 2, c: 3}) 1 */ return Math.min.apply(Math, Ox.values(obj)); }; Ox.merge = function(arr) { - Ox.each(Array.prototype.slice.call(arguments, 1), function(i, arg) { - Ox.each(arg, function(i, val) { + /* + >>> Ox.merge(['foo'], ['bar'], ['baz']) + ['foo', 'bar', 'baz'] + */ + Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg) { + Ox.forEach(arg, function(val) { arr.push(val); }); }); @@ -446,19 +503,25 @@ Ox.range = function(start, stop, step) { Ox.serialize = function(obj) { /* - >>> Ox.serialize({a: 0, b: 1}) - a=0&b=1 + >>> Ox.serialize({a: 1, b: 2, c: 3}) + 'a=1&b=2&c=3' */ var arr = []; - Ox.each(obj, function(k, v) { - v !== '' && arr.push(k + '=' + v); + Ox.forEach(obj, function(val, key) { + val !== '' && arr.push(key + '=' + val); }); return arr.join('&'); }; Ox.setPropertyOnce = function(arr, str) { + /* + >>> Ox.setPropertyOnce([{selected: false}, {selected: false}]) + 0 + >>> Ox.setPropertyOnce([{selected: true}, {selected: true}]) + 0 + */ var pos = -1; - Ox.each(arr, function(i, v) { + Ox.forEach(arr, function(v, i) { if (pos == -1 && arr[i][str]) { pos = i; } else if (pos > -1 && arr[i][str]) { @@ -490,7 +553,7 @@ Ox.some = function(obj, fn) { true >>> Ox.some({a: 1, b: 2, c: 3}, function(v) { return v == 1; }) true - >>> Ox.some("foo", function(v) { return v == "f"; }) + >>> Ox.some("foo", function(v) { return v == 'f'; }) true */ return Ox.filter(Ox.values(obj), fn).length > 0; @@ -500,12 +563,12 @@ Ox.sum = function(obj) { /* >>> Ox.sum([-1, 0, 1]) 0 - >>> Ox.sum({"a": 1, "b": 2, "c": 3}) + >>> Ox.sum({a: 1, b: 2, c: 3}) 6 */ var sum = 0; - Ox.each(obj, function(k, v) { - sum += v; + Ox.forEach(obj, function(val) { + sum += val; }); return sum; }; @@ -523,9 +586,13 @@ Ox.unique = function(arr) { }; Ox.unserialize = function(str) { + /* + >>> Ox.unserialize('a=1&b=2&c=3').c + '3' + */ var arr, obj = {}; - Ox.each(str.split('&'), function(i, v) { - arr = v.split('='); + Ox.forEach(str.split('&'), function(val) { + arr = val.split('='); obj[arr[0]] = arr[1]; }); return obj; @@ -533,21 +600,20 @@ Ox.unserialize = function(str) { Ox.values = function(obj) { /* - >>> Ox.values({"a": 1, "b": 2, "c": 3}).join(",") + >>> Ox.values({a: 1, b: 2, c: 3}) [1, 2, 3] - >>> Ox.values([1, 2, 3]).join(",") + >>> Ox.values([1, 2, 3]) [1, 2, 3] */ var values = []; - Ox.each(obj, function(k, v) { - values.push(v); + Ox.forEach(obj, function(val) { + values.push(val); }); return values; }; Ox.zip = function() { /* - // fixme: Ox.each doesn't work here >>> Ox.zip([[0, 1], [2, 3], [4, 5]]) [[0, 2, 4], [1, 3, 5]] >>> Ox.zip([0, 1, 2], [3, 4, 5]) @@ -833,31 +899,32 @@ Ox.canvas = function() { image = isImage ? arguments[0] : { width: arguments[0], height: arguments[1] }; - c.context = (c.canvas = Ox.element("canvas").attr({ + c.context = (c.canvas = Ox.element('canvas').attr({ width: image.width, height: image.height - })[0]).getContext("2d"); + })[0]).getContext('2d'); isImage && c.context.drawImage(image, 0, 0); - c.data = (c.imageData = c.context.getImageData(0, 0, - image.width, image.height)).data; + c.data = (c.imageData = c.context.getImageData( + 0, 0, image.width, image.height + )).data; return c; }; Ox.element = function(str) { /* - >>> Ox.element("div").attr({id: "foo"}).attr("id") - "foo" - >>> Ox.element("div").html("foo").html() - "foo" + >>> Ox.element('div').attr({id: 'foo'}).attr('id') + 'foo' + >>> Ox.element('div').html('foo').html() + 'foo' */ return { - 0: str[0] == "#" ? document.getElementById(str.substr(1)) : + 0: str[0] == '#' ? document.getElementById(str.substr(1)) : 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 { - Ox.each(Ox.makeObject.apply(this, arguments), function(k, v) { + Ox.forEach(Ox.makeObject.apply(this, arguments), function(v, k) { that[0].setAttribute(k, v); }); ret = this; @@ -885,10 +952,10 @@ Encoding functions (function() { - var aliases = {"I": "1", "L": "1", "O": "0", "U": "V"}, - digits = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; + var aliases = {'I': '1', 'L': '1', 'O': '0', 'U': 'V'}, + digits = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; - function max(width, height) { + function cap(width, height) { // returns maximum encoding capacity of an image return parseInt(width * height * 3/8) - 4; } @@ -897,7 +964,7 @@ Encoding functions // returns this, or the next, opaque pixel while (data[px * 4 + 3] < 255) { if (++px * 4 == data.length) { - throwPNGError("de"); + throwPNGError('de'); } } return px; @@ -906,61 +973,65 @@ Encoding functions function xor(byte) { // returns "1"-bits-in-byte % 2 var xor = 0; - $.each(new Array(8), function(i) { // fixme: Ox.each doesn't work + Ox.range(8).forEach(function(i) { xor ^= byte >> i & 1; }); return xor; } function throwPNGError(str) { - throw new RangeError("PNG codec can't " + - (str == "en" ? "encode data" : "decode image")); + throw new RangeError( + 'PNG codec can\'t ' + + (str == 'en' ? 'encode data' : 'decode image') + ); } function throwUTF8Error(byte, pos) { - throw new RangeError("UTF-8 codec can't decode byte 0x" + - byte.toString(16).toUpperCase() + " at position " + pos); + throw new RangeError( + 'UTF-8 codec can\'t decode byte 0x' + + byte.toString(16).toUpperCase() + ' at position ' + pos + ); } Ox.encodeBase32 = function(num) { // see http://www.crockford.com/wrmg/base32.html /* >>> Ox.encodeBase32(15360) - "F00" + 'F00' >>> Ox.encodeBase32(33819) - "110V" + '110V' */ return Ox.map(num.toString(32), function(char) { return digits[parseInt(char, 32)]; - }).join(""); + }).join(''); } Ox.decodeBase32 = function(str) { /* - >>> Ox.decodeBase32("foo") + >>> Ox.decodeBase32('foo') 15360 - >>> Ox.decodeBase32("ilou") + >>> Ox.decodeBase32('ilou') 33819 - >>> Ox.decodeBase32("?").toString() // fixme: toString shouldn't be necessary here - "NaN" + >>> Ox.decodeBase32('?').toString() + 'NaN' */ return parseInt($.map(str.toUpperCase(), function(char) { var index = digits.indexOf(aliases[char] || char); - return (index == -1 ? " " : index).toString(32); - }).join(""), 32); + return (index == -1 ? ' ' : index).toString(32); + }).join(''), 32); } Ox.encodeBase64 = function(num) { /* >>> Ox.encodeBase64(32394) - "foo" + 'foo' */ return btoa(Ox.encodeBase256(num)).replace(/=/g, ""); } Ox.decodeBase64 = function(str) { /* - >>> Ox.decodeBase64("foo") + >>> Ox.decodeBase64('foo') 32394 */ return Ox.decodeBase256(atob(str)); @@ -969,9 +1040,9 @@ Encoding functions Ox.encodeBase128 = function(num) { /* >>> Ox.encodeBase128(1685487) - "foo" + 'foo' */ - var str = ""; + var str = ''; while (num) { str = Ox.char(num & 127) + str; num >>= 7; @@ -981,11 +1052,11 @@ Encoding functions Ox.decodeBase128 = function(str) { /* - >>> Ox.decodeBase128("foo") + >>> Ox.decodeBase128('foo') 1685487 */ var num = 0, len = str.length; - Ox.each(str, function(i, char) { + Ox.forEach(str, function(char, i) { num += char.charCodeAt(0) << (len - i - 1) * 7; }); return num; @@ -994,9 +1065,9 @@ Encoding functions Ox.encodeBase256 = function(num) { /* >>> Ox.encodeBase256(6713199) - "foo" + 'foo' */ - var str = ""; + var str = ''; while (num) { str = Ox.char(num & 255) + str; num >>= 8; @@ -1006,11 +1077,11 @@ Encoding functions Ox.decodeBase256 = function(str) { /* - >>> Ox.decodeBase256("foo") + >>> Ox.decodeBase256('foo') 6713199 */ var num = 0, len = str.length; - Ox.each(str, function(i, char) { + Ox.forEach(str, function(char, i) { num += char.charCodeAt(0) << (len - i - 1) * 8; }); return num; @@ -1025,7 +1096,7 @@ Encoding functions 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 + - Ox.repeat("\u00FF", (4 - len % 4) % 4); // simpler? Ox.pad()? + Ox.repeat('\u00FF', (4 - len % 4) % 4); // simpler? Ox.pad()? /* 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; @@ -1035,56 +1106,52 @@ Encoding functions c.data[i] = i % 4 < 3 ? str.charCodeAt(i - parseInt(i / 4)) : 255; } c.context.putImageData(c.imageData, 0, 0); - data = atob(c.canvas.toDataURL().split(",")[1]); - //Ox.print("deflate", len, "->", data.length - 20); + Ox.print(c.canvas.toDataURL()) + data = atob(c.canvas.toDataURL().split(',')[1]); + Ox.print('data', data); return data.substr(8, data.length - 20); } Ox.decodeDeflate = function(str) { var image = new Image(); - image.src = "data:image/png;base64," + btoa("\u0089PNG\r\n\u001A\n" + - str + Ox.repeat("\u0000", 4) + "IEND\u00AEB`\u0082"); - while (!image.width) {} // wait for image data + 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 str = Ox.map(Ox.canvas(image).data, function(v, i) { - return i % 4 < 3 ? Ox.char(v) : ""; - }).join(""); - //Ox.print(str.length, "len", Ox.decodeBase256(str.substr(0, 4)), str) + return i % 4 < 3 ? Ox.char(v) : ''; + }).join(''); return Ox.decodeUTF8(str.substr(4, Ox.decodeBase256(str.substr(0, 4)))); } - Ox.encodeHTML = function() { + Ox.encodeHTML = function(str) { /* - >>> Ox.encodeHTML("'<\"&\">'") - "'<"&">'" - >>> Ox.encodeHTML("äbçdê") - "äbçdê" + >>> Ox.encodeHTML('\'<"&">\'') + ''<"&">'' + >>> Ox.encodeHTML('äbçdê') + 'äbçdê' */ - var entities = { - '"': """, "&": "&", "'": "'", "<": "<", ">": ">" - }; - return function(str) { - return $.map(Array.prototype.slice.call(str), function(v) { - var code = v.charCodeAt(0); - return code < 128 ? (v in entities ? entities[v] : v) : - "" + Ox.pad(code.toString(16).toUpperCase(), 4) + ";"; - }).join(""); - }; - }(); + return $.map(str, function(v) { + var code = v.charCodeAt(0); + return code < 128 ? (v in Ox.HTML_ENTITIES ? Ox.HTML_ENTITIES[v] : v) : + '' + Ox.pad(code.toString(16).toUpperCase(), 4) + ';'; + }).join(''); + }; Ox.decodeHTML = function(str) { /* - >>> Ox.decodeHTML("'<"&">'") - "'<\"&\">'" - >>> Ox.decodeHTML("'<"&">'") - "'<\"&\">'" - >>> Ox.decodeHTML("äbçdê") - "äbçdê" - >>> Ox.decodeHTML("äbçdê") - "äbçdê" + >>> Ox.decodeHTML(''<"&">'') + '\'<"&">\'' + >>> Ox.decodeHTML(''<"&">'') + '\'<"&">\'' + >>> Ox.decodeHTML('äbçdê') + 'äbçdê' + >>> Ox.decodeHTML('äbçdê') + 'äbçdê' */ // relies on dom, but shorter than using this: // http://www.w3.org/TR/html5/named-character-references.html - return $("
").html(str)[0].childNodes[0].nodeValue; + return $('').html(str)[0].childNodes[0].nodeValue; }; Ox.encodePNG = function(img, str) { @@ -1102,17 +1169,18 @@ Encoding functions (and flip the second least significant bit, if at all) - write an extra png chunk containing some key */ - str = Ox.encodeDeflate(str); + //str = Ox.encodeDeflate(str); currently broken + str = Ox.encodeUTF8(str); var c = Ox.canvas(img), len = str.length, px = 0; - if (len == 0 || len > max(img.width, img.height)) { - throwPNGError("en") + if (len == 0 || len > cap(img.width, img.height)) { + throwPNGError('en') } len = Ox.pad(Ox.encodeBase256(len), 4, Ox.char(0)); - Ox.each(Ox.map(len + str, function(byte) { - return Ox.map(new Array(8), function(v, i) { + Ox.forEach(Ox.map(len + str, function(byte) { + return Ox.map(Ox.range(8), function(i) { return byte.charCodeAt(0) >> 7 - i & 1; - }).join(""); - }).join(""), function(i, bit) { + }).join(''); + }).join(''), function(bit, i) { var index = parseInt((px = seek(c.data, px)) * 4 + i % 3), byte = c.data[index]; c.data[index] = bit == xor(byte) ? byte : @@ -1125,47 +1193,48 @@ Encoding functions Ox.decodePNG = function(img) { // decodes image, returns string - var data = Ox.canvas(img).data, bits = "", str = "", - px = 0, i = 0; len = 4, flag = false; + var bits = '', data = Ox.canvas(img).data, flag = false, i = 0, + len = 4, max = cap(img.width, img.height), px = 0, str = ''; 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)); - bits = ""; + bits = ''; len--; if (len == 0 && !flag) { len = Ox.decodeBase256(str); - if (len <= 0 || len > max(img.width, img.height)) { + if (len <= 0 || len > max) { Ox.print(len); - throwPNGError("de"); + throwPNGError('de'); } - str = ""; + str = ''; flag = true; } } } while (len); try { - return Ox.decodeDeflate(str); + //return Ox.decodeDeflate(str); currently broken + return Ox.decodeUTF8(str); } catch(e) { Ox.print(e.toString()); - throwPNGError("de"); + throwPNGError('de'); } } Ox.encodeUTF8 = function(str) { /* see http://en.wikipedia.org/wiki/UTF-8 - >>> Ox.encodeUTF8("foo") - "foo" - >>> Ox.encodeUTF8("¥€$") - "\u00C2\u00A5\u00E2\u0082\u00AC\u0024" + >>> Ox.encodeUTF8('foo') + 'foo' + >>> Ox.encodeUTF8('¥€$') + '\u00C2\u00A5\u00E2\u0082\u00AC\u0024' */ - return $.map(Array.prototype.slice.call(str), function(char) { // fixme: why not str? - var code = char.charCodeAt(0), - str = ""; + return $.map(Array.prototype.slice.call(str), function(chr) { + var code = chr.charCodeAt(0), + str = ''; if (code < 128) { - str = char; + str = chr; } else if (code < 2048) { str = String.fromCharCode(code >> 6 | 192) + String.fromCharCode(code & 63 | 128); @@ -1175,28 +1244,30 @@ Encoding functions String.fromCharCode(code & 63 | 128); } return str; - }).join(""); + }).join(''); } Ox.decodeUTF8 = function(str) { /* - >>> Ox.decodeUTF8("foo") - "foo" - >>> Ox.decodeUTF8("\u00C2\u00A5\u00E2\u0082\u00AC\u0024") - "¥€$" + >>> Ox.decodeUTF8('foo') + 'foo' + >>> Ox.decodeUTF8('\u00C2\u00A5\u00E2\u0082\u00AC\u0024') + '¥€$' */ var bytes = $.map(str, function(v) { return v.charCodeAt(0); }), i = 0, len = str.length, - str = ""; + str = ''; while (i < len) { if (bytes[i] <= 128) { str += String.fromCharCode(bytes[i]); i++; - } else if (bytes[i] >= 192 && bytes[i] < 240 && - i < len - (bytes[i] < 224 ? 1 : 2)) { + } else if ( + bytes[i] >= 192 && bytes[i] < 240 && + i < len - (bytes[i] < 224 ? 1 : 2) + ) { if (bytes[i + 1] >= 128 && bytes[i + 1] < 192) { if (bytes[i] < 224) { str += String.fromCharCode((bytes[i] & 31) << 6 | @@ -1419,15 +1490,15 @@ Ox.formatDate = function() { Ox.formatDuration = function(sec, dec, format) { /* >>> Ox.formatDuration(123456.789, 3) - 1:10:17:36.789 + "1:10:17:36.789" >>> Ox.formatDuration(12345.6789) - 03:25:46 + "03:25:46" >>> Ox.formatDuration(12345.6789, true) - 0:03:25:46 + "0:03:25:46" >>> Ox.formatDuration(3599.999, 3) - 00:59:59.999 + "00:59:59.999" >>> Ox.formatDuration(3599.999) - 01:00:00 + "01:00:00" */ var format = arguments.length == 3 ? format : (Ox.isString(dec) ? dec : "short"), dec = (arguments.length == 3 || Ox.isNumber(dec)) ? dec : 0, @@ -1483,37 +1554,49 @@ Ox.formatNumber = function(num, dec) { }; Ox.formatPercent = function(num, total, dec) { + /* + >>> Ox.formatPercent(1, 1000, 2) + "0.10%" + */ return Ox.formatNumber(num / total * 100, dec) + '%' }; Ox.formatResolution = function(arr, str) { - return arr[0] + ' x ' + arr[1] + ' ' + str; + /* + >>> Ox.formatResolution([1920, 1080], 'px') + "1920 x 1080 px" + */ + return arr[0] + ' x ' + arr[1] + (str ? ' ' + str : ''); } -Ox.formatString = function (s, args) { - /* Python(ish) string formatting: - * >>> format('{0}', ['zzz']) - * "zzz" - * >>> format('{x}', {x: 1}) - * "1" - */ - var re = /\{([^}]+)\}/g; - return s.replace(re, function(_, match){ return args[match]; }); +Ox.formatString = function (str, obj) { + /* + >>> Ox.formatString('{0}{1}', ['foo', 'bar']) + "foobar" + >>> Ox.formatString('{a}{b}', {a: 'foo', b: 'bar'}) + "foobar" + */ + return str.replace(/\{([^}]+)\}/g, function(str, match) { + return obj[match]; + }); } -Ox.formatValue = function(num, str) { +Ox.formatValue = function(num, str, bin) { /* >>> Ox.formatValue(0, "B") - ??? + "0 KB" >>> Ox.formatValue(123456789, "B") - ??? + "123.5 MB" + >>> Ox.formatValue(1234567890, "B", true) + "1.15 GiB" */ - var arr = ["K", "M", "G", "T", "P"], - len = arr.length, - val = ""; - $.each(arr, function(i, v) { - if (num < Math.pow(1024, i + 2) || i == len - 1) { - val = Ox.formatNumber(num / Math.pow(1024, i + 1), i) + " " + v + str; + 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; return false; } }); @@ -1551,6 +1634,127 @@ Ox.getMetersPerDegree = function(point) { return Math.cos(point[0] * Math.PI / 180) * Ox.EARTH_CIRCUMFERENCE / 360; }; +/* +================================================================================ +HTML functions +================================================================================ +*/ + +Ox.parseEmailAddresses = function(html) { + return html.replace( + /\b([0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi, + '$1' + ); +}; + +Ox.parseHTML = (function() { + /* + >>> Ox.parseHTML('http://foo.com, bar') + 'foo.com, bar' + >>> Ox.parseHTML('(see: www.foo.com)') + '(see: www.foo.com)' + >>> Ox.parseHTML('foo@bar.com') + 'foo@bar.com' + >>> Ox.parseHTML('foo') + 'foo' + >>> Ox.parseHTML('foo') + '<a href="javascript:alert()">foo</a>' + >>> Ox.parseHTML('[http://foo.com foo]') + 'foo' + >>> Ox.parseHTML('