diff --git a/CHANGES.md b/CHANGES.md index 74ecd0138..10c9f5b1a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,9 @@ # Changes -### cordova-sqlite-legacy-express-core 1.0.0-pre1 +### cordova-sqlite-legacy-express-core 1.0.0-pre2 - Drop engine constraints in package.json & plugin.xml (in this version branch) +- Remove Lawnchair adapter from this version branch - Support macOS platform with builtin libsqlite3.dylib framework in this version branch ## 1.2.2 diff --git a/Lawnchair-adapter/Lawnchair-sqlitePlugin.js b/Lawnchair-adapter/Lawnchair-sqlitePlugin.js deleted file mode 100644 index 9af1033f6..000000000 --- a/Lawnchair-adapter/Lawnchair-sqlitePlugin.js +++ /dev/null @@ -1,201 +0,0 @@ -Lawnchair.adapter('cordova-sqlite', (function () { - // private methods - var fail = function (e, i) { console.log('error in sqlite adaptor!', e, i) } - , now = function () { return new Date() } // FIXME need to use better date fn - // not entirely sure if this is needed... - if (!Function.prototype.bind) { - Function.prototype.bind = function( obj ) { - var slice = [].slice - , args = slice.call(arguments, 1) - , self = this - , nop = function () {} - , bound = function () { - return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments))) - } - nop.prototype = self.prototype - bound.prototype = new nop() - return bound - } - } - - // public methods - return { - - valid: function() { return !!(sqlitePlugin.openDatabase) }, - - init: function (options, callback) { - var that = this - , cb = that.fn(that.name, callback) - , dbname = options.db || this.name - , bgType = options.bgType || 1 - , create = "CREATE TABLE IF NOT EXISTS " + this.name + " (id NVARCHAR(32) UNIQUE PRIMARY KEY, value TEXT, timestamp REAL)" - , win = function(){ return cb.call(that, that); } - // open a connection and create the db if it doesn't exist - this.db = sqlitePlugin.openDatabase({name:dbname,bgType:bgType}) - this.db.transaction(function (t) { - t.executeSql(create, [], win, fail) - }) - }, - - keys: function (callback) { - var cb = this.lambda(callback) - , that = this - , keys = "SELECT id FROM " + this.name + " ORDER BY timestamp DESC" - - this.db.transaction(function(t) { - var win = function (xxx, results) { - if (results.rows.length == 0 ) { - cb.call(that, []) - } else { - var r = []; - for (var i = 0, l = results.rows.length; i < l; i++) { - r.push(results.rows.item(i).id); - } - cb.call(that, r) - } - } - t.executeSql(keys, [], win, fail) - }) - return this - }, - // you think thats air you're breathing now? - save: function (obj, callback) { - var that = this - , id = obj.key || that.uuid() - , ins = "INSERT INTO " + this.name + " (value, timestamp, id) VALUES (?,?,?)" - , up = "UPDATE " + this.name + " SET value=?, timestamp=? WHERE id=?" - , win = function () { if (callback) { obj.key = id; that.lambda(callback).call(that, obj) }} - , val = [now(), id] - // existential - that.exists(obj.key, function(exists) { - // transactions are like condoms - that.db.transaction(function(t) { - // TODO move timestamp to a plugin - var insert = function (obj) { - val.unshift(JSON.stringify(obj)) - t.executeSql(ins, val, win, fail) - } - // TODO move timestamp to a plugin - var update = function (obj) { - delete(obj.key) - val.unshift(JSON.stringify(obj)) - t.executeSql(up, val, win, fail) - } - // pretty - exists ? update(obj) : insert(obj) - }) - }); - return this - }, - - // FIXME this should be a batch insert / just getting the test to pass... - batch: function (objs, cb) { - - var results = [] - , done = false - , that = this - - var updateProgress = function(obj) { - results.push(obj) - done = results.length === objs.length - } - - var checkProgress = setInterval(function() { - if (done) { - if (cb) that.lambda(cb).call(that, results) - clearInterval(checkProgress) - } - }, 200) - - for (var i = 0, l = objs.length; i < l; i++) - this.save(objs[i], updateProgress) - - return this - }, - - get: function (keyOrArray, cb) { - var that = this - , sql = '' - // batch selects support - if (this.isArray(keyOrArray)) { - sql = 'SELECT id, value FROM ' + this.name + " WHERE id IN ('" + keyOrArray.join("','") + "')" - } else { - sql = 'SELECT id, value FROM ' + this.name + " WHERE id = '" + keyOrArray + "'" - } - // FIXME - // will always loop the results but cleans it up if not a batch return at the end.. - // in other words, this could be faster - var win = function (xxx, results) { - var o = null - , r = [] - if (results.rows.length) { - for (var i = 0, l = results.rows.length; i < l; i++) { - o = JSON.parse(results.rows.item(i).value) - o.key = results.rows.item(i).id - r.push(o) - } - } - if (!that.isArray(keyOrArray)) r = r.length ? r[0] : null - if (cb) that.lambda(cb).call(that, r) - } - this.db.transaction(function(t){ t.executeSql(sql, [], win, fail) }) - return this - }, - - exists: function (key, cb) { - var is = "SELECT * FROM " + this.name + " WHERE id = ?" - , that = this - , win = function(xxx, results) { if (cb) that.fn('exists', cb).call(that, (results.rows.length > 0)) } - this.db.transaction(function(t){ t.executeSql(is, [key], win, fail) }) - return this - }, - - all: function (callback) { - var that = this - , all = "SELECT * FROM " + this.name - , r = [] - , cb = this.fn(this.name, callback) || undefined - , win = function (xxx, results) { - if (results.rows.length != 0) { - for (var i = 0, l = results.rows.length; i < l; i++) { - var obj = JSON.parse(results.rows.item(i).value) - obj.key = results.rows.item(i).id - r.push(obj) - } - } - if (cb) cb.call(that, r) - } - - this.db.transaction(function (t) { - t.executeSql(all, [], win, fail) - }) - return this - }, - - remove: function (keyOrObj, cb) { - var that = this - , key = typeof keyOrObj === 'string' ? keyOrObj : (Array.isArray(keyOrObj) ? null : keyOrObj.key) - , del = "DELETE FROM " + this.name + (Array.isArray(keyOrObj) ? " WHERE id IN ('" + keyOrObj.join("','") + "')" : " WHERE id = ?") - , win = function () { if (cb) that.lambda(cb).call(that) } - - this.db.transaction(function (t) { - if (key == null) - t.executeSql(del, [], win, fail); - else - t.executeSql(del, [key], win, fail); - }); - - return this; - }, - - nuke: function (cb) { - var nuke = "DELETE FROM " + this.name - , that = this - , win = cb ? function() { that.lambda(cb).call(that) } : function(){} - this.db.transaction(function (t) { - t.executeSql(nuke, [], win, fail) - }) - return this - } -////// -}})()) diff --git a/Lawnchair-adapter/test-www/Lawnchair-sqlitePlugin.js b/Lawnchair-adapter/test-www/Lawnchair-sqlitePlugin.js deleted file mode 100644 index e4ca0d580..000000000 --- a/Lawnchair-adapter/test-www/Lawnchair-sqlitePlugin.js +++ /dev/null @@ -1,198 +0,0 @@ -Lawnchair.adapter('webkit-sqlite', (function () { - // private methods - var fail = function (e, i) { console.log('error in sqlite adaptor!', e, i) } - , now = function () { return new Date() } // FIXME need to use better date fn - // not entirely sure if this is needed... - if (!Function.prototype.bind) { - Function.prototype.bind = function( obj ) { - var slice = [].slice - , args = slice.call(arguments, 1) - , self = this - , nop = function () {} - , bound = function () { - return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments))) - } - nop.prototype = self.prototype - bound.prototype = new nop() - return bound - } - } - - // public methods - return { - - valid: function() { return !!(sqlitePlugin.openDatabase) }, - - init: function (options, callback) { - var that = this - , cb = that.fn(that.name, callback) - , dbname = options.db || this.name - , bgType = options.bgType || 1 - , create = "CREATE TABLE IF NOT EXISTS " + this.name + " (id NVARCHAR(32) UNIQUE PRIMARY KEY, value TEXT, timestamp REAL)" - , win = function(){ return cb.call(that, that); } - // open a connection and create the db if it doesn't exist - this.db = sqlitePlugin.openDatabase({name:dbname,bgType:bgType}) - this.db.transaction(function (t) { - t.executeSql(create, [], win, fail) - }) - }, - - keys: function (callback) { - var cb = this.lambda(callback) - , that = this - , keys = "SELECT id FROM " + this.name + " ORDER BY timestamp DESC" - - this.db.transaction(function(t) { - var win = function (xxx, results) { - if (results.rows.length == 0 ) { - cb.call(that, []) - } else { - var r = []; - for (var i = 0, l = results.rows.length; i < l; i++) { - r.push(results.rows.item(i).id); - } - cb.call(that, r) - } - } - t.executeSql(keys, [], win, fail) - }) - return this - }, - // you think thats air you're breathing now? - save: function (obj, callback) { - var that = this - , id = obj.key || that.uuid() - , ins = "INSERT INTO " + this.name + " (value, timestamp, id) VALUES (?,?,?)" - , up = "UPDATE " + this.name + " SET value=?, timestamp=? WHERE id=?" - , win = function () { if (callback) { obj.key = id; that.lambda(callback).call(that, obj) }} - , val = [now(), id] - // existential - that.exists(obj.key, function(exists) { - // transactions are like condoms - that.db.transaction(function(t) { - // TODO move timestamp to a plugin - var insert = function (obj) { - val.unshift(JSON.stringify(obj)) - t.executeSql(ins, val, win, fail) - } - // TODO move timestamp to a plugin - var update = function (obj) { - delete(obj.key) - val.unshift(JSON.stringify(obj)) - t.executeSql(up, val, win, fail) - } - // pretty - exists ? update(obj) : insert(obj) - }) - }); - return this - }, - - // FIXME this should be a batch insert / just getting the test to pass... - batch: function (objs, cb) { - - var results = [] - , done = false - , that = this - - var updateProgress = function(obj) { - results.push(obj) - done = results.length === objs.length - } - - var checkProgress = setInterval(function() { - if (done) { - if (cb) that.lambda(cb).call(that, results) - clearInterval(checkProgress) - } - }, 200) - - for (var i = 0, l = objs.length; i < l; i++) - this.save(objs[i], updateProgress) - - return this - }, - - get: function (keyOrArray, cb) { - var that = this - , sql = '' - // batch selects support - if (this.isArray(keyOrArray)) { - sql = 'SELECT id, value FROM ' + this.name + " WHERE id IN ('" + keyOrArray.join("','") + "')" - } else { - sql = 'SELECT id, value FROM ' + this.name + " WHERE id = '" + keyOrArray + "'" - } - // FIXME - // will always loop the results but cleans it up if not a batch return at the end.. - // in other words, this could be faster - var win = function (xxx, results) { - var o = null - , r = [] - if (results.rows.length) { - for (var i = 0, l = results.rows.length; i < l; i++) { - o = JSON.parse(results.rows.item(i).value) - o.key = results.rows.item(i).id - r.push(o) - } - } - if (!that.isArray(keyOrArray)) r = r.length ? r[0] : null - if (cb) that.lambda(cb).call(that, r) - } - this.db.transaction(function(t){ t.executeSql(sql, [], win, fail) }) - return this - }, - - exists: function (key, cb) { - var is = "SELECT * FROM " + this.name + " WHERE id = ?" - , that = this - , win = function(xxx, results) { if (cb) that.fn('exists', cb).call(that, (results.rows.length > 0)) } - this.db.transaction(function(t){ t.executeSql(is, [key], win, fail) }) - return this - }, - - all: function (callback) { - var that = this - , all = "SELECT * FROM " + this.name - , r = [] - , cb = this.fn(this.name, callback) || undefined - , win = function (xxx, results) { - if (results.rows.length != 0) { - for (var i = 0, l = results.rows.length; i < l; i++) { - var obj = JSON.parse(results.rows.item(i).value) - obj.key = results.rows.item(i).id - r.push(obj) - } - } - if (cb) cb.call(that, r) - } - - this.db.transaction(function (t) { - t.executeSql(all, [], win, fail) - }) - return this - }, - - remove: function (keyOrObj, cb) { - var that = this - , key = typeof keyOrObj === 'string' ? keyOrObj : keyOrObj.key - , del = "DELETE FROM " + this.name + " WHERE id = ?" - , win = function () { if (cb) that.lambda(cb).call(that) } - - this.db.transaction( function (t) { - t.executeSql(del, [key], win, fail); - }); - - return this; - }, - - nuke: function (cb) { - var nuke = "DELETE FROM " + this.name - , that = this - , win = cb ? function() { that.lambda(cb).call(that) } : function(){} - this.db.transaction(function (t) { - t.executeSql(nuke, [], win, fail) - }) - return this - } -////// -}})()) diff --git a/Lawnchair-adapter/test-www/index.html b/Lawnchair-adapter/test-www/index.html deleted file mode 100644 index f07373d16..000000000 --- a/Lawnchair-adapter/test-www/index.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - Lawnchair Spec - - - - - - - - - - - - - - - - - - - -

