Fixed a bunch of issues, added more unit tests. All pass

This commit is contained in:
Timothy Warren 2011-07-14 21:52:17 -04:00
parent afde37c6e3
commit 457ccf07a4
2 changed files with 287 additions and 182 deletions

406
kis.js
View File

@ -6,7 +6,7 @@
*/ */
(function (){ (function (){
"use strict"; //"use strict";
// Property name for expandos on DOM objects // Property name for expandos on DOM objects
var kis_expando = "KIS_0_2_0"; var kis_expando = "KIS_0_2_0";
@ -17,17 +17,7 @@
return; return;
} }
var $_, $, dcopy; var $_, $, dcopy, sel;
/**
* String trim function polyfill
*/
if(typeof String.prototype.trim === "undefined")
{
String.prototype.trim = function(){
return this.replace(/^\s+|\s+$/g, "");
};
}
/** /**
* $ * $
@ -37,7 +27,7 @@
$ = function (a) $ = function (a)
{ {
var x; var x;
if (typeof a !== "string"){ return a;} if (typeof a !== "string" || typeof a === "undefined"){ return a;}
//Pick the quickest method for each kind of selector //Pick the quickest method for each kind of selector
if(a.match(/^#([\w\-]+$)/)) if(a.match(/^#([\w\-]+$)/))
@ -62,21 +52,22 @@
* *
* Constructor function * Constructor function
*/ */
$_ = function(sel) $_ = function(s)
{ {
//Have documentElement be default selector, just in case
if(typeof s == "undefined")
{
sel = (typeof $_.el !== "undefined")
? $_.el
: document.documentElement;
}
else
{
sel = $(s);// || document.documentElement;
}
// Make a copy before adding properties // Make a copy before adding properties
var self = dcopy($_); var self = dcopy($_);
//Get the DOM objects from the selector
sel = $(sel);
//Have window be default selector, just in case
if(typeof sel === "undefined")
{
sel = (typeof self.el !== "undefined")
? self.el
: window;
}
self.el = sel; self.el = sel;
@ -114,6 +105,40 @@
return new f(); return new f();
}; };
//Function to add to $_ object, and get sel
$_.ext = function(name, obj)
{
$_[name] = obj;
obj.el = sel;
console.log(obj.el);
};
//Selector iteration
$_.ext('each', function (callback)
{
if(typeof sel.length !== "undefined")
{
var len = sel.length;
if (len === 0)
{
return;
}
var selx;
for (var x = 0; x < len; x++)
{
selx = (sel.item(x)) ? sel.item(x) : sel[x];
callback(selx);
}
}
else
{
callback(sel);
}
});
//Set global variables //Set global variables
$_ = window.$_ = window.$_ || $_; $_ = window.$_ = window.$_ || $_;
@ -127,44 +152,22 @@
}; };
} }
// -------------------------------------------------------------------------- /**
* String trim function polyfill
$_.each = function (callback) */
if(typeof String.prototype.trim === "undefined")
{ {
var sel = $_.el; String.prototype.trim = function(){
return this.replace(/^\s+|\s+$/g, "");
//Don't try to iterate over the window object };
if(sel === window || typeof sel === "undefined") }
{
return; // --------------------------------------------------------------------------
} }());
if(typeof sel.length !== "undefined")
{
var len = sel.length;
if (len === 0) (function(){
{
return; "use strict";
}
if (len === 1)
{
return callback(sel);
}
var selx;
for (var x = 0; x < sel.length; x++)
{
selx = (sel.item(x)) ? sel.item(x) : sel[x];
callback(selx);
}
}
else
{
callback(sel);
}
};
/** /**
* Ajax * Ajax
@ -239,15 +242,13 @@
} }
}; };
$_.get = function (url, data, callback) $_.ext('get', function (url, data, callback){
{
ajax._do(url, data, callback, false); ajax._do(url, data, callback, false);
}; });
$_.post = function (url, data, callback) $_.ext('post', function (url, data, callback){
{
ajax._do(url, data, callback, true); ajax._do(url, data, callback, true);
}; });
}()); }());
/** /**
@ -338,7 +339,7 @@
} }
}; };
$_.qs = qs; $_.ext('qs', qs);
}()); }());
@ -380,7 +381,7 @@
} }
}; };
$_.store = store; $_.ext('store', store);
}()); }());
/** /**
@ -469,21 +470,10 @@
}; };
} }
add_remove = function (event, callback, add) add_remove = function (sel, event, callback, add)
{ {
var i, len; var i, len;
//Get the DOM object
var sel = $_.el;
if(arguments.length === 4)
{
sel = arguments[0];
event = arguments[1];
callback = arguments[2];
add = arguments[3];
}
if(typeof sel === "undefined") if(typeof sel === "undefined")
{ {
console.log(arguments); console.log(arguments);
@ -500,34 +490,34 @@
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
{ {
add_remove(event[i], callback, add); add_remove(sel, event[i], callback, add);
} }
return; return;
} }
//Go over additonal DOM objects as needed
$_.each(function(e){
(add === true) (add === true)
? attach(e, event, callback) ? attach(e, event, callback)
: remove(e, event, callback); : remove(e, event, callback);
});
}; };
e = { e = {
add: function (event, callback) add: function (event, callback)
{ {
add_remove(event, callback, true); $_.each(function(e){
add_remove(e, event, callback, true);
});
}, },
remove: function (event, callback) remove: function (event, callback)
{ {
add_remove(event, callback, false); $_.each(function(e){
add_remove(e, event, callback, false);
});
} }
}; };
$_.event = e; $_.ext('event', e);
}()); }());
@ -601,87 +591,164 @@
return (typeof value !== "undefined") ? value : oldVal; return (typeof value !== "undefined") ? value : oldVal;
} }
/*
* classList.js: Cross-browser full element.classList implementation.
* 2011-06-15
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
// Private function for class manipulation /*global self, document, DOMException */
function _class(sel, c, add)
/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if (typeof document !== "undefined" && !("classList" in document.createElement("a")))
{ {
var ec, cs, len, i, classInd; (function (view){
"use strict";
//We can do this the easy way var classListProp = "classList",
if (sel.classList) protoProp = "prototype",
{ elemCtrProto = (view.HTMLElement || view.Element)[protoProp],
if (add === true) objCtr = Object,
{ strTrim = String[protoProp].trim ||
sel.classList.add(c); function ()
return;
}
else if (add === false)
{
sel.classList.remove(c);
return;
}
}
else //Or the hard way
{
//No class attribute? Set an empty string
ec = sel.className;//_attr("class");
ec = (typeof ec === "string") ? ec : '';
//Convert class attribute string into array
if (typeof ec === "string")
{
cs = (ec !== '') ? ec.split(" ") : [];
len = cs.length;
classInd = false;
//Check for the class in the array
for (i = 0; i < len; i++)
{ {
if (cs[i] === c) return this.replace(/^\s+|\s+$/g, "");
},
arrIndexOf = Array[protoProp].indexOf ||
function (item)
{
var
i = 0,
len = this.length;
for (; i < len; i++)
{ {
classInd = i; if (i in this && this[i] === item)
break; {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
,
DOMEx = function (type, message)
{
this.name = type;
this.code = DOMException[type];
this.message = message;
},
checkTokenAndGetIndex = function (classList, token)
{
if (token === "")
{
throw new DOMEx("SYNTAX_ERR", "An invalid or illegal string was specified");
}
if (/\s/.test(token))
{
throw new DOMEx("INVALID_CHARACTER_ERR", "String contains an invalid character");
}
return arrIndexOf.call(classList, token);
},
ClassList = function (elem)
{
var
trimmedClasses = strTrim.call(elem.className),
classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
i = 0,
len = classes.length;
for (; i < len; i++)
{
this.push(classes[i]);
}
this._updateClassName = function ()
{
elem.className = this.toString();
};
},
classListProto = ClassList[protoProp] = [],
classListGetter = function ()
{
return new ClassList(this);
};
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i)
{
return this[i] || null;
};
classListProto.contains = function (token)
{
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function (token)
{
token += "";
if (checkTokenAndGetIndex(this, token) === -1)
{
this.push(token);
this._updateClassName();
}
};
classListProto.remove = function (token)
{
token += "";
var index = checkTokenAndGetIndex(this, token);
if (index !== -1)
{
this.splice(index, 1);
this._updateClassName();
}
};
classListProto.toggle = function (token)
{
token += "";
if (checkTokenAndGetIndex(this, token) === -1)
{
this.add(token);
}
else
{
this.remove(token);
}
};
classListProto.toString = function ()
{
return this.join(" ");
};
if (objCtr.defineProperty)
{
var classListPropDesc = {
get: classListGetter,
enumerable: true,
configurable: true
};
try
{
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
catch (ex)
{ // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54)
{
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} }
} }
} }
else if (objCtr[protoProp].__defineGetter__)
//Add or remove from class array
if (add === true)
{ {
//Only add the class if isn't already there elemCtrProto.__defineGetter__(classListProp, classListGetter);
if (classInd === false)
{
cs.push(c);
}
}
else if (add === false)
{
//Make sure the class you want to remove exists
if (classInd !== false)
{
cs.splice(classInd, 1);
}
} }
var cName = (cs.length > 1) ? cs.join(" ") : cs[0]; }(self));
if (typeof sel.className !== "undefined")
{
sel.className = cName;
}
else if (typeof sel.setAttribute !== "undefined")
{
sel.setAttribute('class', cName);
}
else
{
console.log(sel);
}
return cName;
}
} }
function _toCamel(s) function _toCamel(s)
@ -733,13 +800,15 @@
addClass: function (c) addClass: function (c)
{ {
$_.each(function (e){ $_.each(function (e){
_class(e, c, true); console.log(e);
console.log(c);
e.classList.add(c);
}); });
}, },
removeClass: function (c) removeClass: function (c)
{ {
$_.each(function (e){ $_.each(function (e){
_class(e, c, false); e.classList.remove(c);
}); });
}, },
hide: function () hide: function ()
@ -757,7 +826,7 @@
}, },
attr: function (name, value) attr: function (name, value)
{ {
var sel = $_.el; var sel = this.el;
//Make sure you don't try to get a bunch of elements //Make sure you don't try to get a bunch of elements
if (sel.length > 1 && typeof value === "undefined") if (sel.length > 1 && typeof value === "undefined")
@ -769,7 +838,7 @@
else if (sel.length > 1 && typeof value !== "undefined") //You can set a bunch, though else if (sel.length > 1 && typeof value !== "undefined") //You can set a bunch, though
{ {
$_.each(function (e){ $_.each(function (e){
_attr(e, name, value); return _attr(e, name, value);
}); });
} }
else //Normal behavior else //Normal behavior
@ -781,7 +850,7 @@
{ {
var oldValue, set, type, sel; var oldValue, set, type, sel;
sel = $_.el; sel = this.el;
set = (typeof value !== "undefined") ? true : false; set = (typeof value !== "undefined") ? true : false;
@ -811,7 +880,8 @@
} }
}; };
$_.dom = d; $_.ext('dom', d);
}()); }());
}()); }());