Lawnchair Spec

-

-

-
    - - diff --git a/Lawnchair-adapter/test-www/lawnchair-spec.js b/Lawnchair-adapter/test-www/lawnchair-spec.js deleted file mode 100755 index 7b373ac36..000000000 --- a/Lawnchair-adapter/test-www/lawnchair-spec.js +++ /dev/null @@ -1,431 +0,0 @@ -module('Lawnchair construction/destruction', { - setup:function() { - }, - teardown:function() { - } -}); - -test('ctor requires callbacks in each form', function() { - QUnit.stop(); - QUnit.expect(6); - - // raise exception if no ctor callback is supplied - try { - var lc2 = new Lawnchair(); - } catch(e) { - ok(true, 'exception raised if no callback supplied to init'); - } - try { - var lc3 = new Lawnchair({}, {}); - } catch(e) { - ok(true, 'exception raised if no callback supplied to init, but two args are present'); - } - try { - var lc3 = new Lawnchair({}); - } catch(e) { - ok(true, 'exception raised if no callback supplied to init, but one arg is present'); - } - - var lc = new Lawnchair({name:store.name}, function(ref) { - ok(true, 'should call passed in callback when using obj+function ctor form') - equals(this, ref, "lawnchair callback scoped to lawnchair instance") - equals(ref, this, "lawnchair passes self into callback too") - QUnit.start() - }); -}); - -/** NOTE: may cause a failure due to difference in SQLitePlugin database initialization. -test('independent data stores', function() { - - var store1 = new Lawnchair({name: "store1"}, function() {}); - - store1 .save({key: 'apple', quantity: 3}, function() { - - var store2 = new Lawnchair({name: "store2"}, function() {}); - - store1.all(function(r) { - equals(r.length, 1); - }); - - store2.all(function(r) { - equals(r.length, 0); - }); - - }) - - -}) -**/ - -module('all()', { - setup:function() { - QUnit.stop(); - - // I like to make all my variables globals. Starting a new trend. - me = {name:'brian', age:30}; - store.nuke(function() { QUnit.start(); }); - }, - teardown:function() { - me = null; - } -}) - -test('chainable', function() { - QUnit.stop(); - QUnit.expect(1); - - same(store.all(function(r) { QUnit.start(); }), store, 'should be chainable (return itself)'); -}) - -test('full callback syntax', function() { - QUnit.stop(); - QUnit.expect(4); - - store.all(function(r) { - ok(true, 'calls callback'); - ok(r instanceof Array, 'should provide array as parameter'); - equals(r.length, 0, 'parameter should initially have zero length'); - same(this, store, '"this" should be scoped to the lawnchair object inside callback'); - QUnit.start(); - }); -}) - -test('adding, nuking and size tests', function() { - QUnit.stop(); - QUnit.expect(2); - - store.save(me, function() { - store.all(function(r) { - equals(r.length, 1, 'parameter should have length 1 after saving a single record'); - store.nuke(function() { - store.all(function(r) { - equals(r.length, 0, 'parameter should have length 0 after nuking'); - QUnit.start(); - }); - }); - }); - }); -}) - -test( 'shorthand callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.all('ok(true, "shorthand syntax callback gets evaled"); same(this, store, "`this` should be scoped to the Lawnchair instance"); QUnit.start();'); - - // Is this test block necessary? - // - // var tmp = new Lawnchair({name:'temps', record:'tmp'}, function(){ - // QUnit.start() - // var Temps = this; - // equals(this, Temps, 'this is bound to Lawnchair') - // QUnit.stop() - // Temps.all('ok(temps, "this.name is passed to all callback"); QUnit.start()') - // }) -}) - -/** TBD issue with Android: -test('scoped variable in shorthand callback', function() { - QUnit.expect(1); - QUnit.stop(); - - // FIXME fkn qunit being weird here... expect(1) - var tmp = new Lawnchair({name:'temps', record:'tmp'}, function() { - this.nuke(function() { - this.save({a:1}, function() { - this.each('ok(tmp, "this.record is passed to each callback"); QUnit.start()') - }) - }) - }) -}) -**/ - -module('nuke()', { - setup:function() { - QUnit.stop(); - store.nuke(function() { - QUnit.start() - }); - }, - teardown:function() { - } -}) - -test( 'chainable', function() { - QUnit.expect(1); - QUnit.stop() - - same(store.nuke(function() { QUnit.start() }), store, 'should be chainable'); -}) - -test( 'full callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.nuke(function() { - ok(true, "should call callback in nuke"); - same(this, store, '"this" should be scoped to the Lawnchair instance'); - QUnit.start(); - }); -}) - -test( 'shorthand callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.nuke('ok(true, "shorthand syntax callback gets evaled"); same(this, store, "`this` should be scoped to the Lawnchair instance"); QUnit.start();'); -}) - -module('save()', { - setup:function() { - QUnit.stop(); - - // I like to make all my variables globals. Starting a new trend. - me = {name:'brian', age:30}; - store.nuke(function() { QUnit.start(); }); - }, - teardown:function() { - me = null; - } -}) - -test( 'chainable', function() { - QUnit.stop(); - QUnit.expect(1); - - same(store.save(me, function() { QUnit.start(); }), store, 'should be chainable'); -}) - -test( 'full callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.save(me, function(it) { - ok(true, 'should call passed in callback'); - same(it, me, 'should pass in original saved object in callback'); - QUnit.start(); - }); -}) - -test( 'shorthand callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.save(me, 'ok(true, "shorthand syntax callback gets evaled"); same(this, store, "`this` should be scoped to the Lawnchair instance"); QUnit.start();'); -}) - -test( 'saving objects', function() { - QUnit.stop(); - QUnit.expect(1); - - store.save(me, function() { - store.save({key:"something", value:"else"}, function(r) { - store.all(function(r) { - equals(r.length, 2, 'after saving two keys, num. records should equal to 2'); - QUnit.start(); - }); - }); - }) -}) - -test( 'save without callback', function() { - - QUnit.stop(); - QUnit.expect(1); - - store.save(me, function(obj) { - var key = obj.key; - store.save(obj); - equals(obj.key, key, "save without callback retains key"); - QUnit.start(); - }) - -}); - -module('batch()', { - setup:function() { - QUnit.stop(); - - // I like to make all my variables globals. Starting a new trend. - me = {name:'brian', age:30}; - store.nuke(function() { QUnit.start(); }); - }, - teardown:function() { - me = null; - } -}) - -test('batch insertion', function(){ - QUnit.expect(3); - QUnit.stop(); - - ok(store.batch, 'batch implemented'); - equals(store.batch([]), store, 'chainable') - - store.batch([{i:1},{i:2}], function() { - store.all(function(r){ - equals(r.length, 2, 'should be two records from batch insert with array of two objects'); - QUnit.start(); - }); - }); -}) - -test( 'full callback syntax', function() { - QUnit.stop(1500); // timing changed by batch processing improvements - QUnit.expect(2); - - store.batch([{j:'k'}], function() { - ok(true, 'callback called with full syntax'); - same(this, store, '"this" should be the LAwnchair instance'); - QUnit.start(); - }) -}) - -test( 'shorthand callback syntax', function() { - QUnit.stop(1500); // timing changed by batch processing improvements - QUnit.expect(2); - - store.batch([{o:'k'}], 'ok(true, "shorthand syntax callback gets evaled"); same(this, store, "`this` should be scoped to the Lawnchair instance"); QUnit.start();') -}) - -module('get()', { - setup:function() { - QUnit.stop(); - - // I like to make all my variables globals. Starting a new trend. - me = {name:'brian', age:30}; - store.nuke(function() { QUnit.start(); }); - }, - teardown:function() { - me = null; - } -}); - -test( 'should it be chainable?', function() { - QUnit.expect(1); - QUnit.stop(); - - equals(store.get('foo', function() { QUnit.start(); }), store, 'get chainable'); -}); - -test('get functionality', function() { - QUnit.expect(4); - QUnit.stop(); - - store.save({key:'xyz', name:'tim'}, function() { - store.get('xyz', function(r) { - equals(r.key, 'xyz', 'should return key in loaded object'); - equals(r.name, 'tim', 'should return proper object when calling get with a key'); - store.get('doesntexist', function(s) { - ok(true, 'should call callback even for non-existent key'); - equals(s, null, 'should return null for non-existent key'); - QUnit.start(); - }); - }); - }); -}); - -test('get batch functionality', function() { - QUnit.expect(3); - QUnit.stop(1500); // timing changed by batch processing improvements - - var t = [{key:'test-get'},{key:'test-get-1'}] - store.batch(t, function() { - this.get(['test-get','test-get-1'], function(r) { - equals(r[0].key, 'test-get', "get first object"); - equals(r[1].key, 'test-get-1', "get second object"); - equals(r.length, t.length, "should batch get") - QUnit.start() - }) - }) -}); - -test( 'full callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.get('somekey', function(r){ - ok(true, 'callback got called'); - same(this, store, '"this" should be teh Lawnchair instance'); - QUnit.start(); - }); -}); - -test('short callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.get('somekey', 'ok(true, "shorthand syntax callback gets evaled"); same(this, store, "`this` should be scoped to the Lawnchair instance"); QUnit.start();'); -}); - -module('remove()', { - setup:function() { - QUnit.stop(); - - // I like to make all my variables globals. Starting a new trend. - me = {name:'brian', age:30}; - store.nuke(function() { QUnit.start(); }); - }, - teardown:function() { - me = null; - } -}); - - -test( 'chainable', function() { - QUnit.expect(1); - QUnit.stop(); - - store.save({key:'me', name:'brian'}, function() { - same(store.remove('me', function() { - QUnit.start(); - }), store, 'should be chainable'); - - }); -}); - -test( 'full callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.save({key:'somekey', name:'something'}, function() { - store.remove('somekey', function(r){ - ok(true, 'callback got called'); - same(this, store, '"this" should be teh Lawnchair instance'); - QUnit.start(); - }); - }); -}); - -test('short callback syntax', function() { - QUnit.stop(); - QUnit.expect(2); - - store.save({key:'somekey', name:'something'}, function() { - store.remove('somekey', 'ok(true, "shorthand syntax callback gets evaled"); same(this, store, "`this` should be scoped to the Lawnchair instance"); QUnit.start();'); - }); -}); - -// FIXME need to add tests for batch deletion -test( 'remove functionality', function() { - QUnit.stop(); - QUnit.expect(2); - - store.save({name:'joni'}, function(r) { - //store.find("r.name == 'joni'", function(r){ - store.remove(r, function(r) { - store.all(function(all) { - equals(all.length, 0, "should have length 0 after saving, finding, and removing a record using entire object"); - store.save({key:'die', name:'dudeman'}, function(r) { - store.remove('die', function(r){ - store.all(function(rec) { - equals(rec.length, 0, "should have length 0 after saving and removing by string key"); - QUnit.start(); - }); - }); - }); - }); - }); - //}); - }); -}); diff --git a/Lawnchair-adapter/test-www/lib/json2.js b/Lawnchair-adapter/test-www/lib/json2.js deleted file mode 100644 index a1a3b170c..000000000 --- a/Lawnchair-adapter/test-www/lib/json2.js +++ /dev/null @@ -1,482 +0,0 @@ -/* - http://www.JSON.org/json2.js - 2010-03-20 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. - - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ - -/*jslint evil: true, strict: false */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (!this.JSON) { - this.JSON = {}; -} - -(function () { - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function (key) { - - return isFinite(this.valueOf()) ? - this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } - - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? - '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : - '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 ? '[]' : - gap ? '[\n' + gap + - partial.join(',\n' + gap) + '\n' + - mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - k = rep[i]; - if (typeof k === 'string') { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 ? '{}' : - gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + - mind + '}' : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/. -test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). -replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). -replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' ? - walk({'': j}, '') : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); diff --git a/Lawnchair-adapter/test-www/lib/lawnchair.js b/Lawnchair-adapter/test-www/lib/lawnchair.js deleted file mode 100644 index 3f67835af..000000000 --- a/Lawnchair-adapter/test-www/lib/lawnchair.js +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Lawnchair! - * --- - * clientside json store - * - */ -var Lawnchair = function (options, callback) { - // ensure Lawnchair was called as a constructor - if (!(this instanceof Lawnchair)) return new Lawnchair(options, callback); - - // lawnchair requires json - if (!JSON) throw 'JSON unavailable! Include http://www.json.org/json2.js to fix.' - // options are optional; callback is not - if (arguments.length <= 2 && arguments.length > 0) { - callback = (typeof arguments[0] === 'function') ? arguments[0] : arguments[1]; - options = (typeof arguments[0] === 'function') ? {} : arguments[0]; - } else { - throw 'Incorrect # of ctor args!' - } - // TODO perhaps allow for pub/sub instead? - if (typeof callback !== 'function') throw 'No callback was provided'; - - // default configuration - this.record = options.record || 'record' // default for records - this.name = options.name || 'records' // default name for underlying store - - // mixin first valid adapter - var adapter - // if the adapter is passed in we try to load that only - if (options.adapter) { - for (var i = 0, l = Lawnchair.adapters.length; i < l; i++) { - if (Lawnchair.adapters[i].adapter === options.adapter) { - adapter = Lawnchair.adapters[i].valid() ? Lawnchair.adapters[i] : undefined; - break; - } - } - // otherwise find the first valid adapter for this env - } - else { - for (var i = 0, l = Lawnchair.adapters.length; i < l; i++) { - adapter = Lawnchair.adapters[i].valid() ? Lawnchair.adapters[i] : undefined - if (adapter) break - } - } - - // we have failed - if (!adapter) throw 'No valid adapter.' - - // yay! mixin the adapter - for (var j in adapter) - this[j] = adapter[j] - - // call init for each mixed in plugin - for (var i = 0, l = Lawnchair.plugins.length; i < l; i++) - Lawnchair.plugins[i].call(this) - - // init the adapter - this.init(options, callback) -} - -Lawnchair.adapters = [] - -/** - * queues an adapter for mixin - * === - * - ensures an adapter conforms to a specific interface - * - */ -Lawnchair.adapter = function (id, obj) { - // add the adapter id to the adapter obj - // ugly here for a cleaner dsl for implementing adapters - obj['adapter'] = id - // methods required to implement a lawnchair adapter - var implementing = 'adapter valid init keys save batch get exists all remove nuke'.split(' ') - , indexOf = this.prototype.indexOf - // mix in the adapter - for (var i in obj) { - if (indexOf(implementing, i) === -1) throw 'Invalid adapter! Nonstandard method: ' + i - } - // if we made it this far the adapter interface is valid - // insert the new adapter as the preferred adapter - Lawnchair.adapters.splice(0,0,obj) -} - -Lawnchair.plugins = [] - -/** - * generic shallow extension for plugins - * === - * - if an init method is found it registers it to be called when the lawnchair is inited - * - yes we could use hasOwnProp but nobody here is an asshole - */ -Lawnchair.plugin = function (obj) { - for (var i in obj) - i === 'init' ? Lawnchair.plugins.push(obj[i]) : this.prototype[i] = obj[i] -} - -/** - * helpers - * - */ -Lawnchair.prototype = { - - isArray: Array.isArray || function(o) { return Object.prototype.toString.call(o) === '[object Array]' }, - - /** - * this code exists for ie8... for more background see: - * http://www.flickr.com/photos/westcoastlogic/5955365742/in/photostream - */ - indexOf: function(ary, item, i, l) { - if (ary.indexOf) return ary.indexOf(item) - for (i = 0, l = ary.length; i < l; i++) if (ary[i] === item) return i - return -1 - }, - - // awesome shorthand callbacks as strings. this is shameless theft from dojo. - lambda: function (callback) { - return this.fn(this.record, callback) - }, - - // first stab at named parameters for terse callbacks; dojo: first != best // ;D - fn: function (name, callback) { - return typeof callback == 'string' ? new Function(name, callback) : callback - }, - - // returns a unique identifier (by way of Backbone.localStorage.js) - // TODO investigate smaller UUIDs to cut on storage cost - uuid: function () { - var S4 = function () { - return (((1+Math.random())*0x10000)|0).toString(16).substring(1); - } - return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); - }, - - // a classic iterator - each: function (callback) { - var cb = this.lambda(callback) - // iterate from chain - if (this.__results) { - for (var i = 0, l = this.__results.length; i < l; i++) cb.call(this, this.__results[i], i) - } - // otherwise iterate the entire collection - else { - this.all(function(r) { - for (var i = 0, l = r.length; i < l; i++) cb.call(this, r[i], i) - }) - } - return this - } -// -- -}; diff --git a/Lawnchair-adapter/test-www/lib/qunit.css b/Lawnchair-adapter/test-www/lib/qunit.css deleted file mode 100644 index b3c6db523..000000000 --- a/Lawnchair-adapter/test-www/lib/qunit.css +++ /dev/null @@ -1,225 +0,0 @@ -/** - * QUnit - A JavaScript Unit Testing Framework - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2011 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. - */ - -/** Font Family and Sizes */ - -#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; -} - -#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } -#qunit-tests { font-size: smaller; } - - -/** Resets */ - -#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { - margin: 0; - padding: 0; -} - - -/** Header */ - -#qunit-header { - padding: 0.5em 0 0.5em 1em; - - color: #8699a4; - background-color: #0d3349; - - font-size: 1.5em; - line-height: 1em; - font-weight: normal; - - border-radius: 15px 15px 0 0; - -moz-border-radius: 15px 15px 0 0; - -webkit-border-top-right-radius: 15px; - -webkit-border-top-left-radius: 15px; -} - -#qunit-header a { - text-decoration: none; - color: #c2ccd1; -} - -#qunit-header a:hover, -#qunit-header a:focus { - color: #fff; -} - -#qunit-banner { - height: 5px; -} - -#qunit-testrunner-toolbar { - padding: 0.5em 0 0.5em 2em; - color: #5E740B; - background-color: #eee; -} - -#qunit-userAgent { - padding: 0.5em 0 0.5em 2.5em; - background-color: #2b81af; - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; -} - - -/** Tests: Pass/Fail */ - -#qunit-tests { - list-style-position: inside; -} - -#qunit-tests li { - padding: 0.4em 0.5em 0.4em 2.5em; - border-bottom: 1px solid #fff; - list-style-position: inside; -} - -#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { - display: none; -} - -#qunit-tests li strong { - cursor: pointer; -} - -#qunit-tests li a { - padding: 0.5em; - color: #c2ccd1; - text-decoration: none; -} -#qunit-tests li a:hover, -#qunit-tests li a:focus { - color: #000; -} - -#qunit-tests ol { - margin-top: 0.5em; - padding: 0.5em; - - background-color: #fff; - - border-radius: 15px; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - - box-shadow: inset 0px 2px 13px #999; - -moz-box-shadow: inset 0px 2px 13px #999; - -webkit-box-shadow: inset 0px 2px 13px #999; -} - -#qunit-tests table { - border-collapse: collapse; - margin-top: .2em; -} - -#qunit-tests th { - text-align: right; - vertical-align: top; - padding: 0 .5em 0 0; -} - -#qunit-tests td { - vertical-align: top; -} - -#qunit-tests pre { - margin: 0; - white-space: pre-wrap; - word-wrap: break-word; -} - -#qunit-tests del { - background-color: #e0f2be; - color: #374e0c; - text-decoration: none; -} - -#qunit-tests ins { - background-color: #ffcaca; - color: #500; - text-decoration: none; -} - -/*** Test Counts */ - -#qunit-tests b.counts { color: black; } -#qunit-tests b.passed { color: #5E740B; } -#qunit-tests b.failed { color: #710909; } - -#qunit-tests li li { - margin: 0.5em; - padding: 0.4em 0.5em 0.4em 0.5em; - background-color: #fff; - border-bottom: none; - list-style-position: inside; -} - -/*** Passing Styles */ - -#qunit-tests li li.pass { - color: #5E740B; - background-color: #fff; - border-left: 26px solid #C6E746; -} - -#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } -#qunit-tests .pass .test-name { color: #366097; } - -#qunit-tests .pass .test-actual, -#qunit-tests .pass .test-expected { color: #999999; } - -#qunit-banner.qunit-pass { background-color: #C6E746; } - -/*** Failing Styles */ - -#qunit-tests li li.fail { - color: #710909; - background-color: #fff; - border-left: 26px solid #EE5757; -} - -#qunit-tests > li:last-child { - border-radius: 0 0 15px 15px; - -moz-border-radius: 0 0 15px 15px; - -webkit-border-bottom-right-radius: 15px; - -webkit-border-bottom-left-radius: 15px; -} - -#qunit-tests .fail { color: #000000; background-color: #EE5757; } -#qunit-tests .fail .test-name, -#qunit-tests .fail .module-name { color: #000000; } - -#qunit-tests .fail .test-actual { color: #EE5757; } -#qunit-tests .fail .test-expected { color: green; } - -#qunit-banner.qunit-fail { background-color: #EE5757; } - - -/** Result */ - -#qunit-testresult { - padding: 0.5em 0.5em 0.5em 2.5em; - - color: #2b81af; - background-color: #D2E0E6; - - border-bottom: 1px solid white; -} - -/** Fixture */ - -#qunit-fixture { - position: absolute; - top: -10000px; - left: -10000px; -} diff --git a/Lawnchair-adapter/test-www/lib/qunit.js b/Lawnchair-adapter/test-www/lib/qunit.js deleted file mode 100644 index 3d640c73c..000000000 --- a/Lawnchair-adapter/test-www/lib/qunit.js +++ /dev/null @@ -1,1448 +0,0 @@ -/** - * QUnit - A JavaScript Unit Testing Framework - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2011 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. - */ - -(function(window) { - -var defined = { - setTimeout: typeof window.setTimeout !== "undefined", - sessionStorage: (function() { - try { - return !!sessionStorage.getItem; - } catch(e){ - return false; - } - })() -}; - -var testId = 0; - -var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { - this.name = name; - this.testName = testName; - this.expected = expected; - this.testEnvironmentArg = testEnvironmentArg; - this.async = async; - this.callback = callback; - this.assertions = []; -}; -Test.prototype = { - init: function() { - var tests = id("qunit-tests"); - if (tests) { - var b = document.createElement("strong"); - b.innerHTML = "Running " + this.name; - var li = document.createElement("li"); - li.appendChild( b ); - li.className = "running"; - li.id = this.id = "test-output" + testId++; - tests.appendChild( li ); - } - }, - setup: function() { - if (this.module != config.previousModule) { - if ( config.previousModule ) { - QUnit.moduleDone( { - name: config.previousModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - } ); - } - config.previousModule = this.module; - config.moduleStats = { all: 0, bad: 0 }; - QUnit.moduleStart( { - name: this.module - } ); - } - - config.current = this; - this.testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, this.moduleTestEnvironment); - if (this.testEnvironmentArg) { - extend(this.testEnvironment, this.testEnvironmentArg); - } - - QUnit.testStart( { - name: this.testName - } ); - - // allow utility functions to access the current test environment - // TODO why?? - QUnit.current_testEnvironment = this.testEnvironment; - - try { - if ( !config.pollution ) { - saveGlobal(); - } - - this.testEnvironment.setup.call(this.testEnvironment); - } catch(e) { - QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); - } - }, - run: function() { - if ( this.async ) { - QUnit.stop(); - } - - if ( config.notrycatch ) { - this.callback.call(this.testEnvironment); - return; - } - try { - this.callback.call(this.testEnvironment); - } catch(e) { - fail("Test " + this.testName + " died, exception and test follows", e, this.callback); - QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - start(); - } - } - }, - teardown: function() { - try { - this.testEnvironment.teardown.call(this.testEnvironment); - checkPollution(); - } catch(e) { - QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); - } - }, - finish: function() { - if ( this.expected && this.expected != this.assertions.length ) { - QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); - } - - var good = 0, bad = 0, - tests = id("qunit-tests"); - - config.stats.all += this.assertions.length; - config.moduleStats.all += this.assertions.length; - - if ( tests ) { - var ol = document.createElement("ol"); - - for ( var i = 0; i < this.assertions.length; i++ ) { - var assertion = this.assertions[i]; - - var li = document.createElement("li"); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - - // store result when possible - if ( QUnit.config.reorder && defined.sessionStorage ) { - if (bad) { - sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); - } else { - sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); - } - } - - if (bad == 0) { - ol.style.display = "none"; - } - - var b = document.createElement("strong"); - b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - - var a = document.createElement("a"); - a.innerHTML = "Rerun"; - a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); - - addEvent(b, "click", function() { - var next = b.nextSibling.nextSibling, - display = next.style.display; - next.style.display = display === "none" ? "block" : "none"; - }); - - addEvent(b, "dblclick", function(e) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); - } - }); - - var li = id(this.id); - li.className = bad ? "fail" : "pass"; - li.removeChild( li.firstChild ); - li.appendChild( b ); - li.appendChild( a ); - li.appendChild( ol ); - - } else { - for ( var i = 0; i < this.assertions.length; i++ ) { - if ( !this.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - try { - QUnit.reset(); - } catch(e) { - fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); - } - - QUnit.testDone( { - name: this.testName, - failed: bad, - passed: this.assertions.length - bad, - total: this.assertions.length - } ); - }, - - queue: function() { - var test = this; - synchronize(function() { - test.init(); - }); - function run() { - // each of these can by async - synchronize(function() { - test.setup(); - }); - synchronize(function() { - test.run(); - }); - synchronize(function() { - test.teardown(); - }); - synchronize(function() { - test.finish(); - }); - } - // defer when previous test run passed, if storage is available - var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); - if (bad) { - run(); - } else { - synchronize(run); - }; - } - -}; - -var QUnit = { - - // call on start of module test to prepend name to all tests - module: function(name, testEnvironment) { - config.currentModule = name; - config.currentModuleTestEnviroment = testEnvironment; - }, - - asyncTest: function(testName, expected, callback) { - if ( arguments.length === 2 ) { - callback = expected; - expected = 0; - } - - QUnit.test(testName, expected, callback, true); - }, - - test: function(testName, expected, callback, async) { - var name = '' + testName + '', testEnvironmentArg; - - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - // is 2nd argument a testEnvironment? - if ( expected && typeof expected === 'object') { - testEnvironmentArg = expected; - expected = null; - } - - if ( config.currentModule ) { - name = '' + config.currentModule + ": " + name; - } - - if ( !validTest(config.currentModule + ": " + testName) ) { - return; - } - - var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); - test.module = config.currentModule; - test.moduleTestEnvironment = config.currentModuleTestEnviroment; - test.queue(); - }, - - /** - * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. - */ - expect: function(asserts) { - config.current.expected = asserts; - }, - - /** - * Asserts true. - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ - ok: function(a, msg) { - a = !!a; - var details = { - result: a, - message: msg - }; - msg = escapeHtml(msg); - QUnit.log(details); - config.current.assertions.push({ - result: a, - message: msg - }); - }, - - /** - * Checks that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * - * Prefered to ok( actual == expected, message ) - * - * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); - * - * @param Object actual - * @param Object expected - * @param String message (optional) - */ - equal: function(actual, expected, message) { - QUnit.push(expected == actual, actual, expected, message); - }, - - notEqual: function(actual, expected, message) { - QUnit.push(expected != actual, actual, expected, message); - }, - - deepEqual: function(actual, expected, message) { - QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); - }, - - notDeepEqual: function(actual, expected, message) { - QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); - }, - - strictEqual: function(actual, expected, message) { - QUnit.push(expected === actual, actual, expected, message); - }, - - notStrictEqual: function(actual, expected, message) { - QUnit.push(expected !== actual, actual, expected, message); - }, - - raises: function(block, expected, message) { - var actual, ok = false; - - if (typeof expected === 'string') { - message = expected; - expected = null; - } - - try { - block(); - } catch (e) { - actual = e; - } - - if (actual) { - // we don't want to validate thrown error - if (!expected) { - ok = true; - // expected is a regexp - } else if (QUnit.objectType(expected) === "regexp") { - ok = expected.test(actual); - // expected is a constructor - } else if (actual instanceof expected) { - ok = true; - // expected is a validation function which returns true is validation passed - } else if (expected.call({}, actual) === true) { - ok = true; - } - } - - QUnit.ok(ok, message); - }, - - start: function() { - config.semaphore--; - if (config.semaphore > 0) { - // don't start until equal number of stop-calls - return; - } - if (config.semaphore < 0) { - // ignore if start is called more often then stop - config.semaphore = 0; - } - // A slight delay, to avoid any current callbacks - if ( defined.setTimeout ) { - window.setTimeout(function() { - if ( config.timeout ) { - clearTimeout(config.timeout); - } - - config.blocking = false; - process(); - }, 13); - } else { - config.blocking = false; - process(); - } - }, - - stop: function(timeout) { - config.semaphore++; - config.blocking = true; - - if ( timeout && defined.setTimeout ) { - clearTimeout(config.timeout); - config.timeout = window.setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - QUnit.start(); - }, timeout); - } - } -}; - -// Backwards compatibility, deprecated -QUnit.equals = QUnit.equal; -QUnit.same = QUnit.deepEqual; - -// Maintain internal state -var config = { - // The queue of tests to run - queue: [], - - // block until document ready - blocking: true, - - // by default, run previously failed tests first - // very useful in combination with "Hide passed tests" checked - reorder: true, - - noglobals: false, - notrycatch: false -}; - -// Load paramaters -(function() { - var location = window.location || { search: "", protocol: "file:" }, - params = location.search.slice( 1 ).split( "&" ), - length = params.length, - urlParams = {}, - current; - - if ( params[ 0 ] ) { - for ( var i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - urlParams[ current[ 0 ] ] = current[ 1 ]; - if ( current[ 0 ] in config ) { - config[ current[ 0 ] ] = current[ 1 ]; - } - } - } - - QUnit.urlParams = urlParams; - config.filter = urlParams.filter; - - // Figure out if we're running the tests from a server or not - QUnit.isLocal = !!(location.protocol === 'file:'); -})(); - -// Expose the API as global variables, unless an 'exports' -// object exists, in that case we assume we're in CommonJS -if ( typeof exports === "undefined" || typeof require === "undefined" ) { - extend(window, QUnit); - window.QUnit = QUnit; -} else { - extend(exports, QUnit); - exports.QUnit = QUnit; -} - -// define these after exposing globals to keep them in these QUnit namespace only -extend(QUnit, { - config: config, - - // Initialize the configuration options - init: function() { - extend(config, { - stats: { all: 0, bad: 0 }, - moduleStats: { all: 0, bad: 0 }, - started: +new Date, - updateRate: 1000, - blocking: false, - autostart: true, - autorun: false, - filter: "", - queue: [], - semaphore: 0 - }); - - var tests = id( "qunit-tests" ), - banner = id( "qunit-banner" ), - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = 'Running...
     '; - } - }, - - /** - * Resets the test setup. Useful for tests that modify the DOM. - * - * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. - */ - reset: function() { - if ( window.jQuery ) { - jQuery( "#qunit-fixture" ).html( config.fixture ); - } else { - var main = id( 'qunit-fixture' ); - if ( main ) { - main.innerHTML = config.fixture; - } - } - }, - - /** - * Trigger an event on an element. - * - * @example triggerEvent( document.body, "click" ); - * - * @param DOMElement elem - * @param String type - */ - triggerEvent: function( elem, type, event ) { - if ( document.createEvent ) { - event = document.createEvent("MouseEvents"); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - elem.dispatchEvent( event ); - - } else if ( elem.fireEvent ) { - elem.fireEvent("on"+type); - } - }, - - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) == type; - }, - - objectType: function( obj ) { - if (typeof obj === "undefined") { - return "undefined"; - - // consider: typeof null === object - } - if (obj === null) { - return "null"; - } - - var type = Object.prototype.toString.call( obj ) - .match(/^\[object\s(.*)\]$/)[1] || ''; - - switch (type) { - case 'Number': - if (isNaN(obj)) { - return "nan"; - } else { - return "number"; - } - case 'String': - case 'Boolean': - case 'Array': - case 'Date': - case 'RegExp': - case 'Function': - return type.toLowerCase(); - } - if (typeof obj === "object") { - return "object"; - } - return undefined; - }, - - push: function(result, actual, expected, message) { - var details = { - result: result, - message: message, - actual: actual, - expected: expected - }; - - message = escapeHtml(message) || (result ? "okay" : "failed"); - message = '' + message + ""; - expected = escapeHtml(QUnit.jsDump.parse(expected)); - actual = escapeHtml(QUnit.jsDump.parse(actual)); - var output = message + ''; - if (actual != expected) { - output += ''; - output += ''; - } - if (!result) { - var source = sourceFromStacktrace(); - if (source) { - details.source = source; - output += ''; - } - } - output += "
    Expected:
    ' + expected + '
    Result:
    ' + actual + '
    Diff:
    ' + QUnit.diff(expected, actual) +'
    Source:
    ' + source +'
    "; - - QUnit.log(details); - - config.current.assertions.push({ - result: !!result, - message: output - }); - }, - - url: function( params ) { - params = extend( extend( {}, QUnit.urlParams ), params ); - var querystring = "?", - key; - for ( key in params ) { - querystring += encodeURIComponent( key ) + "=" + - encodeURIComponent( params[ key ] ) + "&"; - } - return window.location.pathname + querystring.slice( 0, -1 ); - }, - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: function() {}, - // done: { failed, passed, total, runtime } - done: function() {}, - // log: { result, actual, expected, message } - log: function() {}, - // testStart: { name } - testStart: function() {}, - // testDone: { name, failed, passed, total } - testDone: function() {}, - // moduleStart: { name } - moduleStart: function() {}, - // moduleDone: { name, failed, passed, total } - moduleDone: function() {} -}); - -if ( typeof document === "undefined" || document.readyState === "complete" ) { - config.autorun = true; -} - -addEvent(window, "load", function() { - QUnit.begin({}); - - // Initialize the config, saving the execution queue - var oldconfig = extend({}, config); - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - var userAgent = id("qunit-userAgent"); - if ( userAgent ) { - userAgent.innerHTML = navigator.userAgent; - } - var banner = id("qunit-header"); - if ( banner ) { - banner.innerHTML = ' ' + banner.innerHTML + ' ' + - '' + - ''; - addEvent( banner, "change", function( event ) { - var params = {}; - params[ event.target.name ] = event.target.checked ? true : undefined; - window.location = QUnit.url( params ); - }); - } - - var toolbar = id("qunit-testrunner-toolbar"); - if ( toolbar ) { - var filter = document.createElement("input"); - filter.type = "checkbox"; - filter.id = "qunit-filter-pass"; - addEvent( filter, "click", function() { - var ol = document.getElementById("qunit-tests"); - if ( filter.checked ) { - ol.className = ol.className + " hidepass"; - } else { - var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; - ol.className = tmp.replace(/ hidepass /, " "); - } - if ( defined.sessionStorage ) { - if (filter.checked) { - sessionStorage.setItem("qunit-filter-passed-tests", "true"); - } else { - sessionStorage.removeItem("qunit-filter-passed-tests"); - } - } - }); - if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { - filter.checked = true; - var ol = document.getElementById("qunit-tests"); - ol.className = ol.className + " hidepass"; - } - toolbar.appendChild( filter ); - - var label = document.createElement("label"); - label.setAttribute("for", "qunit-filter-pass"); - label.innerHTML = "Hide passed tests"; - toolbar.appendChild( label ); - } - - var main = id('qunit-fixture'); - if ( main ) { - config.fixture = main.innerHTML; - } - - if (config.autostart) { - QUnit.start(); - } -}); - -function done() { - config.autorun = true; - - // Log the last module results - if ( config.currentModule ) { - QUnit.moduleDone( { - name: config.currentModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - } ); - } - - var banner = id("qunit-banner"), - tests = id("qunit-tests"), - runtime = +new Date - config.started, - passed = config.stats.all - config.stats.bad, - html = [ - 'Tests completed in ', - runtime, - ' milliseconds.
    ', - '', - passed, - ' tests of ', - config.stats.all, - ' passed, ', - config.stats.bad, - ' failed.' - ].join(''); - - if ( banner ) { - banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); - } - - if ( tests ) { - id( "qunit-testresult" ).innerHTML = html; - } - - if ( typeof document !== "undefined" && document.title ) { - // show ✖ for good, ✔ for bad suite result in title - // use escape sequences in case file gets loaded with non-utf-8-charset - document.title = (config.stats.bad ? "\u2716" : "\u2714") + " " + document.title; - } - - QUnit.done( { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - } ); -} - -function validTest( name ) { - var filter = config.filter, - run = false; - - if ( !filter ) { - return true; - } - - var not = filter.charAt( 0 ) === "!"; - if ( not ) { - filter = filter.slice( 1 ); - } - - if ( name.indexOf( filter ) !== -1 ) { - return !not; - } - - if ( not ) { - run = true; - } - - return run; -} - -// so far supports only Firefox, Chrome and Opera (buggy) -// could be extended in the future to use something like https://github.com/csnover/TraceKit -function sourceFromStacktrace() { - try { - throw new Error(); - } catch ( e ) { - if (e.stacktrace) { - // Opera - return e.stacktrace.split("\n")[6]; - } else if (e.stack) { - // Firefox, Chrome - return e.stack.split("\n")[4]; - } - } -} - -function escapeHtml(s) { - if (!s) { - return ""; - } - s = s + ""; - return s.replace(/[\&"<>\\]/g, function(s) { - switch(s) { - case "&": return "&"; - case "\\": return "\\\\"; - case '"': return '\"'; - case "<": return "<"; - case ">": return ">"; - default: return s; - } - }); -} - -function synchronize( callback ) { - config.queue.push( callback ); - - if ( config.autorun && !config.blocking ) { - process(); - } -} - -function process() { - var start = (new Date()).getTime(); - - while ( config.queue.length && !config.blocking ) { - if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { - config.queue.shift()(); - } else { - window.setTimeout( process, 13 ); - break; - } - } - if (!config.blocking && !config.queue.length) { - done(); - } -} - -function saveGlobal() { - config.pollution = []; - - if ( config.noglobals ) { - for ( var key in window ) { - config.pollution.push( key ); - } - } -} - -function checkPollution( name ) { - var old = config.pollution; - saveGlobal(); - - var newGlobals = diff( config.pollution, old ); - if ( newGlobals.length > 0 ) { - ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); - } - - var deletedGlobals = diff( old, config.pollution ); - if ( deletedGlobals.length > 0 ) { - ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); - } -} - -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var result = a.slice(); - for ( var i = 0; i < result.length; i++ ) { - for ( var j = 0; j < b.length; j++ ) { - if ( result[i] === b[j] ) { - result.splice(i, 1); - i--; - break; - } - } - } - return result; -} - -function fail(message, exception, callback) { - if ( typeof console !== "undefined" && console.error && console.warn ) { - console.error(message); - console.error(exception); - console.warn(callback.toString()); - - } else if ( window.opera && opera.postError ) { - opera.postError(message, exception, callback.toString); - } -} - -function extend(a, b) { - for ( var prop in b ) { - if ( b[prop] === undefined ) { - delete a[prop]; - } else { - a[prop] = b[prop]; - } - } - - return a; -} - -function addEvent(elem, type, fn) { - if ( elem.addEventListener ) { - elem.addEventListener( type, fn, false ); - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, fn ); - } else { - fn(); - } -} - -function id(name) { - return !!(typeof document !== "undefined" && document && document.getElementById) && - document.getElementById( name ); -} - -// Test for equality any JavaScript type. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv -// Author: Philippe Rathé -QUnit.equiv = function () { - - var innerEquiv; // the real equiv function - var callers = []; // stack to decide between skip/abort functions - var parents = []; // stack to avoiding loops from circular referencing - - // Call the o related callback with the given arguments. - function bindCallbacks(o, callbacks, args) { - var prop = QUnit.objectType(o); - if (prop) { - if (QUnit.objectType(callbacks[prop]) === "function") { - return callbacks[prop].apply(callbacks, args); - } else { - return callbacks[prop]; // or undefined - } - } - } - - var callbacks = function () { - - // for string, boolean, number and null - function useStrictEquality(b, a) { - if (b instanceof a.constructor || a instanceof b.constructor) { - // to catch short annotaion VS 'new' annotation of a declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function (b) { - return isNaN(b); - }, - - "date": function (b, a) { - return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function (b, a) { - return QUnit.objectType(b) === "regexp" && - a.source === b.source && // the regex itself - a.global === b.global && // and its modifers (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function () { - var caller = callers[callers.length - 1]; - return caller !== Object && - typeof caller !== "undefined"; - }, - - "array": function (b, a) { - var i, j, loop; - var len; - - // b could be an object literal here - if ( ! (QUnit.objectType(b) === "array")) { - return false; - } - - len = a.length; - if (len !== b.length) { // safe and faster - return false; - } - - //track reference to avoid circular references - parents.push(a); - for (i = 0; i < len; i++) { - loop = false; - for(j=0;j= 0) { - type = "array"; - } else { - type = typeof obj; - } - return type; - }, - separator:function() { - return this.multiline ? this.HTML ? '
    ' : '\n' : this.HTML ? ' ' : ' '; - }, - indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing - if ( !this.multiline ) - return ''; - var chr = this.indentChar; - if ( this.HTML ) - chr = chr.replace(/\t/g,' ').replace(/ /g,' '); - return Array( this._depth_ + (extra||0) ).join(chr); - }, - up:function( a ) { - this._depth_ += a || 1; - }, - down:function( a ) { - this._depth_ -= a || 1; - }, - setParser:function( name, parser ) { - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote:quote, - literal:literal, - join:join, - // - _depth_: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers:{ - window: '[Window]', - document: '[Document]', - error:'[ERROR]', //when no parser is found, shouldn't happen - unknown: '[Unknown]', - 'null':'null', - 'undefined':'undefined', - 'function':function( fn ) { - var ret = 'function', - name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE - if ( name ) - ret += ' ' + name; - ret += '('; - - ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); - return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); - }, - array: array, - nodelist: array, - arguments: array, - object:function( map ) { - var ret = [ ]; - QUnit.jsDump.up(); - for ( var key in map ) - ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); - QUnit.jsDump.down(); - return join( '{', ret, '}' ); - }, - node:function( node ) { - var open = QUnit.jsDump.HTML ? '<' : '<', - close = QUnit.jsDump.HTML ? '>' : '>'; - - var tag = node.nodeName.toLowerCase(), - ret = open + tag; - - for ( var a in QUnit.jsDump.DOMAttrs ) { - var val = node[QUnit.jsDump.DOMAttrs[a]]; - if ( val ) - ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); - } - return ret + close + open + '/' + tag + close; - }, - functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function - var l = fn.length; - if ( !l ) return ''; - - var args = Array(l); - while ( l-- ) - args[l] = String.fromCharCode(97+l);//97 is 'a' - return ' ' + args.join(', ') + ' '; - }, - key:quote, //object calls it internally, the key part of an item in a map - functionCode:'[code]', //function calls it internally, it's the content of the function - attribute:quote, //node calls it internally, it's an html attribute value - string:quote, - date:quote, - regexp:literal, //regex - number:literal, - 'boolean':literal - }, - DOMAttrs:{//attributes to dump from nodes, name=>realName - id:'id', - name:'name', - 'class':'className' - }, - HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) - indentChar:' ',//indentation unit - multiline:true //if true, items in a collection, are separated by a \n, else just a space. - }; - - return jsDump; -})(); - -// from Sizzle.js -function getText( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -}; - -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - function diff(o, n){ - var ns = new Object(); - var os = new Object(); - - for (var i = 0; i < n.length; i++) { - if (ns[n[i]] == null) - ns[n[i]] = { - rows: new Array(), - o: null - }; - ns[n[i]].rows.push(i); - } - - for (var i = 0; i < o.length; i++) { - if (os[o[i]] == null) - os[o[i]] = { - rows: new Array(), - n: null - }; - os[o[i]].rows.push(i); - } - - for (var i in ns) { - if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { - n[ns[i].rows[0]] = { - text: n[ns[i].rows[0]], - row: os[i].rows[0] - }; - o[os[i].rows[0]] = { - text: o[os[i].rows[0]], - row: ns[i].rows[0] - }; - } - } - - for (var i = 0; i < n.length - 1; i++) { - if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && - n[i + 1] == o[n[i].row + 1]) { - n[i + 1] = { - text: n[i + 1], - row: n[i].row + 1 - }; - o[n[i].row + 1] = { - text: o[n[i].row + 1], - row: i + 1 - }; - } - } - - for (var i = n.length - 1; i > 0; i--) { - if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && - n[i - 1] == o[n[i].row - 1]) { - n[i - 1] = { - text: n[i - 1], - row: n[i].row - 1 - }; - o[n[i].row - 1] = { - text: o[n[i].row - 1], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function(o, n){ - o = o.replace(/\s+$/, ''); - n = n.replace(/\s+$/, ''); - var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); - - var str = ""; - - var oSpace = o.match(/\s+/g); - if (oSpace == null) { - oSpace = [" "]; - } - else { - oSpace.push(" "); - } - var nSpace = n.match(/\s+/g); - if (nSpace == null) { - nSpace = [" "]; - } - else { - nSpace.push(" "); - } - - if (out.n.length == 0) { - for (var i = 0; i < out.o.length; i++) { - str += '' + out.o[i] + oSpace[i] + ""; - } - } - else { - if (out.n[0].text == null) { - for (n = 0; n < out.o.length && out.o[n].text == null; n++) { - str += '' + out.o[n] + oSpace[n] + ""; - } - } - - for (var i = 0; i < out.n.length; i++) { - if (out.n[i].text == null) { - str += '' + out.n[i] + nSpace[i] + ""; - } - else { - var pre = ""; - - for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { - pre += '' + out.o[n] + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; -})(); - -})(this); \ No newline at end of file diff --git a/README.md b/README.md index 93172365e..205fde612 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Use the `location` or `iosDatabaseLocation` option in `sqlitePlugin.openDatabase ## Announcements - [brodybits / cordova-sqlite-test-app](https://github.com/brodybits/cordova-sqlite-test-app) project is a CC0 (public domain) starting point (NOTE that this plugin must be added) and may also be used to reproduce issues with this plugin. -- The Lawnchair adapter is now supported in [litehelpers / cordova-sqlite-lawnchair-adapter](https://github.com/litehelpers/cordova-sqlite-lawnchair-adapter). +- The Lawnchair adapter is now moved to [litehelpers / cordova-sqlite-lawnchair-adapter](https://github.com/litehelpers/cordova-sqlite-lawnchair-adapter). - [litehelpers / cordova-sqlite-ext](https://github.com/litehelpers/cordova-sqlite-ext) now supports SELECT BLOB data in Base64 format on all platforms in addition to REGEXP (Android/iOS/macOS) and pre-populated database (all platforms). - [brodybits / sql-promise-helper](https://github.com/brodybits/sql-promise-helper) provides a Promise-based API wrapper. - [nolanlawson / pouchdb-adapter-cordova-sqlite](https://github.com/nolanlawson/pouchdb-adapter-cordova-sqlite) supports this plugin along with other implementations such as [nolanlawson / sqlite-plugin-2](https://github.com/nolanlawson/sqlite-plugin-2) and [Microsoft / cordova-plugin-websql](https://github.com/Microsoft/cordova-plugin-websql). @@ -778,7 +778,6 @@ cordova platform add ios - `ios` - Objective-C plugin code for iOS - `spec`: test suite using Jasmine (2.2.0) - `tests`: very simple Jasmine test suite that is run on Circle CI (Android version) and Travis CI (iOS version) (used as a placeholder) -- `Lawnchair-adapter`: Lawnchair adaptor, based on the version from the Lawnchair repository, with the basic Lawnchair test suite in `test-www` subdirectory ## Installation test @@ -898,43 +897,7 @@ To run from a windows powershell (here is a sample for android target): ## Lawnchair Adapter -**BROKEN:** The Lawnchair adapter does not support the `openDatabase` options such as `location` or `iosDatabaseLocation` options and is therefore *not* expected to work with this plugin. - -NOW SUPPORTED IN: [litehelpers / cordova-sqlite-lawnchair-adapter](https://github.com/litehelpers/cordova-sqlite-lawnchair-adapter) - -### Common adapter - -Please look at the `Lawnchair-adapter` tree that contains a common adapter, which should also work with the Android version, along with a test-www directory. - -### Included files - -Include the following Javascript files in your HTML: - -- `cordova.js` (don't forget!) -- `lawnchair.js` (you provide) -- `SQLitePlugin.js` (in case of Cordova pre-3.0) -- `Lawnchair-sqlitePlugin.js` (must come after `SQLitePlugin.js` in case of Cordova pre-3.0) - -### Sample - -The `name` option determines the sqlite database filename, *with no extension automatically added*. Optionally, you can change the db filename using the `db` option. - -In this example, you would be using/creating a database with filename `kvstore`: - -```Javascript -kvstore = new Lawnchair({name: "kvstore"}, function() { - // do stuff -); -``` - -Using the `db` option you can specify the filename with the desired extension and be able to create multiple stores in the same database file. (There will be one table per store.) - -```Javascript -recipes = new Lawnchair({db: "cookbook", name: "recipes", ...}, myCallback()); -ingredients = new Lawnchair({db: "cookbook", name: "ingredients", ...}, myCallback()); -``` - -**KNOWN ISSUE:** the new db options are *not* supported by the Lawnchair adapter. The workaround is to first open the database file using `sqlitePlugin.openDatabase()`. +- [litehelpers / cordova-sqlite-lawnchair-adapter](https://github.com/litehelpers/cordova-sqlite-lawnchair-adapter) ## PouchDB diff --git a/package.json b/package.json index ca479ab82..be8847a4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-sqlite-legacy-express-core", - "version": "1.0.0-pre1", + "version": "1.0.0-pre2", "description": "Native interface to SQLite for PhoneGap/Cordova (legacy express core version)", "cordova": { "id": "cordova-sqlite-legacy-express-core", diff --git a/plugin.xml b/plugin.xml index ffd6362c2..5e027b26e 100644 --- a/plugin.xml +++ b/plugin.xml @@ -2,7 +2,7 @@ + version="1.0.0-pre2"> Cordova sqlite storage plugin - legacy express core version