View File

@ -17,36 +17,68 @@
var y = $_("aside"); var y = $_("aside");
expect(1); expect(1);
notEqual(x.el, y.el, "Unique Query Objects - see Issue #5"); notStrictEqual(x.el, y.el, "Unique Query Objects - see Issue #5");
});
test("Extend function", function(){
var o = $_("ol");
expect(3);
ok(o.ext, "Extend function exists");
$_.ext('test', {});
strictEqual(typeof o.test, "object", "Extend function adds to $_");
equal(o.test.el, $_("ol").el, "Extend function adds selector to passed object");
});
test("Selector tests", function(){
var i=0;
$_("div").each(function(e){
equal(e, $_("div").el[i], ".each function has current selector");
i++;
});
equal($_().el, window.document.documentElement, "Empty selector is set to documentElement");
}); });
test("Sub-modules", function(){ test("Sub-modules", function(){
expect(5); expect(4);
ok($_.get, "AJAX get method");
ok($_.post, "AJAX post method");
ok($_.qs, "Query String module"); ok($_.qs, "Query String module");
ok($_().event, "Event module");
ok($_.store, "Local Storage module"); ok($_.store, "Local Storage module");
ok($_.dom, "Dom manipulation module"); ok($_().dom, "Dom manipulation module");
}); });
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
module("ajax"); module("ajax");
test("Methods defined", function(){
expect(2);
ok($_.get, "AJAX get method");
ok($_.post, "AJAX post method");
});
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
module("events"); module("events");
test("Events defined", function(){
expect(2);
ok($_.event.add, "Add Method Exists");
ok($_.event.remove, "Remove Method Exists");
});
test("Browser expando support", function() { test("Browser expando support", function() {
expect(3); expect(3);
// kis-js events uses expando properties to store event listeners // kis-js events uses expando properties to store event listeners for IE
// If this test fails, the event module will likely fail as well // If this test fails, the event module will likely fail as well
var ele = document.createElement("div"); var ele = document.createElement("div");
ele.expando = {a:5, b:"c", c: function cool(){return ele}}; ele.expando = {a:5, b:"c", c: function cool(){return ele}};
equals(ele.expando.a, 5); equal(ele.expando.a, 5);
equals(ele.expando.b, "c"); equal(ele.expando.b, "c");
equals(ele.expando.c(), ele, equal(ele.expando.c(), ele,
"Closure isn't broken by being assigned to an expando property"); "Closure isn't broken by being assigned to an expando property");
}); });
@ -56,19 +88,22 @@
test("Add/Remove Class", function() { test("Add/Remove Class", function() {
expect(4); expect(4);
var $test = $_("#testSpan"); //var $test = $_("#testSpan");
var ele = $test.el; //var ele = $test.el;
var ele = document.getElementById('testSpan');
var $test = $_(ele);
$test.dom.addClass("coolClass"); $test.dom.addClass("coolClass");
equals(ele.className, "coolClass"); equal(ele.className, "coolClass");
$test.dom.addClass("anotherClass"); $test.dom.addClass("anotherClass");
equals(ele.className, "coolClass anotherClass"); equal(ele.className, "coolClass anotherClass");
$test.dom.removeClass("coolClass"); $test.dom.removeClass("coolClass");
equals(ele.className, "anotherClass"); equal(ele.className, "anotherClass");
$test.dom.removeClass("anotherClass"); $test.dom.removeClass("anotherClass");
ok(ele.className === undefined || ele.className === "", "testSpan.className is empty"); ok(ele.className === undefined || ele.className === "", "testSpan.className is empty");
}); });
}()); }());