Updated entwine dependency

And removed unnecessary files, just adds
to the security surface of the webroot.
This commit is contained in:
Ingo Schommer 2013-08-20 15:19:51 +02:00
parent 6627a19994
commit a1419b2f7e
108 changed files with 101 additions and 27008 deletions

0
thirdparty/jquery-entwine/LICENSE vendored Normal file → Executable file
View File

0
thirdparty/jquery-entwine/README.textile vendored Normal file → Executable file
View File

View File

@ -1,49 +0,0 @@
#!/bin/sh
# Specify the output file's name
FILE="dist/jquery.entwine-dist.js"
mkdir -p dist
rm dist/*.js
echo "/* jQuery.Entwine - Copyright 2009-2011 Hamish Friedlander and SilverStripe. Version $VER. */" > $FILE
for x in \
vendor/jquery.selector/jquery.class.js \
vendor/jquery.selector/jquery.selector.js \
vendor/jquery.selector/jquery.selector.specifity.js \
vendor/jquery.selector/jquery.selector.matches.js \
src/jquery.selector.affectedby.js \
src/jquery.focusinout.js \
src/jquery.entwine.js \
src/domevents/jquery.entwine.domevents.addrem.js \
src/domevents/jquery.entwine.domevents.maybechanged.js \
src/jquery.entwine.events.js \
src/jquery.entwine.eventcapture.js \
src/jquery.entwine.ctors.js \
src/jquery.entwine.addrem.js \
src/jquery.entwine.properties.js \
src/jquery.entwine.legacy.js
do \
echo >> $FILE
echo "/* $x */" >> $FILE
echo >> $FILE
cat $x >> $FILE
echo ';' >> $FILE
echo >> $FILE
done
cp $FILE "dist/jquery.concrete-dist.js"
# cp LICENSE /tmp/
# cp $FILE /tmp/
# git checkout dist
# mv /tmp/$FILE .
# mv /tmp/LICENSE .
# git add $FILE
# git add LICENSE
# git commit -m "Update dist to master version $VER"
# git checkout master

77
thirdparty/jquery-entwine/dist/jquery.concrete-dist.js vendored Normal file → Executable file
View File

@ -753,8 +753,11 @@ Sizzle is good for finding elements for a selector, but not so good for telling
* Add focusin and focusout support to bind and live for browers other than IE. Designed to be usable in a delegated fashion (like $.live)
* Copyright (c) 2007 Jörn Zaefferer
*/
$.support.focusInOut = !!($.browser.msie);
if (!$.support.focusInOut) {
if ($.support.focusinBubbles === undefined) {
$.support.focusinBubbles = !!($.browser.msie);
}
if (!$.support.focusinBubbles && !$.event.special.focusin) {
// Emulate focusin and focusout by binding focus and blur in capturing mode
$.each({focus: 'focusin', blur: 'focusout'}, function(original, fix){
$.event.special[fix] = {
@ -807,8 +810,30 @@ catch (e) {
window.console = undefined;
}
(function($) {
(function($) {
/* Create a subclass of the jQuery object. This was introduced in jQuery 1.5, but removed again in 1.9 */
var sub = function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, $ );
jQuerySub.superclass = $;
jQuerySub.fn = jQuerySub.prototype = $();
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.fn.init = function init( selector, context ) {
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
context = jQuerySub( context );
}
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
return jQuerySub;
};
var namespaces = {};
$.entwine = function() {
@ -928,49 +953,9 @@ catch (e) {
}
else {
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
// jQuery 1.5 already provides a nice way to subclass, so use it
if ($.sub) {
this.$ = $.sub();
this.injectee = this.$.prototype;
}
// For jQuery < 1.5 we have to do it ourselves
else {
var subfn = function(){};
this.injectee = subfn.prototype = new $;
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
var bound$ = this.$ = function(a) {
// Try the simple way first
var jq = $.fn.init.apply(new subfn(), arguments);
if (jq instanceof subfn) return jq;
// That didn't return a bound object, so now we need to copy it
var rv = new subfn();
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
while (i--) rv[i] = jq[i];
return rv;
};
this.injectee.pushStack = function(elems, name, selector){
var ret = bound$(elems);
this.$ = $.sub ? $.sub() : sub();
this.injectee = this.$.prototype;
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) ret.selector = this.selector + (this.selector ? " " : "") + selector;
else if ( name ) ret.selector = this.selector + "." + name + "(" + selector + ")";
// Return the newly-formed element set
return ret;
};
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
$.extend(this.$, $);
}
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
var entwine_wrapper = this.injectee.entwine = function(spacename) {
var args = arguments;

140
thirdparty/jquery-entwine/dist/jquery.entwine-dist.js vendored Normal file → Executable file
View File

@ -753,8 +753,11 @@ Sizzle is good for finding elements for a selector, but not so good for telling
* Add focusin and focusout support to bind and live for browers other than IE. Designed to be usable in a delegated fashion (like $.live)
* Copyright (c) 2007 Jörn Zaefferer
*/
$.support.focusInOut = !!($.browser.msie);
if (!$.support.focusInOut) {
if ($.support.focusinBubbles === undefined) {
$.support.focusinBubbles = !!($.browser.msie);
}
if (!$.support.focusinBubbles && !$.event.special.focusin) {
// Emulate focusin and focusout by binding focus and blur in capturing mode
$.each({focus: 'focusin', blur: 'focusout'}, function(original, fix){
$.event.special[fix] = {
@ -807,8 +810,30 @@ catch (e) {
window.console = undefined;
}
(function($) {
(function($) {
/* Create a subclass of the jQuery object. This was introduced in jQuery 1.5, but removed again in 1.9 */
var sub = function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, $ );
jQuerySub.superclass = $;
jQuerySub.fn = jQuerySub.prototype = $();
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.fn.init = function init( selector, context ) {
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
context = jQuerySub( context );
}
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
return jQuerySub;
};
var namespaces = {};
$.entwine = function() {
@ -928,49 +953,12 @@ catch (e) {
}
else {
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
// jQuery 1.5 already provides a nice way to subclass, so use it
if ($.sub) {
this.$ = $.sub();
this.injectee = this.$.prototype;
}
// For jQuery < 1.5 we have to do it ourselves
else {
var subfn = function(){};
this.injectee = subfn.prototype = new $;
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
var bound$ = this.$ = function(a) {
// Try the simple way first
var jq = $.fn.init.apply(new subfn(), arguments);
if (jq instanceof subfn) return jq;
// That didn't return a bound object, so now we need to copy it
var rv = new subfn();
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
while (i--) rv[i] = jq[i];
return rv;
};
this.injectee.pushStack = function(elems, name, selector){
var ret = bound$(elems);
this.$ = $.sub ? $.sub() : sub();
// Work around bug in sub() - subclass must share cache with root or data won't get cleared by cleanData
this.$.cache = $.cache;
this.injectee = this.$.prototype;
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) ret.selector = this.selector + (this.selector ? " " : "") + selector;
else if ( name ) ret.selector = this.selector + "." + name + "(" + selector + ")";
// Return the newly-formed element set
return ret;
};
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
$.extend(this.$, $);
}
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
var entwine_wrapper = this.injectee.entwine = function(spacename) {
var args = arguments;
@ -1205,32 +1193,37 @@ catch (e) {
var dontTrigger = false;
var patchDomManipCallback = function(original) {
var patched = function(elem){
var added = [];
if (!dontTrigger) {
if (elem.nodeType == 1) added[added.length] = elem;
getElements(added, elem);
}
var rv = original.apply(this, arguments);
if (!dontTrigger && added.length) {
var event = $.Event('EntwineElementsAdded');
event.targets = added;
$(document).triggerHandler(event);
}
return rv;
}
patched.patched = true;
return patched;
}
var version = $.prototype.jquery.split('.');
var callbackIdx = (version[0] > 1 || version[1] >= 10 ? 1 : 2);
// Monkey patch $.fn.domManip to catch all regular jQuery add element calls
var _domManip = $.prototype.domManip;
$.prototype.domManip = function(args, table, callback) {
if (!callback.patched) {
var original = callback;
arguments[2] = function(elem){
var added = [];
if (!dontTrigger) {
if (elem.nodeType == 1) added[added.length] = elem;
getElements(added, elem);
}
var rv = original.apply(this, arguments);
if (!dontTrigger && added.length) {
var event = $.Event('EntwineElementsAdded');
event.targets = added;
$(document).triggerHandler(event);
}
return rv;
}
arguments[2].patched = true;
}
$.prototype.domManip = function() {
if (!arguments[callbackIdx].patched) arguments[callbackIdx] = patchDomManipCallback(arguments[callbackIdx]);
return _domManip.apply(this, arguments);
}
@ -1772,6 +1765,12 @@ catch (e) {
}
};
var document_proxy = function(selector, handler, includechildren) {
return function(e){
if (e.target === document) return handler.apply(this, arguments);
}
};
var window_proxy = function(selector, handler, includechildren) {
return function(e){
if (e.target === window) return handler.apply(this, arguments);
@ -1805,6 +1804,7 @@ catch (e) {
if (from.match(/[^\w]/)) proxyGen = selector_proxy;
else if (from == 'Window' || from == 'window') proxyGen = window_proxy;
else if (from == 'Document' || from == 'document') proxyGen = document_proxy;
else proxyGen = property_proxy;
for (var onevent in v) {

View File

@ -1,86 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Test Runner</title>
<link rel="stylesheet" type="text/css" href="../vendor/jasmine/jasmine.css">
<script type="text/javascript" src="../vendor/jasmine/jasmine.js"></script>
<script type="text/javascript" src="../vendor/jasmine/jasmine-html.js"></script>
<script type="text/javascript" src="../vendor/jasmine-dom/jasmine-dom-matchers.js"></script>
<script type="text/javascript" src="../vendor/jasmine-dom/jasmine-dom-fixtures.js"></script>
<script type="text/javascript">
versionarg = window.location.search.match(/version=([^&]+)/);
jQueryVersion = versionarg ? versionarg[1] : '1.8.0';
jQuerySource = 'local';
var jQuery;
document.write('<'+'script src="../vendor/jquery-'+jQueryVersion+'.js"'+'><'+'/script'+'>');
</script>
<script type="text/javascript">
if (!jQuery) {
jQuerySource = 'Google CDN';
document.write('<'+'script src="http://ajax.googleapis.com/ajax/libs/jquery/'+jQueryVersion+'/jquery.min.js"'+'><'+'/script'+'>');
}
</script>
<script src="../vendor/jquery.selector/jquery.class.js"></script>
<script src="../vendor/jquery.selector/jquery.selector.js"></script>
<script src="../vendor/jquery.selector/jquery.selector.specifity.js"></script>
<script src="../vendor/jquery.selector/jquery.selector.matches.js"></script>
<script src="../src/jquery.selector.affectedby.js"></script>
<script src="../src/jquery.entwine.js"></script>
<script src="../src/domevents/jquery.entwine.domevents.addrem.js"></script>
<script src="../src/domevents/jquery.entwine.domevents.maybechanged.js"></script>
<script src="../src/jquery.entwine.events.js"></script>
<script src="../src/jquery.entwine.eventcapture.js"></script>
<script src="../src/jquery.entwine.ctors.js"></script>
<script src="../src/jquery.entwine.addrem.js"></script>
<script src="../src/jquery.entwine.properties.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec.entwine.basics.js"></script>
<script type="text/javascript" src="spec.entwine.eventcapture.js"></script>
<script type="text/javascript" src="spec.entwine.ctors.js"></script>
<script type="text/javascript" src="spec.entwine.addrem.js"></script>
<script type="text/javascript" src="spec.entwine.events.js"></script>
<script type="text/javascript" src="spec.entwine.namespaces.js"></script>
<script type="text/javascript" src="spec.entwine.properties.js"></script>
<script type="text/javascript" src="spec.entwine.super.js"></script>
<script type="text/javascript" src="spec.entwine.synchronous.js"></script>
<style type="text/css">
#jqver {
margin: 0;
padding: 4px 15px;
}
#jqver.error {
padding: 4px 13px;
border: 2px solid red;
}
</style>
</head>
<body>
</body>
<script type="text/javascript">
if (!jQuery) {
document.body.innerHTML = '<h4 id="jqver" class="error">jQuery version '+jQueryVersion+' not found</h4>';
}
else {
document.body.innerHTML = '<h4 id="jqver">jQuery version '+jQueryVersion+' ('+jQuerySource+')</h4>';
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
}
</script>
</html>

View File

@ -1,113 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('onadd and onremove', function(){
beforeEach(function(){
$.entwine.synchronous_mode();
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c"></div>');
});
describe('onremove', function(){
it('calls onremove on a removed element', function(){
var called = false;
$('#a').entwine({
onremove: function(){called = true;}
});
$('#a').remove();
expect(called).toBeTruthy();
});
it('calls onremove only on elements that match selectors, and does so when multiple elements are removed', function(){
var removed = [];
$('#a').html('<div id="b" class="catchremove"></div><div id="c"></div><div id="d" class="catchremove"></div>');
$('.catchremove').entwine({
onremove: function(){removed.push(this.attr('id'));}
});
$('#a').remove();
expect(removed).toEqual(['d', 'b']);
});
it('allows access to data in an onremove handler', function(){
var val = 0;
$('#a').data('Bam', 1);
$('#a').entwine({
onremove: function(){val = this.data('Bam');}
});
$('#a').remove();
expect(val).toEqual(1);
});
});
describe('onadd', function(){
it('calls onadd on an appended', function(){
var called = false;
$('#b').entwine({
onadd: function(){called = true;}
});
$('#a').append('<div id="b"></div>');
expect(called).toBeTruthy();
});
it('calls onadd on an child thats nested when appended', function(){
var called = false;
$('#b').entwine({
onadd: function(){called = true;}
});
$('#a').append('<div><div id="b"></div></div>');
expect(called).toBeTruthy();
});
it('calls onadd on an item added via html', function(){
var called = false;
$('#b').entwine({
onadd: function(){called = true;}
});
$('#a').html('<div></div><div><div id="b"></div></div>');
expect(called).toBeTruthy();
});
it('calls onadd and onremove correctly via replaceWith', function(){
var added = [], removed = [], sequence = [];
$('#a,#b').entwine({
onadd: function(){
added.push(this.attr('id'));
sequence.push(this.attr('id'));
},
onremove: function(){
removed.push(this.attr('id'));
sequence.push(this.attr('id'));
}
});
$('#a').replaceWith('<div></div><div><div id="b"></div></div>');
expect(added).toEqual(['b']);
expect(removed).toEqual(['a']);
expect(sequence).toEqual(['a', 'b']);
});
});
});
});

View File

@ -1,103 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$.entwine.warningLevel = $.entwine.WARN_LEVEL_BESTPRACTISE;
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Basics', function(){
beforeEach(function(){
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c" data-fieldtype="foo"></div><div id="b" class="c d e"></div>');
});
it('can attach and call a base function', function(){
$('#a').entwine({
foo: function(){return this.attr('id');}
});
expect($('.a').foo()).toEqual('a');
});
it('can attach and call a base function on a selector using a data attribute selection', function(){
$('[data-fieldtype=foo]').entwine({
foo: function(){return this.attr('id');}
});
expect($('.a').foo()).toEqual('a');
});
it('can attach and call a base function on a selector using a psuedo-selector taken from jquery', function(){
$('#a:visible').entwine({
foo: function(){return this.attr('id');}
});
expect($('.a').foo()).toEqual('a');
});
it('can attach and call several base functions', function(){
$('#a').entwine({
foo: function(){return 'foo_' + this.attr('id');},
bar: function(){return 'bar_' + this.attr('id');}
});
expect($('.a').foo()).toEqual('foo_a');
expect($('.a').bar()).toEqual('bar_a');
});
it('can attach and call a namespaced function', function(){
$.entwine('bar', function($){
$('#a').entwine({
foo: function(){return this.attr('id');}
});
});
expect($('.a').entwine('bar').foo()).toEqual('a');
});
it('can attach and call a nested namespaced function', function(){
$.entwine('qux.baz.bar', function($){
$('#a').entwine({
foo: function(){return this.attr('id');}
});
});
expect($('.a').entwine('qux.baz.bar').foo()).toEqual('a');
});
it('can call two functions on two elements', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(this.attr('id'));}
});
$('#b.c').entwine({
foo: function(){res.push(this.attr('id'));}
});
$('#dom_test div').foo();
expect(res).toEqual(['b', 'a']);
});
it('can call two namespaced functions on two elements', function(){
var res = [];
$.entwine('bar', function($){
$('#a').entwine({
foo: function(){res.push(this.attr('id'));}
});
$('#b.c').entwine({
foo: function(){res.push(this.attr('id'));}
});
});
$('#dom_test div').entwine('bar').foo();
expect(res).toEqual(['b', 'a']);
});
});
});

View File

@ -1,147 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Ctors', function(){
beforeEach(function(){
$.entwine.synchronous_mode();
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c"></div>');
});
it('calls onmatch when new element created', function(){
var a = false;
$('#b').entwine({
onmatch: function(){a = true;}
});
expect(a).toBeFalsy();
$('#a').after('<div id="b"></div>');
expect(a).toBeTruthy();
});
it('calls onunmatch when new element deleted', function(){
var a = 0;
$('#b').entwine({
onmatch: function(){a = 1;},
onunmatch: function(){a = 2;}
});
expect(a).toEqual(0);
$('#a').after('<div id="b"></div>');
expect(a).toEqual(1);
$('#b').remove();
expect(a).toEqual(2);
});
it('calls onmatch when ruleset matches after class added', function(){
var a = 0;
$('#a.foo').entwine({
onmatch: function(){a = 1;}
});
expect(a).toEqual(0);
$('#a').addClass('foo');
expect(a).toEqual(1);
});
it('calls onmatch in both direct and namespaced onmatch, does not call less specific onmatch', function(){
var a = 0, b = 0, c = 0, d = 0;
$('.foo').entwine({
onmatch: function(){a = 1;}
});
$('.foo').entwine('bar', function($){return{
onmatch: function(){b = 1;}
};});
$('#a.foo').entwine({
onmatch: function(){c = 1;}
});
$('#a.foo').entwine('bar', function($){return{
onmatch: function(){d = 1;}
};});
expect([a, b, c, d]).toEqual([0, 0, 0, 0]);
$('#a').addClass('foo');
expect([a, b, c, d]).toEqual([0, 0, 1, 1]);
});
it('calls onmatch in both direct and namespaced onmatch, super works as expected', function(){
var a = 0, b = 0, c = 0, d = 0;
$('.foo').entwine({
onmatch: function(){a += 1;}
});
$('.foo').entwine('bar', function($){return{
onmatch: function(){b += 1;}
};});
$('#a.foo').entwine({
onmatch: function(){this._super(); c = 1; this._super();}
});
$('#a.foo').entwine('bar', function($){return{
onmatch: function(){this._super(); d = 1; this._super();}
};});
expect([a, b, c, d]).toEqual([0, 0, 0, 0]);
$('#a').addClass('foo');
expect([a, b, c, d]).toEqual([2, 2, 1, 1]);
});
it('handles onmatch rules being added post document.onready', function(){
var a = 0, b = 0;
$('#a').entwine({
onmatch: function(){a += 1;}
});
$('#a.a').entwine({
onmatch: function(){b += 1;}
});
// Rules are new, and no DOM change, so no triggers yet
expect([a, b]).toEqual([0, 0]);
// New #a.a rule thinks it matches no nodes, and so removing .a would normally not release it. Check we handle
$('#a').removeClass('a');
expect([a, b]).toEqual([1, 0]);
});
it('calls onmatch in less specific rule when more specific rule no longer matches', function(){
var a = 0, b = 0, c = 0;
$('#a').entwine({
onmatch: function(){a += 1;}
});
$('#a.a').entwine({
onmatch: function(){b += 1;}
});
$('#a.a.b').entwine({
onmatch: function(){c += 1;}
});
$.entwine.triggerMatching();
expect([a, b, c]).toEqual([0, 0, 1]);
$('#a').removeClass('b');
expect([a, b, c]).toEqual([0, 1, 1]);
$('#a').removeClass('a');
expect([a, b, c]).toEqual([1, 1, 1]);
});
});
});

View File

@ -1,141 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Event Capture', function(){
beforeEach(function(){
$.entwine.synchronous_mode();
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c"><div id="d" class="d e f"></div></div>');
});
it('can capture by direct selector', function(){
var triggers = [];
$('#d').entwine({
'from#a': {
onsynthetic: function(){ triggers.push(this.attr('id')); }
}
});
$('#a').trigger('synthetic');
expect(triggers).toEqual(['d'])
$('#a').trigger('synthetic');
expect(triggers).toEqual(['d', 'd']);
$('#dom_test').trigger('synthetic');
expect(triggers).toEqual(['d', 'd']);
});
it('can capture by indirect selector', function(){
var triggercount = 0;
$('#d').entwine({
A: '#a',
fromA: {
onsynthetic: function(){ triggercount += 1;}
}
});
$('#a').trigger('synthetic');
expect(triggercount).toEqual(1);
$('#a').trigger('synthetic');
expect(triggercount).toEqual(2);
$('#dom_test').trigger('synthetic');
expect(triggercount).toEqual(2);
});
it('can capture by returning element set', function(){
var triggercount = 0;
$('#d').entwine({
getA: function(){ return this.parent(); },
fromA: {
onsynthetic: function(){ triggercount += 1;}
}
});
$('#a').trigger('synthetic');
expect(triggercount).toEqual(1);
$('#a').trigger('synthetic');
expect(triggercount).toEqual(2);
$('#dom_test').trigger('synthetic');
expect(triggercount).toEqual(2);
});
it('can capture by selector, more specific rules override correct', function(){
var triggerlist = [];
$('.d').entwine({
'from#a': {
onsynthetic: function(){ triggerlist.push(1); }
}
});
$('#d').entwine({
'from#a': {
onsynthetic: function(){ triggerlist.push(2); }
}
});
$('#a').trigger('synthetic');
expect(triggerlist).toEqual([2]);
});
it('gets events and data passed through correctly', function(){
var a, b;
$('#d').entwine({
'from#a': {
onsynthetic: function(e, data){ a = e.passthrough; b = data; }
}
});
var e = $.Event('synthetic'); e.passthrough = 'foo';
$('#a').trigger(e, ['bam']);
expect(a).toEqual('foo');
expect(b).toEqual('bam');
});
it('can handle different from endings', function(){
var triggercount = 0;
$('#d').entwine({
'from#a': {
onsynthetic: function(){ triggercount += 1;}
},
'from.b': {
onsynthetic: function(){ triggercount += 1;}
}
});
$('#a').trigger('synthetic');
expect(triggercount).toEqual(2);
});
it('can capture from window', function(){
var triggercount = 0;
$('#d').entwine({
fromWindow: {
onsynthetic: function(){ triggercount += 1;}
}
});
$(window).trigger('synthetic');
expect(triggercount).toEqual(1);
});
});
});

View File

@ -1,223 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Events', function(){
beforeEach(function(){
$.entwine.synchronous_mode();
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c"></div>');
});
it('calls onfoo when foo triggered', function(){
var a = 0;
$('#a').entwine({
onfoo: function(){a = 1;}
});
expect(a).toEqual(0);
$('#a').trigger('foo');
expect(a).toEqual(1);
});
it('only calls most specific onfoo when foo triggered', function(){
var a = 0, b = 0;
$('#a.a').entwine({
onfoo: function(){a = 1;}
});
$('#a').entwine({
onfoo: function(){b = 1;}
});
expect(a).toEqual(0);
expect(b).toEqual(0);
$('#a').trigger('foo');
expect(a).toEqual(1);
expect(b).toEqual(0);
});
it('calls namespaced onfoo when foo triggered', function(){
var a = 0;
$('#a').entwine('bar', function($){return{
onfoo: function(){a = 1;}
};});
expect(a).toEqual(0);
$('#a').trigger('foo');
expect(a).toEqual(1);
});
it('calls most specific namespaced onfoo and most specific non-namespaced onfoo when foo triggered', function(){
var a = 0, b = 0, c = 0, d = 0;
$('#a.a').entwine({
onfoo: function(){a = 1;}
});
$('#a').entwine({
onfoo: function(){b = 1;}
});
$('#a.a').entwine('bar', function($){return{
onfoo: function(){c = 1;}
};});
$('#a').entwine('bar', function($){return{
onfoo: function(){d = 1;}
};});
expect([a, b, c, d]).toEqual([0, 0, 0, 0]);
$('#a').trigger('foo');
expect([a, b, c, d]).toEqual([1, 0, 1, 0]);
});
it('calls up correctly on _super', function(){
var a = 0, b = 0;
$('#a').entwine({
onfoo: function(){a += 1;}
});
$('#a.a').entwine({
onfoo: function(){this._super(); b += 1; this._super();}
});
expect([a, b]).toEqual([0, 0]);
$('#a').trigger('foo')
expect([a, b]).toEqual([2, 1]);
});
it('passes event object', function(){
var event;
$('#a').entwine({
onfoo: function(e){event = e;}
});
$('#a').trigger('foo');
expect(event.type).toBeDefined();
expect(event.type).toEqual('foo');
expect(event.target).toHaveAttr('id', 'a');
});
it('delegates submit events to forms', function(){
var a = 0;
$('<form class="foo" action="javascript:undefined">').appendTo('#dom_test');
$('.foo').entwine({
onsubmit: function(e, d){a = 1;}
});
expect(a).toEqual(0);
$('.foo').trigger('submit');
expect(a).toEqual(1);
});
describe('can pass event data', function(){
it('on custom events', function(){
var data;
$('#a').entwine({
onfoo: function(e, d){data = d;}
});
$('#a').trigger('foo', {cheese: 'burger'});
expect(data.cheese).toEqual('burger');
});
it('on normal events', function(){
var data;
$('#a').entwine({
onclick: function(e, d){data = d;}
});
$('#a').trigger('click', {finger: 'left'});
expect(data.finger).toEqual('left');
});
it('on submit', function(){
var data;
$('<form class="foo" action="javascript:undefined">').appendTo('#dom_test');
$('.foo').entwine({
onsubmit: function(e, d){data = d; return false;}
});
$('.foo').trigger('submit', {cheese: 'burger'});
expect(data.cheese).toEqual('burger');
});
});
describe('calls onchange on checkboxes properly', function(){
beforeEach(function(){
$('#dom_test').html('<input id="i" type="checkbox" name="test_input_i" value="i" />');
});
it('calls onchange', function(){
var a = 0;
$('#i').entwine({
onchange: function(){a += 1;}
});
// Can't just "click()" - it's not the same as an actual click event
$('#i').trigger('focusin');
$('#i')[0].click();
expect(a).toEqual(1);
});
it('calls onchange only once per change', function(){
var a = 0;
$('#i').entwine({
onchange: function(){a += 1;}
});
$('#i').trigger('focusin');
$('#i')[0].click();
expect(a).toEqual(1);
$('#i').trigger('focusout');
$('#i').trigger('focusin');
$('#i').trigger('focusout');
expect(a).toEqual(1);
$('#i')[0].click();
expect(a).toEqual(2);
});
it('calls onchange even if checked attribute altered in mean time', function(){
var a = 0;
$('#i').entwine({
onchange: function(){a += 1;}
});
$('#i').trigger('focusin');
$('#i')[0].click();
expect(a).toEqual(1);
$('#i').removeAttr('checked');
$('#i').trigger('focusin');
$('#i')[0].click();
expect(a).toEqual(2);
});
});
});
});

View File

@ -1,275 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Namespaces', function(){
beforeEach(function() {
$.entwine.synchronous_mode();
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c"></div><div id="b" class="c d e"></div>');
});
it('namespaced functions work (single definition mode)', function(){
$('#a').entwine('bar', function($){return{
bar: function(){return 'a';}
};});
expect($('#a').entwine('bar').bar()).toEqual('a');
});
it('namespaced functions work (block definition mode)', function(){
$.entwine('zap', function($){
$('#a').entwine({
bar: function(){return 'a';}
});
});
expect($('#a').entwine('zap').bar()).toEqual('a');
});
it('double-namespaced functions work (block definition mode)', function(){
$.entwine('zap', function($){
$.entwine('pow', function($){
$('#a').entwine({
bar: function(){return 'a';}
});
});
});
expect($('#a').entwine('zap.pow').bar()).toEqual('a');
})
it('revert to base namespacing work (block definition mode)', function(){
$.entwine('zap', function($){
$.entwine('.pow', function($){
$('#a').entwine({
bar: function(){return 'a';}
});
});
});
expect($('#a').entwine('pow').bar()).toEqual('a');
});
it('internal to namespace, will look up functions in namespace before in base', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(1);},
bar: function(){res.push(2); this.foo();}
});
$('#a').entwine('bar', function($){return{
foo: function(){res.push(3);},
bar: function(){res.push(4); $(this).foo();}
};});
$('#dom_test div').bar();
expect(res).toEqual([2, 1]);
$('#dom_test div').entwine('bar').bar();
expect(res).toEqual([2, 1, 4, 3]);
});
it('internal to namespace, will look up functions in namespace before in base, even in closure', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(1);},
bar: function(){res.push(2); this.foo();}
});
$('#a').entwine('bar', function($){return{
foo: function(){res.push(3);},
bar: function(){
res.push(4);
$('#a').each(function(){$(this).foo();});
}
};});
$('#dom_test div').bar();
expect(res).toEqual([2, 1]);
$('#dom_test div').entwine('bar').bar();
expect(res).toEqual([2, 1, 4, 3]);
});
it('internal to namespace, will look up functions in namespace before in base, even in onmatch', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(1);},
bar: function(){res.push(2); this.foo();}
});
$('#a').entwine('bar', function($){return{
foo: function(){res.push(3);}
};});
$('#a.d').entwine('bar', function($){return{
onmatch: function(){res.push(4); this.foo();}
};});
$('#dom_test div').bar();
expect(res).toEqual([2, 1]);
$('#a').addClass('d');
expect(res).toEqual([2, 1, 4, 3]);
});
it('internal to namespace, will look up functions in base when not present in namespace', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(1);}
});
$('#a').entwine('bar', function($){return{
bar: function(){res.push(2); this.foo();}
};});
$('#dom_test div').entwine('bar').bar();
expect(res).toEqual([2, 1]);
});
it('internal to namespace, will not look up functions in base if present in namespace, even when not applicable to selector', function(){
var res = [];
$('#a').entwine('bar', function($){return{
foo: function(){this.bar();}
};});
$('#a').entwine({
bar: function(){res.push(1);}
});
$('span').entwine('bar', function($){return{
bar: function(){res.push(2);}
};});
$('#a').entwine('bar').foo()
expect(res).toEqual([]);
});
it('internal to namespace, can be directed to base namespace', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(1);},
bar: function(){res.push(2); this.foo();}
});
$('#a').entwine('bar', function($){return{
foo: function(){res.push(3);},
bar: function(){res.push(4); this.foo(); this.entwine('.').foo();}
};});
$('#dom_test div').bar();
expect(res).toEqual([2, 1]);
$('#dom_test div').entwine('bar').bar();
expect(res).toEqual([2, 1, 4, 3, 1]);
});
it('internal to namespace, will look up functions in namespace called the same as a regular jQuery base function', function(){
var res = [];
$('#a').entwine('bar', function($){return{
load: function(){res.push(1);},
bar: function(){res.push(2); this.load();}
};});
$('#dom_test div').entwine('bar').bar();
expect(res).toEqual([2, 1]);
});
it('internal to namespace, can be directed to regular jQuery base function', function(){
var res = [];
$.fn.testy = function(){res.push(1);}
$('#a').entwine('bar', function($){return{
testy: function(){res.push(3);},
bar: function(){res.push(2); this.entwine('.').testy();}
};});
$('#dom_test div').entwine('bar').bar();
expect(res).toEqual([2, 1]);
});
it('internal to namespace, can be directed to sub namespace', function(){
var res = [];
$.entwine('zap', function($){
$('#a').entwine({
foo: function(){res.push(1); this.entwine('pow').bar();}
});
$.entwine('pow', function($){
$('#a').entwine({
bar: function(){res.push(2);}
});
});
});
$('#dom_test div').entwine('zap').foo();
expect(res).toEqual([1, 2]);
});
it('internal to namespace, can be directed to unrelated namespace', function(){
var res = [];
$.entwine('zap', function($){
$('#a').entwine({
foo: function(){res.push(1); this.entwine('.pow').bar();}
});
$.entwine('pow', function($){
$('#a').entwine({
bar: function(){res.push(2);}
});
});
});
$.entwine('pow', function($){
$('#a').entwine({
bar: function(){res.push(3);}
});
});
$('#dom_test div').entwine('zap').foo();
expect(res).toEqual([1, 3]);
});
it('a function passed out of a namespace will remember its namespace', function(){
var res = [];
var func = function(func){
func.call($('#a, #b'));
};
$('#a, #b').entwine('bar', function($){return{
zap: function(){res.push($(this).attr('id'));},
bar: function(){res.push(2); func(this.zap);}
};});
$('#dom_test #a').entwine('bar').bar();
expect(res).toEqual([2, 'b', 'a']);
});
it('using block functions', function(){
var res = [];
$('#a').entwine({
foo: function(){res.push(1);}
});
$('#a').entwine('bar', function($){return{
foo: function(){res.push(3);}
};});
$('#dom_test div').foo();
expect(res).toEqual([1]);
$('#dom_test div').entwine('bar', function($){$(this).foo();});
expect(res).toEqual([1, 3]);
});
});
});

View File

@ -1,126 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Properties', function(){
beforeEach(function(){
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c"></div><div id="b" class="b c"></div>');
});
it('can define and get a basic property', function(){
$('#a').entwine({
Foo: null
});
expect($('.a').getFoo()).toBeNull();
});
it('can define and set a basic property', function(){
$('#a').entwine({
Foo: null
});
$('.a').setFoo(1);
expect($('.a').getFoo()).toEqual(1)
});
it('can define a default value', function(){
$('#a').entwine({
Foo: 1
});
expect($('.a').getFoo()).toEqual(1);
});
it('can override a default value with a true-ish value', function(){
$('#a').entwine({
Foo: 1
});
$('#a').setFoo(2);
expect($('.a').getFoo()).toEqual(2);
});
it('can override a default value with a false-ish value', function(){
$('#a').entwine({
Foo: 1
});
$('#a').setFoo(0);
expect($('.a').getFoo()).toEqual(0);
});
it('should manage proprties in namespaces without clashing', function(){
$('#a').entwine({
Foo: 1
});
$.entwine('test', function($){
$('#a').entwine({
Foo: 2
});
});
expect($('.a').getFoo()).toEqual(1);
expect($('.a').entwine('test').getFoo()).toEqual(2)
$('.a').setFoo(4);
$('.a').entwine('test').setFoo(8);
expect($('.a').getFoo()).toEqual(4)
expect($('.a').entwine('test').getFoo()).toEqual(8)
});
it('should manage directly setting properties in namespaces without clashing', function(){
$('#a').entwine({
Foo: null
});
$.entwine('test', function($){
$('#a').entwine({
Foo: null
});
});
$('.a').entwineData('Foo', 4);
$('.a').entwine('test').entwineData('Foo', 8);
expect($('.a').entwineData('Foo')).toEqual(4);
expect($('.a').entwine('test').entwineData('Foo')).toEqual(8);
});
describe('jQuery style accessors', function(){
it('can define and get a basic property', function(){
$('#a').entwine({
Foo: null
});
expect($('.a').Foo()).toBeNull();
});
it('can define and set a basic property', function(){
$('#a').entwine({
Foo: null
});
$('.a').Foo(1);
expect($('.a').Foo()).toEqual(1)
});
it('can define a default value', function(){
$('#a').entwine({
Foo: 1
});
expect($('.a').Foo()).toEqual(1)
});
});
});
});

View File

@ -1,75 +0,0 @@
describe('Entwine', function(){
beforeEach(function(){
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
});
describe('Super', function(){
beforeEach(function(){
$.entwine.clear_all_rules();
$('#dom_test').html('<div id="a" class="a b c">Foo</div><div id="b" class="c d e">Bar</div>');
});
it('can call the super function', function(){
var a = 1;
$('#a').entwine({
foo: function(){a *= 2;}
});
$('#a.a').entwine({
foo: function(){a += 2; this._super();}
});
$('#a').foo();
expect(a).toEqual(6)
});
it('super to a non-existant class should be ignored', function(){
var a = 1;
$('#a').entwine({
foo: function(){a *= 2; this._super();}
});
$('#a.a').entwine({
foo: function(){a += 2; this._super();}
});
$('#a').foo();
expect(a).toEqual(6)
});
it('can call super from two different functions without screwing up what super points to', function(){
var list = [];
$('#a').entwine({
foo: function(){list.push('foo'); this.bar();},
bar: function(){list.push('bar');}
});
$('#a.a').entwine({
foo: function(){list.push('foo2'); this._super(); list.push('foo2'); this._super();},
bar: function(){list.push('bar2'); this._super();}
});
$('#a').foo();
expect(list).toEqual(['foo2', 'foo', 'bar2', 'bar', 'foo2', 'foo', 'bar2', 'bar'])
});
it('can override (and call via super) a non-entwine jquery function', function(){
var a = 1;
$('#a').entwine({
text: function(){a = this._super();}
});
expect($('#a').text()).toBeUndefined();
expect(a).toEqual('Foo')
expect($('#b').text()).toEqual('Bar')
});
});
});

View File

@ -1,41 +0,0 @@
describe('Entwine', function(){
beforeEach(function() {
$.entwine.warningLevel = $.entwine.WARN_LEVEL_BESTPRACTISE;
$.entwine.synchronous_mode(true);
$('body').append('<div id="dom_test"></div>');
});
afterEach(function(){
$('#dom_test').remove();
$.entwine.synchronous_mode(false);
});
describe('Synchronous Mode', function(){
beforeEach(function(){
// $.entwine.clear_all_rules();
});
it('can modify the DOM in onmatch', function(){
$('#a').entwine({
onmatch: function(){this.append('<div class="appended"></div>');}
});
$('#dom_test').append('<div id="a" class="a b c" data-fieldtype="foo"></div><div id="b" class="c d e"></div>');
expect($('#a .appended').length).toEqual(1);
});
it('can modify the DOM in onunmatch', function(){
$('#a').entwine({
onmatch: function(){ /* NOP */ },
onunmatch: function(){$('#dom_test').append('<div class="appended"></div>');}
});
$('#dom_test').append('<div id="a" class="a b c" data-fieldtype="foo"></div><div id="b" class="c d e"></div>');
$('#dom_test').find('#a').remove();
expect($('#dom_test .appended').length).toEqual(1);
});
});
});

View File

@ -1,133 +0,0 @@
(function($){
// Gets all the child elements of a particular elements, stores it in an array
function getElements(store, original) {
var node, i = store.length, next = original.firstChild;
while ((node = next)) {
if (node.nodeType === 1) store[i++] = node;
next = node.firstChild || node.nextSibling;
while (!next && (node = node.parentNode) && node !== original) next = node.nextSibling;
}
}
// This might be faster? Or slower? @todo: benchmark.
function getElementsAlt(store, node) {
if (node.getElementsByTagName) {
var els = node.getElementsByTagName('*'), len = els.length, i = 0, j = store.length;
for(; i < len; i++, j++) {
store[j] = els[i];
}
}
else if (node.childNodes) {
var els = node.childNodes, len = els.length, i = 0;
for(; i < len; i++) {
getElements(store, els[i]);
}
}
}
var dontTrigger = false;
// Monkey patch $.fn.domManip to catch all regular jQuery add element calls
var _domManip = $.prototype.domManip;
$.prototype.domManip = function(args, table, callback) {
if (!callback.patched) {
var original = callback;
arguments[2] = function(elem){
var added = [];
if (!dontTrigger) {
if (elem.nodeType == 1) added[added.length] = elem;
getElements(added, elem);
}
var rv = original.apply(this, arguments);
if (!dontTrigger && added.length) {
var event = $.Event('EntwineElementsAdded');
event.targets = added;
$(document).triggerHandler(event);
}
return rv;
}
arguments[2].patched = true;
}
return _domManip.apply(this, arguments);
}
// Monkey patch $.fn.html to catch when jQuery sets innerHTML directly
var _html = $.prototype.html;
$.prototype.html = function(value) {
if (value === undefined) return _html.apply(this, arguments);
dontTrigger = true;
var res = _html.apply(this, arguments);
dontTrigger = false;
var added = [];
var i = 0, length = this.length;
for (; i < length; i++ ) getElements(added, this[i]);
var event = $.Event('EntwineElementsAdded');
event.targets = added;
$(document).triggerHandler(event);
return res;
}
// If this is true, we've changed something to call cleanData so that we can catch the elements, but we don't
// want to call the underlying original $.cleanData
var supressActualClean = false;
// Monkey patch $.cleanData to catch element removal
var _cleanData = $.cleanData;
$.cleanData = function( elems ) {
// By default we can assume all elements passed are legitimately being removeed
var removed = elems;
// Except if we're supressing actual clean - we might be being called by jQuery "being careful" about detaching nodes
// before attaching them. So we need to check to make sure these nodes currently are in a document
if (supressActualClean) {
var i = 0, len = elems.length, removed = [], ri = 0;
for(; i < len; i++) {
var node = elems[i], current = node;
while (current = current.parentNode) {
if (current.nodeType == 9) { removed[ri++] = node; break; }
}
}
}
if (removed.length) {
var event = $.Event('EntwineElementsRemoved');
event.targets = removed;
$(document).triggerHandler(event);
}
if (!supressActualClean) _cleanData.apply(this, arguments);
}
// Monkey patch $.fn.remove to catch when we're just detaching (keepdata == 1) -
// this doesn't call cleanData but still needs to trigger event
var _remove = $.prototype.remove;
$.prototype.remove = function(selector, keepdata) {
supressActualClean = keepdata;
var rv = _remove.call(this, selector);
supressActualClean = false;
return rv;
}
// And on DOM ready, trigger adding once
$(function(){
var added = []; getElements(added, document);
var event = $.Event('EntwineElementsAdded');
event.targets = added;
$(document).triggerHandler(event);
});
})(jQuery);

View File

@ -1,149 +0,0 @@
(function($){
/** Utility function to monkey-patch a jQuery method */
var monkey = function( /* method, method, ...., patch */){
var methods = $.makeArray(arguments);
var patch = methods.pop();
$.each(methods, function(i, method){
var old = $.fn[method];
$.fn[method] = function() {
var self = this, args = $.makeArray(arguments);
var rv = old.apply(self, args);
patch.apply(self, args);
return rv;
}
});
}
/** What to call to run a function 'soon'. Normally setTimeout, but for syncronous mode we override so soon === now */
var runSoon = window.setTimeout;
/** The timer handle for the asyncronous matching call */
var ChangeDetails = Base.extend({
init: function() {
this.global = false;
this.attrs = {};
this.classes = {};
},
/** Fire the change event. Only fires on the document node, so bind to that */
triggerEvent: function() {
// If we're not the active changes instance any more, don't trigger
if (changes != this) return;
// Cancel any pending timeout (if we're directly called in the mean time)
if (this.check_id) clearTimeout(this.check_id);
// Reset the global changes object to be a new instance (do before trigger, in case trigger fires changes itself)
changes = new ChangeDetails();
// Fire event
$(document).triggerHandler("EntwineSubtreeMaybeChanged", [this]);
},
changed: function() {
if (!this.check_id) {
var self = this;
this.check_id = runSoon(function(){ self.check_id = null; self.triggerEvent(); }, 10);
}
},
addAll: function() {
if (this.global) return this; // If we've already flagged as a global change, just skip
this.global = true;
this.changed();
return this;
},
addSubtree: function(node) {
return this.addAll();
},
/* For now we don't do this. It's expensive, and jquery.entwine.ctors doesn't use this information anyway */
addSubtreeFuture: function(node) {
if (this.global) return this; // If we've already flagged as a global change, just skip
this.subtree = this.subtree ? this.subtree.add(node) : $(node);
this.changed();
return this;
},
addAttr: function(attr, node) {
if (this.global) return this;
this.attrs[attr] = (attr in this.attrs) ? this.attrs[attr].add(node) : $(node);
this.changed();
return this;
},
addClass: function(klass, node) {
if (this.global) return this;
this.classes[klass] = (klass in this.classes) ? this.classes[klass].add(node) : $(node);
this.changed();
return this;
}
});
var changes = new ChangeDetails();
// Element add events trigger maybechanged events
$(document).bind('EntwineElementsAdded', function(e){ changes.addSubtree(e.targets); });
// Element remove events trigger maybechanged events, but we have to wait until after the nodes are actually removed
// (EntwineElementsRemoved fires _just before_ the elements are removed so the data still exists), especially in syncronous mode
var removed = null;
$(document).bind('EntwineElementsRemoved', function(e){ removed = e.targets; });
monkey('remove', 'html', 'empty', function(){
var subtree = removed; removed = null;
if (subtree) changes.addSubtree(subtree);
});
// We also need to know when an attribute, class, etc changes. Patch the relevant jQuery methods here
monkey('removeAttr', function(attr){
changes.addAttr(attr, this);
});
monkey('addClass', 'removeClass', 'toggleClass', function(klass){
if (typeof klass == 'string') changes.addClass(klass, this);
});
monkey('attr', function(a, b){
if (b !== undefined && typeof a == 'string') changes.addAttr(a, this);
else if (typeof a != 'string') { for (var k in a) changes.addAttr(k, this); }
});
// Add some usefull accessors to $.entwine
$.extend($.entwine, {
/**
* Make onmatch and onunmatch work in synchronous mode - that is, new elements will be detected immediately after
* the DOM manipulation that made them match. This is only really useful for during testing, since it's pretty slow
* (otherwise we'd make it the default).
*/
synchronous_mode: function() {
if (changes && changes.check_id) clearTimeout(changes.check_id);
changes = new ChangeDetails();
runSoon = function(func, delay){ func.call(this); return null; };
},
/**
* Trigger onmatch and onunmatch now - usefull for after DOM manipulation by methods other than through jQuery.
* Called automatically on document.ready
*/
triggerMatching: function() {
changes.addAll();
}
});
})(jQuery);

View File

@ -1,63 +0,0 @@
(function($) {
$.entwine.Namespace.addMethods({
build_addrem_proxy: function(name) {
var one = this.one(name, 'func');
return function() {
if (this.length === 0){
return;
}
else if (this.length) {
var rv, i = this.length;
while (i--) rv = one(this[i], arguments);
return rv;
}
else {
return one(this, arguments);
}
};
},
bind_addrem_proxy: function(selector, name, func) {
var rulelist = this.store[name] || (this.store[name] = $.entwine.RuleList());
var rule = rulelist.addRule(selector, name); rule.func = func;
if (!this.injectee.hasOwnProperty(name)) {
this.injectee[name] = this.build_addrem_proxy(name);
this.injectee[name].isentwinemethod = true;
}
}
});
$.entwine.Namespace.addHandler({
order: 30,
bind: function(selector, k, v) {
if ($.isFunction(v) && (k == 'onadd' || k == 'onremove')) {
this.bind_addrem_proxy(selector, k, v);
return true;
}
}
});
$(document).bind('EntwineElementsAdded', function(e){
// For every namespace
for (var k in $.entwine.namespaces) {
var namespace = $.entwine.namespaces[k];
if (namespace.injectee.onadd) namespace.injectee.onadd.call(e.targets);
}
});
$(document).bind('EntwineElementsRemoved', function(e){
for (var k in $.entwine.namespaces) {
var namespace = $.entwine.namespaces[k];
if (namespace.injectee.onremove) namespace.injectee.onremove.call(e.targets);
}
});
})(jQuery);

View File

@ -1,242 +0,0 @@
(function($) {
/* Add the methods to handle constructor & destructor binding to the Namespace class */
$.entwine.Namespace.addMethods({
bind_condesc: function(selector, name, func) {
var ctors = this.store.ctors || (this.store.ctors = $.entwine.RuleList()) ;
var rule;
for (var i = 0 ; i < ctors.length; i++) {
if (ctors[i].selector.selector == selector.selector) {
rule = ctors[i]; break;
}
}
if (!rule) {
rule = ctors.addRule(selector, 'ctors');
}
rule[name] = func;
if (!ctors[name+'proxy']) {
var one = this.one('ctors', name);
var namespace = this;
var proxy = function(els, i, func) {
var j = els.length;
while (j--) {
var el = els[j];
var tmp_i = el.i, tmp_f = el.f;
el.i = i; el.f = one;
try { func.call(namespace.$(el)); }
catch(e) { $.entwine.warn_exception(name, el, e); }
finally { el.i = tmp_i; el.f = tmp_f; }
}
};
ctors[name+'proxy'] = proxy;
}
}
});
$.entwine.Namespace.addHandler({
order: 30,
bind: function(selector, k, v) {
if ($.isFunction(v) && (k == 'onmatch' || k == 'onunmatch')) {
// When we add new matchers we need to trigger a full global recalc once, regardless of the DOM changes that triggered the event
this.matchersDirty = true;
this.bind_condesc(selector, k, v);
return true;
}
}
});
/**
* Finds all the elements that now match a different rule (or have been removed) and call onmatch on onunmatch as appropriate
*
* Because this has to scan the DOM, and is therefore fairly slow, this is normally triggered off a short timeout, so that
* a series of DOM manipulations will only trigger this once.
*
* The downside of this is that things like:
* $('#foo').addClass('tabs'); $('#foo').tabFunctionBar();
* won't work.
*/
$(document).bind('EntwineSubtreeMaybeChanged', function(e, changes){
// var start = (new Date).getTime();
// For every namespace
for (var k in $.entwine.namespaces) {
var namespace = $.entwine.namespaces[k];
// That has constructors or destructors
var ctors = namespace.store.ctors;
if (ctors) {
// Keep a record of elements that have matched some previous more specific rule.
// Not that we _don't_ actually do that until this is needed. If matched is null, it's not been calculated yet.
// We also keep track of any elements that have newly been taken or released by a specific rule
var matched = null, taken = $([]), released = $([]);
// Updates matched to contain all the previously matched elements as if we'd been keeping track all along
var calcmatched = function(j){
if (matched !== null) return;
matched = $([]);
var cache, k = ctors.length;
while ((--k) > j) {
if (cache = ctors[k].cache) matched = matched.add(cache);
}
}
// Some declared variables used in the loop
var add, rem, res, rule, sel, ctor, dtor, full;
// Stepping through each selector from most to least specific
var j = ctors.length;
while (j--) {
// Build some quick-access variables
rule = ctors[j];
sel = rule.selector.selector;
ctor = rule.onmatch;
dtor = rule.onunmatch;
/*
Rule.cache might be stale or fresh. It'll be stale if
- some more specific selector now has some of rule.cache in it
- some change has happened that means new elements match this selector now
- some change has happened that means elements no longer match this selector
The first we can just compare rules.cache with matched, removing anything that's there already.
*/
// Reset the "elements that match this selector and no more specific selector with an onmatch rule" to null.
// Staying null means this selector is fresh.
res = null;
// If this gets changed to true, it's too hard to do a delta update, so do a full update
full = false;
if (namespace.matchersDirty || changes.global) {
// For now, just fall back to old version. We need to do something like changed.Subtree.find('*').andSelf().filter(sel), but that's _way_ slower on modern browsers than the below
full = true;
}
else {
// We don't deal with attributes yet, so any attribute change means we need to do a full recalc
for (var k in changes.attrs) { full = true; break; }
/*
If a class changes, but it isn't listed in our selector, we don't care - the change couldn't affect whether or not any element matches
If it is listed on our selector
- If it is on the direct match part, it could have added or removed the node it changed on
- If it is on the context part, it could have added or removed any node that were previously included or excluded because of a match or failure to match with the context required on that node
- NOTE: It might be on _both_
*/
var method = rule.selector.affectedBy(changes);
if (method.classes.context) {
full = true;
}
else {
for (var k in method.classes.direct) {
calcmatched(j);
var recheck = changes.classes[k].not(matched);
if (res === null) {
res = rule.cache ? rule.cache.not(taken).add(released.filter(sel)) : $([]);
}
res = res.not(recheck).add(recheck.filter(sel));
}
}
}
if (full) {
calcmatched(j);
res = $(sel).not(matched);
}
else {
if (!res) {
// We weren't stale because of any changes to the DOM that affected this selector, but more specific
// onmatches might have caused stale-ness
// Do any of the previous released elements match this selector?
add = released.length && released.filter(sel);
if (add && add.length) {
// Yes, so we're stale as we need to include them. Filter for any possible taken value at the same time
res = rule.cache ? rule.cache.not(taken).add(add) : add;
}
else {
// Do we think we own any of the elements now taken by more specific rules?
rem = taken.length && rule.cache && rule.cache.filter(taken);
if (rem && rem.length) {
// Yes, so we're stale as we need to exclude them.
res = rule.cache.not(rem);
}
}
}
}
// Res will be null if we know we are fresh (no full needed, selector not affectedBy changes)
if (res === null) {
// If we are tracking matched, add ourselves
if (matched && rule.cache) matched = matched.add(rule.cache);
}
else {
// If this selector has a list of elements it matched against last time
if (rule.cache) {
// Find the ones that are extra this time
add = res.not(rule.cache);
rem = rule.cache.not(res);
}
else {
add = res; rem = null;
}
if ((add && add.length) || (rem && rem.length)) {
if (rem && rem.length) {
released = released.add(rem);
if (dtor && !rule.onunmatchRunning) {
rule.onunmatchRunning = true;
ctors.onunmatchproxy(rem, j, dtor);
rule.onunmatchRunning = false;
}
}
// Call the constructor on the newly matched ones
if (add && add.length) {
taken = taken.add(add);
released = released.not(add);
if (ctor && !rule.onmatchRunning) {
rule.onmatchRunning = true;
ctors.onmatchproxy(add, j, ctor);
rule.onmatchRunning = false;
}
}
}
// If we are tracking matched, add ourselves
if (matched) matched = matched.add(res);
// And remember this list of matching elements again this selector, so next matching we can find the unmatched ones
rule.cache = res;
}
}
namespace.matchersDirty = false;
}
}
// console.log((new Date).getTime() - start);
});
})(jQuery);

View File

@ -1,111 +0,0 @@
(function($) {
$.entwine.Namespace.addMethods({
bind_capture: function(selector, event, name, capture) {
var store = this.captures || (this.captures = {});
var rulelists = store[event] || (store[event] = {});
var rulelist = rulelists[name] || (rulelists[name] = $.entwine.RuleList());
rule = rulelist.addRule(selector, event);
rule.handler = name;
this.bind_proxy(selector, name, capture);
}
});
var bindings = $.entwine.capture_bindings = {};
var event_proxy = function(event) {
return function(e) {
var namespace, capturelists, forevent, capturelist, rule, handler, sel;
for (var k in $.entwine.namespaces) {
namespace = $.entwine.namespaces[k];
capturelists = namespace.captures;
if (capturelists && (forevent = capturelists[event])) {
for (var k in forevent) {
var capturelist = forevent[k];
var triggered = namespace.$([]);
// Stepping through each selector from most to least specific
var j = capturelist.length;
while (j--) {
rule = capturelist[j];
handler = rule.handler;
sel = rule.selector.selector;
var matching = namespace.$(sel).not(triggered);
matching[handler].apply(matching, arguments);
triggered = triggered.add(matching);
}
}
}
}
}
};
var selector_proxy = function(selector, handler, includechildren) {
var matcher = $.selector(selector);
return function(e){
if (matcher.matches(e.target)) return handler.apply(this, arguments);
}
};
var window_proxy = function(selector, handler, includechildren) {
return function(e){
if (e.target === window) return handler.apply(this, arguments);
}
};
var property_proxy = function(property, handler, includechildren) {
var matcher;
return function(e){
var match = this['get'+property]();
if (typeof(match) == 'string') {
var matcher = (matcher && match == matcher.selector) ? matcher : $.selector(match);
if (matcher.matches(e.target)) return handler.apply(this, arguments);
}
else {
if ($.inArray(e.target, match) !== -1) return handler.apply(this, arguments);
}
}
};
$.entwine.Namespace.addHandler({
order: 10,
bind: function(selector, k, v) {
var match;
if ($.isPlainObject(v) && (match = k.match(/^from\s*(.*)/))) {
var from = match[1];
var proxyGen;
if (from.match(/[^\w]/)) proxyGen = selector_proxy;
else if (from == 'Window' || from == 'window') proxyGen = window_proxy;
else proxyGen = property_proxy;
for (var onevent in v) {
var handler = v[onevent];
match = onevent.match(/^on(.*)/);
var event = match[1];
this.bind_capture(selector, event, k + '_' + event, proxyGen(from, handler));
if (!bindings[event]) {
var namespaced = event.replace(/(\s+|$)/g, '.entwine$1');
bindings[event] = event_proxy(event);
$(proxyGen == window_proxy ? window : document).bind(namespaced, bindings[event]);
}
}
return true;
}
}
});
})(jQuery);

View File

@ -1,249 +0,0 @@
(function($) {
/** Taken from jQuery 1.5.2 for backwards compatibility */
if ($.support.changeBubbles == undefined) {
$.support.changeBubbles = true;
var el = document.createElement("div");
eventName = "onchange";
if (el.attachEvent) {
var isSupported = (eventName in el);
if (!isSupported) {
el.setAttribute(eventName, "return;");
isSupported = typeof el[eventName] === "function";
}
$.support.changeBubbles = isSupported;
}
}
/* Return true if node b is the same as, or is a descendant of, node a */
if (document.compareDocumentPosition) {
var is_or_contains = function(a, b) {
return a && b && (a == b || !!(a.compareDocumentPosition(b) & 16));
};
}
else {
var is_or_contains = function(a, b) {
return a && b && (a == b || (a.contains ? a.contains(b) : true));
};
}
/* Add the methods to handle event binding to the Namespace class */
$.entwine.Namespace.addMethods({
build_event_proxy: function(name) {
var one = this.one(name, 'func');
var prxy = function(e, data) {
// For events that do not bubble we manually trigger delegation (see delegate_submit below)
// If this event is a manual trigger, the event we actually want to bubble is attached as a property of the passed event
e = e.delegatedEvent || e;
var el = e.target;
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
var ret = one(el, arguments);
if (ret !== undefined) e.result = ret;
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
el = el.parentNode;
}
};
return prxy;
},
build_mouseenterleave_proxy: function(name) {
var one = this.one(name, 'func');
var prxy = function(e) {
var el = e.target;
var rel = e.relatedTarget;
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
/* We know el contained target. If it also contains relatedTarget then we didn't mouseenter / leave. What's more, every ancestor will also
contan el and rel, and so we can just stop bubbling */
if (is_or_contains(el, rel)) break;
var ret = one(el, arguments);
if (ret !== undefined) e.result = ret;
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
el = el.parentNode;
}
};
return prxy;
},
build_change_proxy: function(name) {
var one = this.one(name, 'func');
/*
This change bubble emulation code is taken mostly from jQuery 1.6 - unfortunately we can't easily reuse any of
it without duplication, so we'll have to re-migrate any bugfixes
*/
// Get the value of an item. Isn't supposed to be interpretable, just stable for some value, and different
// once the value changes
var getVal = function( elem ) {
var type = elem.type, val = elem.value;
if (type === "radio" || type === "checkbox") {
val = elem.checked;
}
else if (type === "select-multiple") {
val = "";
if (elem.selectedIndex > -1) {
val = jQuery.map(elem.options, function(elem){ return elem.selected; }).join("-");
}
}
else if (jQuery.nodeName(elem, "select")) {
val = elem.selectedIndex;
}
return val;
};
// Test if a node name is a form input
var rformElems = /^(?:textarea|input|select)$/i;
// Check if this event is a change, and bubble the change event if it is
var testChange = function(e) {
var elem = e.target, data, val;
if (!rformElems.test(elem.nodeName) || elem.readOnly) return;
data = jQuery.data(elem, "_entwine_change_data");
val = getVal(elem);
// the current data will be also retrieved by beforeactivate
if (e.type !== "focusout" || elem.type !== "radio") {
jQuery.data(elem, "_entwine_change_data", val);
}
if (data === undefined || val === data) return;
if (data != null || val) {
e.type = "change";
while (elem && elem.nodeType == 1 && !e.isPropagationStopped()) {
var ret = one(elem, arguments);
if (ret !== undefined) e.result = ret;
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
elem = elem.parentNode;
}
}
};
// The actual proxy - responds to several events, some of which triger a change check, some
// of which just store the value for future change checks
var prxy = function(e) {
var event = e.type, elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
switch (event) {
case 'focusout':
case 'beforedeactivate':
testChange.apply(this, arguments);
break;
case 'click':
if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
testChange.apply(this, arguments);
}
break;
// Change has to be called before submit
// Keydown will be called before keypress, which is used in submit-event delegation
case 'keydown':
if (
(e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
type === "select-multiple"
) {
testChange.apply(this, arguments);
}
break;
// Beforeactivate happens also before the previous element is blurred
// with this event you can't trigger a change event, but you can store
// information
case 'focusin':
case 'beforeactivate':
jQuery.data( elem, "_entwine_change_data", getVal(elem) );
break;
}
}
return prxy;
},
bind_event: function(selector, name, func, event) {
var funcs = this.store[name] || (this.store[name] = $.entwine.RuleList()) ;
var proxies = funcs.proxies || (funcs.proxies = {});
var rule = funcs.addRule(selector, name); rule.func = func;
if (!proxies[name]) {
switch (name) {
case 'onmouseenter':
proxies[name] = this.build_mouseenterleave_proxy(name);
event = 'mouseover';
break;
case 'onmouseleave':
proxies[name] = this.build_mouseenterleave_proxy(name);
event = 'mouseout';
break;
case 'onchange':
if (!$.support.changeBubbles) {
proxies[name] = this.build_change_proxy(name);
event = 'click keydown focusin focusout beforeactivate beforedeactivate';
}
break;
case 'onsubmit':
event = 'delegatedSubmit';
break;
case 'onfocus':
case 'onblur':
$.entwine.warn('Event '+event+' not supported - using focusin / focusout instead', $.entwine.WARN_LEVEL_IMPORTANT);
}
// If none of the special handlers created a proxy, use the generic proxy
if (!proxies[name]) proxies[name] = this.build_event_proxy(name);
$(document).bind(event.replace(/(\s+|$)/g, '.entwine$1'), proxies[name]);
}
}
});
$.entwine.Namespace.addHandler({
order: 40,
bind: function(selector, k, v){
var match, event;
if ($.isFunction(v) && (match = k.match(/^on(.*)/))) {
event = match[1];
this.bind_event(selector, k, v, event);
return true;
}
}
});
// Find all forms and bind onsubmit to trigger on the document too.
// This is the only event that can't be grabbed via delegation
var delegate_submit = function(e, data){
var delegationEvent = $.Event('delegatedSubmit'); delegationEvent.delegatedEvent = e;
return $(document).trigger(delegationEvent, data);
};
$(document).bind('EntwineElementsAdded', function(e){
var forms = $(e.targets).filter('form');
if (!forms.length) return;
forms.bind('submit.entwine_delegate_submit', delegate_submit);
});
})(jQuery);

View File

@ -1,240 +0,0 @@
jQuery(function($){
// Create a new style element
var styleEl = document.createElement('style');
styleEl.setAttribute('type', 'text/css');
(document.head || document.getElementsByTagName('head')[0]).appendChild(styleEl);
var inspectorCSS = [
'#entwine-inspector { position: fixed; z-index: 1000001; left: 0; right: 0; height: 400px; background: white; -webkit-box-shadow: 0 5px 40px 0 black; -moz-box-shadow: 0 5px 40px 0 black; }',
'#entwine-inspector li { list-style: none; margin: 2px 0; padding: 2px 0; }',
'#entwine-inspector li:hover { background: #eee; }',
'#entwine-inspector li.selected { background: #ddd; }',
'#ei-columns { overflow: hidden; display: -webkit-box; display: -moz-box; width: 100%; height: 380px; }',
'.ei-column { height: 380px; width: 1px; -webkit-box-flex: 1; -moz-box-flex: 1; }',
'#entwine-inspector .ei-column h1 { display: block; margin: 0; padding: 5px 2px; height: 20px; text-align: center; background: #444; color: #eee; font-size: 14px; font-weight: bold; }',
'#entwine-inspector .ei-column ul { overflow-y: scroll; height: 350px; }',
'#ei-options { overflow: hidden; height: 20px; background: #444; color: #eee; }',
'#ei-options label { padding-right: 5px; border-right: 1px solid #eee; }',
'.ei-entwined:hover, .ei-selected { background: rgba(128,0,0,0.2); }',
'.ei-hovernode { position: absolute; z-index: 1000000; background: rgba(0,0,0,0.3); border: 1px solid white; outline: 1px solid white; }',
'#ei-selectors li { color: #aaa; display: none; }',
'#ei-selectors li.matching, #entwine-inspector.show-unmatched #ei-selectors li { display: block; }',
'#ei-selectors li.matching { color: black; }'
].join("\n");
// Set the style element to style up the inspector panel
if(styleEl.styleSheet){
styleEl.styleSheet.cssText = inspectorCSS;
}else{
styleEl.appendChild(document.createTextNode(inspectorCSS));
}
var inspectorPanel = $('<div id="entwine-inspector" class="show-unmatched"></div>').appendTo('body');
var columnHolder = $('<div id="ei-columns"></div>').appendTo(inspectorPanel);
var optionsHolder = $('<div id="ei-options"></div>').appendTo(inspectorPanel);
inspectorPanel.css({
top: -400,
visibility: 'hidden'
});
$('body').bind('keypress', function(e){
if (e.ctrlKey && e.which == 96) {
if (inspectorPanel.css('visibility') != 'visible') {
inspectorPanel.css({top: 0, visibility: 'visible'});
$('body').css({marginTop: 400});
initialise();
}
else {
inspectorPanel.css({top: -400, visibility: 'hidden'});
$('body').css({marginTop: 0});
reset();
}
return false;
}
});
var showUnmatching = $('<input id="ei-option-showunmatching" type="checkbox" checked="checked" />').appendTo(optionsHolder);
var showUnmatchingLabel = $('<label>Show selectors that dont match</label>').appendTo(optionsHolder);
showUnmatching.bind('click', function(){
inspectorPanel.toggleClass('show-unmatched', $(this).val());
});
var hovernode;
var reset = function() {
$('.ei-entwined').unbind('.entwine-inspector').removeClass('ei-entwined');
if (hovernode) hovernode.remove();
}
var initialise = function(){
reset();
$.each($.entwine.namespaces, function(name, namespace){
$.each(namespace.store, function(name, list){
$.each(list, function(i, rule){
var match = $(rule.selector.selector);
match.addClass('ei-entwined').bind('click.entwine-inspector', displaydetails);
})
});
});
};
var dumpElement = function(el) {
var frag = document.createDocumentFragment();
var div = document.createElement('div'); frag.appendChild(div);
var clone = el.cloneNode(false); $(clone).removeClass('ei-entwined').removeAttr('style');
var i = clone.attributes.length;
while (i--) {
var attr = clone.attributes.item(i);
if (attr.name != 'class' && attr.name != 'id' && attr.value.length > 20) attr.value = attr.value.substr(0, 18)+'..'+attr.value.substr(-2);
}
div.appendChild(clone);
return div.innerHTML;
};
var displaydetails = function(e){
e.preventDefault(); e.stopPropagation();
columnHolder.empty();
var columns = {};
$.each(['elements', 'namespaces', 'methods', 'selectors'], function(i, col){
columns[col] = $('<div id="ei-'+col+'" class="ei-column"><h1>'+col+'</h1></div>').appendTo(columnHolder);
})
var lists = {};
var ctr = 0;
lists.elements = $('<ul></ul>').appendTo(columns.elements);
var displayelement = function(){
var target = $(this);
var li = $('<li></li>');
li.text(dumpElement(this)).attr('data-id', ++ctr).data('el', target).prependTo(lists.elements);
var namespaces = $('<ul data-element="'+ctr+'"></ul>').appendTo(columns.namespaces);
$.each($.entwine.namespaces, function(name, namespace){
var methods = $('<ul data-namespace="'+ctr+'-'+name+'"></ul>');
$.each(namespace.store, function(method, list){
if (method == 'ctors') {
var matchselectors = $('<ul data-method="'+ctr+'-'+name+'-onmatch"></ul>');
var unmatchselectors = $('<ul data-method="'+ctr+'-'+name+'-onunmatch"></ul>');
$.each(list, function(i, rule){
var matchitem = $('<li>'+rule.selector.selector+'</li>').prependTo(matchselectors);
var unmatchitem = rule.onunmatch ? $('<li>'+rule.selector.selector+'</li>').prependTo(unmatchselectors) : null;
if (target.is(rule.selector.selector)) {
matchitem.addClass('matching'); unmatchitem && unmatchitem.addClass('matching');
if (!methods.parent().length) {
$('<li data-namespace="'+ctr+'-'+name+'">'+name+'</li>').prependTo(namespaces);
methods.appendTo(columns.methods);
}
if (!matchselectors.parent().length) {
$('<li data-method="'+ctr+'-'+name+'-onmatch">onmatch</li>').prependTo(methods);
matchselectors.appendTo(columns.selectors);
}
if (rule.onunmatch && !unmatchselectors.parent().length) {
$('<li data-method="'+ctr+'-'+name+'-onunmatch">onunmatch</li>').prependTo(methods);
unmatchselectors.appendTo(columns.selectors);
}
}
});
}
else {
var selectors = $('<ul data-method="'+ctr+'-'+name+'-'+method+'"></ul>');
$.each(list, function(i, rule){
var ruleitem = $('<li>'+rule.selector.selector+'</li>').prependTo(selectors);
if (target.is(rule.selector.selector)){
ruleitem.addClass('matching');
if (!methods.parent().length) {
$('<li data-namespace="'+ctr+'-'+name+'">'+name+'</li>').prependTo(namespaces);
methods.appendTo(columns.methods);
}
if (!selectors.parent().length) {
$('<li data-method="'+ctr+'-'+name+'-'+method+'">'+method+'</li>').prependTo(methods);
selectors.appendTo(columns.selectors);
}
}
})
}
});
});
};
$.each($(e.target).parents().andSelf().filter('.ei-entwined'), displayelement);
$('#ei-elements > ul:first > li:first').click();
}
var activatelist = function(list) {
list = $(list);
list.siblings('ul').css('display', 'none');
list.css('display', 'block');
list.children().first().click();
}
$('#entwine-inspector').live('mouseleave', function(){
if (hovernode) hovernode.hide();
})
$('#entwine-inspector').live('mouseenter', function(){
if (hovernode) hovernode.show();
})
$('#ei-elements > ul > li').live('click', function(e){
var target = $(e.target), id = target.attr('data-id');
target.addClass('selected').siblings().removeClass('selected');
if (!hovernode) {
hovernode = $('<div class="ei-hovernode"></div>').appendTo('body');
}
var hover = target.data('el');
hovernode.css({width: hover.outerWidth()-2, height: hover.outerHeight()-2, top: hover.offset().top, left: hover.offset().left});
$('.ei-selected').removeClass('ei-selected');
activatelist('#ei-namespaces ul[data-element="'+id+'"]');
});
$('#ei-namespaces > ul > li').live('click', function(e){
var target = $(e.target), namespace = target.attr('data-namespace');
target.addClass('selected').siblings().removeClass('selected');
activatelist('#ei-methods ul[data-namespace="'+namespace+'"]');
});
$('#ei-methods > ul > li').live('click', function(e){
var target = $(e.target), method = target.attr('data-method');
target.addClass('selected').siblings().removeClass('selected');
activatelist('#ei-selectors ul[data-method="'+method+'"]');
});
});

View File

@ -1,369 +0,0 @@
try {
console.log;
}
catch (e) {
window.console = undefined;
}
(function($) {
var namespaces = {};
$.entwine = function() {
$.fn.entwine.apply(null, arguments);
};
/**
* A couple of utility functions for accessing the store outside of this closure, and for making things
* operate in a little more easy-to-test manner
*/
$.extend($.entwine, {
/**
* Get all the namespaces. Useful for introspection? Internal interface of Namespace not guaranteed consistant
*/
namespaces: namespaces,
/**
* Remove all entwine rules
*/
clear_all_rules: function() {
// Remove proxy functions
for (var k in $.fn) { if ($.fn[k].isentwinemethod) delete $.fn[k]; }
// Remove bound events - TODO: Make this pluggable, so this code can be moved to jquery.entwine.events.js
$(document).unbind('.entwine');
$(window).unbind('.entwine');
// Remove namespaces, and start over again
for (var k in namespaces) delete namespaces[k];
for (var k in $.entwine.capture_bindings) delete $.entwine.capture_bindings[k];
},
WARN_LEVEL_NONE: 0,
WARN_LEVEL_IMPORTANT: 1,
WARN_LEVEL_BESTPRACTISE: 2,
/**
* Warning level. Set to a higher level to get warnings dumped to console.
*/
warningLevel: 0,
/** Utility to optionally display warning messages depending on level */
warn: function(message, level) {
if (level <= $.entwine.warningLevel && console && console.warn) {
console.warn(message);
if (console.trace) console.trace();
}
},
warn_exception: function(where, /* optional: */ on, e) {
if ($.entwine.WARN_LEVEL_IMPORTANT <= $.entwine.warningLevel && console && console.warn) {
if (arguments.length == 2) { e = on; on = null; }
if (on) console.warn('Uncaught exception',e,'in',where,'on',on);
else console.warn('Uncaught exception',e,'in',where);
if (e.stack) console.warn("Stack Trace:\n" + e.stack);
}
}
});
/** Stores a count of definitions, so that we can sort identical selectors by definition order */
var rulecount = 0;
var Rule = Base.extend({
init: function(selector, name) {
this.selector = selector;
this.specifity = selector.specifity();
this.important = 0;
this.name = name;
this.rulecount = rulecount++;
}
});
Rule.compare = function(a, b) {
var as = a.specifity, bs = b.specifity;
return (a.important - b.important) ||
(as[0] - bs[0]) ||
(as[1] - bs[1]) ||
(as[2] - bs[2]) ||
(a.rulecount - b.rulecount) ;
};
$.entwine.RuleList = function() {
var list = [];
list.addRule = function(selector, name){
var rule = Rule(selector, name);
list[list.length] = rule;
list.sort(Rule.compare);
return rule;
};
return list;
};
var handlers = [];
/**
* A Namespace holds all the information needed for adding entwine methods to a namespace (including the _null_ namespace)
*/
$.entwine.Namespace = Base.extend({
init: function(name){
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.entwine.warn('Entwine namespace '+name+' is not formatted as period seperated identifiers', $.entwine.WARN_LEVEL_BESTPRACTISE);
name = name || '__base';
this.name = name;
this.store = {};
namespaces[name] = this;
if (name == "__base") {
this.injectee = $.fn;
this.$ = $;
}
else {
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
// jQuery 1.5 already provides a nice way to subclass, so use it
if ($.sub) {
this.$ = $.sub();
this.injectee = this.$.prototype;
}
// For jQuery < 1.5 we have to do it ourselves
else {
var subfn = function(){};
this.injectee = subfn.prototype = new $;
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
var bound$ = this.$ = function(a) {
// Try the simple way first
var jq = $.fn.init.apply(new subfn(), arguments);
if (jq instanceof subfn) return jq;
// That didn't return a bound object, so now we need to copy it
var rv = new subfn();
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
while (i--) rv[i] = jq[i];
return rv;
};
this.injectee.pushStack = function(elems, name, selector){
var ret = bound$(elems);
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) ret.selector = this.selector + (this.selector ? " " : "") + selector;
else if ( name ) ret.selector = this.selector + "." + name + "(" + selector + ")";
// Return the newly-formed element set
return ret;
};
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
$.extend(this.$, $);
}
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
var entwine_wrapper = this.injectee.entwine = function(spacename) {
var args = arguments;
if (!spacename || typeof spacename != 'string') { args = $.makeArray(args); args.unshift(name); }
else if (spacename.charAt(0) != '.') args[0] = name+'.'+spacename;
return $.fn.entwine.apply(this, args);
};
this.$.entwine = function() {
entwine_wrapper.apply(null, arguments);
};
for (var i = 0; i < handlers.length; i++) {
var handler = handlers[i], builder;
// Inject jQuery object method overrides
if (builder = handler.namespaceMethodOverrides) {
var overrides = builder(this);
for (var k in overrides) this.injectee[k] = overrides[k];
}
// Inject $.entwine function overrides
if (builder = handler.namespaceStaticOverrides) {
var overrides = builder(this);
for (var k in overrides) this.$.entwine[k] = overrides[k];
}
}
}
},
/**
* Returns a function that does selector matching against the function list for a function name
* Used by proxy for all calls, and by ctorProxy to handle _super calls
* @param {String} name - name of the function as passed in the construction object
* @param {String} funcprop - the property on the Rule object that gives the actual function to call
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
*/
one: function(name, funcprop, basefunc) {
var namespace = this;
var funcs = this.store[name];
var one = function(el, args, i){
if (i === undefined) i = funcs.length;
while (i--) {
if (funcs[i].selector.matches(el)) {
var ret, tmp_i = el.i, tmp_f = el.f;
el.i = i; el.f = one;
try { ret = funcs[i][funcprop].apply(namespace.$(el), args); }
finally { el.i = tmp_i; el.f = tmp_f; }
return ret;
}
}
// If we didn't find a entwine-defined function, but there is a non-entwine function to use as a base, try that
if (basefunc) return basefunc.apply(namespace.$(el), args);
};
return one;
},
/**
* A proxy is a function attached to a callable object (either the base jQuery.fn or a subspace object) which handles
* finding and calling the correct function for each member of the current jQuery context
* @param {String} name - name of the function as passed in the construction object
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
*/
build_proxy: function(name, basefunc) {
var one = this.one(name, 'func', basefunc);
var prxy = function() {
var rv, ctx = $(this);
var i = ctx.length;
while (i--) rv = one(ctx[i], arguments);
return rv;
};
return prxy;
},
bind_proxy: function(selector, name, func) {
var rulelist = this.store[name] || (this.store[name] = $.entwine.RuleList());
var rule = rulelist.addRule(selector, name); rule.func = func;
if (!this.injectee.hasOwnProperty(name) || !this.injectee[name].isentwinemethod) {
this.injectee[name] = this.build_proxy(name, this.injectee.hasOwnProperty(name) ? this.injectee[name] : null);
this.injectee[name].isentwinemethod = true;
}
if (!this.injectee[name].isentwinemethod) {
$.entwine.warn('Warning: Entwine function '+name+' clashes with regular jQuery function - entwine function will not be callable directly on jQuery object', $.entwine.WARN_LEVEL_IMPORTANT);
}
},
add: function(selector, data) {
// For every item in the hash, try ever method handler, until one returns true
for (var k in data) {
var v = data[k];
for (var i = 0; i < handlers.length; i++) {
if (handlers[i].bind && handlers[i].bind.call(this, selector, k, v)) break;
}
}
},
has: function(ctx, name) {
var rulelist = this.store[name];
if (!rulelist) return false;
/* We go forward this time, since low specifity is likely to knock out a bunch of elements quickly */
for (var i = 0 ; i < rulelist.length; i++) {
ctx = ctx.not(rulelist[i].selector);
if (!ctx.length) return true;
}
return false;
}
});
/**
* A handler is some javascript code that adds support for some time of key / value pair passed in the hash to the Namespace add method.
* The default handlers provided (and included by default) are event, ctor and properties
*/
$.entwine.Namespace.addHandler = function(handler) {
for (var i = 0; i < handlers.length && handlers[i].order < handler.order; i++) { /* Pass */ }
handlers.splice(i, 0, handler);
};
$.entwine.Namespace.addHandler({
order: 50,
bind: function(selector, k, v){
if ($.isFunction(v)) {
this.bind_proxy(selector, k, v);
return true;
}
}
});
$.extend($.fn, {
/**
* Main entwine function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
*
*/
entwine: function(spacename) {
var i = 0;
/* Don't actually work out selector until we try and define something on it - we might be opening a namespace on an function-traveresed object
which have non-standard selectors like .parents(.foo).slice(0,1) */
var selector = null;
/* By default we operator on the base namespace */
var namespace = namespaces.__base || $.entwine.Namespace();
/* If the first argument is a string, then it's the name of a namespace. Look it up */
if (typeof spacename == 'string') {
if (spacename.charAt('0') == '.') spacename = spacename.substr(1);
if (spacename) namespace = namespaces[spacename] || $.entwine.Namespace(spacename);
i=1;
}
/* All remaining arguments should either be using blocks or definition hashs */
while (i < arguments.length) {
var res = arguments[i++];
// If it's a function, call it - either it's a using block or it's a namespaced entwine definition
if ($.isFunction(res)) {
if (res.length != 1) $.entwine.warn('Function block inside entwine definition does not take $ argument properly', $.entwine.WARN_LEVEL_IMPORTANT);
res = res.call(namespace.$(this), namespace.$);
}
// If we have a entwine definition hash, inject it into namespace
if (res) {
if (selector === null) selector = this.selector ? $.selector(this.selector) : false;
if (selector) namespace.add(selector, res);
else $.entwine.warn('Entwine block given to entwine call without selector. Make sure you call $(selector).entwine when defining blocks', $.entwine.WARN_LEVEL_IMPORTANT);
}
}
/* Finally, return the jQuery object 'this' refers to, wrapped in the new namespace */
return namespace.$(this);
},
/**
* Calls the next most specific version of the current entwine method
*/
_super: function(){
var rv, i = this.length;
while (i--) {
var el = this[0];
rv = el.f(el, arguments, el.i);
}
return rv;
}
});
})(jQuery);

View File

@ -1,21 +0,0 @@
(function($) {
// Adds back concrete methods for backwards compatibility
$.concrete = $.entwine;
$.fn.concrete = $.fn.entwine;
$.fn.concreteData = $.fn.entwineData;
// Use addHandler to hack in the namespace.$.concrete equivilent to the namespace.$.entwine namespace-injection
$.entwine.Namespace.addHandler({
order: 100,
bind: function(selector, k, v) { return false; },
namespaceMethodOverrides: function(namespace){
namespace.$.concrete = namespace.$.entwine;
namespace.injectee.concrete = namespace.injectee.entwine;
namespace.injectee.concreteData = namespace.injectee.entwineData;
return {};
}
});
})(jQuery);

View File

@ -1,85 +0,0 @@
(function($) {
var entwine_prepend = '__entwine!';
var getEntwineData = function(el, namespace, property) {
return el.data(entwine_prepend + namespace + '!' + property);
};
var setEntwineData = function(el, namespace, property, value) {
return el.data(entwine_prepend + namespace + '!' + property, value);
};
var getEntwineDataAsHash = function(el, namespace) {
var hash = {};
var id = jQuery.data(el[0]);
var matchstr = entwine_prepend + namespace + '!';
var matchlen = matchstr.length;
var cache = jQuery.cache[id];
for (var k in cache) {
if (k.substr(0,matchlen) == matchstr) hash[k.substr(matchlen)] = cache[k];
}
return hash;
};
var setEntwineDataFromHash = function(el, namespace, hash) {
for (var k in hash) setEntwineData(namespace, k, hash[k]);
};
var entwineData = function(el, namespace, args) {
switch (args.length) {
case 0:
return getEntwineDataAsHash(el, namespace);
case 1:
if (typeof args[0] == 'string') return getEntwineData(el, namespace, args[0]);
else return setEntwineDataFromHash(el, namespace, args[0]);
default:
return setEntwineData(el, namespace, args[0], args[1]);
}
};
$.extend($.fn, {
entwineData: function() {
return entwineData(this, '__base', arguments);
}
});
$.entwine.Namespace.addHandler({
order: 60,
bind: function(selector, k, v) {
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.entwine.warn('Entwine property '+k+' does not start with a capital letter', $.entwine.WARN_LEVEL_BESTPRACTISE);
// Create the getters and setters
var getterName = 'get'+k;
var setterName = 'set'+k;
this.bind_proxy(selector, getterName, function() { var r = this.entwineData(k); return r === undefined ? v : r; });
this.bind_proxy(selector, setterName, function(v){ return this.entwineData(k, v); });
// Get the get and set proxies we just created
var getter = this.injectee[getterName];
var setter = this.injectee[setterName];
// And bind in the jQuery-style accessor
this.bind_proxy(selector, k, function(v){ return (arguments.length == 1 ? setter : getter).call(this, v) ; });
return true;
},
namespaceMethodOverrides: function(namespace){
return {
entwineData: function() {
return entwineData(this, namespace.name, arguments);
}
};
}
});
})(jQuery);

View File

@ -1,49 +0,0 @@
(function($){
/**
* Add focusin and focusout support to bind and live for browers other than IE. Designed to be usable in a delegated fashion (like $.live)
* Copyright (c) 2007 Jörn Zaefferer
*/
$.support.focusInOut = !!($.browser.msie);
if (!$.support.focusInOut) {
// Emulate focusin and focusout by binding focus and blur in capturing mode
$.each({focus: 'focusin', blur: 'focusout'}, function(original, fix){
$.event.special[fix] = {
setup: function(){
if (!this.addEventListener) return false;
this.addEventListener(original, $.event.special[fix].handler, true);
},
teardown: function(){
if (!this.removeEventListener) return false;
this.removeEventListener(original, $.event.special[fix].handler, true);
},
handler: function(e){
arguments[0] = $.event.fix(e);
arguments[0].type = fix;
return $.event.handle.apply(this, arguments);
}
};
});
}
(function(){
//IE has some trouble with focusout with select and keyboard navigation
var activeFocus = null;
$(document)
.bind('focusin', function(e){
var target = e.realTarget || e.target;
if (activeFocus && activeFocus !== target) {
e.type = 'focusout';
$(activeFocus).trigger(e);
e.type = 'focusin';
e.target = target;
}
activeFocus = target;
})
.bind('focusout', function(e){
activeFocus = null;
});
})();
})(jQuery);

View File

@ -1,58 +0,0 @@
(function($) {
// TODO:
// Make attributes & IDs work
var DIRECT = /DIRECT/g;
var CONTEXT = /CONTEXT/g;
var EITHER = /DIRECT|CONTEXT/g;
$.selector.SelectorBase.addMethod('affectedBy', function(props) {
this.affectedBy = new Function('props', ([
'var direct_classes, context_classes, direct_attrs, context_attrs, t;',
this.ABC_compile().replace(DIRECT, 'direct').replace(CONTEXT, 'context'),
'return {classes: {context: context_classes, direct: direct_classes}, attrs: {context: context_attrs, direct: direct_attrs}};'
]).join("\n"));
// DEBUG: Print out the compiled funciton
// console.log(this.selector, ''+this.affectedBy);
return this.affectedBy(props);
});
$.selector.SimpleSelector.addMethod('ABC_compile', function() {
var parts = [];
$.each(this.classes, function(i, cls){
parts[parts.length] = "if (t = props.classes['"+cls+"']) (DIRECT_classes || (DIRECT_classes = {}))['"+cls+"'] = t;";
});
$.each(this.nots, function(i, not){
parts[parts.length] = not.ABC_compile();
});
return parts.join("\n");
});
$.selector.Selector.addMethod('ABC_compile', function(arg){
var parts = [];
var i = this.parts.length-1;
parts[parts.length] = this.parts[i].ABC_compile();
while ((i = i - 2) >= 0) parts[parts.length] = this.parts[i].ABC_compile().replace(EITHER, 'CONTEXT');
return parts.join("\n");
});
$.selector.SelectorsGroup.addMethod('ABC_compile', function(){
var parts = [];
$.each(this.parts, function(i,part){
parts[parts.length] = part.ABC_compile();
});
return parts.join("\n");
});
})(jQuery);

View File

@ -1,105 +0,0 @@
== Firebug Lite Change Log ==
2009-03-09 Azer Koculu <azer@kodfabrik.com>
* firebug-lite.js: Removed getElementPosXY method.
Added toggle method to settings object.
2009-03-07 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed issue 1554: Text nodes could not be accessed through the inspect button.
2009-03-07 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1566: Added firebug.env.targetWindow variable to hold target window
2009-03-06 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Changed default for firebug.env.detectFirebug to false
Fixed issue 1555: Ajax calls ... we should not assume that the same domain policy is applied, use try catch instead
Fixed Issue 1541: Add XHR tab to Firebug Lite popup window
progress.gif: Corrected mime type
2009-03-03 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js, firebug-lite.css, progress.gif: Fixed Issue 1544: Lite settings menu should have a "processing" gif
2009-02-21 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed Issue 1542: FBLite F12 etc should dock the popup instead of hiding the panel
2009-02-21 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js, firebug-lite.css:
o Issue 1513 ... added:
- Settings dialog
- Settings storage cookie (stores settings, panel height, popup window positions etc.)
- firebug.env:
openInPopup
popupTop
popupLeft
popupWidth
popupHeight
o Various popup window bugfixes and performance improvements
2009-02-21 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js, firebug-lite.css, firebug_logo.png: Issue 1503: FBLite should have a visible sign it is running when starting hidden.
Added FBLite icon when hidden and firebug.env.showIconWhenHidden (default true).
2009-02-18 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed issue 1086 - FBLite can now be used locally over HTTPS if firebug.env.css is set.
2009-02-17 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed problem with issue 1481 - A DIV was created instead of an IFRAME so the shield was ineffective.
2009-02-14 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1487 - Added firebug.env.liteFilename ... this allows for the renaming of the FBLite script for use in popup windows.
2009-02-12 Azer Koculu <azer@kodfabrik.com>
* minifier.py, jsmin.py, minify: Added minifier library and compressing scripts.
2009-02-12 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Corrected 2 syntax errors
2009-02-11 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1400 - firebug.env.override is now false by default ... I have also added
two methods to make it easier for the user to control the console:
firebug.overrideConsole() & firebug.restoreConsole()
2009-02-09 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1400 - Re-implemented firebug.env.override. Default is now true ... it can only be manually changed in FBLite code.
The reason this is needed is because a number of browsers have a window.console object.
2009-02-08 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1406 - Added firebug.env.hideDOMFunctions to allow hiding of DOM functions in the DOM tab.
2009-02-06 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Removed firebug.env.override to prevent problems when override is set in FF3 where window.console
is a getter and allow more control over initialization.
* firebug-lite.js: Refactored code to allow firebug.env.detectFirebug to be set from user code
* firebug-lite.js: Moved console initialization code inside of the Firebug object to remove some global variables
* firebug-lite.js & firebug-lite.css: Fixed Issue 1348 - String, Date and Boolean objects should be displayed similar
to their primitive counterparts
* firebug-lite.js & firebug-lite.css: Fixed Issue 1023 - Elements such as Flash in iframes and dropdowns in IE bleed through FBLite,
I have put an iframe 'shield' behind FBLite to prevent this
* Updated mime-types for all FBLite SVN files
2009-02-05 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Added firebug.env.detectFirebug to prevent FBLite opening when Firebug is enabled (actually the Firebug Console).
To run FBLite and Firebug at the same time it is now necessary to change the value of detectFirebug directly in firebug-lite.js
* Fixed multiple console initialization and override issues
2009-02-05 Azer Koculu <azer@kodfabrik.com>
* firebug-lite.css: mime-type property has been set to "text/css".
2009-02-04 Azer Koculu <azer@kodfabrik.com>
* firebug-lite.js: Changed default css url getfirebug.com to fbug.google.com
* firebug-lite-compressed.js: It was unnecesseary, removed.
2009-02-02 Azer Koculu <azer@kodfabrik.com>
* Copied latest source to googlecode repository.
2009-01-31 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Added extra hotkeys to show / hide FBLite:
F12, (CTRL|CMD)+SHIFT+L, SHIFT+ENTER
* firebug-lite.js: Added console.firebug command to show FBLite version number
* firebug-lite.js: Fixed problem with Open in New Window in Safari
* firebug-lite.js: Added debug="true/false" to show or hide FBLite on startup
2009-01-01 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js & firebug-lite.css: Added Open in New Window
* firebug-lite.js: Fixed: HTML Inspect only worked in 1 very specific situation ... it now works in all situations
* firebug-lite.js: Fixed: Permission was occasionally denied to inspect CSS or scripts when it should not have been
* firebug-lite.js: Fixed: Domain check now works with domain names containing - and _

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

View File

@ -1,214 +0,0 @@
/* */
#Firebug div, #Firebug h3, #Firebug span, #Firebug input, #Firebug textarea, #Firebug select, #Firebug option, #Firebug a, #Firebug strong, #Firebug em, #Firebug label, #Firebug center {
position:static; float:none; width:auto; height:auto; text-align:left; border:0; overflow:visible; background:transparent none repeat left top; color:#111; font-size:1em; font-weight:normal; font-style:normal; font-family:sans-serif; margin:0; padding:0; min-height:0;
}
#Firebug input, #Firebug select, #Firebug textarea { background:#fff; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; border:1px outset #aaa; padding:2px }
#Firebug center { text-align:center; }
#Firebug strong { font-weight:bold; }
#Firebug em { font-style:italic; }
/* */
#FirebugIFrame { position:fixed !important; position:absolute; z-index:99999998; left:0; bottom:0; width:100%; height:295px; background:#fff; border-width:0px; }
#Firebug { position:fixed !important; position:absolute; z-index:99999999; left:0; bottom:0; width:100%; height:295px; background:#fff; overflow:hidden; }
#Firebug .Resizer { position:absolute; top:0; width:100%; height:5px; background:transparent; *background:url(spacer.gif); cursor:n-resize; -moz-user-select:none; }
#Firebug .Header { height:38px; background:#ccc url(firebug.gif) 0 -85px; }
#Firebug .Left, #Firebug > .Right { background:#fff; height:257px;}
#Firebug .Left { float:left; width:100%; }
#Firebug .Right { float:left; display:none; width:30%; overflow:hidden; }
#Firebug .Right .Container { height:100%; border-left:1px solid #ccc; }
/*
* buttonset
*/
#Firebug .ButtonContainer { padding:8px 0 5px 10px; *margin-top:-3px; _margin-top:0; }
#Firebug .ButtonContainer .Button { cursor:pointer; font:12px "MS Sans Serif", Geneva, sans-serif; color:#000; margin-right:5px; padding:4px 4px 4px 4px; border:1px solid transparent !important; border-color:#ccc; text-decoration:none; }
#Firebug .ButtonContainer .Button:hover { border:1px outset #aaa !important; }
#Firebug .ButtonContainer .Button:active { border-style:inset !important; background-color:#ccc; }
#Firebug .ButtonContainer .Enabled { border:1px outset #aaa !important; }
#Firebug .ButtonContainer .Logo { text-decoration:none; padding-left:24px; background:url(firebug.gif) no-repeat 5px 3px; border:0 !important; opacity:0.7; filter:Alpha(Opacity=70); }
#Firebug .ButtonContainer .Logo:hover, #Firebug .ButtonContainer .Logo:active { border:0 !important; background-color:transparent; opacity:1; filter:Alpha(Opacity=100); }
#Firebug .ButtonContainer .Maximize, #Firebug .ButtonContainer .Minimize, #Firebug .ButtonContainer .NewWindow, #Firebug .ButtonContainer .Dock, #Firebug .ButtonContainer .Close { position:absolute; right:0; top:12px; padding:6px 8px 8px 8px; background:url(firebug.gif) no-repeat -3px -48px; border:0 !important; opacity:0.7; filter:Alpha(Opacity:80); *padding:0px 7px 1px 7px; }
#Firebug .ButtonContainer .Maximize:hover, #Firebug .ButtonContainer .Maximize:active, #Firebug .ButtonContainer .NewWindow:hover, #Firebug .ButtonContainer .NewWindow:active, #Firebug .ButtonContainer .Dock:hover, #Firebug .ButtonContainer .Dock:active, #Firebug .ButtonContainer .Minimize:hover, #Firebug .ButtonContainer .Minimize:active, #Firebug .ButtonContainer .Close:hover, #Firebug .ButtonContainer .Close:active { border:0 !important; background-color:transparent; opacity:1; filter:Alpha(Opacity:100); }
#Firebug .ButtonContainer .Minimize { background-position:-3px -20px; right:40px; }
#Firebug .ButtonContainer .Maximize { display:none; background-position:-3px -34px; right:40px; }
#Firebug .ButtonContainer .NewWindow { background-position:-3px -123px; right:20px; }
#Firebug .ButtonContainer .Dock { background-position:-3px -137px; }
#Firebug .ButtonContainer .ButtonSet { border-left:1px solid #ccc; padding:0 0 0 3px; display:inline; }
/*
* navigation
*/
#Firebug .Nav { height:23px; background:url(firebug.gif) repeat-x 0 -62px; padding-left:10px; }
#Firebug .Nav .Tab { display:block; width:auto; float:left; padding:3px 6px 2px 6px; cursor:pointer; border:1px outset transparent !important; border:0; font:bold 11px Arial, Helvetica, sans-serif; color:#666; }
#Firebug .Nav .Tab:hover, #Firebug .Nav .Selected { border:1px outset #ccc !important; border-top-color:transparent !important; }
#Firebug .Nav .Selected { color:#111; cursor:default; background-color:#f2f2f2; }
#Firebug .Nav .Settings { float:right; }
/*
* inspector
*/
#FirebugBorderInspector { display:none; z-index:99999998; position:absolute; top:0; left:0; border:2px solid #0000ff; background:transparent; *background:url(spacer.gif); opacity:0.5; filter:Alpha(Opacity=50); padding:0; margin:0; }
#FirebugBGInspector { display:none; z-index:99999998; position:absolute; top:0; left:0; background:rgb(0,150,255); opacity:0.5; filter:Alpha(Opacity=50); padding:0; margin:0; }
/*
* dom
*/
#Firebug .DOMRow { width:100% !important; width:90%; }
#Firebug .DOMRow .DOMRowLeft { float:left; width:30%; overflow:hidden; }
#Firebug .DOMRow .DOMRowLeft a { padding-left:15px; }
#Firebug .DOMRow .DOMRowRight { float:left; width:60%; *width:60%; _overflow:hidden; white-space:nowrap; }
#Firebug .DOMRow .DOMRowLeft .Object { background:url(tree_open.gif) no-repeat left center; cursor:pointer; }
#Firebug .DOMRow .DOMRowLeft .Object:hover { text-decoration:underline; color:#0000ff; }
#Firebug .DOMRow .DOMRowLeft .Opened { background-image:url(tree_close.gif) }
#Firebug .DOMRow .DOMRowSubContainer { display:none; padding-left:25px; }
/*
* console
*/
#Firebug .Left .Console { overflow:hidden; }
#Firebug .Left .Console .Monitor { height:210px; border-bottom:1px solid #ccc; overflow:scroll; overflow-x:hidden; }
#Firebug .Left .Console .Monitor .Error { background:#ffeff1; color:#ff0000; }
#Firebug .Left .Console .Monitor .Error strong { color:#ff0000; }
#Firebug .Left .Console .Monitor .Row { padding:2px 5px 2px 5px; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; overflow:hidden; border-bottom:1px solid #e5e5e5; }
#Firebug .Left .Console .Monitor .Arrow { color:rgb(0,0,255); white-space:nowrap; }
#Firebug .Left .Console .InputArrow { position:absolute; left:0px; width:20px; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; color:#0000ff; padding:2px 4px 0 4px; }
#Firebug .Left .Console .InputContainer { margin-left:35px; margin-right:5px; }
#Firebug .Left .Console .Input { width:100% !important; margin-top:2px; width:98%; overflow:hidden; border:0; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Console .MLButton { cursor:pointer; position:absolute; top:276px; right:-22px; width:20px; padding:4px 10px 10px 10px; font-size:1px; *padding:2px 10px 10px 10px; background:url(firebug.gif) no-repeat -3px -34px; opacity:0.8; filter:Alpha(Opacity:80); }
#Firebug .Console .MLButton:hover { opacity:1; filter:Alpha(Opacity:100); }
#Firebug .Console .CloseML { background-position:-3px -20px; }
#Firebug .Right .Console { background:#eee; }
#Firebug .Right .Console .Input { width:100%; _width:98%; height:228px; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; background:#fff; border:0; border-bottom:1px solid #ccc; margin-bottom:2px; *overflow:scroll; }
#Firebug .Right .Console .Button { cursor:pointer; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:1px 4px 1px 4px; margin:0 4px 0 4px; background:#eee; border:1px solid #eee; text-decoration:none; *display:block; *width:auto; *float:left; *margin-top:-1px; }
#Firebug .Right .Console .Button:hover { border:1px outset #ccc; background:#fff; }
#Firebug .Right .Console .Button:active { border:1px inset #ccc; background:#ccc; }
#Firebug .Left .Console .Monitor .Warn { background:url(warningIcon.png) #00FFFF no-repeat 2px center; padding-left:20px; }
#Firebug .Left .Console .Monitor .Info { background:url(infoIcon.png) #fff no-repeat 2px center; padding-left:20px; }
#Firebug .Left .Console .Monitor .Error { background:url(errorIcon.png) #FFFFE0 no-repeat 2px center; padding-left:20px; }
/*
* html
*/
#Firebug .Left .HTML { display:none; height:250px; overflow:scroll; padding:0 10px 2px 10px; }
#Firebug .Left .HTML .Block { padding:0 0 0 0px; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Left .HTML .Block .Spacer { cursor:default; padding:2px 2px 2px 15px; }
#Firebug .Left .HTML .Block .Link { display:block; color:#333; padding:2px 2px 2px 0; }
#Firebug .Left .HTML .Block .Link .Content { padding:2px 2px 2px 2px; }
#Firebug .Left .HTML .Block .Link .TagName { cursor:pointer; }
#Firebug .Left .HTML .Block .Parent { font-weight:bold; color:#111; text-decoration:none; }
#Firebug .Left .HTML .Block .Parent .Spacer { background:#fff center no-repeat; }
#Firebug .Left .HTML .Block .Parent .Spacer { background-image:url(tree_open.gif); }
#Firebug .Left .HTML .Block .Open .Spacer { background-image:url(tree_close.gif) }
#Firebug .Left .HTML .Block .Selected { background-color:#4473c4; }
#Firebug .Left .HTML .Block .Selected * { color:#fff; }
#Firebug .Left .HTML .Block .SubContainer { padding-left:20px; height:0; font-size:0px; }
#Firebug .Left .HTML .Block .OpenSubContainer { height:auto; }
#Firebug .Left .HTML .Unvisible { opacity:0.5; filter:Alpha(Opacity=50); }
#Firebug .Right .HTML { display:none; }
#Firebug .Right .HTML .Content { overflow:scroll; height:235px; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Right .HTML .Content .CSSItem { padding:5px; color:#333; height:6px }
#Firebug .Right .HTML .Content .CSSProperty { width:45%; float:left; overflow:hidden; }
#Firebug .Right .HTML .Content .CSSValue { width:55%; float:left; white-space:nowrap; overflow:visible !important; overflow:hidden; }
#Firebug .Right .HTML .Content .CSSValue input { font:11px ArArial, Helvetica, sans-serif; color:#333; 3px 0 0 -3px; }
#Firebug .Right .HTML .Content .CSSItem center { color:rgb(0,150,0); padding:0 0 3px 0; font:bold 12px Arial, Helvetica, sans-serif; }
#Firebug .ButtonContainer .HTML { display:none; }
/*
* CSS
*/
#Firebug .Left .CSS { display:none; padding:5px; height:225px; overflow:scroll; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Right .CSS { display:none; }
#Firebug .Left .CSS .Selector { margin-top:10px }
#Firebug .Left .CSS .CSSText { padding-left:20px; }
#Firebug .Left .CSS .CSSProperty { color:#005500; margin-top:10px; }
#Firebug .Left .CSS .CSSValue { padding-left:5px; color:#000088; }
#Firebug .ButtonContainer .CSS { display:none; }
#Firebug .Right .CSS { background:#eee; }
#Firebug .Right .CSS .Input { width:100%; _width:98%; height:205px; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; background:#fff; border:0; border-bottom:1px solid #ccc; margin-bottom:2px; *overflow:scroll; }
#Firebug .Right .CSS .Button { cursor:pointer; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:1px 4px 1px 4px; margin:0 4px 0 4px; background:#eee; border:1px solid #eee; text-decoration:none; *display:block; *width:auto; *float:left; *margin-top:-1px; }
#Firebug .Right .CSS .Button:hover { border:1px outset #ccc; background:#fff; }
#Firebug .Right .CSS .Button:active { border:1px inset #ccc; background:#ccc; }
/*
* Scripts
*/
#Firebug .Left .Scripts { display:none; height:225px; *height:235px; overflow:scroll; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Left .Scripts .LineNumber { float:left; width:30px; height:20px; padding:0 2px 0 0; background:#eee; color:#666; font-family:Courier; text-align:right; border-right:1px solid #ccc; }
#Firebug .Left .Scripts .CodeContainer { padding:5px; }
#Firebug .Left .Scripts .Code { height:20px; }
#Firebug .Left .Scripts .CodeContainer, #Firebug .Left .Scripts .Code { word-wrap:normal; white-space:pre; }
#Firebug .Right .Scripts { display:none; }
#Firebug .ButtonContainer .Scripts { display:none; }
/*
* DOM
*/
#Firebug .Left .DOM { display:none; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; overflow:scroll; height:225px; }
#Firebug .Left .DOM .Object { font-weight:bold; }
#Firebug .Right .DOM { display:none; overflow:scroll; }
#Firebug .ButtonContainer .DOM { display:none; }
#Firebug .ButtonContainer .DOM label { font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
/*
* XHR
*/
#Firebug .Left .XHR { display:none; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; overflow:scroll; height:225px; }
#Firebug .Left .XHR .Block { float:left; width:30%; }
#Firebug .Left .XHR .BlockContent { padding:3px; border-right:1px dotted #aaa; }
#Firebug .Left .XHR .Block strong { display:block; text-align:center; padding:3px; background:rgb(200,225,255); color:rgb(50,50,50); }
#Firebug .Left .XHR .Block span { display:block; text-align:center; overflow:hidden; }
#Firebug .Left .XHR .Block span a { cursor:pointer; color:rgb(0,0,200); }
#Firebug .Right .XHR { display:none; overflow:scroll; }
#Firebug .ButtonContainer .XHR { display:none; }
#Firebug .ButtonContainer .XHR label { font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Left .STR { display:none; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; overflow:scroll; height:225px; }
/*
* settings
*/
#Firebug .SettingsDiv {position:absolute;width:190px;top:60px;border:1px outset #000;-x-system-font:none;color:#000;font-family:"MS Sans Serif",Geneva,sans-serif;font-size:12px;font-size-adjust:none;font-stretch:normal;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;display:none;background-color:#FFF;}
#Firebug .SettingsDiv .Header {background:#CCC url(firebug.gif) repeat scroll 0 -85px;height:30px;border-bottom:1px inset #000;}
#Firebug .SettingsDiv .Header .Title {padding-top:10px;text-align:center;}
#Firebug .SettingsDiv .Content {padding:5px;}
#Firebug .SettingsDiv .Content .SettingsCBX{position:relative;top:2px;margin: 4px 5px 0 0; border:0 !important; padding:0 !important; height: 15px !important;}
#Firebug .SettingsDiv .Content .ButtonsLeft {float:left;padding:10px 0px 5px 0px;}
#Firebug .SettingsDiv .Content .ButtonsRight {float:right;padding:10px 0px 5px 0px;}
#Firebug .SettingsDiv .Content .ProgressDiv {background-color:#FFF;width:100%;height:100%;position:absolute;left:0;top:0;z-index:1;opacity:.8;filter:alpha(opacity=80);display:none;}
#Firebug .SettingsDiv .Content .Progress {background-image:url(progress.gif);width:66px;height:66px;position:absolute;top:50%;left:50%;margin-left:-33px;margin-top:-33px;}
/*
* element highlighting
*/
#Firebug .Italic { font-style:italic; }
#Firebug .Strong { font-weight:bold; }
#Firebug .NormalWeight { font-weight:normal; }
#Firebug .Green { color:#008800; }
#Firebug .Gray { color:#666; }
#Firebug .Blue { color:#0000ee; }
#Firebug .DarkBlue { color:#000099; }
#Firebug .Red { color:#ee0000; }
#Firebug .Maroon { color:#800000; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Null { font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; color:#fff; padding:0 2px 0 2px; background:#999; border:1px solid #666; }
#Firebug .ObjectLink, #Firebug .ObjectLinkHover { cursor:pointer; }
#Firebug .ObjectLinkHover { border-bottom:1px solid #008800; }
#Firebug .Clear { clear:both; height:0px; font-size:0px; }
#firebugIconDiv {width:38px;height:38px;right:15pt;bottom:5pt;border:2px solid #000;display:none;position:fixed;background-image:url(firebug_logo.png);text-decoration:underline;cursor:pointer;filter:alpha(opacity:60);opacity:.6;z-index:99999998;}

View File

@ -1,2518 +0,0 @@
var firebug = {
version:[1.23,20090309],
el:{},
env:{
"cache":{},
"extConsole":null,
"css":"http://getfirebug.com/releases/lite/1.2/firebug-lite.css",
"debug":true,
"detectFirebug":false,
"dIndex":"console",
"height":295,
"hideDOMFunctions":false,
"init":false,
"isPopup":false,
"liteFilename":"firebug-lite.js",
"minimized":false,
"openInPopup": false,
"override":false,
"ml":false,
"popupWin":null,
"showIconWhenHidden":true,
"targetWindow":undefined,
"popupTop":1,
"popupLeft":1,
"popupWidth":undefined,
"popupHeight":undefined
},
initConsole:function(){
/*
* initialize the console - user defined values are not available within this method because FBLite is not yet initialized
*/
var command;
try{
if((!window.console || (window.console && !window.console.firebug)) || (firebug.env.override && !(/Firefox\/3/i.test(navigator.userAgent)))){
window.console = { "provider":"Firebug Lite" };
for(command in firebug.d.console.cmd){
window.console[command] = firebug.lib.util.Curry(firebug.d.console.run,window,command);
};
}
window.onerror = function(_message,_file,_line){
firebug.d.console.run('error',firebug.lib.util.String.format('{0} ({1},{2})',_message,firebug.getFileName(_file),_line));
};
} catch(e){}
},
overrideConsole:function(){
with (firebug){
env.override=true;
try{
env.extConsole=window.console;
} catch(e){}
initConsole();
}
},
restoreConsole:function(){
with(firebug){
if(env.extConsole){
env.override=false;
try{
window.console=env.extConsole;
} catch(e){}
env.extConsole=null;
}
}
},
init:function(_css){
var iconTitle = "Click here or press F12, (CTRL|CMD)+SHIFT+L or SHIFT+ENTER to show Firebug Lite. CTRL|CMD click this icon to hide it.";
with(firebug){
if(document.getElementsByTagName('html')[0].attributes.getNamedItem('debug')){
env.debug = document.getElementsByTagName('html')[0].attributes.getNamedItem('debug').nodeValue !== "false";
}
if(env.isPopup) {
env.openInPopup = false;
env.targetWindow = window.opener;
env.popupWidth = window.opener.firebug.env.popupWidth || window.opener.firebug.lib.util.GetViewport().width;
env.popupHeight = window.opener.firebug.env.popupHeight || window.opener.firebug.lib.util.GetViewport().height;
} else {
env.targetWindow = window;
env.popupWidth = env.popupWidth || lib.util.GetViewport().width;
env.popupHeight = env.popupHeight || lib.util.GetViewport().height;
}
settings.readCookie();
if(env.init || (env.detectFirebug && window.console && window.console.firebug)) {
return;
}
document.getElementsByTagName("head")[0].appendChild(
new lib.element("link").attribute.set("rel","stylesheet").attribute.set("type","text/css").attribute.set("href",env.css).element
);
if(env.override){
overrideConsole();
}
/*
* Firebug Icon
*/
el.firebugIcon = new lib.element("div").attribute.set("id","firebugIconDiv").attribute.set("title",iconTitle).attribute.set("alt",iconTitle).event.addListener("mousedown",win.iconClicked).insert(document.body);
/*
* main interface
*/
el.content = {};
el.mainiframe = new lib.element("IFRAME").attribute.set("id","FirebugIFrame").environment.addStyle({ "display":"none", "width":lib.util.GetViewport().width+"px" }).insert(document.body);
el.main = new lib.element("DIV").attribute.set("id","Firebug").environment.addStyle({ "display":"none", "width":lib.util.GetViewport().width+"px" }).insert(document.body);
if(!env.isPopup){
el.resizer = new lib.element("DIV").attribute.addClass("Resizer").event.addListener("mousedown",win.resizer.start).insert(el.main);
}
el.header = new lib.element("DIV").attribute.addClass("Header").insert(el.main);
el.left = {};
el.left.container = new lib.element("DIV").attribute.addClass("Left").insert(el.main);
el.right = {};
el.right.container = new lib.element("DIV").attribute.addClass("Right").insert(el.main);
el.main.child.add(new lib.element("DIV").attribute.addClass('Clear'));
/*
* buttons
*/
el.button = {};
el.button.container = new lib.element("DIV").attribute.addClass("ButtonContainer").insert(el.header);
el.button.logo = new lib.element("A").attribute.set("title","Firebug Lite").attribute.set("target","_blank").attribute.set("href","http://getfirebug.com/lite.html").update("&nbsp;").attribute.addClass("Button Logo").insert(el.button.container);
el.button.inspect = new lib.element("A").attribute.addClass("Button").event.addListener("click",env.targetWindow.firebug.d.inspector.toggle).update("Inspect").insert(el.button.container);
el.button.dock = new lib.element("A").attribute.addClass("Button Dock").event.addListener("click", win.dock).insert(el.button.container);
el.button.newWindow = new lib.element("A").attribute.addClass("Button NewWindow").event.addListener("click", win.newWindow).insert(el.button.container);
if(!env.isPopup){
el.button.maximize = new lib.element("A").attribute.addClass("Button Maximize").event.addListener("click",win.maximize).insert(el.button.container);
el.button.minimize = new lib.element("A").attribute.addClass("Button Minimize").event.addListener("click",win.minimize).insert(el.button.container);
el.button.close = new lib.element("A").attribute.addClass("Button Close").event.addListener("click",win.hide).insert(el.button.container);
}
if(lib.env.ie||lib.env.webkit){
el.button.container.environment.addStyle({ "paddingTop":"12px" });
}
/*
* navigation
*/
el.nav = {};
el.nav.container = new lib.element("DIV").attribute.addClass("Nav").insert(el.left.container);
el.nav.console = new lib.element("A").attribute.addClass("Tab Selected").event.addListener("click",lib.util.Curry(d.navigate,window,"console")).update("Console").insert(el.nav.container);
el.nav.html = new lib.element("A").attribute.addClass("Tab").update("HTML").event.addListener("click",lib.util.Curry(d.navigate,window,"html")).insert(el.nav.container);
el.nav.css = new lib.element("A").attribute.addClass("Tab").update("CSS").event.addListener("click",lib.util.Curry(d.navigate,window,"css")).insert(el.nav.container);
if(!env.isPopup){
el.nav.scripts = new lib.element("A").attribute.addClass("Tab").update("Script").event.addListener("click",lib.util.Curry(d.navigate,window,"scripts")).insert(el.nav.container);
}
el.nav.dom = new lib.element("A").attribute.addClass("Tab").update("DOM").event.addListener("click",lib.util.Curry(d.navigate,env.targetWindow,"dom")).insert(el.nav.container);
el.nav.xhr = new lib.element("A").attribute.addClass("Tab").update("XHR").event.addListener("click",lib.util.Curry(d.navigate,window,"xhr")).insert(el.nav.container);
el.nav.optionsdiv = new lib.element("DIV").attribute.addClass("Settings").insert(el.nav.container);
el.nav.options = new lib.element("A").attribute.addClass("Tab").update("Options&nbsp;&or;").event.addListener("click", settings.toggle).insert(el.nav.optionsdiv);
/*
* inspector
*/
el.borderInspector = new lib.element("DIV").attribute.set("id","FirebugBorderInspector").event.addListener("click",listen.inspector).insert(document.body);
el.bgInspector = new lib.element("DIV").attribute.set("id","FirebugBGInspector").insert(document.body);
/*
* console
*/
el.left.console = {};
el.left.console.container = new lib.element("DIV").attribute.addClass("Console").insert(el.left.container);
el.left.console.mlButton = new lib.element("A").attribute.addClass("MLButton").event.addListener("click",d.console.toggleML).insert(el.left.console.container);
el.left.console.monitor = new lib.element("DIV").insert(
new lib.element("DIV").attribute.addClass("Monitor").insert(el.left.console.container)
);
el.left.console.container.child.add(
new lib.element("DIV").attribute.addClass("InputArrow").update(">>>")
);
el.left.console.input = new lib.element("INPUT").attribute.set("type","text").attribute.addClass("Input").event.addListener("keydown",listen.consoleTextbox).insert(
new lib.element("DIV").attribute.addClass("InputContainer").insert(el.left.console.container)
);
el.right.console = {};
el.right.console.container = new lib.element("DIV").attribute.addClass("Console Container").insert(el.right.container);
el.right.console.mlButton = new lib.element("A").attribute.addClass("MLButton CloseML").event.addListener("click",d.console.toggleML).insert(el.right.console.container);
el.right.console.input = new lib.element("TEXTAREA").attribute.addClass("Input").insert(el.right.console.container);
el.right.console.input.event.addListener("keydown",lib.util.Curry(tab,window,el.right.console.input.element));
el.right.console.run = new lib.element("A").attribute.addClass("Button").event.addListener("click",listen.runMultiline).update("Run").insert(el.right.console.container);
el.right.console.clear = new lib.element("A").attribute.addClass("Button").event.addListener("click",lib.util.Curry(d.clean,window,el.right.console.input)).update("Clear").insert(el.right.console.container);
el.button.console = {};
el.button.console.container = new lib.element("DIV").attribute.addClass("ButtonSet").insert(el.button.container);
el.button.console.clear = new lib.element("A").attribute.addClass("Button").event.addListener("click",d.console.clear).update("Clear").insert(el.button.console.container);
/*
* html
*/
el.left.html = {};
el.left.html.container = new lib.element("DIV").attribute.addClass("HTML").insert(el.left.container);
el.right.html = {};
el.right.html.container = new lib.element("DIV").attribute.addClass("HTML Container").insert(el.right.container);
el.right.html.nav = {};
el.right.html.nav.container = new lib.element("DIV").attribute.addClass("Nav").insert(el.right.html.container);
el.right.html.nav.computedStyle = new lib.element("A").attribute.addClass("Tab Selected").event.addListener("click",lib.util.Curry(d.html.navigate,firebug,"computedStyle")).update("Computed Style").insert(el.right.html.nav.container);
el.right.html.nav.dom = new lib.element("A").attribute.addClass("Tab").event.addListener("click",lib.util.Curry(d.html.navigate,firebug,"dom")).update("DOM").insert(el.right.html.nav.container);
el.right.html.content = new lib.element("DIV").attribute.addClass("Content").insert(el.right.html.container);
el.button.html = {};
el.button.html.container = new lib.element("DIV").attribute.addClass("ButtonSet HTML").insert(el.button.container);
/*
* css
*/
el.left.css = {};
el.left.css.container = new lib.element("DIV").attribute.addClass("CSS").insert(el.left.container);
el.right.css = {};
el.right.css.container = new lib.element("DIV").attribute.addClass("CSS Container").insert(el.right.container);
el.right.css.nav = {};
el.right.css.nav.container = new lib.element("DIV").attribute.addClass("Nav").insert(el.right.css.container);
el.right.css.nav.runCSS = new lib.element("A").attribute.addClass("Tab Selected").update("Run CSS").insert(el.right.css.nav.container);
el.right.css.mlButton = new lib.element("A").attribute.addClass("MLButton CloseML").event.addListener("click",d.console.toggleML).insert(el.right.css.container);
el.right.css.input = new lib.element("TEXTAREA").attribute.addClass("Input").insert(el.right.css.container);
el.right.css.input.event.addListener("keydown",lib.util.Curry(firebug.tab,window,el.right.css.input.element));
el.right.css.run = new lib.element("A").attribute.addClass("Button").event.addListener("click",listen.runCSS).update("Run").insert(el.right.css.container);
el.right.css.clear = new lib.element("A").attribute.addClass("Button").event.addListener("click",lib.util.Curry(d.clean,window,el.right.css.input)).update("Clear").insert(el.right.css.container);
el.button.css = {};
el.button.css.container = new lib.element("DIV").attribute.addClass("ButtonSet CSS").insert(el.button.container);
el.button.css.selectbox = new lib.element("SELECT").event.addListener("change",listen.cssSelectbox).insert(el.button.css.container);
/*
* scripts
*/
el.left.scripts = {};
el.left.scripts.container = new lib.element("DIV").attribute.addClass("Scripts").insert(el.left.container);
el.right.scripts = {};
el.right.scripts.container = new lib.element("DIV").attribute.addClass("Scripts Container").insert(el.right.container);
el.button.scripts = {};
el.button.scripts.container = new lib.element("DIV").attribute.addClass("ButtonSet Scripts").insert(el.button.container);
el.button.scripts.selectbox = new lib.element("SELECT").event.addListener("change",listen.scriptsSelectbox).insert(el.button.scripts.container);
el.button.scripts.lineNumbers = new lib.element("A").attribute.addClass("Button").event.addListener("click",d.scripts.toggleLineNumbers).update("Show Line Numbers").insert(el.button.scripts.container);
/*
* dom
*/
el.left.dom = {};
el.left.dom.container = new lib.element("DIV").attribute.addClass("DOM").insert(el.left.container);
el.right.dom = {};
el.right.dom.container = new lib.element("DIV").attribute.addClass("DOM Container").insert(el.right.container);
el.button.dom = {};
el.button.dom.container = new lib.element("DIV").attribute.addClass("ButtonSet DOM").insert(el.button.container);
el.button.dom.label = new lib.element("LABEL").update("Object Path:").insert(el.button.dom.container);
el.button.dom.textbox = new lib.element("INPUT").event.addListener("keydown",listen.domTextbox).update(env.isPopup?"window.opener":"window").insert(el.button.dom.container);
/*
* str
*/
el.left.str = {};
el.left.str.container = new lib.element("DIV").attribute.addClass("STR").insert(el.left.container);
el.right.str = {};
el.right.str.container = new lib.element("DIV").attribute.addClass("STR").insert(el.left.container);
el.button.str = {};
el.button.str.container = new lib.element("DIV").attribute.addClass("ButtonSet XHR").insert(el.button.container);
el.button.str.watch = new lib.element("A").attribute.addClass("Button").event.addListener("click",lib.util.Curry(d.navigate,window,"xhr")).update("Back").insert(el.button.str.container);
/*
* xhr
*/
el.left.xhr = {};
el.left.xhr.container = new lib.element("DIV").attribute.addClass("XHR").insert(el.left.container);
el.right.xhr = {};
el.right.xhr.container = new lib.element("DIV").attribute.addClass("XHR").insert(el.left.container);
el.button.xhr = {};
el.button.xhr.container = new lib.element("DIV").attribute.addClass("ButtonSet XHR").insert(el.button.container);
el.button.xhr.label = new lib.element("LABEL").update("XHR Path:").insert(el.button.xhr.container);
el.button.xhr.textbox = new lib.element("INPUT").event.addListener("keydown",listen.xhrTextbox).insert(el.button.xhr.container);
el.button.xhr.watch = new lib.element("A").attribute.addClass("Button").event.addListener("click",listen.addXhrObject).update("Watch").insert(el.button.xhr.container);
/*
* settings
*/
el.settings = {};
el.settings.container = new lib.element("DIV").child.add(
new lib.element("DIV").attribute.addClass("Header").child.add(
new lib.element().attribute.addClass("Title").update('Firebug Lite Settings')
)
).attribute.addClass("SettingsDiv").insert(el.main);
el.settings.content = new lib.element("DIV").attribute.addClass("Content").insert(el.settings.container);
el.settings.progressDiv = new lib.element("DIV").attribute.addClass("ProgressDiv").insert(el.settings.content);
el.settings.progress = new lib.element("DIV").attribute.addClass("Progress").insert(el.settings.progressDiv);
el.settings.cbxDebug = new lib.element("INPUT").attribute.set("type","checkbox").attribute.addClass("SettingsCBX").insert(el.settings.content);
el.settings.content.child.add(document.createTextNode("Start visible"));
new lib.element("BR").insert(el.settings.content);
el.settings.cbxDetectFirebug = new lib.element("INPUT").attribute.set("type","checkbox").attribute.addClass("SettingsCBX").insert(el.settings.content);
el.settings.content.child.add(document.createTextNode("Hide when Firebug active"));
new lib.element("BR").insert(el.settings.content);
el.settings.cbxHideDOMFunctions = new lib.element("INPUT").attribute.set("type","checkbox").attribute.addClass("SettingsCBX").insert(el.settings.content);
el.settings.content.child.add(document.createTextNode("Hide DOM functions"));
new lib.element("BR").insert(el.settings.content);
el.settings.cbxOverride = new lib.element("INPUT").attribute.set("type","checkbox").attribute.addClass("SettingsCBX").insert(el.settings.content);
el.settings.content.child.add(document.createTextNode("Override window.console"));
new lib.element("BR").insert(el.settings.content);
el.settings.cbxShowIcon = new lib.element("INPUT").attribute.set("type","checkbox").attribute.addClass("SettingsCBX").insert(el.settings.content);
el.settings.content.child.add(document.createTextNode("Show icon when hidden"));
new lib.element("BR").insert(el.settings.content);
el.settings.cbxOpenInPopup = new lib.element("INPUT").attribute.set("type","checkbox").attribute.addClass("SettingsCBX").insert(el.settings.content);
el.settings.content.child.add(document.createTextNode("Open in popup"));
el.settings.buttonDiv = new lib.element("DIV").insert(el.settings.content);
el.settings.buttonLeftDiv = new lib.element("DIV").attribute.addClass("ButtonsLeft").insert(el.settings.buttonDiv);
el.settings.resetButton = new lib.element("INPUT").attribute.set("type","button").update("Reset").event.addListener("click",settings.reset).insert(el.settings.buttonLeftDiv);
el.settings.buttonRightDiv = new lib.element("DIV").attribute.addClass("ButtonsRight").insert(el.settings.buttonDiv);
el.settings.cancelButton = new lib.element("INPUT").attribute.set("type","button").update("Cancel").event.addListener("click",settings.hide).insert(el.settings.buttonRightDiv);
el.settings.buttonRightDiv.child.add(document.createTextNode(" "));
el.settings.saveButton = new lib.element("INPUT").attribute.set("type","button").update("Save").event.addListener("click",settings.saveClicked).insert(el.settings.buttonRightDiv);
lib.util.AddEvent(document,"mousemove",listen.mouse)("mousemove",win.resizer.resize)("mouseup",win.resizer.stop)("keydown",listen.keyboard);
env.init = true;
for(var i=0, len=d.console.cache.length; i<len; i++){
var item = d.console.cache[i];
d.console.cmd[item.command].apply(window,item.arg);
};
if(lib.env.ie6){
window.onscroll = lib.util.Curry(win.setVerticalPosition,window,null);
var buttons = [
el.button.inspect,
el.button.close,
el.button.inspect,
el.button.console.clear,
el.right.console.run,
el.right.console.clear,
el.right.css.run,
el.right.css.clear
];
for(var i=0, len=buttons.length; i<len; i++)
buttons[i].attribute.set("href","#");
win.refreshSize();
}
if(env.showIconWhenHidden) {
if(!env.popupWin) {
el.firebugIcon.environment.addStyle({ "display": env.debug&&'none'||'block' });
}
}
lib.util.AddEvent(window, "unload", win.unload);
if (env.isPopup) {
env.height=lib.util.GetViewport().height;
lib.util.AddEvent(window, "resize", win.fitToPopup);
win.fitToPopup();
} else {
lib.util.AddEvent(window, "resize", win.refreshSize);
}
win.setHeight(env.height);
if(env.openInPopup&&!env.isPopup) {
win.newWindow();
} else {
el.main.environment.addStyle({ "display":env.debug&&'block'||'none' });
el.mainiframe.environment.addStyle({ "display":env.debug&&'block'||'none' });
}
}
},
inspect:function(){
return firebug.d.html.inspect.apply(window,arguments);
},
watchXHR:function(){
with(firebug){
d.xhr.addObject.apply(window,arguments);
if(env.dIndex!="xhr"){
d.navigate("xhr");
}
}
},
settings:{
isVisible:false,
show: function() {
with(firebug){
var posXY=lib.util.Element.getPosition(firebug.el.nav.options.element);
settings.refreshForm();
el.settings.container.environment.addStyle({
"display": "block",
"left": (posXY.offsetLeft-125)+"px"
});
el.settings.progressDiv.environment.addStyle({
"display": "none"
});
firebug.settings.isVisible = true;
}
},
hide: function() {
with(firebug){
firebug.el.settings.container.environment.addStyle({
"display": "none"
});
firebug.settings.isVisible = false;
}
},
toggle: function(){
with(firebug){
settings[!settings.isVisible && 'show' || 'hide']();
}
},
saveClicked: function() {
firebug.el.settings.progressDiv.environment.addStyle({
"display": "block"
});
setTimeout(firebug.settings.formToSettings,0);
},
formToSettings: function() {
var fe=firebug.env,
ofe,
elSet=firebug.el.settings,
exdate;
fe.debug=elSet.cbxDebug.element.checked;
fe.detectFirebug=elSet.cbxDetectFirebug.element.checked;
fe.hideDOMFunctions=elSet.cbxHideDOMFunctions.element.checked;
fe.override=elSet.cbxOverride.element.checked;
fe.showIconWhenHidden=elSet.cbxShowIcon.element.checked;
fe.openInPopup=elSet.cbxOpenInPopup.element.checked;
if(fe.isPopup) {
ofe=window.opener.firebug.env;
ofe.debug=fe.debug;
ofe.detectFirebug=fe.detectFirebug;
ofe.hideDOMFunctions=fe.hideDOMFunctions;
ofe.override=fe.override;
ofe.showIconWhenHidden=fe.showIconWhenHidden;
ofe.openInPopup=fe.openInPopup;
ofe.popupTop=fe.popupTop;
ofe.popupLeft=fe.popupLeft;
ofe.popupWidth=fe.popupWidth;
ofe.popupHeight=fe.popupHeight;
}
with(firebug) {
settings.writeCookie();
settings.hide();
win.refreshDOM();
}
},
reset: function() {
var exdate=new Date();
exdate.setTime(exdate.getTime()-1);
document.cookie='FBLiteSettings=;expires='+exdate.toGMTString();
location.reload(true);
},
readCookie: function() {
var i,cookieArr,valueArr,item,value;
with(firebug.env){
if(targetWindow.document.cookie.length>0) {
cookieArr=targetWindow.document.cookie.split('; ');
for(i=0;i<cookieArr.length;i++) {
if(cookieArr[i].split('=')[0]=='FBLiteSettings') {
valueArr=cookieArr[i].split('=')[1].split(',');
}
}
if(valueArr) {
for(i=0;i<valueArr.length;i++) {
item=valueArr[i].split(':')[0];
value=valueArr[i].split(':')[1];
switch(item) {
case 'debug':
debug=value=="true";
break;
case 'detectFirebug':
detectFirebug=value=="true";
break;
case 'hideDOMFunctions':
hideDOMFunctions=value=="true";
break;
case 'override':
override=value=="true";
break;
case 'showIconWhenHidden':
showIconWhenHidden=value=="true";
break;
case 'openInPopup':
openInPopup=value=="true";
break;
case 'popupTop':
popupTop=parseInt(value,10);
break;
case 'popupLeft':
popupLeft=parseInt(value,10);
break;
case 'popupWidth':
popupWidth=parseInt(value,10);
break;
case 'popupHeight':
popupHeight=parseInt(value,10);
break;
case 'height':
height=parseInt(value,10);
break;
}
}
}
}
}
},
writeCookie: function() {
var values;
with(firebug.env){
values='debug:'+debug+',';
values+='detectFirebug:'+detectFirebug+',';
values+='hideDOMFunctions:'+hideDOMFunctions+',';
values+='override:'+override+',';
values+='showIconWhenHidden:'+showIconWhenHidden+',';
values+='openInPopup:'+openInPopup+',';
if(isPopup) {
if(window.outerWidth===undefined) {
values+='popupTop:'+(window.screenTop-56)+',';
values+='popupLeft:'+(window.screenLeft-8)+',';
values+='popupWidth:'+document.body.clientWidth+',';
values+='popupHeight:'+document.body.clientHeight+',';
} else {
values+='popupTop:'+window.screenY+',';
values+='popupLeft:'+window.screenX+',';
values+='popupWidth:'+window.outerWidth+',';
values+='popupHeight:'+window.outerHeight+',';
}
} else {
values+='popupTop:'+popupTop+',';
values+='popupLeft:'+popupLeft+',';
values+='popupWidth:'+popupWidth+',';
values+='popupHeight:'+popupHeight+',';
}
values+='height:'+(parseInt(targetWindow.firebug.el.main.element.style.height.replace(/px/,''),10)-38);
exdate=new Date();
exdate.setDate(exdate.getDate()+365);
targetWindow.document.cookie='FBLiteSettings='+values+';expires='+exdate.toGMTString();
}
},
refreshForm: function() {
var fe=firebug.env,
elSet=firebug.el.settings;
elSet.cbxDebug.element.checked=fe.debug;
elSet.cbxDetectFirebug.element.checked=fe.detectFirebug;
elSet.cbxHideDOMFunctions.element.checked=fe.hideDOMFunctions;
elSet.cbxOverride.element.checked=fe.override;
elSet.cbxShowIcon.element.checked=fe.showIconWhenHidden;
elSet.cbxOpenInPopup.element.checked=fe.openInPopup;
}
},
win:{
hide:function(){
with(firebug){
el.main.environment.addStyle({
"display": "none"
});
el.mainiframe.environment.addStyle({
"display": "none"
});
if(env.showIconWhenHidden) {
el.firebugIcon.environment.addStyle({
"display": "block"
});
}
}
},
show:function(){
with(firebug){
el.main.environment.addStyle({
"display": "block"
});
el.mainiframe.environment.addStyle({
"display": "block"
});
if(env.showIconWhenHidden) {
el.firebugIcon.environment.addStyle({
"display": "none"
});
}
}
},
iconClicked:function(_event) {
with(firebug) {
if(_event.ctrlKey==true||_event.metaKey==true) {
el.firebugIcon.environment.addStyle({ "display": "none" });
env.showIconWhenHidden=false;
} else {
win.show();
}
}
},
minimize:function(){
with(firebug){
env.minimized=true;
el.main.environment.addStyle({ "height":"35px" });
el.mainiframe.environment.addStyle({ "height":"35px" });
el.button.maximize.environment.addStyle({ "display":"block" });
el.button.minimize.environment.addStyle({ "display":"none" });
win.refreshSize();
}
},
maximize:function(){
with(firebug){
env.minimized=false;
el.button.minimize.environment.addStyle({ "display":"block" });
el.button.maximize.environment.addStyle({ "display":"none" });
win.setHeight(env.height);
}
},
newWindow: function() {
var interval,scripts,script,scriptPath,
fe=firebug.env;
if (!fe.popupWin) {
scripts = document.getElementsByTagName('script');
fe.popupWin = window.open("", "_firebug",
"status=0,menubar=0,resizable=1,top="+fe.popupTop+",left="+fe.popupLeft+",width=" + fe.popupWidth +
",height=" + fe.popupHeight + ",scrollbars=0,addressbar=0,outerWidth="+fe.popupWidth+",outerHeight="+fe.popupHeight+
"toolbar=0,location=0,directories=0,dialog=0");
if(!fe.popupWin) {
alert("Firebug Lite could not open a pop-up window, most likely because of a popup blocker.\nPlease enable popups for this domain");
} else {
firebug.settings.hide();
for (i=0,len=scripts.length; i<len; i++) {
if (scripts[i].src.indexOf(fe.liteFilename) > -1) {
scriptPath = scripts[i].src;
break;
}
}
if (scriptPath) {
script = fe.popupWin.document.createElement('script'), done = false;
script.type = 'text/javascript';
script.src = scriptPath;
script[firebug.lib.env.ie?"onreadystatechange":"onload"] = function(){
if(!done && (!firebug.lib.env.ie || this.readyState == "complete" || this.readyState=="loaded")){
done = true;
if(fe.popupWin.firebug) {
with(fe.popupWin.firebug) {
env.isPopup = true;
env.css = fe.css;
init();
el.button.dock.environment.addStyle({ "display": "block"});
el.button.newWindow.environment.addStyle({ "display": "none"});
}
}
}
};
if (!done && firebug.lib.env.webkit) {
fe.popupWin.document.write('<html><head></head><body></body></html>');
interval = setInterval(function() {
if (fe.popupWin.firebug) {
clearInterval(interval);
done = true;
with(fe.popupWin.firebug) {
env.isPopup = true;
env.css = fe.css;
init();
el.button.dock.environment.addStyle({ "display": "block"});
el.button.newWindow.environment.addStyle({ "display": "none"});
}
}
}, 10);
};
if (!done) {
fe.popupWin.document.getElementsByTagName('head')[0].appendChild(script);
firebug.el.main.environment.addStyle({"display": "none"});
firebug.el.mainiframe.environment.addStyle({"display": "none"});
}
} else {
alert("Unable to detect the following script \"" + fe.liteFilename +
"\" ... if the script has been renamed then please set the value of firebug.env.liteFilename to reflect this change");
fe.popupWin.close();
fe.popupWin=null;
}
}
}
},
dock: function() {
with(opener.firebug) {
env.popupWin = null;
el.main.environment.addStyle({
"display": "block"
});
el.mainiframe.environment.addStyle({
"display": "block"
});
settings.readCookie();
window.close();
};
},
unload: function() {
with(firebug){
if(env.isPopup) {
win.dock();
} else if(env.popupWin) {
env.popupWin.close();
}
}
},
fitToPopup: function() {
with(firebug) {
var viewport = lib.util.GetViewport(window);
win.setHeight((window.innerHeight||viewport.height) - 38);
el.main.environment.addStyle({
"width": (viewport.width) + "px"
});
el.mainiframe.environment.addStyle({
"width": (viewport.width) + "px"
});
}
},
resizer:{
y:[], enabled:false,
start:function(_event){
with(firebug){
if(env.minimized)return;
win.resizer.y=[el.main.element.offsetHeight,_event.clientY];
if(lib.env.ie6){
win.resizer.y[3]=parseInt(el.main.environment.getPosition().top);
}
win.resizer.enabled=true;
}
},
resize:function(_event){
with(firebug){
if(!win.resizer.enabled)return;
win.resizer.y[2]=(win.resizer.y[0]+(win.resizer.y[1]-_event.clientY));
el.main.environment.addStyle({ "height":win.resizer.y[2]+"px" });
el.mainiframe.environment.addStyle({ "height":win.resizer.y[2]+"px" });
if(lib.env.ie6){
el.main.environment.addStyle({ "top":win.resizer.y[3]-(win.resizer.y[1]-_event.clientY)+"px" });
el.mainiframe.environment.addStyle({ "top":win.resizer.y[3]-(win.resizer.y[1]-_event.clientY)+"px" });
}
}
},
stop:function(_event){
with(firebug){
if(win.resizer.enabled){
win.resizer.enabled=false;
win.setHeight(win.resizer.y[2]-35);
}
}
}
},
setHeight:function(_height){
with(firebug){
env.height=_height;
el.left.container.environment.addStyle({ "height":_height+"px" });
el.right.container.environment.addStyle({ "height":_height+"px" });
el.main.environment.addStyle({ "height":_height+38+"px" });
el.mainiframe.environment.addStyle({ "height":_height+38+"px" });
win.refreshSize();
// console
el.left.console.monitor.element.parentNode.style.height=_height-47+"px";
el.left.console.mlButton.environment.addStyle({ "top":_height+19+"px" });
el.right.console.mlButton.environment.addStyle({ "top":_height+19+"px" });
el.right.console.input.environment.addStyle({ "height":_height-29+"px" });
// html
el.left.html.container.environment.addStyle({"height":_height-23+"px"});
el.right.html.content.environment.addStyle({"height":_height-23+"px"});
// css
el.left.css.container.environment.addStyle({"height":_height-33+"px"});
el.right.css.input.environment.addStyle({ "height":_height-55+"px" });
// script
el.left.scripts.container.environment.addStyle({"height":_height-23+"px"});
// dom
el.left.dom.container.environment.addStyle({"height":_height-31+"px"});
// xhr
el.left.xhr.container.environment.addStyle({"height":_height-32+"px"});
// string
el.left.str.container.environment.addStyle({"height":_height-32+"px"});
}
},
refreshDOM:function(){
with(firebug){
d.dom.open(eval(el.button.dom.textbox.environment.getElement().value),el.left.dom.container);
if(d.html.nIndex=="dom"){
firebug.d.html.navigate("dom")
}
}
},
refreshSize:function(){
with(firebug){
if(!env.init)
return;
var dim = lib.util.GetViewport();
el.main.environment.addStyle({ "width":dim.width+"px"});
el.mainiframe.environment.addStyle({ "width":dim.width+"px"});
if(lib.env.ie6)
win.setVerticalPosition(dim);
}
},
setVerticalPosition:function(_dim,_event){
with(firebug){
var dim = _dim||lib.util.GetViewport();
el.main.environment.addStyle({ "top":dim.height-el.main.environment.getSize().offsetHeight+Math.max(document.documentElement.scrollTop,document.body.scrollTop)+"px" });
el.mainiframe.environment.addStyle({ "top":dim.height-el.main.environment.getSize().offsetHeight+Math.max(document.documentElement.scrollTop,document.body.scrollTop)+"px" });
}
}
},
d: {
clean:function(_element){
with(firebug){
_element.update("");
}
},
console:{
addLine:function(){
with (firebug) {
return new lib.element("DIV").attribute.addClass("Row").insert(el.left.console.monitor);
}
},
cache:[],
clear:function(){
with(firebug){
d.clean(el.left.console.monitor);
d.console.cache = [];
}
},
formatArgs:function(){
with(firebug){
var content = [];
for(var i=0, len=arguments.length; i<len; i++){
content.push( d.highlight(arguments[i],false,false,true) );
}
return content.join(" ");
}
},
history:[], historyIndex:0,
openObject:function(_index){
with (firebug) {
d.dom.open(d.console.cache[_index], el.left.dom.container, lib.env.ie);
d.navigate("dom");
}
},
print: function(_cmd,_text){
with (firebug){
d.console.addLine().attribute.addClass("Arrow").update(">>> "+_cmd);
d.console.addLine().update(d.highlight(_text,false,false,true));
d.console.scroll();
}
},
printException: function(_exception){
with(firebug){
var message = _exception.description||_exception.message||_exception;
if(_exception.fileName){
message+=' ('+(_exception.name&&(_exception.name+', ')||'')+getFileName(_exception.fileName)+', '+_exception.lineNumber+')';
}
d.console.addLine().attribute.addClass("Error").update("<strong>Error: </strong>"+message,true);
}
},
eval:function(_cmd){
var result;
with(firebug){
if(_cmd.length==0)
return;
el.left.console.input.environment.getElement().value = "";
d.console.historyIndex = d.console.history.push(_cmd);
try {
if(_cmd==='console.firebug') {
d.console.addLine().attribute.addClass("Arrow").update(firebug.version);
} else {
result = eval.call(window,_cmd);
d.console.print(_cmd,result);
}
} catch(e){
d.console.addLine().attribute.addClass("Arrow").update(">>> "+_cmd);
d.console.printException(e);
}
d.console.scroll();
}
},
scroll:function(){
with(firebug){
el.left.console.monitor.environment.getElement().parentNode.scrollTop = Math.abs(el.left.console.monitor.environment.getSize().offsetHeight-(el.left.console.monitor.element.parentNode.offsetHeight-11));
}
},
run:function(_command){
with(firebug){
if(!env.init){
d.console.cache.push({ "command":_command, "arg":Array.prototype.slice.call(arguments,1) });
} else {
d.console.cmd[_command].apply(window,Array.prototype.slice.call(arguments,1));
}
}
},
toggleML:function(){
with(firebug){
var open = !env.ml;
env.ml = !env.ml;
d.navigateRightColumn("console",open);
el[open?"left":"right"].console.mlButton.environment.addStyle({ display:"none" });
el[!open?"left":"right"].console.mlButton.environment.addStyle({ display:"block" });
el.left.console.mlButton.attribute[(open?"add":"remove")+"Class"]("CloseML");
}
},
countMap:{}, timeMap: {},
cmd:{
log: function(_value){
with(firebug){
var args = d.console.formatArgs.apply(window,arguments);
d.console.addLine().attribute.addClass("Log").update(args);
d.console.scroll();
}
},
warn: function(_value){
with(firebug){
var args = d.console.formatArgs.apply(window,arguments);
d.console.addLine().attribute.addClass("Warn").update(args);
d.console.scroll();
}
},
info: function(_value){
with(firebug){
var args = d.console.formatArgs.apply(window,arguments);
d.console.addLine().attribute.addClass("Info").update(args);
d.console.scroll();
}
},
debug: function(_value){
with(firebug){
var args = d.console.formatArgs.apply(window,arguments);
d.console.addLine().attribute.addClass("Debug").update(args);
d.console.scroll();
}
},
error: function(_value){
with(firebug){
var args = d.console.formatArgs.apply(window,arguments);
d.console.addLine().attribute.addClass("Error").update(args);
d.console.scroll();
}
},
trace: function(_value){
with(firebug){
var stackAmt = 3, f = arguments.caller, isArray = lib.util.IsArray(f); //function that called trace
if((!isArray&&f)||(isArray&&f.length>0)){
d.console.addLine().attribute.addClass("Arrow").update(">>> console.trace(stack)");
for(var i=0;i<stackAmt;i++){
var func = f.toString(), args = f.arguments;
d.dom.open({"function":func, "arguments":args},d.console.addLine());
f = f.caller;
}
}
}
},
dir:function(_value){
with(firebug){
d.console.addLine().attribute.addClass("Arrow").update(">>> console.dir("+_value+")");
d.dom.open(_value,d.console.addLine());
}
},
dirxml: function(){
with(firebug){
d.console.cmd.log.apply(this, arguments);
}
},
time: function(_name){
with(firebug){
d.console.timeMap[_name] = new Date().getTime();
}
},
timeEnd: function(_name){
with(firebug){
if(_name in d.console.timeMap){
var delta = new Date().getTime() - d.console.timeMap[_name],
args = d.console.formatArgs.apply(window,[_name+":", delta+"ms"]);
d.console.addLine().attribute.addClass("log").update(args);
delete d.console.timeMap[_name];
}
}
},
count: function(_name){
with(firebug){
if(!d.console.countMap[_name])
d.console.countMap[_name] = 0;
d.console.countMap[_name]++;
d.console.cmd.log.apply(window, [_name, d.console.countMap[_name]]);
}
},
group:function(){
with(firebug){
d.console.cmd.log.apply(this, ["console.group is not supported"]);
}
},
groupEnd:function(){
with(firebug){
d.console.cmd.log.apply(this, ["console.groupEnd is not supported"]);
}
},
profile:function(){
with(firebug){
d.console.cmd.log.apply(this, ["console.profile is not supported"]);
}
},
profileEnd:function(){
with(firebug){
d.console.cmd.log.apply(this, ["console.profileEnd is not supported"]);
}
}
}
},
css:{
index:-1,
open:function(_index){
with (firebug) {
var item = env.targetWindow.document.styleSheets[_index],
uri = item.href;
try {
var rules = item[lib.env.ie ? "rules" : "cssRules"], str = "";
for (var i=0; i<rules.length; i++) {
var item = rules[i];
var selector = item.selectorText;
var cssText = lib.env.ie?item.style.cssText:item.cssText.match(/\{(.*)\}/)[1];
str+=d.css.printRule(selector, cssText.split(";"), el.left.css.container);
}
} catch(e) {
str="<em>Access to restricted URI denied</em>";
}
el.left.css.container.update(str);
}
},
printRule:function(_selector,_css,_layer){
with(firebug){
var str = "<div class='Selector'>"+_selector+" {</div>";
for(var i=0,len=_css.length; i<len; i++){
var item = _css[i];
str += "<div class='CSSText'>"+item.replace(/(.+\:)(.+)/,"<span class='CSSProperty'>$1</span><span class='CSSValue'>$2;</span>")+"</div>";
}
str+="<div class='Selector'>}</div>";
return str;
}
},
refresh:function(){
with(firebug){
el.button.css.selectbox.update("");
var collection = env.targetWindow.document.styleSheets;
for(var i=0,len=collection.length; i<len; i++){
var uri = getFileName(collection[i].href);
d.css.index=d.css.index<0?i:d.css.index;
el.button.css.selectbox.child.add(
new lib.element("OPTION").attribute.set("value",i).update(uri)
)
};
d.css.open(d.css.index);
}
}
},
dom: {
open: function(_object,_layer){
with (firebug) {
_layer.clean();
var container = new lib.element("DIV").attribute.addClass("DOMContent").insert(_layer);
d.dom.print(_object, container);
}
},
print:function(_object,_parent, _inTree){
with (firebug) {
var obj = _object || window, parentElement = _parent;
parentElement.update("");
if(parentElement.opened&&parentElement!=el.left.dom.container){
parentElement.environment.getParent().lib.child.get()[0].lib.child.get()[0].lib.attribute.removeClass("Opened");
parentElement.opened = false;
parentElement.environment.addStyle({ "display":"none" });
return;
}
if(_inTree)
parentElement.environment.getParent().lib.child.get()[0].lib.child.get()[0].lib.attribute.addClass("Opened");
parentElement.opened = true;
for (var key in obj) {
try {
if (env.hideDOMFunctions && typeof(obj[key]) == "function") continue;
var value = obj[key], property = key, container = new lib.element("DIV").attribute.addClass("DOMRow").insert(parentElement),
left = new lib.element("DIV").attribute.addClass("DOMRowLeft").insert(container), right = new lib.element("DIV").attribute.addClass("DOMRowRight").insert(container);
container.child.add(
new lib.element("DIV").attribute.addClass('Clear')
);
var link = new lib.element("A").attribute.addClass(
typeof value=="object"&&Boolean(value)?"Property Object":"Property"
).update(property).insert(left);
right.update(d.highlight(value,false,true));
var subContainer = new lib.element("DIV").attribute.addClass("DOMRowSubContainer").insert(container);
if(typeof value!="object"||Boolean(value)==false)
continue;
link.event.addListener("click",lib.util.Curry(d.dom.print,window,value, subContainer, true));
}catch(e){
}
}
parentElement.environment.addStyle({ "display":"block" });
}
}
},
highlight:function(_value,_inObject,_inArray,_link){
with(firebug){
var isArray = false, isHash, isElement = false, vtype=typeof _value, result=[];
if(vtype=="object"){
if(Object.prototype.toString.call(_value) === "[object Date]"){
vtype = "date";
} else if(Object.prototype.toString.call(_value) === "[object String]"){
vtype = "string";
} else if(Object.prototype.toString.call(_value) === "[object Boolean]"){
vtype = "boolean";
} else if(Object.prototype.toString.call(_value) === "[object RegExp]"){
vtype = "regexp";
}
}
try {
isArray = lib.util.IsArray(_value);
isHash = lib.util.IsHash(_value);
isElement = _value!=undefined&&Boolean(_value.nodeName)&&Boolean(_value.nodeType);
// number, string, boolean, null, function
if(_value==null||vtype=="number"||vtype=="string"||vtype=="boolean"||vtype=="function"||vtype=="regexp"||vtype=="date"){
if(_value==null){
result.push("<span class='Null'>null</span>");
}else if (vtype=="regexp") {
result.push("<span class='Maroon'>" + _value + "</span>");
}else if (vtype=="date") {
result.push("<span class='DarkBlue'>'" + _value + "'</span>");
} else if (vtype=="boolean"||vtype=="number") {
result.push("<span class='DarkBlue'>" + _value + "</span>");
} else if(vtype=="function"){
result.push("<span class='"+(_inObject?"Italic Gray":"Green")+"'>function()</span>");
} else {
result.push("<span class='Red'>\""+( !_inObject&&!_inArray?_value : _value.substring(0,35)+(_value.length>35?" ...":"") ).replace(/\n/g,"\\n").replace(/\s/g,"&nbsp;").replace(/>/g,"&#62;").replace(/</g,"&#60;")+"\"</span>");
}
}
// element
else if(isElement){
if(_value.nodeType==3)
result.push(d.highlight(_value.nodeValue));
else if(_inObject){
result.push("<span class='Gray Italic'>"+_value.nodeName.toLowerCase()+"</span>");
} else {
result.push("<span class='Blue"+ ( !_link?"'":" ObjectLink' onmouseover='this.className=this.className.replace(\"ObjectLink\",\"ObjectLinkHover\")' onmouseout='this.className=this.className.replace(\"ObjectLinkHover\",\"ObjectLink\")' onclick='firebug.d.html.inspect(firebug.d.console.cache[" +( d.console.cache.push( _value ) -1 )+"])'" ) + "'>");
if(_inArray){
result.push(_value.nodeName.toLowerCase());
if(_value.getAttribute){
if(_value.getAttribute&&_value.getAttribute("id"))
result.push("<span class='DarkBlue'>#"+_value.getAttribute("id")+"</span>");
var elClass = _value.getAttribute(lib.env.ie&&!lib.env.ie8?"className":"class")||"";
result.push(!elClass?"":"<span class='Red'>."+elClass.split(" ")[0]+"</span>");
}
result.push("</span>");
} else {
result.push("<span class='DarkBlue'>&#60;<span class='Blue TagName'>"+ _value.nodeName.toLowerCase());
if(_value.attributes){
for(var i=0,len=_value.attributes.length; i<len; i++){
var item = _value.attributes[i];
if(!lib.env.ie||item.nodeValue)
result.push(" <span class='DarkBlue'>"+item.nodeName+"=\"<span class='Red'>"+item.nodeValue+"</span>\"</span>");
}
}
result.push("</span>&#62;</span>");
}
}
}
// array, hash
else if(isArray||isHash){
if(isArray){
if(_inObject){
result.push("<span class='Gray Italic'>["+_value.length+"]</span>");
} else {
result.push("<span class='Strong'>[ ");
for(var i=0,len=_value.length; i<len; i++){
if((_inObject||_inArray)&&i>3){
result.push(", <span class='Strong Gray'>"+(len-4)+" More...</span>");
break;
}
result.push( (i > 0 ? ", " : "") + d.highlight(_value[i], false, true, true) );
}
result.push(" ]</span>");
}
} else if(_inObject){
result.push("<span class='Gray Italic'>Object</span>");
} else {
result.push("<span class='Strong Green"+ ( !_link?"'":" ObjectLink' onmouseover='this.className=this.className.replace(\"ObjectLink\",\"ObjectLinkHover\")' onmouseout='this.className=this.className.replace(\"ObjectLinkHover\",\"ObjectLink\")' onclick='firebug.d.console.openObject(" +( d.console.cache.push( _value ) -1 )+")'" ) + ">Object");
var i=0;
for(var key in _value){
var value = _value[key];
if((_inObject||_inArray)&&i>3){
result.push(" <span class='Strong Gray'>More...</span>");
break;
}
result.push(" "+key+"="+d.highlight(value,true));
i++;
}
result.push("</span>");
}
} else {
result.push(["<span class'Gray Italic'>"+_value+"</span>"]);
}
} catch(e){
result.push("..");
}
return result.join("");
}
},
html:{
nIndex:"computedStyle",
current:null,
highlight:function(_element,_clear,_event){
with(firebug){
if(_element.firebugElement){
return;
}
if(_clear){
env.targetWindow.firebug.el.bgInspector.environment.addStyle({ "display":"none" });
return;
}
d.inspector.inspect(_element,true);
}
},
inspect:function(_element){
var map = [],
parentLayer,
t,
tagName,
parent = _element;
while (parent) {
map.push(parent);
if (parent == firebug.env.targetWindow.document.body) break;
parent = parent.parentNode;
}
map = map.reverse();
with(firebug) {
if (env.dIndex != "html") {
env.targetWindow.firebug.d.navigate("html");
}
env.targetWindow.firebug.d.inspector.toggle(false);
for (t = 0; t < el.left.html.container.child.get().length; t++) {
if (el.left.html.container.child.get()[t].childNodes[0].childNodes[1].childNodes[0].childNodes[0]) {
if (el.left.html.container.child.get()[t].childNodes[0].childNodes[1].childNodes[0].childNodes[0].innerText) {
tagName = el.left.html.container.child.get()[t].childNodes[0].childNodes[1].childNodes[0].childNodes[0].innerText;
} else {
tagName = el.left.html.container.child.get()[t].childNodes[0].childNodes[1].childNodes[0].childNodes[0].textContent;
}
if (/<body/i.test(tagName)) {
parentLayer = el.left.html.container.child.get()[t].childNodes[1].lib;
break;
}
}
}
if (!parentLayer) {
parentLayer = el.left.html.container.child.get()[3].childNodes[1].lib;
}
for (t = 0, len = map.length; map[t]; t++) {
if (t == len - 1) {
var link = parentLayer.environment.getElement().previousSibling.lib;
link.attribute.addClass("Selected");
if (d.html.current) {
d.html.current[1].attribute.removeClass("Selected");
}
d.html.current = [_element, link];
return;
}
parentLayer = d.html.openHtmlTree(map[t], parentLayer, map[t + 1]);
}
}
},
navigate:function(_index,_element){
with(firebug){
el.right.html.nav[d.html.nIndex].attribute.removeClass("Selected");
el.right.html.nav[_index].attribute.addClass("Selected");
d.html.nIndex = _index;
d.html.openProperties();
}
},
openHtmlTree:function(_element,_parent,_returnParentElementByElement,_event){
with(firebug){
var element = _element || env.targetWindow.document.documentElement,
parent = _parent || el.left.html.container,
returnParentEl = _returnParentElementByElement || null,
returnParentVal = null,
len = element.childNodes.length,
nodeLink;
if(parent!=el.left.html.container){
nodeLink = parent.environment.getParent().lib.child.get()[0].lib;
if (d.html.current) {
d.html.current[1].attribute.removeClass("Selected");
}
nodeLink.attribute.addClass("Selected");
d.html.current = [_element,nodeLink];
d.html.openProperties();
};
if(element.childNodes&&(len==0||(len==1&&element.childNodes[0].nodeType==3)))return;
parent.clean();
if(parent.opened&&Boolean(_returnParentElementByElement)==false){
parent.opened = false;
parent.element.previousSibling.lib.attribute.removeClass("Open");
parent.element.lib.attribute.removeClass("OpenSubContainer");
return;
};
if (parent != el.left.html.container) {
parent.element.previousSibling.lib.attribute.addClass("Open");
parent.element.lib.attribute.addClass("OpenSubContainer");
parent.opened = true;
};
if(element==document.documentElement){
new lib.element("A").attribute.addClass("Block").update("<span class='DarkBlue'>&#60;<span class='Blue'>html</span>&#62;").insert(parent);
};
for(var i=0; i<=len; i++){
if(i==len){
new lib.element("A").attribute.addClass("Block").update("<span class='DarkBlue'>&#60;/<span class='Blue'>"+element.nodeName.toLowerCase()+"</span>&#62;").insert(container);
break;
}
var item = element.childNodes[i];
if (item.nodeType != 3){
var container = new lib.element().attribute.addClass("Block").insert(parent),
link = new lib.element("A").attribute.addClass("Link").insert(container),
spacer = new lib.element("SPAN").attribute.addClass("Spacer").update("&nbsp;").insert(link),
html = new lib.element("SPAN").attribute.addClass("Content").update(d.highlight(item)).insert(link),
subContainer = new lib.element("DIV").attribute.addClass("SubContainer").insert(container),
view = lib.util.Element.getView(item);
link.event.addListener("click", lib.util.Curry(d.html.openHtmlTree, window, item, subContainer, false));
link.event.addListener("mouseover", lib.util.Curry(d.html.highlight, window, item, false));
link.event.addListener("mouseout", lib.util.Curry(d.html.highlight, window, item, true));
returnParentVal = returnParentEl == item ? subContainer : returnParentVal;
if(d.html.current==null&&item==document.body){
link.attribute.addClass("Selected");
d.html.current = [item,link];
d.html.openHtmlTree(item,subContainer);
}
if(element.nodeName!="HEAD"&&element!=document.documentElement&&(view.visibility=="hidden"||view.display=="none")){
container.attribute.addClass("Unvisible");
};
if (item.childNodes){
var childLen = item.childNodes.length;
if (childLen == 1 && item.childNodes[0].nodeType == 3) {
html.child.add(document.createTextNode(item.childNodes[0].nodeValue.substring(0, 50)));
html.child.add(document.createTextNode("</"));
html.child.add(new lib.element("span").attribute.addClass("Blue").update(item.nodeName.toLowerCase()).environment.getElement());
html.child.add(document.createTextNode(">"));
continue;
}
else
if (childLen > 0) {
link.attribute.addClass("Parent");
}
}
}
};
return returnParentVal;
}
},
openProperties:function(){
with(firebug){
var index = d.html.nIndex;
var node = d.html.current[0];
d.clean(el.right.html.content);
var str = "";
switch(index){
case "computedStyle":
var property = ["opacity","filter","azimuth","background","backgroundAttachment","backgroundColor","backgroundImage","backgroundPosition","backgroundRepeat","border","borderCollapse","borderColor","borderSpacing","borderStyle","borderTop","borderRight","borderBottom","borderLeft","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","borderTopStyle","borderRightStyle","borderBottomStyle","borderLeftStyle","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderWidth","bottom","captionSide","clear","clip","color","content","counterIncrement","counterReset","cue","cueAfter","cueBefore","cursor","direction","display","elevation","emptyCells","cssFloat","font","fontFamily","fontSize","fontSizeAdjust","fontStretch","fontStyle","fontVariant","fontWeight","height","left","letterSpacing","lineHeight","listStyle","listStyleImage","listStylePosition","listStyleType","margin","marginTop","marginRight","marginBottom","marginLeft","markerOffset","marks","maxHeight","maxWidth","minHeight","minWidth","orphans","outline","outlineColor","outlineStyle","outlineWidth","overflow","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","page","pageBreakAfter","pageBreakBefore","pageBreakInside","pause","pauseAfter","pauseBefore","pitch","pitchRange","playDuring","position","quotes","richness","right","size","speak","speakHeader","speakNumeral","speakPunctuation","speechRate","stress","tableLayout","textAlign","textDecoration","textIndent","textShadow","textTransform","top","unicodeBidi","verticalAlign","visibility","voiceFamily","volume","whiteSpace","widows","width","wordSpacing","zIndex"].sort();
var view = document.defaultView?document.defaultView.getComputedStyle(node,null):node.currentStyle;
for(var i=0,len=property.length; i<len; i++){
var item = property[i];
if(!view[item])continue;
str+="<div class='CSSItem'><div class='CSSProperty'>"+item+"</div><div class='CSSValue'>"+d.highlight(view[item])+"</div></div>";
}
el.right.html.content.update(str);
break;
case "dom":
d.dom.open(node,el.right.html.content,lib.env.ie);
break;
}
}
}
},
inspector:{
enabled:false,
el:null,
inspect:function(_element,_bgInspector){
with(firebug){
var pos = env.targetWindow.firebug.lib.util.Element.getPosition(_element);
env.targetWindow.firebug.el[_bgInspector&&"bgInspector"||"borderInspector"].environment.addStyle({
"width":_element.offsetWidth+"px", "height":_element.offsetHeight+"px",
"top":pos.offsetTop-(_bgInspector?0:2)+"px", "left":pos.offsetLeft-(_bgInspector?0:2)+"px",
"display":"block"
});
9
if(!_bgInspector){
d.inspector.el = _element;
}
};
},
toggle:function(_absoluteValue,_event){
with (firebug) {
if(_absoluteValue==d.inspector.enabled)
return;
d.inspector.enabled = _absoluteValue!=undefined&&!_absoluteValue.clientX?_absoluteValue:!d.inspector.enabled;
el.button.inspect.attribute[(d.inspector.enabled ? "add" : "remove") + "Class"]("Enabled");
if(d.inspector.enabled==false){
el.borderInspector.environment.addStyle({ "display":"none" });
d.inspector.el = null;
} else if(lib.env.dIndex!="html") {
if (env.popupWin) {
env.popupWin.firebug.d.navigate("html");
} else {
d.navigate("html");
}
}
}
}
},
scripts:{
index:-1,
lineNumbers:false,
open:function(_index){
with(firebug){
d.scripts.index = _index;
el.left.scripts.container.update("");
var script = document.getElementsByTagName("script")[_index],uri = script.src||document.location.href,source;
try {
if(uri!=document.location.href){
source = env.cache[uri]||lib.xhr.get(uri).responseText;
env.cache[uri] = source;
} else {
source = script.innerHTML;
}
source = source.replace(/<|>/g,function(_ch){
return ({"<":"&#60;",">":"&#62;"})[_ch];
});
if(!d.scripts.lineNumbers)
el.left.scripts.container.child.add(
new lib.element("DIV").attribute.addClass("CodeContainer").update(source)
);
else {
source = source.split("<br />");
for (var i = 0; i < source.length; i++) {
el.left.scripts.container.child.add(new lib.element("DIV").child.add(new lib.element("DIV").attribute.addClass("LineNumber").update(i + 1), new lib.element("DIV").attribute.addClass("Code").update("&nbsp;" + source[i]), new lib.element("DIV").attribute.addClass('Clear')));
};
};
} catch(e){
el.left.scripts.container.child.add(
new lib.element("DIV").attribute.addClass("CodeContainer").update("<em>Access to restricted URI denied</em>")
);
}
}
},
toggleLineNumbers:function(){
with(firebug){
d.scripts.lineNumbers = !d.scripts.lineNumbers;
el.button.scripts.lineNumbers.attribute[(d.scripts.lineNumbers ? "add" : "remove") + "Class"]("Enabled");
d.scripts.open( d.scripts.index );
}
},
refresh:function(){
with(firebug){
el.button.scripts.selectbox.clean();
var collection = env.targetWindow.document.getElementsByTagName("script");
for(var i=0,len=collection.length; i<len; i++){
var item = collection[i],
fileName = getFileName(item.src||item.baseURI||"..");
d.scripts.index=d.scripts.index<0?i:d.scripts.index;
el.button.scripts.selectbox.child.add(
new lib.element("OPTION").attribute.set("value",i).update(fileName)
);
}
d.scripts.open( d.scripts.index );
}
}
},
str: {
open:function(_str){
with(firebug){
d.navigate("str");
el.left.str.container.update(_str.replace(/\n/g,"<br />"))
}
}
},
xhr:{
objects:[],
addObject:function(){
with(firebug){
for(var i=0,len=arguments.length; i<len; i++){
try {
var item = arguments[i],
val = env.targetWindow.eval(item);
d.xhr.objects.push([item, val]);
} catch(e){
continue;
}
}
}
},
open:function(){
with(firebug){
el.left.xhr.container.update("");
el.left.xhr.name = new lib.element("DIV").attribute.addClass("BlockContent").insert(new lib.element("DIV").attribute.addClass("Block").environment.addStyle({ "width":"20%" }).insert(el.left.xhr.container));
el.left.xhr.nameTitle = new lib.element("STRONG").update("Object Name:").insert(el.left.xhr.name);
el.left.xhr.nameContent = new lib.element("DIV").insert(el.left.xhr.name);
el.left.xhr.status = new lib.element("DIV").attribute.addClass("BlockContent").insert(new lib.element("DIV").attribute.addClass("Block").environment.addStyle({ "width":"10%" }).insert(el.left.xhr.container));
el.left.xhr.statusTitle = new lib.element("STRONG").update("Status:").insert(el.left.xhr.status);
el.left.xhr.statusContent = new lib.element("DIV").insert(el.left.xhr.status);
el.left.xhr.readystate = new lib.element("DIV").attribute.addClass("BlockContent").insert(new lib.element("DIV").environment.addStyle({ "width":"15%" }).attribute.addClass("Block").insert(el.left.xhr.container));
el.left.xhr.readystateTitle =el.left.xhr.nameTitle = new lib.element("STRONG").update("Ready State:").insert(el.left.xhr.readystate);
el.left.xhr.readystateContent = new lib.element("DIV").insert(el.left.xhr.readystate);
el.left.xhr.response = new lib.element("DIV").attribute.addClass("BlockContent").insert(new lib.element("DIV").environment.addStyle({ "width":(lib.env.ie?"50":"55")+"%" }).attribute.addClass("Block").insert(el.left.xhr.container));
el.left.xhr.responseTitle = new lib.element("STRONG").update("Response:").insert(el.left.xhr.response);
el.left.xhr.responseContent = new lib.element("DIV").insert(el.left.xhr.response);
setTimeout(d.xhr.refresh,500);
}
},
refresh:function(){
with(firebug){
el.left.xhr.nameContent.update("");
el.left.xhr.statusContent.update("");
el.left.xhr.readystateContent.update("");
el.left.xhr.responseContent.update("");
for(var i=0,len=d.xhr.objects.length; i<len; i++){
var item = d.xhr.objects[i],
response = item[1].responseText;
if(Boolean(item[1])==false)continue;
el.left.xhr.nameContent.child.add(new lib.element("span").update(item[0]));
try {
el.left.xhr.statusContent.child.add(new lib.element("span").update(item[1].status));
} catch(e){ el.left.xhr.statusContent.child.add(new lib.element("span").update("&nbsp;")); }
el.left.xhr.readystateContent.child.add(new lib.element("span").update(item[1].readyState));
el.left.xhr.responseContent.child.add(new lib.element("span").child.add(
new lib.element("A").event.addListener("click",lib.util.Curry(d.str.open,window,response)).update("&nbsp;"+response.substring(0,50))
));
};
if(env.dIndex=="xhr")
setTimeout(d.xhr.refresh,500);
}
}
},
navigateRightColumn:function(_index,_open){
with(firebug){
el.left.container.environment.addStyle({ "width":_open?"70%":"100%" });
el.right.container.environment.addStyle({ "display":_open?"block":"none" });
}
},
navigate:function(_index){
with(firebug){
var open = _index, close = env.dIndex;
env.dIndex = open;
settings.hide();
el.button[close].container.environment.addStyle({ "display":"none" });
el.left[close].container.environment.addStyle({ "display":"none" });
el.right[close].container.environment.addStyle({ "display":"none" });
el.button[open].container.environment.addStyle({ "display":"inline" });
el.left[open].container.environment.addStyle({ "display":"block" });
el.right[open].container.environment.addStyle({ "display":"block" });
if(el.nav[close])
el.nav[close].attribute.removeClass("Selected");
if(el.nav[open])
el.nav[open].attribute.addClass("Selected");
switch(open){
case "console":
d.navigateRightColumn(_index);
break;
case "html":
d.navigateRightColumn(_index,true);
if(!d.html.current){
var t=Number(new Date);
d.html.openHtmlTree();
}
break;
case "css":
d.navigateRightColumn(_index,true);
d.css.refresh();
break;
case "scripts":
d.navigateRightColumn(_index);
d.scripts.refresh();
break;
case "dom":
d.navigateRightColumn(_index);
if(el.left.dom.container.environment.getElement().innerHTML==""){
var t=Number(new Date);
d.dom.open(eval(el.button.dom.textbox.environment.getElement().value),el.left.dom.container);
}
break;
case "xhr":
d.navigateRightColumn(_index);
d.xhr.open();
break;
}
}
}
},
getFileName:function(_path){
var match = _path&&_path.match(/[\w\-\.\?\=\&]+$/);
return match&&match[0]||_path;
},
cancelEvent:function(_event){
if(_event.stopPropagation)
_event.stopPropagation();
if(_event.preventDefault)
_event.preventDefault();
},
getSelection:function(_el){
with(firebug){
if(lib.env.ie){
var range = document.selection.createRange(),stored = range.duplicate();
stored.moveToElementText(_el);
stored.setEndPoint('EndToEnd', range);
_el.selectionStart = stored.text.length - range.text.length;
_el.selectionEnd = _el.selectionStart + range.text.length;
}
return {
start:_el.selectionStart,
length:_el.selectionEnd-_el.selectionStart
}
}
},
tab:function(_el,_event){
with(firebug){
if(_event.keyCode==9){
if(_el.setSelectionRange){
var position = firebug.getSelection(_el);
_el.value = _el.value.substring(0,position.start) + String.fromCharCode(9) + _el.value.substring(position.start+position.length,_el.value.length);
_el.setSelectionRange(position.start+1,position.start+1);
} else if(document.selection) {
var range = document.selection.createRange(), isCollapsed = range.text == '';
range.text = String.fromCharCode(9);
range.moveStart('character', -1);
}
firebug.cancelEvent(_event);
if(lib.env.ie)
setTimeout(_el.focus,100);
};
}
},
listen: {
addXhrObject:function(){
with(firebug){
d.xhr.addObject.apply(env.targetWindow, el.button.xhr.textbox.environment.getElement().value.split(","));
}
},
consoleTextbox:function(_event){
with(firebug){
if(_event.keyCode==13&&(env.multilinemode==false||_event.shiftKey==false)){
d.console.historyIndex = d.console.history.length;
d.console.eval(el.left.console.input.environment.getElement().value);
return false;
}
switch(_event.keyCode){
case 40:
if(d.console.history[d.console.historyIndex+1]){
d.console.historyIndex+=1;
el.left.console.input.update( d.console.history[d.console.historyIndex] );
}
break;
case 38:
if(d.console.history[d.console.historyIndex-1]){
d.console.historyIndex-=1;
el.left.console.input.update( d.console.history[d.console.historyIndex] );
}
break;
}
}
},
cssSelectbox:function(){
with(firebug){
d.css.open(el.button.css.selectbox.environment.getElement().selectedIndex);
}
},
domTextbox:function(_event){
with(firebug){
if(_event.keyCode==13){
d.dom.open(eval(el.button.dom.textbox.environment.getElement().value),el.left.dom.container);
}
}
},
inspector:function(){
with(firebug){
if (env.popupWin) {
env.popupWin.firebug.d.html.inspect(firebug.d.inspector.el);
} else {
firebug.d.html.inspect(firebug.d.inspector.el);
}
}
},
keyboard:function(_event){
with(firebug){
if(_event.keyCode==27 && d.inspector.enabled){
d.inspector.toggle();
} else if(_event.keyCode === 123 && _event.ctrlKey || _event.metaKey) {
if(env.isPopup){
win.dock();
}else {
win.newWindow();
}
} else if(
(_event.keyCode === 123 && !_event.ctrlKey && !_event.metaKey) ||
(_event.keyCode === 76 && (_event.ctrlKey || _event.metaKey) && _event.shiftKey) ||
(_event.keyCode === 13 && _event.shiftKey)) {
if(env.isPopup){
win.dock();
} else if (el.main.environment.getStyle("display") === 'none') {
win.show();
} else {
win.hide();
}
}
}
},
mouse:function(_event){
with(firebug){
var target;
if(document.elementFromPoint) {
target = document.elementFromPoint(_event.clientX, _event.clientY);
} else {
if(lib.env.ie) {
target = _event.srcElement;
} else {
target = _event.explicitOriginalTarget || _event.target;
}
}
if( d.inspector.enabled&&
target!=document.body&&
target!=document.firstChild&&
target!=document.childNodes[1]&&
target!=el.borderInspector.environment.getElement()&&
target!=el.main.environment.getElement()&&
target.offsetParent!=el.main.environment.getElement() ) {
d.inspector.inspect(target);
}
}
},
runMultiline:function(){
with(firebug){
d.console.eval.call(window,el.right.console.input.environment.getElement().value);
}
},
runCSS:function(){
with(firebug){
var source = el.right.css.input.environment.getElement().value.replace(/\n|\t/g,"").split("}");
for(var i=0, len=source.length; i<len; i++){
var item = source[i]+"}", rule = !lib.env.ie?item:item.split(/{|}/),
styleSheet = document.styleSheets[0];
console.log(rule);
if(item.match(/.+\{.+\}/)){
if(lib.env.ie)
styleSheet.addRule(rule[0],rule[1]);
else
styleSheet.insertRule( rule, styleSheet.cssRules.length );
}
}
}
},
scriptsSelectbox:function(){
with(firebug){
d.scripts.open(parseInt(el.button.scripts.selectbox.environment.getElement().value));
}
},
xhrTextbox:function(_event){
with(firebug){
if(_event.keyCode==13){
d.xhr.addObject.apply(env.targetWindow, el.button.xhr.textbox.environment.getElement().value.split(","));
}
}
}
}
};
(function(_scope){
_scope.lib = {};
var pi = _scope.lib; pi.version = [1.1,2008091000];
pi.env = {
ie: /MSIE/i.test(navigator.userAgent),
ie6: /MSIE 6/i.test(navigator.userAgent),
ie7: /MSIE 7/i.test(navigator.userAgent),
ie8: /MSIE 8/i.test(navigator.userAgent),
firefox: /Firefox/i.test(navigator.userAgent),
opera: /Opera/i.test(navigator.userAgent),
webkit: /Webkit/i.test(navigator.userAgent),
camino: /Camino/i.test(navigator.userAgent)
};
pi.get = function(){
return document.getElementById(arguments[0]);
};
pi.get.byTag = function(){
return document.getElementsByTagName(arguments[0]);
};
pi.get.byClass = function(){ return document.getElementsByClassName.apply(document,arguments); };
pi.util = {
Array:{
clone:function(_array,_undeep){
var tmp = [];
Array.prototype.push.apply(tmp,_array);
pi.util.Array.forEach(tmp,function(_item,_index,_source){
if(_item instanceof Array&&!_undeep)
_source[_index] = pi.util.Array.clone(_source[_index]);
});
return tmp;
},
count:function(_array,_value){
var count = 0;
pi.util.Array.forEach(_array,function(){
count+=Number(arguments[0]==_value);
});
return count;
},
forEach:function(_array,_function){
if(_array.forEach)
return _array.forEach(_function);
for(var i=0,len=_array.length; i<len; i++)
_function.apply(_array,[_array[i],i,_array]);
},
getLatest:function(_array){
return _array[_array.length-1];
},
indexOf:function(_array,_value){
if(!pi.env.ie){
return _array.indexOf(_value);
};
var index = -1;
for(var i=0, len=_array.length; i<len; i++){
if(_array[i]==_value){
index = i;
break;
}
}
return index;
},
remove:function(_array,_index){
var result = _array.slice(0,_index);
_array = Array.prototype.push.apply(result,_array.slice(_index+1));
return result;
}
},
Curry:function(_fn,_scope){
var fn = _fn, scope = _scope||window, args = Array.prototype.slice.call(arguments,2);
return function(){
return fn.apply(scope,args.concat( Array.prototype.slice.call(arguments,0) ));
};
},
Extend:function(_superClass,_prototype,_skipClonning){
var object = new pi.base;
if(_prototype["$Init"]){
object.init = _prototype["$Init"];
delete _prototype["$Init"];
};
object.body = _superClass==pi.base?_prototype:pi.util.Hash.merge(_prototype,_superClass.prototype);
object.init=object.init||function(){
if(_superClass!=pi.base)
_superClass.apply(this,arguments);
};
return object.build(_skipClonning);
},
IsArray:function(_object){
if(_object===null){
return false;
}
if(window.NodeList&&window.NamedNodeMap&&!pi.env.ie8){
if(_object instanceof Array||_object instanceof NodeList||_object instanceof NamedNodeMap||(window.HTMLCollection&&_object instanceof HTMLCollection))
return true;
};
if(!_object||_object==window||typeof _object=="function"||typeof _object=="string"||typeof _object.length!="number"){
return false
};
var len = _object.length;
if(len>0&&_object[0]!=undefined&&_object[len-1]!=undefined){
return true;
} else {
for(var key in _object){
if(key!="item"&&key!="length"&&key!="setNamedItemNS"&&key!="setNamedItem"&&key!="getNamedItem"&&key!="removeNamedItem"&&key!="getNamedItemNS"&&key!="removeNamedItemNS"&&key!="tags"){
return false;
}
}
return true
};
},
IsHash:function(_object){
return _object && typeof _object=="object"&&(_object==window||_object instanceof Object)&&!_object.nodeName&&!pi.util.IsArray(_object)
},
Init:[],
AddEvent: function(_element,_eventName,_fn,_useCapture){
_element[pi.env.ie?"attachEvent":"addEventListener"]((pi.env.ie?"on":"")+_eventName,_fn,_useCapture||false);
return pi.util.Curry(pi.util.AddEvent,this,_element);
},
RemoveEvent: function(_element,_eventName,_fn,_useCapture){
_element[pi.env.ie?"detachEvent":"removeEventListener"]((pi.env.ie?"on":"")+_eventName,_fn,_useCapture||false);
return pi.util.Curry(pi.util.RemoveEvent,this,_element);
},
Element:{
addClass:function(_element,_class){
if( !pi.util.Element.hasClass(_element,_class) )
pi.util.Element.setClass(_element, pi.util.Element.getClass(_element) + " " + _class );
},
getClass:function(_element){
return _element.getAttribute(pi.env.ie&&!pi.env.ie8?"className":"class")||"";
},
hasClass:function(_element,_class){
return pi.util.Array.indexOf(pi.util.Element.getClass(_element).split(" "),_class)>-1;
},
removeClass:function(_element,_class){
if( pi.util.Element.hasClass(_element,_class) ){
var names = pi.util.Element.getClass(_element,_class).split(" ");
pi.util.Element.setClass(
_element,
pi.util.Array.remove(names,pi.util.Array.indexOf(names,_class)).join(" ")
);
}
},
setClass:function(_element,_value){
if(pi.env.ie8){
_element.setAttribute("className", _value );
_element.setAttribute("class", _value );
} else {
_element.setAttribute(pi.env.ie?"className":"class", _value );
}
},
toggleClass:function(){
if(pi.util.Element.hasClass.apply(this,arguments))
pi.util.Element.removeClass.apply(this,arguments);
else
pi.util.Element.addClass.apply(this,arguments);
},
getOpacity:function(_styleObject){
var styleObject = _styleObject;
if(!pi.env.ie)
return styleObject["opacity"];
var alpha = styleObject["filter"].match(/opacity\=(\d+)/i);
return alpha?alpha[1]/100:1;
},
setOpacity:function(_element,_value){
if(!pi.env.ie)
return pi.util.Element.addStyle(_element,{ "opacity":_value });
_value*=100;
pi.util.Element.addStyle(_element,{ "filter":"alpha(opacity="+_value+")" });
return this._parent_;
},
getPosition:function(_element){
var parent = _element,offsetLeft = document.body.offsetLeft, offsetTop = document.body.offsetTop, view = pi.util.Element.getView(_element);
while(parent&&parent!=document.body&&parent!=document.firstChild){
offsetLeft +=parseInt(parent.offsetLeft);
offsetTop += parseInt(parent.offsetTop);
parent = parent.offsetParent;
};
return {
"bottom":view["bottom"],
"clientLeft":_element.clientLeft,
"clientTop":_element.clientTop,
"left":view["left"],
"marginTop":view["marginTop"],
"marginLeft":view["marginLeft"],
"offsetLeft":offsetLeft,
"offsetTop":offsetTop,
"position":view["position"],
"right":view["right"],
"top":view["top"],
"zIndex":view["zIndex"]
};
},
getSize:function(_element){
var view = pi.util.Element.getView(_element);
return {
"height":view["height"],
"clientHeight":_element.clientHeight,
"clientWidth":_element.clientWidth,
"offsetHeight":_element.offsetHeight,
"offsetWidth":_element.offsetWidth,
"width":view["width"]
}
},
addStyle:function(_element,_style){
for(var key in _style){
key = key=="float"?pi.env.ie?"styleFloat":"cssFloat":key;
if (key == "opacity" && pi.env.ie) {
pi.util.Element.setOpacity(_element,_style[key]);
continue;
}
try {
_element.style[key] = _style[key];
}catch(e){}
}
},
getStyle:function(_element,_property){
_property = _property=="float"?pi.env.ie?"styleFloat":"cssFloat":_property;
if(_property=="opacity"&&pi.env.ie)
return pi.util.Element.getOpacity(_element.style);
return typeof _property=="string"?_element.style[_property]:_element.style;
},
getValue:function(_element){
switch(_element.nodeName.toLowerCase()){
case "input":
case "textarea":
return _element.value;
case "select":
return _element.options[_element.selectedIndex].value;
default:
return _element.innerHTML;
break;
}
},
getView:function(_element,_property){
var view = document.defaultView?document.defaultView.getComputedStyle(_element,null):_element.currentStyle;
_property = _property=="float"?pi.env.ie?"styleFloat":"cssFloat":_property;
if(_property=="opacity"&&pi.env.ie)
return pi.util.Element.getOpacity(_element,view);
return typeof _property=="string"?view[_property]:view;
}
},
Hash: {
clone:function(_hash,_undeep){
var tmp = {};
for(var key in _hash){
if( !_undeep&&pi.util.IsArray( _hash[key] ) ){
tmp[key] = pi.util.Array.clone( _hash[key] );
} else if( !_undeep&&pi.util.IsHash( _hash[key] ) ){
tmp[ key ] = pi.util.Hash.clone(_hash[key]);
} else {
tmp[key] = _hash[key];
}
}
return tmp;
},
merge:function(_hash,_source,_undeep){
for(var key in _source){
var value = _source[key];
if (!_undeep&&pi.util.IsArray(_source[key])) {
if(pi.util.IsArray( _hash[key] )){
Array.prototype.push.apply( _source[key], _hash[key] )
}
else
value = pi.util.Array.clone(_source[key]);
}
else if (!_undeep&&pi.util.IsHash(_source[key])) {
if (pi.util.IsHash(_hash[key])) {
value = pi.util.Hash.merge(_hash[key], _source[key]);
} else {
value = pi.util.Hash.clone( _source[key] );
}
} else if( _hash[key] )
value = _hash[ key ];
_hash[key] = value;
};
return _hash;
}
},
String:{
format:function(_str){
var values = Array.prototype.slice.call(arguments,1);
return _str.replace(/\{(\d)\}/g,function(){
return values[arguments[1]];
})
}
},
GetViewport:function(){
return {
height:document.documentElement.clientHeight||document.body.clientHeight,
width:document.documentElement.clientWidth||document.body.clientWidth
}
}
};
pi.base = function(){
this.body = {};
this.init = null;
this.build = function(_skipClonning){
var base = this, skipClonning = _skipClonning||false, _private = {},
fn = function(){
var _p = pi.util.Hash.clone(_private);
if(!skipClonning){
for(var key in this){
if(pi.util.IsArray( this[ key ] ) ){
this[key] = pi.util.Array.clone( this[key] );
} else
if( pi.util.IsHash(this[key]) ){
this[key] = pi.util.Hash.clone(
this[ key ],
function(_key,_object){
this[ _key ]._parent_ = this;
}
);
//this[key]._parent_ = this;
}
}
};
base.createAccessors( _p, this );
if(base.init)
return base.init.apply(this,arguments);
return this;
};
this.movePrivateMembers(this.body,_private);
if(this.init){
fn["$Init"] = this.init;
};
fn.prototype = this.body;
return fn;
};
this.createAccessors = function(_p, _branch){
var getter = function(_property){ return this[_property]; },
setter = function(_property,_value){ this[_property] = _value; return _branch._parent_||_branch; };
for (var name in _p) {
var isPrivate = name.substring(0, 1) == "_", title = name.substring(1, 2).toUpperCase() + name.substring(2);
if (isPrivate) {
_branch[(_branch["get" + title]?"_":"")+"get" + title] = pi.util.Curry(getter,_p,name);
_branch[(_branch["set" + title]?"_":"")+"set" + title] = pi.util.Curry(setter,_p,name);
}
else
if (pi.util.IsHash(_p[name])){
_branch[name]._parent_ = _branch;
if(!_branch[name])
_branch[name] = {};
this.createAccessors(_p[name], _branch[name]);
}
};
};
this.movePrivateMembers = function(_object, _branch){
for (var name in _object) {
var isPrivate = name.substring(0, 1) == "_";
if (isPrivate) {
_branch[name] = _object[name];
delete _object[name];
}
else
if (pi.util.IsHash(_object[name])){
_branch[name] = {};
this.movePrivateMembers(_object[name], _branch[name]);
}
};
};
};
pi.element = new pi.base;
pi.element.init = function(_val){
this.environment.setElement(
typeof _val=="string"||!_val?
document.createElement(_val||"DIV"):
_val
);
return this;
};
pi.element.body = {
"addStyle":function(){
return this.environment.addStyle.apply(this.environment,arguments);
},
"clean":function(){
var childs = this.child.get();
while(childs.length){
childs[0].parentNode.removeChild(childs[0]);
}
},
"clone":function(_deep){
return this.environment.getElement().cloneNode(_deep);
},
"insert":function(_element){
_element = _element.environment?_element.environment.getElement():_element;
_element.appendChild(this.environment.getElement());
return this;
},
"insertAfter":function(_referenceElement){
_referenceElement = _referenceElement.environment?_referenceElement.environment.getElement():_referenceElement;
_referenceElement.nextSibling?this.insertBefore(_referenceElement.nextSibling):this.insert(_referenceElement.parentNode);
return this;
},
"insertBefore":function(_referenceElement){
_referenceElement = _referenceElement.environment?_referenceElement.environment.getElement():_referenceElement;
_referenceElement.parentNode.insertBefore(this.environment.getElement(),_referenceElement);
return this;
},
"query":function(_expression,_resultType,namespaceResolver,_result){
return pi.xpath(_expression,_resultType||"ORDERED_NODE_SNAPSHOT_TYPE",this.environment.getElement(),_namespaceResolver,_result);
},
"remove":function(){
if (this.environment.getParent()) {
this.environment.getParent().removeChild(this.environment.getElement());
}
},
"update":function(_value){
this.element[this.element.nodeName.toLowerCase()=="textarea"||this.element.nodeName.toLowerCase()=="input"?"value":"innerHTML"]=_value;
return this;
},
"attribute":{
"getAll":function(){
return this._parent_.environment.getElement().attributes;
},
"clear":function(_name){
this.set(_name,"");
return this._parent_;
},
"get":function(_name){
return this._parent_.environment.getElement().getAttribute(_name);
},
"has":function(_name){
return pi.env.ie?(this.get(_name)!=null):this._parent_.environment.getElement().hasAttribute(_name);
},
"remove":function(_name){
this._parent_.environment.getElement().removeAttribute(_name);
return this._parent_;
},
"set":function(_name,_value){
this._parent_.environment.getElement().setAttribute(_name,_value);
return this._parent_;
},
"addClass":function(_classes){
for(var i=0,len=arguments.length; i<len; i++){
pi.util.Element.addClass(this._parent_.environment.getElement(),arguments[i]);
};
return this._parent_;
},
"clearClass":function(){
this.setClass("");
this._parent_;
},
"getClass":function(){
return pi.util.Element.getClass( this._parent_.environment.getElement() );
},
"hasClass":function(_class){
return pi.util.Element.hasClass( this._parent_.environment.getElement(), _class );
},
"setClass":function(_value){
return pi.util.Element.setClass( this._parent_.environment.getElement(), _value );
},
"removeClass":function(_class){
pi.util.Element.removeClass( this._parent_.environment.getElement(), _class );
return this._parent_;
},
"toggleClass":function(_class){
pi.util.Element.toggleClass( this._parent_.environment.getElement(), _class );
}
},
"child":{
"get":function(){
return this._parent_.environment.getElement().childNodes;
},
"add":function(_elements){
for (var i = 0; i < arguments.length; i++) {
var el = arguments[i];
this._parent_.environment.getElement().appendChild(
el.environment ? el.environment.getElement() : el
);
}
return this._parent_;
},
"addAfter":function(_element,_referenceElement){
this.addBefore(
_element.environment?_element.environment.getElement():_element,
(_referenceElement.environment?_referenceElement.environment.getElement():_referenceElement).nextSibling
);
return this._parent_;
},
"addBefore":function(_element,_referenceElement){
this._parent_.environment.getElement().insertBefore(
_element.environment?_element.environment.getElement():_element,
_referenceElement.environment?_referenceElement.environment.getElement():_referenceElement
);
return this._parent_;
},
"remove":function(_element){
this._parent_.environment.getElement().removeChild(_element.environment?_element.environment.getElement():_element);
}
},
"environment":{
"_element":null,
"setElement":function(_value){
this._parent_.element = _value;
this._parent_.element.lib = this._parent_;
this._parent_.element.firebugElement = true;
this._setElement(_value);
},
"getParent":function(){
return this.getElement().parentNode;
},
"getPosition":function(){
return pi.util.Element.getPosition(this.getElement());
},
"getSize":function(){
return pi.util.Element.getSize( this.getElement() );
},
"addStyle":function(_styleObject){
pi.util.Element.addStyle(this.getElement(),_styleObject);
return this._parent_;
},
"getStyle":function(_property){
return pi.util.Element.getStyle(this.getElement(),_property);
},
"getName":function(){
return this.getElement().nodeName;
},
"getType":function(){
return this.getElement().nodeType;
},
"getValue":function(){
return pi.util.Element.getValue(this.getElement());
},
"getView":function(_property){
return pi.util.Element.getView(this.getElement(),_property);
}
},
"event":{
"addListener":function(_event,_fn,_useCapture){
pi.util.AddEvent(this._parent_.environment.getElement(),_event,_fn,_useCapture);
return this._parent_;
},
"removeListener":function(_event,_fn,_useCapture){
pi.util.RemoveEvent(this._parent_.environment.getElement(),_event,_fn,_useCapture);
return this._parent_;
}
}
};
pi.element = pi.element.build();
pi.xhr = new pi.base;
pi.xhr.init = function(_url){
if(!window.XMLHttpRequest){
var names = ["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
for (var i = 0; i < names.length; i++) {
try {
this.environment.setApi(new ActiveXObject(names[i]));
break;
} catch (e) { continue; }
}
}
else {
this.environment.setApi(new XMLHttpRequest());
}
this.environment.getApi().onreadystatechange=pi.util.Curry(this.event.readystatechange,this);
this.environment.setUrl(_url);
this.environment.setCallback([]);
return this;
};
pi.xhr.body = {
"addCallback": function(){
return this.environment.addCallback.apply(this.environment,arguments);
},
"addData": function(){
return this.environment.addData.apply(this.environment,arguments);
},
"abort":function(){
this.environment.getApi().abort();
return this;
},
"send":function(){
var url = this.environment.getUrl(), data = this.environment.getData(),dataUrl = "";
if(!this.environment.getCache())
data["forceCache"] = Number(new Date);
for (var key in data)
dataUrl += pi.util.String.format("{0}={1}&",key, data[key]);
if (this.environment.getType()=="GET")
url += (url.search("\\?")==-1?"?":"&")+pi.util.String.format("{0}",dataUrl);
this.api.open(this.environment.getType(),url,this.environment.getAsync());
if(this.environment.getType()=="POST"){
this.api.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
};
this.api.send(this.environment.getType()=="GET"?"":dataUrl);
return this;
}
};
pi.xhr.body.environment = {
"_async":true, "_api":null, "_cache":true, "_callback":null, "_data":{}, "_type":"GET", "_url":"",
"setApi":function(_value){
this._parent_.api = _value;
this._setApi(_value);
},
"addCallback": function(_readyState,_fn){
this.getCallback().push({ "fn":_fn, "readyState":_readyState });
return this._parent_;
},
"addData": function(_key,_value){
this.getData()[_key] = _value;
return this._parent_;
},
"setType": function(_value){
this._setType(_value);
return this._parent_;
}
};
pi.xhr.body.event = {
"readystatechange":function(){
var readyState = this.environment.getApi().readyState, callback=this.environment.getCallback();
for (var i = 0, len=callback.length; i < len; i++) {
if(pi.util.Array.indexOf(callback[i].readyState,readyState)>-1){
callback[i].fn.apply(this);
}
}
}
};
pi.xhr = pi.xhr.build();
/*
* xml.xhr.get
*/
pi.xhr.get = function(_url,_returnPiObject){
var request = new pi.xhr();
request.environment.setAsync(false);
request.environment.setUrl(_url);
request.send();
return _returnPiObject?request:request.environment.getApi();
};
/*
* registering onload event for init functions
*/
pi.util.AddEvent(
pi.env.ie?window:document,
pi.env.ie?"load":"DOMContentLoaded",
function(){
for(var i=0,len=pi.util.Init.length; i<len; i++){
pi.util.Init[ i ]();
}
}
);
})(firebug);
with(firebug){
initConsole();
lib.util.Init.push(firebug.init);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 516 B

View File

@ -1,175 +0,0 @@
/*jsl:declare jasmine*/
function readFixtures()
{
return jasmine.getFixtures()._proxyCallTo('read', arguments);
}
function loadFixtures()
{
jasmine.getFixtures()._proxyCallTo('load', arguments);
}
function setFixtures(html)
{
jasmine.getFixtures().set(html);
}
function sandbox(attributes)
{
return jasmine.getFixtures().sandbox(attributes);
}
jasmine.getFixtures = function()
{
return jasmine._currentFixtures = jasmine._currentFixtures || new jasmine.Fixtures();
}
jasmine.Fixtures = function()
{
this.containerId = 'jasmine-fixtures';
this._fixturesCache = {};
}
jasmine.Fixtures.XHR= window.XMLHttpRequest || (function(){
var progIdCandidates= ['Msxml2.XMLHTTP.4.0', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP'];
var len= progIdCandidates.length;
var progId;
var xhr;
function ConstructXhr()
{
return new window.ActiveXObject(ConstructXhr.progId);
}
while (len--)
{
try
{
progId= progIdCandidates[len];
xhr= new window.ActiveXObject(progId);
// ActiveXObject constructor throws an exception
// if the component isn't available.
xhr= null;
ConstructXhr.progId= progId;
return ConstructXhr;
}
catch (e)
{
// Ignore the error
}
}
throw new Error('No XMLHttpRequest implementation found');
})();
jasmine.Fixtures.prototype= {
set: function(html)
{
this.cleanUp();
this._createContainer(html);
},
load: function()
{
this.cleanUp();
this._createContainer(this.read.apply(this, arguments));
},
read: function()
{
var htmlChunks = [];
var fixtureUrls = arguments;
for (var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++)
htmlChunks.push(this._getFixtureHtml(fixtureUrls[urlIndex]));
return htmlChunks.join('');
},
clearCache: function()
{
this._fixturesCache = {};
},
cleanUp: function()
{
var container= document.getElementById(this.containerId);
if (container)
container.parentNode.removeChild(container);
},
sandbox: function(attributes)
{
var attributesToSet = attributes || {};
var sandbox= document.createElement('div');
sandbox.id= 'sandbox';
if ("string"===typeof(attributes))
{
sandbox.innerHTML= attributes;
if (1===sandbox.childNodes.length && 1===sandbox.firstChild.nodeType)
{
sandbox= sandbox.firstChild;
if (!sandbox.id)
sandbox.id= 'sandbox';
}
return sandbox;
}
for (var attr in attributesToSet)
sandbox.setAttribute(attr, attributesToSet[attr]);
return sandbox;
},
_createContainer: function(html)
{
var container = document.createElement('div');
container.id= this.containerId;
if (html && html.nodeType===1)
container.appendChild(html);
else
container.innerHTML= html;
document.body.appendChild(container);
},
_getFixtureHtml: function(url)
{
if (void(0)===this._fixturesCache[url])
this._loadFixtureIntoCache(url);
return this._fixturesCache[url];
},
_loadFixtureIntoCache: function(url)
{
var self= this;
var xhr= new jasmine.Fixtures.XHR();
xhr.open('GET', url, true);
xhr.onreadystatechange= function()
{
if (4!==xhr.readyState)
return;
var status= xhr.status;
var succeeded= 0===status || (status>=200 && status<300) || 304==status;
if (!succeeded)
throw new Error('Failed to load resource: status=' + status + ' url=' + url);
self._fixturesCache[url]= xhr.responseText;
xhr.onreadystatechange= null;
xhr= null;
}
xhr.send(null);
},
_proxyCallTo: function(methodName, passedArguments)
{
return this[methodName].apply(this, passedArguments);
}
};

View File

@ -1,205 +0,0 @@
/*jsl:declare jasmine*/
/*jsl:declare Sizzle*/
/*jsl:declare Prototype*/
/*jsl:declare jQuery*/
jasmine.DOM = {};
jasmine.DOM.browserTagCaseIndependentHtml = function(html)
{
var div= document.createElement('div');
div.innerHTML= html;
return div.innerHTML;
}
jasmine.DOM.elementToString = function(element)
{
var div= document.createElement('div');
div.appendChild(element.cloneNode(true));
return div.innerHTML;
}
jasmine.DOM.trim= function(string)
{
var str= string.replace(/^\s+/, '');
for (var i = str.length - 1; i > 0; --i)
if (/\S/.test(str.charAt(i)))
{
str = str.substring(0, i + 1);
break;
}
return str;
}
jasmine.DOM.slice= function(arrayLike, startIndex)
{
return [].slice.call(arrayLike, startIndex||0);
}
jasmine.DOM.uniqueId= 1;
jasmine.DOM.assignId= function(element)
{
return element.id || (element.id=('jasmine_id_' + jasmine.DOM.uniqueId++));
};
/**
jasmine.DOM.queryAll(selector[, scope]) -> array
*/
jasmine.DOM.queryAll= (function(){
if ('undefined'!==typeof(Sizzle))
return Sizzle;
if ('undefined'!==typeof(Prototype))
return function(selector, node)
{
return Element.getElementsBySelector(node||document, selector);
};
if ('undefined'!==typeof(jQuery))
return function(selector, node)
{
var result= jQuery(selector, node);
var nodes= [];
var len= result.length;
for (var i=0; i<len; ++i)
nodes.push(result[i]);
return nodes;
};
if (document.querySelectorAll)
return function(selector, node)
{
if (!node)
node= document;
else if (node!==document)
selector = ['#', jasmine.DOM.assignId(node), ' ', selector].join('');
return jasmine.DOM.slice(node.querySelectorAll(selector));
};
throw new Error("Can't determine selector engine...");
})();
jasmine.DOM.matchers = {};
(function(){
var matchers = {
toHaveClass: function(className)
{
var classes= jasmine.DOM.trim(this.actual.className).split(" ");
return -1!==classes.indexOf(className);
},
toBeVisible: function()
{
return (this.actual.offsetWidth!==0 || this.actual.offsetHeight!==0);
},
toBeHidden: function()
{
return (0===this.actual.offsetWidth && 0===this.actual.offsetHeight);
},
toBeSelected: function()
{
return this.actual.selected;
},
toBeChecked: function()
{
return this.actual.checked;
},
toBeEmpty: function()
{
return !this.actual.firstChild;
},
toExist: function()
{
return !!this.actual;
},
toHaveAttr: function(attributeName, expectedAttributeValue)
{
if (!this.actual.hasAttribute(attributeName))
return false;
return comparePropertyValues(this.actual.getAttribute(attributeName), expectedAttributeValue);
},
toHaveId: function(id)
{
return this.actual.id===id;
},
toHaveHtml: function(html)
{
return this.actual.innerHTML === jasmine.DOM.browserTagCaseIndependentHtml(html);
},
toHaveText: function(text)
{
return (this.actual.textContent||this.actual.innerText) === text;
},
toHaveValue: function(value)
{
return this.actual.value === value;
},
toMatchSelector: function(selector)
{
// This isn't efficient
var nodes= jasmine.DOM.queryAll(selector);
return -1!==nodes.indexOf(this.actual);
},
toContain: function(selector)
{
var nodes= jasmine.DOM.queryAll(selector, this.actual);
return nodes.length > 0;
}
};
function comparePropertyValues(actualValue, expectedValue)
{
if (void(0) === expectedValue)
return void(0) !== actualValue;
return actualValue == expectedValue;
}
function bindMatcher(methodName)
{
var originalMatcher = jasmine.Matchers.prototype[methodName];
jasmine.DOM.matchers[methodName] = function()
{
// If the actual value is a DOM node...
if (this.actual && this.actual.nodeType)
{
var result = matchers[methodName].apply(this, arguments);
this.actual = jasmine.DOM.elementToString(this.actual);
return result;
}
if (originalMatcher)
return originalMatcher.apply(this, arguments);
return false;
}
}
for (var methodName in matchers)
bindMatcher(methodName);
})();
beforeEach(function() {
this.addMatchers(jasmine.DOM.matchers);
});
afterEach(function() {
jasmine.getFixtures().cleanUp();
});

View File

@ -1,20 +0,0 @@
Copyright (c) 2008-2011 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,616 +0,0 @@
jasmine.HtmlReporterHelpers = {};
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
return status;
};
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};
jasmine.HtmlReporter = function(_doc) {
var self = this;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.logRunningSpecs = false;
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
if (self.logRunningSpecs) {
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
self.reportSpecResults = function(spec) {
reporterView.specComplete(spec);
};
self.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
if (!focusedSpecName()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
};
return self;
function focusedSpecName() {
var specName;
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var paramMap = [];
var params = doc.location.search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
specName = paramMap.spec;
})();
return specName;
}
function createReporterDom(version) {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Jasmine "),
self.createDom('span', { className: 'version' }, version)),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'}),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
this.createResultsMenu = function() {
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
' | ',
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
this.summaryMenuItem.onclick = function() {
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
};
this.detailsMenuItem.onclick = function() {
showDetails();
};
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
this.views = {
specs: {},
suites: {}
};
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
};
this.specComplete = function(spec) {
this.completeSpecCount++;
if (isUndefined(this.views.specs[spec.id])) {
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
}
var specView = this.views.specs[spec.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'skipped':
this.skippedCount++;
break;
}
specView.refresh();
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
return;
}
suiteView.refresh();
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
}
// currently running UI
if (isUndefined(this.runningAlert)) {
this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
dom.alert.appendChild(this.runningAlert);
}
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
// skipped specs UI
if (isUndefined(this.skippedAlert)) {
this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
}
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.skippedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.skippedAlert);
}
// passing specs UI
if (isUndefined(this.passedAlert)) {
this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
}
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
// failing specs UI
if (isUndefined(this.failedAlert)) {
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
}
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
if (this.failedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.failedAlert);
dom.alert.appendChild(this.resultsMenu);
}
// summary info
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
};
this.complete = function() {
dom.alert.removeChild(this.runningAlert);
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.failedCount === 0) {
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
} else {
showDetails();
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDefined(obj) {
return !isUndefined(obj);
}
function specPluralizedFor(count) {
var str = count + " spec";
if (count > 1) {
str += "s"
}
return str;
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
this.spec = spec;
this.dom = dom;
this.views = views;
this.symbol = this.createDom('li', { className: 'pending' });
this.dom.symbolSummary.appendChild(this.symbol);
this.summary = this.createDom('div', { className: 'specSummary' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.description)
);
this.detail = this.createDom('div', { className: 'specDetail' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.getFullName())
);
};
jasmine.HtmlReporter.SpecView.prototype.status = function() {
return this.getSpecStatus(this.spec);
};
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'skipped':
break;
case 'passed':
this.appendSummaryToSuiteDiv();
break;
case 'failed':
this.appendSummaryToSuiteDiv();
this.appendFailureDetail();
break;
}
};
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
this.summary.className += ' ' + this.status();
this.appendToSummary(this.spec, this.summary);
};
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
this.detail.className += ' ' + this.status();
var resultItems = this.spec.results().getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
/* @deprecated Use jasmine.HtmlReporter instead
*/
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};

View File

@ -1,81 +0,0 @@
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }

View File

@ -1,2529 +0,0 @@
var isCommonJS = typeof window == "undefined";
/**
* Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
*
* @namespace
*/
var jasmine = {};
if (isCommonJS) exports.jasmine = jasmine;
/**
* @private
*/
jasmine.unimplementedMethod_ = function() {
throw new Error("unimplemented method");
};
/**
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
* a plain old variable and may be redefined by somebody else.
*
* @private
*/
jasmine.undefined = jasmine.___undefined___;
/**
* Show diagnostic messages in the console if set to true
*
*/
jasmine.VERBOSE = false;
/**
* Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
*
*/
jasmine.DEFAULT_UPDATE_INTERVAL = 250;
/**
* Default timeout interval in milliseconds for waitsFor() blocks.
*/
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
jasmine.getGlobal = function() {
function getGlobal() {
return this;
}
return getGlobal();
};
/**
* Allows for bound functions to be compared. Internal use only.
*
* @ignore
* @private
* @param base {Object} bound 'this' for the function
* @param name {Function} function to find
*/
jasmine.bindOriginal_ = function(base, name) {
var original = base[name];
if (original.apply) {
return function() {
return original.apply(base, arguments);
};
} else {
// IE support
return jasmine.getGlobal()[name];
}
};
jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
jasmine.MessageResult = function(values) {
this.type = 'log';
this.values = values;
this.trace = new Error(); // todo: test better
};
jasmine.MessageResult.prototype.toString = function() {
var text = "";
for (var i = 0; i < this.values.length; i++) {
if (i > 0) text += " ";
if (jasmine.isString_(this.values[i])) {
text += this.values[i];
} else {
text += jasmine.pp(this.values[i]);
}
}
return text;
};
jasmine.ExpectationResult = function(params) {
this.type = 'expect';
this.matcherName = params.matcherName;
this.passed_ = params.passed;
this.expected = params.expected;
this.actual = params.actual;
this.message = this.passed_ ? 'Passed.' : params.message;
var trace = (params.trace || new Error(this.message));
this.trace = this.passed_ ? '' : trace;
};
jasmine.ExpectationResult.prototype.toString = function () {
return this.message;
};
jasmine.ExpectationResult.prototype.passed = function () {
return this.passed_;
};
/**
* Getter for the Jasmine environment. Ensures one gets created
*/
jasmine.getEnv = function() {
var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
return env;
};
/**
* @ignore
* @private
* @param value
* @returns {Boolean}
*/
jasmine.isArray_ = function(value) {
return jasmine.isA_("Array", value);
};
/**
* @ignore
* @private
* @param value
* @returns {Boolean}
*/
jasmine.isString_ = function(value) {
return jasmine.isA_("String", value);
};
/**
* @ignore
* @private
* @param value
* @returns {Boolean}
*/
jasmine.isNumber_ = function(value) {
return jasmine.isA_("Number", value);
};
/**
* @ignore
* @private
* @param {String} typeName
* @param value
* @returns {Boolean}
*/
jasmine.isA_ = function(typeName, value) {
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
};
/**
* Pretty printer for expecations. Takes any object and turns it into a human-readable string.
*
* @param value {Object} an object to be outputted
* @returns {String}
*/
jasmine.pp = function(value) {
var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
stringPrettyPrinter.format(value);
return stringPrettyPrinter.string;
};
/**
* Returns true if the object is a DOM Node.
*
* @param {Object} obj object to check
* @returns {Boolean}
*/
jasmine.isDomNode = function(obj) {
return obj.nodeType > 0;
};
/**
* Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
*
* @example
* // don't care about which function is passed in, as long as it's a function
* expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
*
* @param {Class} clazz
* @returns matchable object of the type clazz
*/
jasmine.any = function(clazz) {
return new jasmine.Matchers.Any(clazz);
};
/**
* Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
* attributes on the object.
*
* @example
* // don't care about any other attributes than foo.
* expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
*
* @param sample {Object} sample
* @returns matchable object for the sample
*/
jasmine.objectContaining = function (sample) {
return new jasmine.Matchers.ObjectContaining(sample);
};
/**
* Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
*
* Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
* expectation syntax. Spies can be checked if they were called or not and what the calling params were.
*
* A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
*
* Spies are torn down at the end of every spec.
*
* Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
*
* @example
* // a stub
* var myStub = jasmine.createSpy('myStub'); // can be used anywhere
*
* // spy example
* var foo = {
* not: function(bool) { return !bool; }
* }
*
* // actual foo.not will not be called, execution stops
* spyOn(foo, 'not');
// foo.not spied upon, execution will continue to implementation
* spyOn(foo, 'not').andCallThrough();
*
* // fake example
* var foo = {
* not: function(bool) { return !bool; }
* }
*
* // foo.not(val) will return val
* spyOn(foo, 'not').andCallFake(function(value) {return value;});
*
* // mock example
* foo.not(7 == 7);
* expect(foo.not).toHaveBeenCalled();
* expect(foo.not).toHaveBeenCalledWith(true);
*
* @constructor
* @see spyOn, jasmine.createSpy, jasmine.createSpyObj
* @param {String} name
*/
jasmine.Spy = function(name) {
/**
* The name of the spy, if provided.
*/
this.identity = name || 'unknown';
/**
* Is this Object a spy?
*/
this.isSpy = true;
/**
* The actual function this spy stubs.
*/
this.plan = function() {
};
/**
* Tracking of the most recent call to the spy.
* @example
* var mySpy = jasmine.createSpy('foo');
* mySpy(1, 2);
* mySpy.mostRecentCall.args = [1, 2];
*/
this.mostRecentCall = {};
/**
* Holds arguments for each call to the spy, indexed by call count
* @example
* var mySpy = jasmine.createSpy('foo');
* mySpy(1, 2);
* mySpy(7, 8);
* mySpy.mostRecentCall.args = [7, 8];
* mySpy.argsForCall[0] = [1, 2];
* mySpy.argsForCall[1] = [7, 8];
*/
this.argsForCall = [];
this.calls = [];
};
/**
* Tells a spy to call through to the actual implemenatation.
*
* @example
* var foo = {
* bar: function() { // do some stuff }
* }
*
* // defining a spy on an existing property: foo.bar
* spyOn(foo, 'bar').andCallThrough();
*/
jasmine.Spy.prototype.andCallThrough = function() {
this.plan = this.originalValue;
return this;
};
/**
* For setting the return value of a spy.
*
* @example
* // defining a spy from scratch: foo() returns 'baz'
* var foo = jasmine.createSpy('spy on foo').andReturn('baz');
*
* // defining a spy on an existing property: foo.bar() returns 'baz'
* spyOn(foo, 'bar').andReturn('baz');
*
* @param {Object} value
*/
jasmine.Spy.prototype.andReturn = function(value) {
this.plan = function() {
return value;
};
return this;
};
/**
* For throwing an exception when a spy is called.
*
* @example
* // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
* var foo = jasmine.createSpy('spy on foo').andThrow('baz');
*
* // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
* spyOn(foo, 'bar').andThrow('baz');
*
* @param {String} exceptionMsg
*/
jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
this.plan = function() {
throw exceptionMsg;
};
return this;
};
/**
* Calls an alternate implementation when a spy is called.
*
* @example
* var baz = function() {
* // do some stuff, return something
* }
* // defining a spy from scratch: foo() calls the function baz
* var foo = jasmine.createSpy('spy on foo').andCall(baz);
*
* // defining a spy on an existing property: foo.bar() calls an anonymnous function
* spyOn(foo, 'bar').andCall(function() { return 'baz';} );
*
* @param {Function} fakeFunc
*/
jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
this.plan = fakeFunc;
return this;
};
/**
* Resets all of a spy's the tracking variables so that it can be used again.
*
* @example
* spyOn(foo, 'bar');
*
* foo.bar();
*
* expect(foo.bar.callCount).toEqual(1);
*
* foo.bar.reset();
*
* expect(foo.bar.callCount).toEqual(0);
*/
jasmine.Spy.prototype.reset = function() {
this.wasCalled = false;
this.callCount = 0;
this.argsForCall = [];
this.calls = [];
this.mostRecentCall = {};
};
jasmine.createSpy = function(name) {
var spyObj = function() {
spyObj.wasCalled = true;
spyObj.callCount++;
var args = jasmine.util.argsToArray(arguments);
spyObj.mostRecentCall.object = this;
spyObj.mostRecentCall.args = args;
spyObj.argsForCall.push(args);
spyObj.calls.push({object: this, args: args});
return spyObj.plan.apply(this, arguments);
};
var spy = new jasmine.Spy(name);
for (var prop in spy) {
spyObj[prop] = spy[prop];
}
spyObj.reset();
return spyObj;
};
/**
* Determines whether an object is a spy.
*
* @param {jasmine.Spy|Object} putativeSpy
* @returns {Boolean}
*/
jasmine.isSpy = function(putativeSpy) {
return putativeSpy && putativeSpy.isSpy;
};
/**
* Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
* large in one call.
*
* @param {String} baseName name of spy class
* @param {Array} methodNames array of names of methods to make spies
*/
jasmine.createSpyObj = function(baseName, methodNames) {
if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
}
var obj = {};
for (var i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
}
return obj;
};
/**
* All parameters are pretty-printed and concatenated together, then written to the current spec's output.
*
* Be careful not to leave calls to <code>jasmine.log</code> in production code.
*/
jasmine.log = function() {
var spec = jasmine.getEnv().currentSpec;
spec.log.apply(spec, arguments);
};
/**
* Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
*
* @example
* // spy example
* var foo = {
* not: function(bool) { return !bool; }
* }
* spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
*
* @see jasmine.createSpy
* @param obj
* @param methodName
* @returns a Jasmine spy that can be chained with all spy methods
*/
var spyOn = function(obj, methodName) {
return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
};
if (isCommonJS) exports.spyOn = spyOn;
/**
* Creates a Jasmine spec that will be added to the current suite.
*
* // TODO: pending tests
*
* @example
* it('should be true', function() {
* expect(true).toEqual(true);
* });
*
* @param {String} desc description of this specification
* @param {Function} func defines the preconditions and expectations of the spec
*/
var it = function(desc, func) {
return jasmine.getEnv().it(desc, func);
};
if (isCommonJS) exports.it = it;
/**
* Creates a <em>disabled</em> Jasmine spec.
*
* A convenience method that allows existing specs to be disabled temporarily during development.
*
* @param {String} desc description of this specification
* @param {Function} func defines the preconditions and expectations of the spec
*/
var xit = function(desc, func) {
return jasmine.getEnv().xit(desc, func);
};
if (isCommonJS) exports.xit = xit;
/**
* Starts a chain for a Jasmine expectation.
*
* It is passed an Object that is the actual value and should chain to one of the many
* jasmine.Matchers functions.
*
* @param {Object} actual Actual value to test against and expected value
*/
var expect = function(actual) {
return jasmine.getEnv().currentSpec.expect(actual);
};
if (isCommonJS) exports.expect = expect;
/**
* Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
*
* @param {Function} func Function that defines part of a jasmine spec.
*/
var runs = function(func) {
jasmine.getEnv().currentSpec.runs(func);
};
if (isCommonJS) exports.runs = runs;
/**
* Waits a fixed time period before moving to the next block.
*
* @deprecated Use waitsFor() instead
* @param {Number} timeout milliseconds to wait
*/
var waits = function(timeout) {
jasmine.getEnv().currentSpec.waits(timeout);
};
if (isCommonJS) exports.waits = waits;
/**
* Waits for the latchFunction to return true before proceeding to the next block.
*
* @param {Function} latchFunction
* @param {String} optional_timeoutMessage
* @param {Number} optional_timeout
*/
var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
};
if (isCommonJS) exports.waitsFor = waitsFor;
/**
* A function that is called before each spec in a suite.
*
* Used for spec setup, including validating assumptions.
*
* @param {Function} beforeEachFunction
*/
var beforeEach = function(beforeEachFunction) {
jasmine.getEnv().beforeEach(beforeEachFunction);
};
if (isCommonJS) exports.beforeEach = beforeEach;
/**
* A function that is called after each spec in a suite.
*
* Used for restoring any state that is hijacked during spec execution.
*
* @param {Function} afterEachFunction
*/
var afterEach = function(afterEachFunction) {
jasmine.getEnv().afterEach(afterEachFunction);
};
if (isCommonJS) exports.afterEach = afterEach;
/**
* Defines a suite of specifications.
*
* Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
* are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
* of setup in some tests.
*
* @example
* // TODO: a simple suite
*
* // TODO: a simple suite with a nested describe block
*
* @param {String} description A string, usually the class under test.
* @param {Function} specDefinitions function that defines several specs.
*/
var describe = function(description, specDefinitions) {
return jasmine.getEnv().describe(description, specDefinitions);
};
if (isCommonJS) exports.describe = describe;
/**
* Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
*
* @param {String} description A string, usually the class under test.
* @param {Function} specDefinitions function that defines several specs.
*/
var xdescribe = function(description, specDefinitions) {
return jasmine.getEnv().xdescribe(description, specDefinitions);
};
if (isCommonJS) exports.xdescribe = xdescribe;
// Provide the XMLHttpRequest class for IE 5.x-6.x:
jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
function tryIt(f) {
try {
return f();
} catch(e) {
}
return null;
}
var xhr = tryIt(function() {
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
}) ||
tryIt(function() {
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
}) ||
tryIt(function() {
return new ActiveXObject("Msxml2.XMLHTTP");
}) ||
tryIt(function() {
return new ActiveXObject("Microsoft.XMLHTTP");
});
if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
return xhr;
} : XMLHttpRequest;
/**
* @namespace
*/
jasmine.util = {};
/**
* Declare that a child class inherit it's prototype from the parent class.
*
* @private
* @param {Function} childClass
* @param {Function} parentClass
*/
jasmine.util.inherit = function(childClass, parentClass) {
/**
* @private
*/
var subclass = function() {
};
subclass.prototype = parentClass.prototype;
childClass.prototype = new subclass();
};
jasmine.util.formatException = function(e) {
var lineNumber;
if (e.line) {
lineNumber = e.line;
}
else if (e.lineNumber) {
lineNumber = e.lineNumber;
}
var file;
if (e.sourceURL) {
file = e.sourceURL;
}
else if (e.fileName) {
file = e.fileName;
}
var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
if (file && lineNumber) {
message += ' in ' + file + ' (line ' + lineNumber + ')';
}
return message;
};
jasmine.util.htmlEscape = function(str) {
if (!str) return str;
return str.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
};
jasmine.util.argsToArray = function(args) {
var arrayOfArgs = [];
for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
return arrayOfArgs;
};
jasmine.util.extend = function(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
};
/**
* Environment for Jasmine
*
* @constructor
*/
jasmine.Env = function() {
this.currentSpec = null;
this.currentSuite = null;
this.currentRunner_ = new jasmine.Runner(this);
this.reporter = new jasmine.MultiReporter();
this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
this.lastUpdate = 0;
this.specFilter = function() {
return true;
};
this.nextSpecId_ = 0;
this.nextSuiteId_ = 0;
this.equalityTesters_ = [];
// wrap matchers
this.matchersClass = function() {
jasmine.Matchers.apply(this, arguments);
};
jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
};
jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
jasmine.Env.prototype.setInterval = jasmine.setInterval;
jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
/**
* @returns an object containing jasmine version build info, if set.
*/
jasmine.Env.prototype.version = function () {
if (jasmine.version_) {
return jasmine.version_;
} else {
throw new Error('Version not set');
}
};
/**
* @returns string containing jasmine version build info, if set.
*/
jasmine.Env.prototype.versionString = function() {
if (!jasmine.version_) {
return "version unknown";
}
var version = this.version();
var versionString = version.major + "." + version.minor + "." + version.build;
if (version.release_candidate) {
versionString += ".rc" + version.release_candidate;
}
versionString += " revision " + version.revision;
return versionString;
};
/**
* @returns a sequential integer starting at 0
*/
jasmine.Env.prototype.nextSpecId = function () {
return this.nextSpecId_++;
};
/**
* @returns a sequential integer starting at 0
*/
jasmine.Env.prototype.nextSuiteId = function () {
return this.nextSuiteId_++;
};
/**
* Register a reporter to receive status updates from Jasmine.
* @param {jasmine.Reporter} reporter An object which will receive status updates.
*/
jasmine.Env.prototype.addReporter = function(reporter) {
this.reporter.addReporter(reporter);
};
jasmine.Env.prototype.execute = function() {
this.currentRunner_.execute();
};
jasmine.Env.prototype.describe = function(description, specDefinitions) {
var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
var parentSuite = this.currentSuite;
if (parentSuite) {
parentSuite.add(suite);
} else {
this.currentRunner_.add(suite);
}
this.currentSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch(e) {
declarationError = e;
}
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
});
}
this.currentSuite = parentSuite;
return suite;
};
jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
if (this.currentSuite) {
this.currentSuite.beforeEach(beforeEachFunction);
} else {
this.currentRunner_.beforeEach(beforeEachFunction);
}
};
jasmine.Env.prototype.currentRunner = function () {
return this.currentRunner_;
};
jasmine.Env.prototype.afterEach = function(afterEachFunction) {
if (this.currentSuite) {
this.currentSuite.afterEach(afterEachFunction);
} else {
this.currentRunner_.afterEach(afterEachFunction);
}
};
jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
return {
execute: function() {
}
};
};
jasmine.Env.prototype.it = function(description, func) {
var spec = new jasmine.Spec(this, this.currentSuite, description);
this.currentSuite.add(spec);
this.currentSpec = spec;
if (func) {
spec.runs(func);
}
return spec;
};
jasmine.Env.prototype.xit = function(desc, func) {
return {
id: this.nextSpecId(),
runs: function() {
}
};
};
jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
return true;
}
a.__Jasmine_been_here_before__ = b;
b.__Jasmine_been_here_before__ = a;
var hasKey = function(obj, keyName) {
return obj !== null && obj[keyName] !== jasmine.undefined;
};
for (var property in b) {
if (!hasKey(a, property) && hasKey(b, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
}
for (property in a) {
if (!hasKey(b, property) && hasKey(a, property)) {
mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
}
}
for (property in b) {
if (property == '__Jasmine_been_here_before__') continue;
if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
}
}
if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
mismatchValues.push("arrays were not the same length");
}
delete a.__Jasmine_been_here_before__;
delete b.__Jasmine_been_here_before__;
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
for (var i = 0; i < this.equalityTesters_.length; i++) {
var equalityTester = this.equalityTesters_[i];
var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
if (result !== jasmine.undefined) return result;
}
if (a === b) return true;
if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
return (a == jasmine.undefined && b == jasmine.undefined);
}
if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
return a === b;
}
if (a instanceof Date && b instanceof Date) {
return a.getTime() == b.getTime();
}
if (a.jasmineMatches) {
return a.jasmineMatches(b);
}
if (b.jasmineMatches) {
return b.jasmineMatches(a);
}
if (a instanceof jasmine.Matchers.ObjectContaining) {
return a.matches(b);
}
if (b instanceof jasmine.Matchers.ObjectContaining) {
return b.matches(a);
}
if (jasmine.isString_(a) && jasmine.isString_(b)) {
return (a == b);
}
if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
return (a == b);
}
if (typeof a === "object" && typeof b === "object") {
return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
}
//Straight check
return (a === b);
};
jasmine.Env.prototype.contains_ = function(haystack, needle) {
if (jasmine.isArray_(haystack)) {
for (var i = 0; i < haystack.length; i++) {
if (this.equals_(haystack[i], needle)) return true;
}
return false;
}
return haystack.indexOf(needle) >= 0;
};
jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
this.equalityTesters_.push(equalityTester);
};
/** No-op base class for Jasmine reporters.
*
* @constructor
*/
jasmine.Reporter = function() {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportSpecResults = function(spec) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.log = function(str) {
};
/**
* Blocks are functions with executable code that make up a spec.
*
* @constructor
* @param {jasmine.Env} env
* @param {Function} func
* @param {jasmine.Spec} spec
*/
jasmine.Block = function(env, func, spec) {
this.env = env;
this.func = func;
this.spec = spec;
};
jasmine.Block.prototype.execute = function(onComplete) {
try {
this.func.apply(this.spec);
} catch (e) {
this.spec.fail(e);
}
onComplete();
};
/** JavaScript API reporter.
*
* @constructor
*/
jasmine.JsApiReporter = function() {
this.started = false;
this.finished = false;
this.suites_ = [];
this.results_ = {};
};
jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
this.started = true;
var suites = runner.topLevelSuites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
this.suites_.push(this.summarize_(suite));
}
};
jasmine.JsApiReporter.prototype.suites = function() {
return this.suites_;
};
jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
var isSuite = suiteOrSpec instanceof jasmine.Suite;
var summary = {
id: suiteOrSpec.id,
name: suiteOrSpec.description,
type: isSuite ? 'suite' : 'spec',
children: []
};
if (isSuite) {
var children = suiteOrSpec.children();
for (var i = 0; i < children.length; i++) {
summary.children.push(this.summarize_(children[i]));
}
}
return summary;
};
jasmine.JsApiReporter.prototype.results = function() {
return this.results_;
};
jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
return this.results_[specId];
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
this.finished = true;
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
this.results_[spec.id] = {
messages: spec.results().getItems(),
result: spec.results().failedCount > 0 ? "failed" : "passed"
};
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.log = function(str) {
};
jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
var results = {};
for (var i = 0; i < specIds.length; i++) {
var specId = specIds[i];
results[specId] = this.summarizeResult_(this.results_[specId]);
}
return results;
};
jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
var summaryMessages = [];
var messagesLength = result.messages.length;
for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
var resultMessage = result.messages[messageIndex];
summaryMessages.push({
text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
passed: resultMessage.passed ? resultMessage.passed() : true,
type: resultMessage.type,
message: resultMessage.message,
trace: {
stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
}
});
}
return {
result : result.result,
messages : summaryMessages
};
};
/**
* @constructor
* @param {jasmine.Env} env
* @param actual
* @param {jasmine.Spec} spec
*/
jasmine.Matchers = function(env, actual, spec, opt_isNot) {
this.env = env;
this.actual = actual;
this.spec = spec;
this.isNot = opt_isNot || false;
this.reportWasCalled_ = false;
};
// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
jasmine.Matchers.pp = function(str) {
throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
};
// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
jasmine.Matchers.prototype.report = function(result, failing_message, details) {
throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
};
jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
for (var methodName in prototype) {
if (methodName == 'report') continue;
var orig = prototype[methodName];
matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
}
};
jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
return function() {
var matcherArgs = jasmine.util.argsToArray(arguments);
var result = matcherFunction.apply(this, arguments);
if (this.isNot) {
result = !result;
}
if (this.reportWasCalled_) return result;
var message;
if (!result) {
if (this.message) {
message = this.message.apply(this, arguments);
if (jasmine.isArray_(message)) {
message = message[this.isNot ? 1 : 0];
}
} else {
var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
if (matcherArgs.length > 0) {
for (var i = 0; i < matcherArgs.length; i++) {
if (i > 0) message += ",";
message += " " + jasmine.pp(matcherArgs[i]);
}
}
message += ".";
}
}
var expectationResult = new jasmine.ExpectationResult({
matcherName: matcherName,
passed: result,
expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
actual: this.actual,
message: message
});
this.spec.addMatcherResult(expectationResult);
return jasmine.undefined;
};
};
/**
* toBe: compares the actual to the expected using ===
* @param expected
*/
jasmine.Matchers.prototype.toBe = function(expected) {
return this.actual === expected;
};
/**
* toNotBe: compares the actual to the expected using !==
* @param expected
* @deprecated as of 1.0. Use not.toBe() instead.
*/
jasmine.Matchers.prototype.toNotBe = function(expected) {
return this.actual !== expected;
};
/**
* toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
*
* @param expected
*/
jasmine.Matchers.prototype.toEqual = function(expected) {
return this.env.equals_(this.actual, expected);
};
/**
* toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
* @param expected
* @deprecated as of 1.0. Use not.toEqual() instead.
*/
jasmine.Matchers.prototype.toNotEqual = function(expected) {
return !this.env.equals_(this.actual, expected);
};
/**
* Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
* a pattern or a String.
*
* @param expected
*/
jasmine.Matchers.prototype.toMatch = function(expected) {
return new RegExp(expected).test(this.actual);
};
/**
* Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
* @param expected
* @deprecated as of 1.0. Use not.toMatch() instead.
*/
jasmine.Matchers.prototype.toNotMatch = function(expected) {
return !(new RegExp(expected).test(this.actual));
};
/**
* Matcher that compares the actual to jasmine.undefined.
*/
jasmine.Matchers.prototype.toBeDefined = function() {
return (this.actual !== jasmine.undefined);
};
/**
* Matcher that compares the actual to jasmine.undefined.
*/
jasmine.Matchers.prototype.toBeUndefined = function() {
return (this.actual === jasmine.undefined);
};
/**
* Matcher that compares the actual to null.
*/
jasmine.Matchers.prototype.toBeNull = function() {
return (this.actual === null);
};
/**
* Matcher that boolean not-nots the actual.
*/
jasmine.Matchers.prototype.toBeTruthy = function() {
return !!this.actual;
};
/**
* Matcher that boolean nots the actual.
*/
jasmine.Matchers.prototype.toBeFalsy = function() {
return !this.actual;
};
/**
* Matcher that checks to see if the actual, a Jasmine spy, was called.
*/
jasmine.Matchers.prototype.toHaveBeenCalled = function() {
if (arguments.length > 0) {
throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
}
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
return [
"Expected spy " + this.actual.identity + " to have been called.",
"Expected spy " + this.actual.identity + " not to have been called."
];
};
return this.actual.wasCalled;
};
/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
/**
* Matcher that checks to see if the actual, a Jasmine spy, was not called.
*
* @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
*/
jasmine.Matchers.prototype.wasNotCalled = function() {
if (arguments.length > 0) {
throw new Error('wasNotCalled does not take arguments');
}
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
return [
"Expected spy " + this.actual.identity + " to not have been called.",
"Expected spy " + this.actual.identity + " to have been called."
];
};
return !this.actual.wasCalled;
};
/**
* Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
*
* @example
*
*/
jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
var expectedArgs = jasmine.util.argsToArray(arguments);
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
if (this.actual.callCount === 0) {
// todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
return [
"Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
"Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
];
} else {
return [
"Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
"Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
];
}
};
return this.env.contains_(this.actual.argsForCall, expectedArgs);
};
/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
jasmine.Matchers.prototype.wasNotCalledWith = function() {
var expectedArgs = jasmine.util.argsToArray(arguments);
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
return [
"Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
"Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
];
};
return !this.env.contains_(this.actual.argsForCall, expectedArgs);
};
/**
* Matcher that checks that the expected item is an element in the actual Array.
*
* @param {Object} expected
*/
jasmine.Matchers.prototype.toContain = function(expected) {
return this.env.contains_(this.actual, expected);
};
/**
* Matcher that checks that the expected item is NOT an element in the actual Array.
*
* @param {Object} expected
* @deprecated as of 1.0. Use not.toContain() instead.
*/
jasmine.Matchers.prototype.toNotContain = function(expected) {
return !this.env.contains_(this.actual, expected);
};
jasmine.Matchers.prototype.toBeLessThan = function(expected) {
return this.actual < expected;
};
jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
return this.actual > expected;
};
/**
* Matcher that checks that the expected item is equal to the actual item
* up to a given level of decimal precision (default 2).
*
* @param {Number} expected
* @param {Number} precision
*/
jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
if (!(precision === 0)) {
precision = precision || 2;
}
var multiplier = Math.pow(10, precision);
var actual = Math.round(this.actual * multiplier);
expected = Math.round(expected * multiplier);
return expected == actual;
};
/**
* Matcher that checks that the expected exception was thrown by the actual.
*
* @param {String} expected
*/
jasmine.Matchers.prototype.toThrow = function(expected) {
var result = false;
var exception;
if (typeof this.actual != 'function') {
throw new Error('Actual is not a function');
}
try {
this.actual();
} catch (e) {
exception = e;
}
if (exception) {
result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
}
var not = this.isNot ? "not " : "";
this.message = function() {
if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
} else {
return "Expected function to throw an exception.";
}
};
return result;
};
jasmine.Matchers.Any = function(expectedClass) {
this.expectedClass = expectedClass;
};
jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
if (this.expectedClass == String) {
return typeof other == 'string' || other instanceof String;
}
if (this.expectedClass == Number) {
return typeof other == 'number' || other instanceof Number;
}
if (this.expectedClass == Function) {
return typeof other == 'function' || other instanceof Function;
}
if (this.expectedClass == Object) {
return typeof other == 'object';
}
return other instanceof this.expectedClass;
};
jasmine.Matchers.Any.prototype.jasmineToString = function() {
return '<jasmine.any(' + this.expectedClass + ')>';
};
jasmine.Matchers.ObjectContaining = function (sample) {
this.sample = sample;
};
jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
var env = jasmine.getEnv();
var hasKey = function(obj, keyName) {
return obj != null && obj[keyName] !== jasmine.undefined;
};
for (var property in this.sample) {
if (!hasKey(other, property) && hasKey(this.sample, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
}
}
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
};
// Mock setTimeout, clearTimeout
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
jasmine.FakeTimer = function() {
this.reset();
var self = this;
self.setTimeout = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
return self.timeoutsMade;
};
self.setInterval = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
return self.timeoutsMade;
};
self.clearTimeout = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
self.clearInterval = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
};
jasmine.FakeTimer.prototype.reset = function() {
this.timeoutsMade = 0;
this.scheduledFunctions = {};
this.nowMillis = 0;
};
jasmine.FakeTimer.prototype.tick = function(millis) {
var oldMillis = this.nowMillis;
var newMillis = oldMillis + millis;
this.runFunctionsWithinRange(oldMillis, newMillis);
this.nowMillis = newMillis;
};
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
var scheduledFunc;
var funcsToRun = [];
for (var timeoutKey in this.scheduledFunctions) {
scheduledFunc = this.scheduledFunctions[timeoutKey];
if (scheduledFunc != jasmine.undefined &&
scheduledFunc.runAtMillis >= oldMillis &&
scheduledFunc.runAtMillis <= nowMillis) {
funcsToRun.push(scheduledFunc);
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
}
}
if (funcsToRun.length > 0) {
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
for (var i = 0; i < funcsToRun.length; ++i) {
try {
var funcToRun = funcsToRun[i];
this.nowMillis = funcToRun.runAtMillis;
funcToRun.funcToCall();
if (funcToRun.recurring) {
this.scheduleFunction(funcToRun.timeoutKey,
funcToRun.funcToCall,
funcToRun.millis,
true);
}
} catch(e) {
}
}
this.runFunctionsWithinRange(oldMillis, nowMillis);
}
};
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
this.scheduledFunctions[timeoutKey] = {
runAtMillis: this.nowMillis + millis,
funcToCall: funcToCall,
recurring: recurring,
timeoutKey: timeoutKey,
millis: millis
};
};
/**
* @namespace
*/
jasmine.Clock = {
defaultFakeTimer: new jasmine.FakeTimer(),
reset: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.reset();
},
tick: function(millis) {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.tick(millis);
},
runFunctionsWithinRange: function(oldMillis, nowMillis) {
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
},
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
},
useMock: function() {
if (!jasmine.Clock.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Clock.uninstallMock);
jasmine.Clock.installMock();
}
},
installMock: function() {
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
},
uninstallMock: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.installed = jasmine.Clock.real;
},
real: {
setTimeout: jasmine.getGlobal().setTimeout,
clearTimeout: jasmine.getGlobal().clearTimeout,
setInterval: jasmine.getGlobal().setInterval,
clearInterval: jasmine.getGlobal().clearInterval
},
assertInstalled: function() {
if (!jasmine.Clock.isInstalled()) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
isInstalled: function() {
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
if (jasmine.Clock.installed.setInterval.apply) {
return jasmine.Clock.installed.setInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.setInterval(funcToCall, millis);
}
};
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
jasmine.getGlobal().clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
/**
* @constructor
*/
jasmine.MultiReporter = function() {
this.subReporters_ = [];
};
jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
jasmine.MultiReporter.prototype.addReporter = function(reporter) {
this.subReporters_.push(reporter);
};
(function() {
var functionNames = [
"reportRunnerStarting",
"reportRunnerResults",
"reportSuiteResults",
"reportSpecStarting",
"reportSpecResults",
"log"
];
for (var i = 0; i < functionNames.length; i++) {
var functionName = functionNames[i];
jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
return function() {
for (var j = 0; j < this.subReporters_.length; j++) {
var subReporter = this.subReporters_[j];
if (subReporter[functionName]) {
subReporter[functionName].apply(subReporter, arguments);
}
}
};
})(functionName);
}
})();
/**
* Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
*
* @constructor
*/
jasmine.NestedResults = function() {
/**
* The total count of results
*/
this.totalCount = 0;
/**
* Number of passed results
*/
this.passedCount = 0;
/**
* Number of failed results
*/
this.failedCount = 0;
/**
* Was this suite/spec skipped?
*/
this.skipped = false;
/**
* @ignore
*/
this.items_ = [];
};
/**
* Roll up the result counts.
*
* @param result
*/
jasmine.NestedResults.prototype.rollupCounts = function(result) {
this.totalCount += result.totalCount;
this.passedCount += result.passedCount;
this.failedCount += result.failedCount;
};
/**
* Adds a log message.
* @param values Array of message parts which will be concatenated later.
*/
jasmine.NestedResults.prototype.log = function(values) {
this.items_.push(new jasmine.MessageResult(values));
};
/**
* Getter for the results: message & results.
*/
jasmine.NestedResults.prototype.getItems = function() {
return this.items_;
};
/**
* Adds a result, tracking counts (total, passed, & failed)
* @param {jasmine.ExpectationResult|jasmine.NestedResults} result
*/
jasmine.NestedResults.prototype.addResult = function(result) {
if (result.type != 'log') {
if (result.items_) {
this.rollupCounts(result);
} else {
this.totalCount++;
if (result.passed()) {
this.passedCount++;
} else {
this.failedCount++;
}
}
}
this.items_.push(result);
};
/**
* @returns {Boolean} True if <b>everything</b> below passed
*/
jasmine.NestedResults.prototype.passed = function() {
return this.passedCount === this.totalCount;
};
/**
* Base class for pretty printing for expectation results.
*/
jasmine.PrettyPrinter = function() {
this.ppNestLevel_ = 0;
};
/**
* Formats a value in a nice, human-readable string.
*
* @param value
*/
jasmine.PrettyPrinter.prototype.format = function(value) {
if (this.ppNestLevel_ > 40) {
throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
}
this.ppNestLevel_++;
try {
if (value === jasmine.undefined) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === jasmine.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString());
} else if (typeof value === 'string') {
this.emitString(value);
} else if (jasmine.isSpy(value)) {
this.emitScalar("spy on " + value.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (typeof value.nodeType === 'number') {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (value.__Jasmine_been_here_before__) {
this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
} else if (jasmine.isArray_(value) || typeof value == 'object') {
value.__Jasmine_been_here_before__ = true;
if (jasmine.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
delete value.__Jasmine_been_here_before__;
} else {
this.emitScalar(value.toString());
}
} finally {
this.ppNestLevel_--;
}
};
jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
for (var property in obj) {
if (property == '__Jasmine_been_here_before__') continue;
fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
obj.__lookupGetter__(property) !== null) : false);
}
};
jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
jasmine.StringPrettyPrinter = function() {
jasmine.PrettyPrinter.call(this);
this.string = '';
};
jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
this.append(value);
};
jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
this.append("'" + value + "'");
};
jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
this.append('[ ');
for (var i = 0; i < array.length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
this.append(' ]');
};
jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
var self = this;
this.append('{ ');
var first = true;
this.iterateObject(obj, function(property, isGetter) {
if (first) {
first = false;
} else {
self.append(', ');
}
self.append(property);
self.append(' : ');
if (isGetter) {
self.append('<getter>');
} else {
self.format(obj[property]);
}
});
this.append(' }');
};
jasmine.StringPrettyPrinter.prototype.append = function(value) {
this.string += value;
};
jasmine.Queue = function(env) {
this.env = env;
this.blocks = [];
this.running = false;
this.index = 0;
this.offset = 0;
this.abort = false;
};
jasmine.Queue.prototype.addBefore = function(block) {
this.blocks.unshift(block);
};
jasmine.Queue.prototype.add = function(block) {
this.blocks.push(block);
};
jasmine.Queue.prototype.insertNext = function(block) {
this.blocks.splice((this.index + this.offset + 1), 0, block);
this.offset++;
};
jasmine.Queue.prototype.start = function(onComplete) {
this.running = true;
this.onComplete = onComplete;
this.next_();
};
jasmine.Queue.prototype.isRunning = function() {
return this.running;
};
jasmine.Queue.LOOP_DONT_RECURSE = true;
jasmine.Queue.prototype.next_ = function() {
var self = this;
var goAgain = true;
while (goAgain) {
goAgain = false;
if (self.index < self.blocks.length && !this.abort) {
var calledSynchronously = true;
var completedSynchronously = false;
var onComplete = function () {
if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
completedSynchronously = true;
return;
}
if (self.blocks[self.index].abort) {
self.abort = true;
}
self.offset = 0;
self.index++;
var now = new Date().getTime();
if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
self.env.lastUpdate = now;
self.env.setTimeout(function() {
self.next_();
}, 0);
} else {
if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
goAgain = true;
} else {
self.next_();
}
}
};
self.blocks[self.index].execute(onComplete);
calledSynchronously = false;
if (completedSynchronously) {
onComplete();
}
} else {
self.running = false;
if (self.onComplete) {
self.onComplete();
}
}
}
};
jasmine.Queue.prototype.results = function() {
var results = new jasmine.NestedResults();
for (var i = 0; i < this.blocks.length; i++) {
if (this.blocks[i].results) {
results.addResult(this.blocks[i].results());
}
}
return results;
};
/**
* Runner
*
* @constructor
* @param {jasmine.Env} env
*/
jasmine.Runner = function(env) {
var self = this;
self.env = env;
self.queue = new jasmine.Queue(env);
self.before_ = [];
self.after_ = [];
self.suites_ = [];
};
jasmine.Runner.prototype.execute = function() {
var self = this;
if (self.env.reporter.reportRunnerStarting) {
self.env.reporter.reportRunnerStarting(this);
}
self.queue.start(function () {
self.finishCallback();
});
};
jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.splice(0,0,beforeEachFunction);
};
jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.splice(0,0,afterEachFunction);
};
jasmine.Runner.prototype.finishCallback = function() {
this.env.reporter.reportRunnerResults(this);
};
jasmine.Runner.prototype.addSuite = function(suite) {
this.suites_.push(suite);
};
jasmine.Runner.prototype.add = function(block) {
if (block instanceof jasmine.Suite) {
this.addSuite(block);
}
this.queue.add(block);
};
jasmine.Runner.prototype.specs = function () {
var suites = this.suites();
var specs = [];
for (var i = 0; i < suites.length; i++) {
specs = specs.concat(suites[i].specs());
}
return specs;
};
jasmine.Runner.prototype.suites = function() {
return this.suites_;
};
jasmine.Runner.prototype.topLevelSuites = function() {
var topLevelSuites = [];
for (var i = 0; i < this.suites_.length; i++) {
if (!this.suites_[i].parentSuite) {
topLevelSuites.push(this.suites_[i]);
}
}
return topLevelSuites;
};
jasmine.Runner.prototype.results = function() {
return this.queue.results();
};
/**
* Internal representation of a Jasmine specification, or test.
*
* @constructor
* @param {jasmine.Env} env
* @param {jasmine.Suite} suite
* @param {String} description
*/
jasmine.Spec = function(env, suite, description) {
if (!env) {
throw new Error('jasmine.Env() required');
}
if (!suite) {
throw new Error('jasmine.Suite() required');
}
var spec = this;
spec.id = env.nextSpecId ? env.nextSpecId() : null;
spec.env = env;
spec.suite = suite;
spec.description = description;
spec.queue = new jasmine.Queue(env);
spec.afterCallbacks = [];
spec.spies_ = [];
spec.results_ = new jasmine.NestedResults();
spec.results_.description = description;
spec.matchersClass = null;
};
jasmine.Spec.prototype.getFullName = function() {
return this.suite.getFullName() + ' ' + this.description + '.';
};
jasmine.Spec.prototype.results = function() {
return this.results_;
};
/**
* All parameters are pretty-printed and concatenated together, then written to the spec's output.
*
* Be careful not to leave calls to <code>jasmine.log</code> in production code.
*/
jasmine.Spec.prototype.log = function() {
return this.results_.log(arguments);
};
jasmine.Spec.prototype.runs = function (func) {
var block = new jasmine.Block(this.env, func, this);
this.addToQueue(block);
return this;
};
jasmine.Spec.prototype.addToQueue = function (block) {
if (this.queue.isRunning()) {
this.queue.insertNext(block);
} else {
this.queue.add(block);
}
};
/**
* @param {jasmine.ExpectationResult} result
*/
jasmine.Spec.prototype.addMatcherResult = function(result) {
this.results_.addResult(result);
};
jasmine.Spec.prototype.expect = function(actual) {
var positive = new (this.getMatchersClass_())(this.env, actual, this);
positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
return positive;
};
/**
* Waits a fixed time period before moving to the next block.
*
* @deprecated Use waitsFor() instead
* @param {Number} timeout milliseconds to wait
*/
jasmine.Spec.prototype.waits = function(timeout) {
var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
this.addToQueue(waitsFunc);
return this;
};
/**
* Waits for the latchFunction to return true before proceeding to the next block.
*
* @param {Function} latchFunction
* @param {String} optional_timeoutMessage
* @param {Number} optional_timeout
*/
jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
var latchFunction_ = null;
var optional_timeoutMessage_ = null;
var optional_timeout_ = null;
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
switch (typeof arg) {
case 'function':
latchFunction_ = arg;
break;
case 'string':
optional_timeoutMessage_ = arg;
break;
case 'number':
optional_timeout_ = arg;
break;
}
}
var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
this.addToQueue(waitsForFunc);
return this;
};
jasmine.Spec.prototype.fail = function (e) {
var expectationResult = new jasmine.ExpectationResult({
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception',
trace: { stack: e.stack }
});
this.results_.addResult(expectationResult);
};
jasmine.Spec.prototype.getMatchersClass_ = function() {
return this.matchersClass || this.env.matchersClass;
};
jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
var parent = this.getMatchersClass_();
var newMatchersClass = function() {
parent.apply(this, arguments);
};
jasmine.util.inherit(newMatchersClass, parent);
jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
this.matchersClass = newMatchersClass;
};
jasmine.Spec.prototype.finishCallback = function() {
this.env.reporter.reportSpecResults(this);
};
jasmine.Spec.prototype.finish = function(onComplete) {
this.removeAllSpies();
this.finishCallback();
if (onComplete) {
onComplete();
}
};
jasmine.Spec.prototype.after = function(doAfter) {
if (this.queue.isRunning()) {
this.queue.add(new jasmine.Block(this.env, doAfter, this));
} else {
this.afterCallbacks.unshift(doAfter);
}
};
jasmine.Spec.prototype.execute = function(onComplete) {
var spec = this;
if (!spec.env.specFilter(spec)) {
spec.results_.skipped = true;
spec.finish(onComplete);
return;
}
this.env.reporter.reportSpecStarting(this);
spec.env.currentSpec = spec;
spec.addBeforesAndAftersToQueue();
spec.queue.start(function () {
spec.finish(onComplete);
});
};
jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
var runner = this.env.currentRunner();
var i;
for (var suite = this.suite; suite; suite = suite.parentSuite) {
for (i = 0; i < suite.before_.length; i++) {
this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
}
}
for (i = 0; i < runner.before_.length; i++) {
this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
}
for (i = 0; i < this.afterCallbacks.length; i++) {
this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
}
for (suite = this.suite; suite; suite = suite.parentSuite) {
for (i = 0; i < suite.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
}
}
for (i = 0; i < runner.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
}
};
jasmine.Spec.prototype.explodes = function() {
throw 'explodes function should not have been called';
};
jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
if (obj == jasmine.undefined) {
throw "spyOn could not find an object to spy upon for " + methodName + "()";
}
if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
throw methodName + '() method does not exist';
}
if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
throw new Error(methodName + ' has already been spied upon');
}
var spyObj = jasmine.createSpy(methodName);
this.spies_.push(spyObj);
spyObj.baseObj = obj;
spyObj.methodName = methodName;
spyObj.originalValue = obj[methodName];
obj[methodName] = spyObj;
return spyObj;
};
jasmine.Spec.prototype.removeAllSpies = function() {
for (var i = 0; i < this.spies_.length; i++) {
var spy = this.spies_[i];
spy.baseObj[spy.methodName] = spy.originalValue;
}
this.spies_ = [];
};
/**
* Internal representation of a Jasmine suite.
*
* @constructor
* @param {jasmine.Env} env
* @param {String} description
* @param {Function} specDefinitions
* @param {jasmine.Suite} parentSuite
*/
jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
var self = this;
self.id = env.nextSuiteId ? env.nextSuiteId() : null;
self.description = description;
self.queue = new jasmine.Queue(env);
self.parentSuite = parentSuite;
self.env = env;
self.before_ = [];
self.after_ = [];
self.children_ = [];
self.suites_ = [];
self.specs_ = [];
};
jasmine.Suite.prototype.getFullName = function() {
var fullName = this.description;
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
fullName = parentSuite.description + ' ' + fullName;
}
return fullName;
};
jasmine.Suite.prototype.finish = function(onComplete) {
this.env.reporter.reportSuiteResults(this);
this.finished = true;
if (typeof(onComplete) == 'function') {
onComplete();
}
};
jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.unshift(beforeEachFunction);
};
jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.unshift(afterEachFunction);
};
jasmine.Suite.prototype.results = function() {
return this.queue.results();
};
jasmine.Suite.prototype.add = function(suiteOrSpec) {
this.children_.push(suiteOrSpec);
if (suiteOrSpec instanceof jasmine.Suite) {
this.suites_.push(suiteOrSpec);
this.env.currentRunner().addSuite(suiteOrSpec);
} else {
this.specs_.push(suiteOrSpec);
}
this.queue.add(suiteOrSpec);
};
jasmine.Suite.prototype.specs = function() {
return this.specs_;
};
jasmine.Suite.prototype.suites = function() {
return this.suites_;
};
jasmine.Suite.prototype.children = function() {
return this.children_;
};
jasmine.Suite.prototype.execute = function(onComplete) {
var self = this;
this.queue.start(function () {
self.finish(onComplete);
});
};
jasmine.WaitsBlock = function(env, timeout, spec) {
this.timeout = timeout;
jasmine.Block.call(this, env, null, spec);
};
jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
jasmine.WaitsBlock.prototype.execute = function (onComplete) {
if (jasmine.VERBOSE) {
this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
}
this.env.setTimeout(function () {
onComplete();
}, this.timeout);
};
/**
* A block which waits for some condition to become true, with timeout.
*
* @constructor
* @extends jasmine.Block
* @param {jasmine.Env} env The Jasmine environment.
* @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
* @param {Function} latchFunction A function which returns true when the desired condition has been met.
* @param {String} message The message to display if the desired condition hasn't been met within the given time period.
* @param {jasmine.Spec} spec The Jasmine spec.
*/
jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
this.timeout = timeout || env.defaultTimeoutInterval;
this.latchFunction = latchFunction;
this.message = message;
this.totalTimeSpentWaitingForLatch = 0;
jasmine.Block.call(this, env, null, spec);
};
jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
if (jasmine.VERBOSE) {
this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
}
var latchFunctionResult;
try {
latchFunctionResult = this.latchFunction.apply(this.spec);
} catch (e) {
this.spec.fail(e);
onComplete();
return;
}
if (latchFunctionResult) {
onComplete();
} else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
this.spec.fail({
name: 'timeout',
message: message
});
this.abort = true;
onComplete();
} else {
this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
var self = this;
this.env.setTimeout(function() {
self.execute(onComplete);
}, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
}
};
jasmine.version_= {
"major": 1,
"minor": 2,
"build": 0,
"revision": 1337005947
};

View File

@ -1,9227 +0,0 @@
/*!
* jQuery JavaScript Library v1.8.0
* http://jquery.com/
*
* Includes Sizzle.js
* http://sizzlejs.com/
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time)
*/
(function( window, undefined ) {
var
// A central reference to the root jQuery(document)
rootjQuery,
// The deferred used on DOM ready
readyList,
// Use the correct document accordingly with window argument (sandbox)
document = window.document,
location = window.location,
navigator = window.navigator,
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
// Save a reference to some core methods
core_push = Array.prototype.push,
core_slice = Array.prototype.slice,
core_indexOf = Array.prototype.indexOf,
core_toString = Object.prototype.toString,
core_hasOwn = Object.prototype.hasOwnProperty,
core_trim = String.prototype.trim,
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
// Used for matching numbers
core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
// Used for detecting and trimming whitespace
core_rnotwhite = /\S/,
core_rspace = /\s+/,
// IE doesn't match non-breaking spaces with \s
rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g,
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
// JSON RegExp
rvalidchars = /^[\],:{}\s]*$/,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
// Matches dashed string for camelizing
rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi,
// Used by jQuery.camelCase as callback to replace()
fcamelCase = function( all, letter ) {
return ( letter + "" ).toUpperCase();
},
// The ready event handler and self cleanup method
DOMContentLoaded = function() {
if ( document.addEventListener ) {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
} else if ( document.readyState === "complete" ) {
// we're here because readyState === "complete" in oldIE
// which is good enough for us to call the dom ready!
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
},
// [[Class]] -> type pairs
class2type = {};
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// Handle $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// Handle HTML strings
if ( typeof selector === "string" ) {
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
doc = ( context && context.nodeType ? context.ownerDocument || context : document );
// scripts is true for back-compat
selector = jQuery.parseHTML( match[1], doc, true );
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
this.attr.call( selector, context, true );
}
return jQuery.merge( this, selector );
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
return jQuery.makeArray( selector, this );
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
jquery: "1.8.0",
// The default length of a jQuery object is 0
length: 0,
// The number of elements contained in the matched element set
size: function() {
return this.length;
},
toArray: function() {
return core_slice.call( this );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
return num == null ?
// Return a 'clean' array
this.toArray() :
// Return just the object
( num < 0 ? this[ this.length + num ] : this[ num ] );
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) {
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function( callback, args ) {
return jQuery.each( this, callback, args );
},
ready: function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
},
eq: function( i ) {
i = +i;
return i === -1 ?
this.slice( i ) :
this.slice( i, i + 1 );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
slice: function() {
return this.pushStack( core_slice.apply( this, arguments ),
"slice", core_slice.call(arguments).join(",") );
},
map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},
end: function() {
return this.prevObject || this.constructor(null);
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: core_push,
sort: [].sort,
splice: [].splice
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery.extend({
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
jQuery.readyWait++;
} else {
jQuery.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
// Trigger any bound ready events
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger("ready").off("ready");
}
},
// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return jQuery.type(obj) === "function";
},
isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
},
isWindow: function( obj ) {
return obj != null && obj == obj.window;
},
isNumeric: function( obj ) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ core_toString.call(obj) ] || "object";
},
isPlainObject: function( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
try {
// Not own constructor property must be Object
if ( obj.constructor &&
!core_hasOwn.call(obj, "constructor") &&
!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
} catch ( e ) {
// IE8,9 Will throw exceptions on certain host objects #9897
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
return key === undefined || core_hasOwn.call( obj, key );
},
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
}
return true;
},
error: function( msg ) {
throw new Error( msg );
},
// data: string of html
// context (optional): If specified, the fragment will be created in this context, defaults to document
// scripts (optional): If true, will include scripts passed in the html string
parseHTML: function( data, context, scripts ) {
var parsed;
if ( !data || typeof data !== "string" ) {
return null;
}
if ( typeof context === "boolean" ) {
scripts = context;
context = 0;
}
context = context || document;
// Single tag
if ( (parsed = rsingleTag.exec( data )) ) {
return [ context.createElement( parsed[1] ) ];
}
parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
return jQuery.merge( [],
(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
},
parseJSON: function( data ) {
if ( !data || typeof data !== "string") {
return null;
}
// Make sure leading/trailing whitespace is removed (IE can't handle it)
data = jQuery.trim( data );
// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
}
// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
return ( new Function( "return " + data ) )();
}
jQuery.error( "Invalid JSON: " + data );
},
// Cross-browser xml parsing
parseXML: function( data ) {
var xml, tmp;
if ( !data || typeof data !== "string" ) {
return null;
}
try {
if ( window.DOMParser ) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} else { // IE
xml = new ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
} catch( e ) {
xml = undefined;
}
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
},
noop: function() {},
// Evaluates a script in a global context
// Workarounds based on findings by Jim Driscoll
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
globalEval: function( data ) {
if ( data && core_rnotwhite.test( data ) ) {
// We use execScript on Internet Explorer
// We use an anonymous function so that context is window
// rather than jQuery in Firefox
( window.execScript || function( data ) {
window[ "eval" ].call( window, data );
} )( data );
}
},
// Convert dashed to camelCase; used by the css and data modules
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
},
// args is for internal usage only
each: function( obj, callback, args ) {
var name,
i = 0,
length = obj.length,
isObj = length === undefined || jQuery.isFunction( obj );
if ( args ) {
if ( isObj ) {
for ( name in obj ) {
if ( callback.apply( obj[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( obj[ i++ ], args ) === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in obj ) {
if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
break;
}
}
}
}
return obj;
},
// Use native String.trim function wherever possible
trim: core_trim ?
function( text ) {
return text == null ?
"" :
core_trim.call( text );
} :
// Otherwise use our own trimming functionality
function( text ) {
return text == null ?
"" :
text.toString().replace( rtrim, "" );
},
// results is for internal usage only
makeArray: function( arr, results ) {
var type,
ret = results || [];
if ( arr != null ) {
// The window, strings (and functions) also have 'length'
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
type = jQuery.type( arr );
if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
core_push.call( ret, arr );
} else {
jQuery.merge( ret, arr );
}
}
return ret;
},
inArray: function( elem, arr, i ) {
var len;
if ( arr ) {
if ( core_indexOf ) {
return core_indexOf.call( arr, elem, i );
}
len = arr.length;
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
for ( ; i < len; i++ ) {
// Skip accessing in sparse arrays
if ( i in arr && arr[ i ] === elem ) {
return i;
}
}
}
return -1;
},
merge: function( first, second ) {
var l = second.length,
i = first.length,
j = 0;
if ( typeof l === "number" ) {
for ( ; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
},
grep: function( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
},
// arg is for internal usage only
map: function( elems, callback, arg ) {
var value, key,
ret = [],
i = 0,
length = elems.length,
// jquery objects are treated as arrays
isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
// Go through the array, translating each of the items to their
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
// Go through every key on the object,
} else {
for ( key in elems ) {
value = callback( elems[ key ], key, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
}
// Flatten any nested arrays
return ret.concat.apply( [], ret );
},
// A global GUID counter for objects
guid: 1,
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
var tmp, args, proxy;
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
// Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
// Simulated bind
args = core_slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
};
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
return proxy;
},
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
var exec,
bulk = key == null,
i = 0,
length = elems.length;
// Sets many values
if ( key && typeof key === "object" ) {
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
}
chainable = 1;
// Sets one value
} else if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = pass === undefined && jQuery.isFunction( value );
if ( bulk ) {
// Bulk operations only iterate when executing function values
if ( exec ) {
exec = fn;
fn = function( elem, key, value ) {
return exec.call( jQuery( elem ), value );
};
// Otherwise they run against the entire set
} else {
fn.call( elems, value );
fn = null;
}
}
if ( fn ) {
for (; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
}
chainable = 1;
}
return chainable ?
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
},
now: function() {
return ( new Date() ).getTime();
}
});
jQuery.ready.promise = function( obj ) {
if ( !readyList ) {
readyList = jQuery.Deferred();
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready, 1 );
// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else {
// Ensure firing before onload, maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var top = false;
try {
top = window.frameElement == null && document.documentElement;
} catch(e) {}
if ( top && top.doScroll ) {
(function doScrollCheck() {
if ( !jQuery.isReady ) {
try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch(e) {
return setTimeout( doScrollCheck, 50 );
}
// and execute any waiting functions
jQuery.ready();
}
})();
}
}
}
return readyList.promise( obj );
};
// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
// String to Object options format cache
var optionsCache = {};
// Convert String-formatted options into Object-formatted ones and store in cache
function createOptions( options ) {
var object = optionsCache[ options ] = {};
jQuery.each( options.split( core_rspace ), function( _, flag ) {
object[ flag ] = true;
});
return object;
}
/*
* Create a callback list using the following parameters:
*
* options: an optional list of space-separated options that will change how
* the callback list behaves or a more traditional option object
*
* By default a callback list will act like an event callback list and can be
* "fired" multiple times.
*
* Possible options:
*
* once: will ensure the callback list can only be fired once (like a Deferred)
*
* memory: will keep track of previous values and will call any callback added
* after the list has been fired right away with the latest "memorized"
* values (like a Deferred)
*
* unique: will ensure a callback can only be added once (no duplicate in the list)
*
* stopOnFalse: interrupt callings when a callback returns false
*
*/
jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
jQuery.extend( {}, options );
var // Last fire value (for non-forgettable lists)
memory,
// Flag to know if list was already fired
fired,
// Flag to know if list is currently firing
firing,
// First callback to fire (used internally by add and fireWith)
firingStart,
// End of the loop when firing
firingLength,
// Index of currently firing callback (modified by remove if needed)
firingIndex,
// Actual callback list
list = [],
// Stack of fire calls for repeatable lists
stack = !options.once && [],
// Fire callbacks
fire = function( data ) {
memory = options.memory && data;
fired = true;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
memory = false; // To prevent further calls using add
break;
}
}
firing = false;
if ( list ) {
if ( stack ) {
if ( stack.length ) {
fire( stack.shift() );
}
} else if ( memory ) {
list = [];
} else {
self.disable();
}
}
},
// Actual Callbacks object
self = {
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// First, we save the current length
var start = list.length;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) {
list.push( arg );
} else if ( arg && arg.length ) {
// Inspect recursively
add( arg );
}
});
})( arguments );
// Do we need to add the callbacks to the
// current firing batch?
if ( firing ) {
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
firingStart = start;
fire( memory );
}
}
return this;
},
// Remove a callback from the list
remove: function() {
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
var index;
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
if ( firing ) {
if ( index <= firingLength ) {
firingLength--;
}
if ( index <= firingIndex ) {
firingIndex--;
}
}
}
});
}
return this;
},
// Control if a given callback is in the list
has: function( fn ) {
return jQuery.inArray( fn, list ) > -1;
},
// Remove all callbacks from the list
empty: function() {
list = [];
return this;
},
// Have the list do nothing anymore
disable: function() {
list = stack = memory = undefined;
return this;
},
// Is it disabled?
disabled: function() {
return !list;
},
// Lock the list in its current state
lock: function() {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
},
// Is it locked?
locked: function() {
return !stack;
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
if ( list && ( !fired || stack ) ) {
if ( firing ) {
stack.push( args );
} else {
fire( args );
}
}
return this;
},
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
// To know if the callbacks have already been called at least once
fired: function() {
return !!fired;
}
};
return self;
};
jQuery.extend({
Deferred: function( func ) {
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
state = "pending",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
function() {
var returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
}
} :
newDefer[ action ]
);
});
fns = null;
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
// Keep pipe for back-compat
promise.pipe = promise.then;
// Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
stateString = tuple[ 3 ];
// promise[ done | fail | progress ] = list.add
promise[ tuple[1] ] = list.add;
// Handle state
if ( stateString ) {
list.add(function() {
// state = [ resolved | rejected ]
state = stateString;
// [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
// deferred[ resolve | reject | notify ] = list.fire
deferred[ tuple[0] ] = list.fire;
deferred[ tuple[0] + "With" ] = list.fireWith;
});
// Make the deferred a promise
promise.promise( deferred );
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
// Deferred helper
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
// the count of uncompleted subordinates
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
// Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
if( values === progressValues ) {
deferred.notifyWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
},
progressValues, progressContexts, resolveContexts;
// add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )
.progress( updateFunc( i, progressContexts, progressValues ) );
} else {
--remaining;
}
}
}
// if we're not waiting on anything, resolve the master
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
return deferred.promise();
}
});
jQuery.support = (function() {
var support,
all,
a,
select,
opt,
input,
fragment,
eventName,
i,
isSupported,
clickFn,
div = document.createElement("div");
// Preliminary tests
div.setAttribute( "className", "t" );
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
all = div.getElementsByTagName("*");
a = div.getElementsByTagName("a")[ 0 ];
a.style.cssText = "top:1px;float:left;opacity:.5";
// Can't get basic test support
if ( !all || !all.length || !a ) {
return {};
}
// First batch of supports tests
select = document.createElement("select");
opt = select.appendChild( document.createElement("option") );
input = div.getElementsByTagName("input")[ 0 ];
support = {
// IE strips leading whitespace when .innerHTML is used
leadingWhitespace: ( div.firstChild.nodeType === 3 ),
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
tbody: !div.getElementsByTagName("tbody").length,
// Make sure that link elements get serialized correctly by innerHTML
// This requires a wrapper element in IE
htmlSerialize: !!div.getElementsByTagName("link").length,
// Get the style information from getAttribute
// (IE uses .cssText instead)
style: /top/.test( a.getAttribute("style") ),
// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
hrefNormalized: ( a.getAttribute("href") === "/a" ),
// Make sure that element opacity exists
// (IE uses filter instead)
// Use a regex to work around a WebKit issue. See #5145
opacity: /^0.5/.test( a.style.opacity ),
// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
cssFloat: !!a.style.cssFloat,
// Make sure that if no value is specified for a checkbox
// that it defaults to "on".
// (WebKit defaults to "" instead)
checkOn: ( input.value === "on" ),
// Make sure that a selected-by-default option has a working selected property.
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
optSelected: opt.selected,
// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
getSetAttribute: div.className !== "t",
// Tests for enctype support on a form(#6743)
enctype: !!document.createElement("form").enctype,
// Makes sure cloning an html5 element does not cause problems
// Where outerHTML is undefined, this still works
html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
boxModel: ( document.compatMode === "CSS1Compat" ),
// Will be defined later
submitBubbles: true,
changeBubbles: true,
focusinBubbles: false,
deleteExpando: true,
noCloneEvent: true,
inlineBlockNeedsLayout: false,
shrinkWrapBlocks: false,
reliableMarginRight: true,
boxSizingReliable: true,
pixelPosition: false
};
// Make sure checked status is properly cloned
input.checked = true;
support.noCloneChecked = input.cloneNode( true ).checked;
// Make sure that the options inside disabled selects aren't marked as disabled
// (WebKit marks them as disabled)
select.disabled = true;
support.optDisabled = !opt.disabled;
// Test to see if it's possible to delete an expando from an element
// Fails in Internet Explorer
try {
delete div.test;
} catch( e ) {
support.deleteExpando = false;
}
if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
div.attachEvent( "onclick", clickFn = function() {
// Cloning a node shouldn't copy over any
// bound event handlers (IE does this)
support.noCloneEvent = false;
});
div.cloneNode( true ).fireEvent("onclick");
div.detachEvent( "onclick", clickFn );
}
// Check if a radio maintains its value
// after being appended to the DOM
input = document.createElement("input");
input.value = "t";
input.setAttribute( "type", "radio" );
support.radioValue = input.value === "t";
input.setAttribute( "checked", "checked" );
// #11217 - WebKit loses check when the name is after the checked attribute
input.setAttribute( "name", "t" );
div.appendChild( input );
fragment = document.createDocumentFragment();
fragment.appendChild( div.lastChild );
// WebKit doesn't clone checked state correctly in fragments
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
// Check if a disconnected checkbox will retain its checked
// value of true after appended to the DOM (IE6/7)
support.appendChecked = input.checked;
fragment.removeChild( input );
fragment.appendChild( div );
// Technique from Juriy Zaytsev
// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
// We only care about the case where non-standard event systems
// are used, namely in IE. Short-circuiting here helps us to
// avoid an eval call (in setAttribute) which can cause CSP
// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
if ( div.attachEvent ) {
for ( i in {
submit: true,
change: true,
focusin: true
}) {
eventName = "on" + i;
isSupported = ( eventName in div );
if ( !isSupported ) {
div.setAttribute( eventName, "return;" );
isSupported = ( typeof div[ eventName ] === "function" );
}
support[ i + "Bubbles" ] = isSupported;
}
}
// Run tests that need a body at doc ready
jQuery(function() {
var container, div, tds, marginDiv,
divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
body = document.getElementsByTagName("body")[0];
if ( !body ) {
// Return for frameset docs that don't have a body
return;
}
container = document.createElement("div");
container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
body.insertBefore( container, body.firstChild );
// Construct the test element
div = document.createElement("div");
container.appendChild( div );
// Check if table cells still have offsetWidth/Height when they are set
// to display:none and there are still other visible table cells in a
// table row; if so, offsetWidth/Height are not reliable for use when
// determining if an element has been hidden directly using
// display:none (it is still safe to use offsets if a parent element is
// hidden; don safety goggles and see bug #4512 for more information).
// (only IE 8 fails this test)
div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
tds = div.getElementsByTagName("td");
tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
isSupported = ( tds[ 0 ].offsetHeight === 0 );
tds[ 0 ].style.display = "";
tds[ 1 ].style.display = "none";
// Check if empty table cells still have offsetWidth/Height
// (IE <= 8 fail this test)
support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
// Check box-sizing and margin behavior
div.innerHTML = "";
div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
support.boxSizing = ( div.offsetWidth === 4 );
support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
// NOTE: To any future maintainer, window.getComputedStyle was used here
// instead of getComputedStyle because it gave a better gzip size.
// The difference between window.getComputedStyle and getComputedStyle is
// 7 bytes
if ( window.getComputedStyle ) {
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
// Check if div with explicit width and no margin-right incorrectly
// gets computed margin-right based on width of container. For more
// info see bug #3333
// Fails in WebKit before Feb 2011 nightlies
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
marginDiv = document.createElement("div");
marginDiv.style.cssText = div.style.cssText = divReset;
marginDiv.style.marginRight = marginDiv.style.width = "0";
div.style.width = "1px";
div.appendChild( marginDiv );
support.reliableMarginRight =
!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
}
if ( typeof div.style.zoom !== "undefined" ) {
// Check if natively block-level elements act like inline-block
// elements when setting their display to 'inline' and giving
// them layout
// (IE < 8 does this)
div.innerHTML = "";
div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
// Check if elements with layout shrink-wrap their children
// (IE 6 does this)
div.style.display = "block";
div.style.overflow = "visible";
div.innerHTML = "<div></div>";
div.firstChild.style.width = "5px";
support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
container.style.zoom = 1;
}
// Null elements to avoid leaks in IE
body.removeChild( container );
container = div = tds = marginDiv = null;
});
// Null elements to avoid leaks in IE
fragment.removeChild( div );
all = a = select = opt = input = fragment = div = null;
return support;
})();
var rbrace = /^(?:\{.*\}|\[.*\])$/,
rmultiDash = /([A-Z])/g;
jQuery.extend({
cache: {},
deletedIds: [],
// Please use with caution
uuid: 0,
// Unique for each copy of jQuery on the page
// Non-digits removed to match rinlinejQuery
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
// The following elements throw uncatchable exceptions if you
// attempt to add expando properties to them.
noData: {
"embed": true,
// Ban all objects except for Flash (which handle expandos)
"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
"applet": true
},
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
return !!elem && !isEmptyDataObject( elem );
},
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, ret,
internalKey = jQuery.expando,
getByName = typeof name === "string",
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
isNode = elem.nodeType,
// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
cache = isNode ? jQuery.cache : elem,
// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
if ( !id ) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid;
} else {
id = internalKey;
}
}
if ( !cache[ id ] ) {
cache[ id ] = {};
// Avoids exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
}
// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
thisCache = cache[ id ];
// jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
if ( !pvt ) {
if ( !thisCache.data ) {
thisCache.data = {};
}
thisCache = thisCache.data;
}
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
if ( getByName ) {
// First Try to find as-is property data
ret = thisCache[ name ];
// Test for null|undefined property data
if ( ret == null ) {
// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}
return ret;
},
removeData: function( elem, name, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, i, l,
isNode = elem.nodeType,
// See jQuery.data for more information
cache = isNode ? jQuery.cache : elem,
id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
// If there is already no cache entry for this object, there is no
// purpose in continuing
if ( !cache[ id ] ) {
return;
}
if ( name ) {
thisCache = pvt ? cache[ id ] : cache[ id ].data;
if ( thisCache ) {
// Support array or space separated string names for data keys
if ( !jQuery.isArray( name ) ) {
// try the string as a key before any manipulation
if ( name in thisCache ) {
name = [ name ];
} else {
// split the camel cased version by spaces unless a key with the spaces exists
name = jQuery.camelCase( name );
if ( name in thisCache ) {
name = [ name ];
} else {
name = name.split(" ");
}
}
}
for ( i = 0, l = name.length; i < l; i++ ) {
delete thisCache[ name[i] ];
}
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
return;
}
}
}
// See jQuery.data for more information
if ( !pvt ) {
delete cache[ id ].data;
// Don't destroy the parent cache unless the internal data object
// had been the only thing left in it
if ( !isEmptyDataObject( cache[ id ] ) ) {
return;
}
}
// Destroy the cache
if ( isNode ) {
jQuery.cleanData( [ elem ], true );
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
delete cache[ id ];
// When all else fails, null
} else {
cache[ id ] = null;
}
},
// For internal use only.
_data: function( elem, name, data ) {
return jQuery.data( elem, name, data, true );
},
// A method for determining if a DOM node can handle the data expando
acceptData: function( elem ) {
var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
// nodes accept data unless otherwise specified; rejection can be conditional
return !noData || noData !== true && elem.getAttribute("classid") === noData;
}
});
jQuery.fn.extend({
data: function( key, value ) {
var parts, part, attr, name, l,
elem = this[0],
i = 0,
data = null;
// Gets all values
if ( key === undefined ) {
if ( this.length ) {
data = jQuery.data( elem );
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
attr = elem.attributes;
for ( l = attr.length; i < l; i++ ) {
name = attr[i].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.substring(5) );
dataAttr( elem, name, data[ name ] );
}
}
jQuery._data( elem, "parsedAttrs", true );
}
}
return data;
}
// Sets multiple values
if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
parts = key.split( ".", 2 );
parts[1] = parts[1] ? "." + parts[1] : "";
part = parts[1] + "!";
return jQuery.access( this, function( value ) {
if ( value === undefined ) {
data = this.triggerHandler( "getData" + part, [ parts[0] ] );
// Try to fetch any internally stored data first
if ( data === undefined && elem ) {
data = jQuery.data( elem, key );
data = dataAttr( elem, key, data );
}
return data === undefined && parts[1] ?
this.data( parts[0] ) :
data;
}
parts[1] = value;
this.each(function() {
var self = jQuery( this );
self.triggerHandler( "setData" + part, parts );
jQuery.data( this, key, value );
self.triggerHandler( "changeData" + part, parts );
});
}, null, value, arguments.length > 1, null, false );
},
removeData: function( key ) {
return this.each(function() {
jQuery.removeData( this, key );
});
}
});
function dataAttr( elem, key, data ) {
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
data = elem.getAttribute( name );
if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
// Only convert to a number if it doesn't change the string
+data + "" === data ? +data :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch( e ) {}
// Make sure we set the data so it isn't changed later
jQuery.data( elem, key, data );
} else {
data = undefined;
}
}
return data;
}
// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
var name;
for ( name in obj ) {
// if the public data object is empty, the private is still empty
if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
continue;
}
if ( name !== "toJSON" ) {
return false;
}
}
return true;
}
jQuery.extend({
queue: function( elem, type, data ) {
var queue;
if ( elem ) {
type = ( type || "fx" ) + "queue";
queue = jQuery._data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !queue || jQuery.isArray(data) ) {
queue = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
queue.push( data );
}
}
return queue || [];
}
},
dequeue: function( elem, type ) {
type = type || "fx";
var queue = jQuery.queue( elem, type ),
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
}
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
// clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
if ( !queue.length && hooks ) {
hooks.empty.fire();
}
},
// not intended for public consumption - generates a queueHooks object, or returns the current one
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
return jQuery._data( elem, key ) || jQuery._data( elem, key, {
empty: jQuery.Callbacks("once memory").add(function() {
jQuery.removeData( elem, type + "queue", true );
jQuery.removeData( elem, key, true );
})
});
}
});
jQuery.fn.extend({
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
if ( arguments.length < setter ) {
return jQuery.queue( this[0], type );
}
return data === undefined ?
this :
this.each(function() {
var queue = jQuery.queue( this, type, data );
// ensure a hooks for this queue
jQuery._queueHooks( this, type );
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
});
},
dequeue: function( type ) {
return this.each(function() {
jQuery.dequeue( this, type );
});
},
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function( next, hooks ) {
var timeout = setTimeout( next, time );
hooks.stop = function() {
clearTimeout( timeout );
};
});
},
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
promise: function( type, obj ) {
var tmp,
count = 1,
defer = jQuery.Deferred(),
elements = this,
i = this.length,
resolve = function() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
};
if ( typeof type !== "string" ) {
obj = type;
type = undefined;
}
type = type || "fx";
while( i-- ) {
if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) {
count++;
tmp.empty.add( resolve );
}
}
resolve();
return defer.promise( obj );
}
});
var nodeHook, boolHook, fixSpecified,
rclass = /[\t\r\n]/g,
rreturn = /\r/g,
rtype = /^(?:button|input)$/i,
rfocusable = /^(?:button|input|object|select|textarea)$/i,
rclickable = /^a(?:rea|)$/i,
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
getSetAttribute = jQuery.support.getSetAttribute;
jQuery.fn.extend({
attr: function( name, value ) {
return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
return this.each(function() {
jQuery.removeAttr( this, name );
});
},
prop: function( name, value ) {
return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
},
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each(function() {
// try/catch handles cases where IE balks (such as removing a property on window)
try {
this[ name ] = undefined;
delete this[ name ];
} catch( e ) {}
});
},
addClass: function( value ) {
var classNames, i, l, elem,
setClass, c, cl;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).addClass( value.call(this, j, this.className) );
});
}
if ( value && typeof value === "string" ) {
classNames = value.split( core_rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
if ( elem.nodeType === 1 ) {
if ( !elem.className && classNames.length === 1 ) {
elem.className = value;
} else {
setClass = " " + elem.className + " ";
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
setClass += classNames[ c ] + " ";
}
}
elem.className = jQuery.trim( setClass );
}
}
}
}
return this;
},
removeClass: function( value ) {
var removes, className, elem, c, cl, i, l;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).removeClass( value.call(this, j, this.className) );
});
}
if ( (value && typeof value === "string") || value === undefined ) {
removes = ( value || "" ).split( core_rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
if ( elem.nodeType === 1 && elem.className ) {
className = (" " + elem.className + " ").replace( rclass, " " );
// loop over each item in the removal list
for ( c = 0, cl = removes.length; c < cl; c++ ) {
// Remove until there is nothing to remove,
while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) {
className = className.replace( " " + removes[ c ] + " " , " " );
}
}
elem.className = value ? jQuery.trim( className ) : "";
}
}
}
return this;
},
toggleClass: function( value, stateVal ) {
var type = typeof value,
isBool = typeof stateVal === "boolean";
if ( jQuery.isFunction( value ) ) {
return this.each(function( i ) {
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
});
}
return this.each(function() {
if ( type === "string" ) {
// toggle individual class names
var className,
i = 0,
self = jQuery( this ),
state = stateVal,
classNames = value.split( core_rspace );
while ( (className = classNames[ i++ ]) ) {
// check each className given, space separated list
state = isBool ? state : !self.hasClass( className );
self[ state ? "addClass" : "removeClass" ]( className );
}
} else if ( type === "undefined" || type === "boolean" ) {
if ( this.className ) {
// store className if set
jQuery._data( this, "__className__", this.className );
}
// toggle whole className
this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
}
});
},
hasClass: function( selector ) {
var className = " " + selector + " ",
i = 0,
l = this.length;
for ( ; i < l; i++ ) {
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
return true;
}
}
return false;
},
val: function( value ) {
var hooks, ret, isFunction,
elem = this[0];
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
return ret;
}
ret = elem.value;
return typeof ret === "string" ?
// handle most common string cases
ret.replace(rreturn, "") :
// handle cases where value is null/undef or number
ret == null ? "" : ret;
}
return;
}
isFunction = jQuery.isFunction( value );
return this.each(function( i ) {
var val,
self = jQuery(this);
if ( this.nodeType !== 1 ) {
return;
}
if ( isFunction ) {
val = value.call( this, i, self.val() );
} else {
val = value;
}
// Treat null/undefined as ""; convert numbers to string
if ( val == null ) {
val = "";
} else if ( typeof val === "number" ) {
val += "";
} else if ( jQuery.isArray( val ) ) {
val = jQuery.map(val, function ( value ) {
return value == null ? "" : value + "";
});
}
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
});
}
});
jQuery.extend({
valHooks: {
option: {
get: function( elem ) {
// attributes.value is undefined in Blackberry 4.7 but
// uses .value. See #6932
var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
},
select: {
get: function( elem ) {
var value, i, max, option,
index = elem.selectedIndex,
values = [],
options = elem.options,
one = elem.type === "select-one";
// Nothing was selected
if ( index < 0 ) {
return null;
}
// Loop through all the selected options
i = one ? index : 0;
max = one ? index + 1 : options.length;
for ( ; i < max; i++ ) {
option = options[ i ];
// Don't return options that are disabled or in a disabled optgroup
if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
// Get the specific value for the option
value = jQuery( option ).val();
// We don't need an array for one selects
if ( one ) {
return value;
}
// Multi-Selects return an array
values.push( value );
}
}
// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
if ( one && !values.length && options.length ) {
return jQuery( options[ index ] ).val();
}
return values;
},
set: function( elem, value ) {
var values = jQuery.makeArray( value );
jQuery(elem).find("option").each(function() {
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
});
if ( !values.length ) {
elem.selectedIndex = -1;
}
return values;
}
}
},
// Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
attrFn: {},
attr: function( elem, name, value, pass ) {
var ret, hooks, notxml,
nType = elem.nodeType;
// don't get/set attributes on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
return;
}
if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
return jQuery( elem )[ name ]( value );
}
// Fallback to prop when attributes are not supported
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
// All attributes are lowercase
// Grab necessary hook if one is defined
if ( notxml ) {
name = name.toLowerCase();
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
}
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
return;
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
elem.setAttribute( name, "" + value );
return value;
}
} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
ret = elem.getAttribute( name );
// Non-existent attributes return null, we normalize to undefined
return ret === null ?
undefined :
ret;
}
},
removeAttr: function( elem, value ) {
var propName, attrNames, name, isBool,
i = 0;
if ( value && elem.nodeType === 1 ) {
attrNames = value.split( core_rspace );
for ( ; i < attrNames.length; i++ ) {
name = attrNames[ i ];
if ( name ) {
propName = jQuery.propFix[ name ] || name;
isBool = rboolean.test( name );
// See #9699 for explanation of this approach (setting first, then removal)
// Do not do this for boolean attributes (see #10870)
if ( !isBool ) {
jQuery.attr( elem, name, "" );
}
elem.removeAttribute( getSetAttribute ? name : propName );
// Set corresponding property to false for boolean attributes
if ( isBool && propName in elem ) {
elem[ propName ] = false;
}
}
}
}
},
attrHooks: {
type: {
set: function( elem, value ) {
// We can't allow the type property to be changed (since it causes problems in IE)
if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
jQuery.error( "type property can't be changed" );
} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
// Setting the type on a radio button after the value resets the value in IE6-9
// Reset value to it's default in case type is set after value
// This is for element creation
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
elem.value = val;
}
return value;
}
}
},
// Use the value property for back compat
// Use the nodeHook for button elements in IE6/7 (#1954)
value: {
get: function( elem, name ) {
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
return nodeHook.get( elem, name );
}
return name in elem ?
elem.value :
null;
},
set: function( elem, value, name ) {
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
return nodeHook.set( elem, value, name );
}
// Does not return so that setAttribute is also used
elem.value = value;
}
}
},
propFix: {
tabindex: "tabIndex",
readonly: "readOnly",
"for": "htmlFor",
"class": "className",
maxlength: "maxLength",
cellspacing: "cellSpacing",
cellpadding: "cellPadding",
rowspan: "rowSpan",
colspan: "colSpan",
usemap: "useMap",
frameborder: "frameBorder",
contenteditable: "contentEditable"
},
prop: function( elem, name, value ) {
var ret, hooks, notxml,
nType = elem.nodeType;
// don't get/set properties on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
return;
}
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
if ( notxml ) {
// Fix name and attach hooks
name = jQuery.propFix[ name ] || name;
hooks = jQuery.propHooks[ name ];
}
if ( value !== undefined ) {
if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
return ( elem[ name ] = value );
}
} else {
if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
return elem[ name ];
}
}
},
propHooks: {
tabIndex: {
get: function( elem ) {
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
var attributeNode = elem.getAttributeNode("tabindex");
return attributeNode && attributeNode.specified ?
parseInt( attributeNode.value, 10 ) :
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
0 :
undefined;
}
}
}
});
// Hook for boolean attributes
boolHook = {
get: function( elem, name ) {
// Align boolean attributes with corresponding properties
// Fall back to attribute presence where some booleans are not supported
var attrNode,
property = jQuery.prop( elem, name );
return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
name.toLowerCase() :
undefined;
},
set: function( elem, value, name ) {
var propName;
if ( value === false ) {
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
} else {
// value is true since we know at this point it's type boolean and not false
// Set boolean attributes to the same name and set the DOM property
propName = jQuery.propFix[ name ] || name;
if ( propName in elem ) {
// Only set the IDL specifically if it already exists on the element
elem[ propName ] = true;
}
elem.setAttribute( name, name.toLowerCase() );
}
return name;
}
};
// IE6/7 do not support getting/setting some attributes with get/setAttribute
if ( !getSetAttribute ) {
fixSpecified = {
name: true,
id: true,
coords: true
};
// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = jQuery.valHooks.button = {
get: function( elem, name ) {
var ret;
ret = elem.getAttributeNode( name );
return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
ret.value :
undefined;
},
set: function( elem, value, name ) {
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
if ( !ret ) {
ret = document.createAttribute( name );
elem.setAttributeNode( ret );
}
return ( ret.value = value + "" );
}
};
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each([ "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
set: function( elem, value ) {
if ( value === "" ) {
elem.setAttribute( name, "auto" );
return value;
}
}
});
});
// Set contenteditable to false on removals(#10429)
// Setting to empty string throws an error as an invalid value
jQuery.attrHooks.contenteditable = {
get: nodeHook.get,
set: function( elem, value, name ) {
if ( value === "" ) {
value = "false";
}
nodeHook.set( elem, value, name );
}
};
}
// Some attributes require a special call on IE
if ( !jQuery.support.hrefNormalized ) {
jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
get: function( elem ) {
var ret = elem.getAttribute( name, 2 );
return ret === null ? undefined : ret;
}
});
});
}
if ( !jQuery.support.style ) {
jQuery.attrHooks.style = {
get: function( elem ) {
// Return undefined in the case of empty string
// Normalize to lowercase since IE uppercases css property names
return elem.style.cssText.toLowerCase() || undefined;
},
set: function( elem, value ) {
return ( elem.style.cssText = "" + value );
}
};
}
// Safari mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
if ( !jQuery.support.optSelected ) {
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
get: function( elem ) {
var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex;
// Make sure that it also works with optgroups, see #5701
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
return null;
}
});
}
// IE6/7 call enctype encoding
if ( !jQuery.support.enctype ) {
jQuery.propFix.enctype = "encoding";
}
// Radios and checkboxes getter/setter
if ( !jQuery.support.checkOn ) {
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = {
get: function( elem ) {
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
return elem.getAttribute("value") === null ? "on" : elem.value;
}
};
});
}
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
set: function( elem, value ) {
if ( jQuery.isArray( value ) ) {
return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
}
}
});
});
var rformElems = /^(?:textarea|input|select)$/i,
rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|contextmenu)|click/,
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
hoverHack = function( events ) {
return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
};
/*
* Helper functions for managing events -- not part of the public interface.
* Props to Dean Edwards' addEvent library for many of the ideas.
*/
jQuery.event = {
add: function( elem, types, handler, data, selector ) {
var elemData, eventHandle, events,
t, tns, type, namespaces, handleObj,
handleObjIn, handlers, special;
// Don't attach events to noData or text/comment nodes (allow plain objects tho)
if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
return;
}
// Caller can pass in an object of custom data in lieu of the handler
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
selector = handleObjIn.selector;
}
// Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
// Init the element's event structure and main handler, if this is the first
events = elemData.events;
if ( !events ) {
elemData.events = events = {};
}
eventHandle = elemData.handle;
if ( !eventHandle ) {
elemData.handle = eventHandle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
eventHandle.elem = elem;
}
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
types = jQuery.trim( hoverHack(types) ).split( " " );
for ( t = 0; t < types.length; t++ ) {
tns = rtypenamespace.exec( types[t] ) || [];
type = tns[1];
namespaces = ( tns[2] || "" ).split( "." ).sort();
// If event changes its type, use the special event handlers for the changed type
special = jQuery.event.special[ type ] || {};
// If selector defined, determine special event api type, otherwise given type
type = ( selector ? special.delegateType : special.bindType ) || type;
// Update special based on newly reset type
special = jQuery.event.special[ type ] || {};
// handleObj is passed to all event handlers
handleObj = jQuery.extend({
type: type,
origType: tns[1],
data: data,
handler: handler,
guid: handler.guid,
selector: selector,
namespace: namespaces.join(".")
}, handleObjIn );
// Init the event handler queue if we're the first
handlers = events[ type ];
if ( !handlers ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;
// Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}
if ( special.add ) {
special.add.call( elem, handleObj );
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}
// Add to the element's handler list, delegates in front
if ( selector ) {
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
// Keep track of which events have ever been used, for event optimization
jQuery.event.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
elem = null;
},
global: {},
// Detach an event or set of events from an element
remove: function( elem, types, handler, selector, mappedTypes ) {
var t, tns, type, origType, namespaces, origCount,
j, events, special, eventType, handleObj,
elemData = jQuery.hasData( elem ) && jQuery._data( elem );
if ( !elemData || !(events = elemData.events) ) {
return;
}
// Once for each type.namespace in types; type may be omitted
types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
for ( t = 0; t < types.length; t++ ) {
tns = rtypenamespace.exec( types[t] ) || [];
type = origType = tns[1];
namespaces = tns[2];
// Unbind all events (on this namespace, if provided) for the element
if ( !type ) {
for ( type in events ) {
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
}
continue;
}
special = jQuery.event.special[ type ] || {};
type = ( selector? special.delegateType : special.bindType ) || type;
eventType = events[ type ] || [];
origCount = eventType.length;
namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
// Remove matching events
for ( j = 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( ( mappedTypes || origType === handleObj.origType ) &&
( !handler || handler.guid === handleObj.guid ) &&
( !namespaces || namespaces.test( handleObj.namespace ) ) &&
( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
eventType.splice( j--, 1 );
if ( handleObj.selector ) {
eventType.delegateCount--;
}
if ( special.remove ) {
special.remove.call( elem, handleObj );
}
}
}
// Remove generic event handler if we removed something and no more handlers exist
// (avoids potential for endless recursion during removal of special event handlers)
if ( eventType.length === 0 && origCount !== eventType.length ) {
if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
delete events[ type ];
}
}
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
delete elemData.handle;
// removeData also checks for emptiness and clears the expando if empty
// so use it instead of delete
jQuery.removeData( elem, "events", true );
}
},
// Events that are safe to short-circuit if no handlers are attached.
// Native DOM events should not be added, they may have inline handlers.
customEvent: {
"getData": true,
"setData": true,
"changeData": true
},
trigger: function( event, data, elem, onlyHandlers ) {
// Don't do events on text and comment nodes
if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
return;
}
// Event object or event type
var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
type = event.type || event,
namespaces = [];
// focus/blur morphs to focusin/out; ensure we're not firing them right now
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
return;
}
if ( type.indexOf( "!" ) >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces)
type = type.slice(0, -1);
exclusive = true;
}
if ( type.indexOf( "." ) >= 0 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split(".");
type = namespaces.shift();
namespaces.sort();
}
if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
// No jQuery handlers for this event type, and it can't have inline handlers
return;
}
// Caller can pass in an Event, Object, or just an event type string
event = typeof event === "object" ?
// jQuery.Event object
event[ jQuery.expando ] ? event :
// Object literal
new jQuery.Event( type, event ) :
// Just the event type (string)
new jQuery.Event( type );
event.type = type;
event.isTrigger = true;
event.exclusive = exclusive;
event.namespace = namespaces.join( "." );
event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
// Handle a global trigger
if ( !elem ) {
// TODO: Stop taunting the data cache; remove global events and always attach to document
cache = jQuery.cache;
for ( i in cache ) {
if ( cache[ i ].events && cache[ i ].events[ type ] ) {
jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
}
}
return;
}
// Clean up the event in case it is being reused
event.result = undefined;
if ( !event.target ) {
event.target = elem;
}
// Clone any incoming data and prepend the event, creating the handler arg list
data = data != null ? jQuery.makeArray( data ) : [];
data.unshift( event );
// Allow special events to draw outside the lines
special = jQuery.event.special[ type ] || {};
if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
return;
}
// Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
eventPath = [[ elem, special.bindType || type ]];
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
bubbleType = special.delegateType || type;
cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
for ( old = elem; cur; cur = cur.parentNode ) {
eventPath.push([ cur, bubbleType ]);
old = cur;
}
// Only add window if we got to document (e.g., not plain obj or detached DOM)
if ( old === (elem.ownerDocument || document) ) {
eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
}
}
// Fire handlers on the event path
for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
cur = eventPath[i][0];
event.type = eventPath[i][1];
handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
// Note that this is a bare JS function and not a jQuery handler
handle = ontype && cur[ ontype ];
if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
event.preventDefault();
}
}
event.type = type;
// If nobody prevented the default action, do it now
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
// Can't use an .isFunction() check here because IE6/7 fails that test.
// Don't do default actions on window, that's where global variables be (#6170)
// IE<9 dies on focus/blur to hidden element (#1486)
if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
// Don't re-trigger an onFOO event when we call its FOO() method
old = elem[ ontype ];
if ( old ) {
elem[ ontype ] = null;
}
// Prevent re-triggering of the same event, since we already bubbled it above
jQuery.event.triggered = type;
elem[ type ]();
jQuery.event.triggered = undefined;
if ( old ) {
elem[ ontype ] = old;
}
}
}
}
return event.result;
},
dispatch: function( event ) {
// Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event || window.event );
var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related,
handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
delegateCount = handlers.delegateCount,
args = [].slice.call( arguments ),
run_all = !event.exclusive && !event.namespace,
special = jQuery.event.special[ event.type ] || {},
handlerQueue = [];
// Use the fix-ed jQuery.Event rather than the (read-only) native event
args[0] = event;
event.delegateTarget = this;
// Call the preDispatch hook for the mapped type, and let it bail if desired
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
return;
}
// Determine handlers that should run if there are delegated events
// Avoid non-left-click bubbling in Firefox (#3861)
if ( delegateCount && !(event.button && event.type === "click") ) {
// Pregenerate a single jQuery object for reuse with .is()
jqcur = jQuery(this);
jqcur.context = this;
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx)
if ( cur.disabled !== true || event.type !== "click" ) {
selMatch = {};
matches = [];
jqcur[0] = cur;
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
sel = handleObj.selector;
if ( selMatch[ sel ] === undefined ) {
selMatch[ sel ] = jqcur.is( sel );
}
if ( selMatch[ sel ] ) {
matches.push( handleObj );
}
}
if ( matches.length ) {
handlerQueue.push({ elem: cur, matches: matches });
}
}
}
}
// Add the remaining (directly-bound) handlers
if ( handlers.length > delegateCount ) {
handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
}
// Run delegates first; they may want to stop propagation beneath us
for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
matched = handlerQueue[ i ];
event.currentTarget = matched.elem;
for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
handleObj = matched.matches[ j ];
// Triggered event must either 1) be non-exclusive and have no namespace, or
// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
event.data = handleObj.data;
event.handleObj = handleObj;
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
.apply( matched.elem, args );
if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}
// Call the postDispatch hook for the mapped type
if ( special.postDispatch ) {
special.postDispatch.call( this, event );
}
return event.result;
},
// Includes some event props shared by KeyEvent and MouseEvent
// *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
fixHooks: {},
keyHooks: {
props: "char charCode key keyCode".split(" "),
filter: function( event, original ) {
// Add which for key events
if ( event.which == null ) {
event.which = original.charCode != null ? original.charCode : original.keyCode;
}
return event;
}
},
mouseHooks: {
props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
filter: function( event, original ) {
var eventDoc, doc, body,
button = original.button,
fromElement = original.fromElement;
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && original.clientX != null ) {
eventDoc = event.target.ownerDocument || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
}
// Add relatedTarget, if necessary
if ( !event.relatedTarget && fromElement ) {
event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
}
// Add which for click: 1 === left; 2 === middle; 3 === right
// Note: button is not normalized, so don't use it
if ( !event.which && button !== undefined ) {
event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
}
return event;
}
},
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
// Create a writable copy of the event object and normalize some properties
var i, prop,
originalEvent = event,
fixHook = jQuery.event.fixHooks[ event.type ] || {},
copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
event = jQuery.Event( originalEvent );
for ( i = copy.length; i; ) {
prop = copy[ --i ];
event[ prop ] = originalEvent[ prop ];
}
// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
if ( !event.target ) {
event.target = originalEvent.srcElement || document;
}
// Target should not be a text node (#504, Safari)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
// For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
event.metaKey = !!event.metaKey;
return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
},
special: {
ready: {
// Make sure the ready event is setup
setup: jQuery.bindReady
},
load: {
// Prevent triggered image.load events from bubbling to window.load
noBubble: true
},
focus: {
delegateType: "focusin"
},
blur: {
delegateType: "focusout"
},
beforeunload: {
setup: function( data, namespaces, eventHandle ) {
// We only want to do this special case on windows
if ( jQuery.isWindow( this ) ) {
this.onbeforeunload = eventHandle;
}
},
teardown: function( namespaces, eventHandle ) {
if ( this.onbeforeunload === eventHandle ) {
this.onbeforeunload = null;
}
}
}
},
simulate: function( type, elem, event, bubble ) {
// Piggyback on a donor event to simulate a different one.
// Fake originalEvent to avoid donor's stopPropagation, but if the
// simulated event prevents default then we do the same on the donor.
var e = jQuery.extend(
new jQuery.Event(),
event,
{ type: type,
isSimulated: true,
originalEvent: {}
}
);
if ( bubble ) {
jQuery.event.trigger( e, null, elem );
} else {
jQuery.event.dispatch.call( elem, e );
}
if ( e.isDefaultPrevented() ) {
event.preventDefault();
}
}
};
// Some plugins are using, but it's undocumented/deprecated and will be removed.
// The 1.7 special event interface should provide all the hooks needed now.
jQuery.event.handle = jQuery.event.dispatch;
jQuery.removeEvent = document.removeEventListener ?
function( elem, type, handle ) {
if ( elem.removeEventListener ) {
elem.removeEventListener( type, handle, false );
}
} :
function( elem, type, handle ) {
var name = "on" + type;
if ( elem.detachEvent ) {
// #8545, #7054, preventing memory leaks for custom events in IE6-8
// detachEvent needed property on element, by name of that event, to properly expose it to GC
if ( typeof elem[ name ] === "undefined" ) {
elem[ name ] = null;
}
elem.detachEvent( name, handle );
}
};
jQuery.Event = function( src, props ) {
// Allow instantiation without the 'new' keyword
if ( !(this instanceof jQuery.Event) ) {
return new jQuery.Event( src, props );
}
// Event object
if ( src && src.type ) {
this.originalEvent = src;
this.type = src.type;
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
// Event type
} else {
this.type = src;
}
// Put explicitly provided properties onto the event object
if ( props ) {
jQuery.extend( this, props );
}
// Create a timestamp if incoming event doesn't have one
this.timeStamp = src && src.timeStamp || jQuery.now();
// Mark it as fixed
this[ jQuery.expando ] = true;
};
function returnFalse() {
return false;
}
function returnTrue() {
return true;
}
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
preventDefault: function() {
this.isDefaultPrevented = returnTrue;
var e = this.originalEvent;
if ( !e ) {
return;
}
// if preventDefault exists run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
// otherwise set the returnValue property of the original event to false (IE)
} else {
e.returnValue = false;
}
},
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
var e = this.originalEvent;
if ( !e ) {
return;
}
// if stopPropagation exists run it on the original event
if ( e.stopPropagation ) {
e.stopPropagation();
}
// otherwise set the cancelBubble property of the original event to true (IE)
e.cancelBubble = true;
},
stopImmediatePropagation: function() {
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse
};
// Create mouseenter/leave events using mouseover/out and event-time checks
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
delegateType: fix,
bindType: fix,
handle: function( event ) {
var ret,
target = this,
related = event.relatedTarget,
handleObj = event.handleObj,
selector = handleObj.selector;
// For mousenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
event.type = handleObj.origType;
ret = handleObj.handler.apply( this, arguments );
event.type = fix;
}
return ret;
}
};
});
// IE submit delegation
if ( !jQuery.support.submitBubbles ) {
jQuery.event.special.submit = {
setup: function() {
// Only need this for delegated form submit events
if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
// Lazy-add a submit handler when a descendant form may potentially be submitted
jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
// Node name check avoids a VML-related crash in IE (#9807)
var elem = e.target,
form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
if ( form && !jQuery._data( form, "_submit_attached" ) ) {
jQuery.event.add( form, "submit._submit", function( event ) {
event._submit_bubble = true;
});
jQuery._data( form, "_submit_attached", true );
}
});
// return undefined since we don't need an event listener
},
postDispatch: function( event ) {
// If form was submitted by the user, bubble the event up the tree
if ( event._submit_bubble ) {
delete event._submit_bubble;
if ( this.parentNode && !event.isTrigger ) {
jQuery.event.simulate( "submit", this.parentNode, event, true );
}
}
},
teardown: function() {
// Only need this for delegated form submit events
if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
jQuery.event.remove( this, "._submit" );
}
};
}
// IE change delegation and checkbox/radio fix
if ( !jQuery.support.changeBubbles ) {
jQuery.event.special.change = {
setup: function() {
if ( rformElems.test( this.nodeName ) ) {
// IE doesn't fire change on a check/radio until blur; trigger it on click
// after a propertychange. Eat the blur-change in special.change.handle.
// This still fires onchange a second time for check/radio after blur.
if ( this.type === "checkbox" || this.type === "radio" ) {
jQuery.event.add( this, "propertychange._change", function( event ) {
if ( event.originalEvent.propertyName === "checked" ) {
this._just_changed = true;
}
});
jQuery.event.add( this, "click._change", function( event ) {
if ( this._just_changed && !event.isTrigger ) {
this._just_changed = false;
}
// Allow triggered, simulated change events (#11500)
jQuery.event.simulate( "change", this, event, true );
});
}
return false;
}
// Delegated event; lazy-add a change handler on descendant inputs
jQuery.event.add( this, "beforeactivate._change", function( e ) {
var elem = e.target;
if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) {
jQuery.event.add( elem, "change._change", function( event ) {
if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
jQuery.event.simulate( "change", this.parentNode, event, true );
}
});
jQuery._data( elem, "_change_attached", true );
}
});
},
handle: function( event ) {
var elem = event.target;
// Swallow native change events from checkbox/radio, we already triggered them above
if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
return event.handleObj.handler.apply( this, arguments );
}
},
teardown: function() {
jQuery.event.remove( this, "._change" );
return rformElems.test( this.nodeName );
}
};
}
// Create "bubbling" focus and blur events
if ( !jQuery.support.focusinBubbles ) {
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler while someone wants focusin/focusout
var attaches = 0,
handler = function( event ) {
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
};
jQuery.event.special[ fix ] = {
setup: function() {
if ( attaches++ === 0 ) {
document.addEventListener( orig, handler, true );
}
},
teardown: function() {
if ( --attaches === 0 ) {
document.removeEventListener( orig, handler, true );
}
}
};
});
}
jQuery.fn.extend({
on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
var origFn, type;
// Types can be a map of types/handlers
if ( typeof types === "object" ) {
// ( types-Object, selector, data )
if ( typeof selector !== "string" ) { // && selector != null
// ( types-Object, data )
data = data || selector;
selector = undefined;
}
for ( type in types ) {
this.on( type, selector, data, types[ type ], one );
}
return this;
}
if ( data == null && fn == null ) {
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if ( fn == null ) {
if ( typeof selector === "string" ) {
// ( types, selector, fn )
fn = data;
data = undefined;
} else {
// ( types, data, fn )
fn = data;
data = selector;
selector = undefined;
}
}
if ( fn === false ) {
fn = returnFalse;
} else if ( !fn ) {
return this;
}
if ( one === 1 ) {
origFn = fn;
fn = function( event ) {
// Can use an empty set, since event contains the info
jQuery().off( event );
return origFn.apply( this, arguments );
};
// Use same guid so caller can remove using origFn
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
}
return this.each( function() {
jQuery.event.add( this, types, fn, data, selector );
});
},
one: function( types, selector, data, fn ) {
return this.on( types, selector, data, fn, 1 );
},
off: function( types, selector, fn ) {
var handleObj, type;
if ( types && types.preventDefault && types.handleObj ) {
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
// ( types-object [, selector] )
for ( type in types ) {
this.off( type, selector, types[ type ] );
}
return this;
}
if ( selector === false || typeof selector === "function" ) {
// ( types [, fn] )
fn = selector;
selector = undefined;
}
if ( fn === false ) {
fn = returnFalse;
}
return this.each(function() {
jQuery.event.remove( this, types, fn, selector );
});
},
bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},
live: function( types, data, fn ) {
jQuery( this.context ).on( types, this.selector, data, fn );
return this;
},
die: function( types, fn ) {
jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
},
delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
// ( namespace ) or ( selector, types [, fn] )
return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
},
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
});
},
triggerHandler: function( type, data ) {
if ( this[0] ) {
return jQuery.event.trigger( type, data, this[0], true );
}
},
toggle: function( fn ) {
// Save reference to arguments for access in closure
var args = arguments,
guid = fn.guid || jQuery.guid++,
i = 0,
toggler = function( event ) {
// Figure out which function to execute
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
// and execute the function
return args[ lastToggle ].apply( this, arguments ) || false;
};
// link all the functions, so any of them can unbind this click handler
toggler.guid = guid;
while ( i < args.length ) {
args[ i++ ].guid = guid;
}
return this.click( toggler );
},
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}
});
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
if ( fn == null ) {
fn = data;
data = null;
}
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
if ( rkeyEvent.test( name ) ) {
jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
}
if ( rmouseEvent.test( name ) ) {
jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
}
});
/*!
* Sizzle CSS Selector Engine
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license
* http://sizzlejs.com/
*/
(function( window, undefined ) {
var cachedruns,
dirruns,
sortOrder,
siblingCheck,
assertGetIdNotName,
document = window.document,
docElem = document.documentElement,
strundefined = "undefined",
hasDuplicate = false,
baseHasDuplicate = true,
done = 0,
slice = [].slice,
push = [].push,
expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
// Regex
// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
whitespace = "[\\x20\\t\\r\\n\\f]",
// http://www.w3.org/TR/css3-syntax/#characters
characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
// Loosely modeled on CSS identifier characters
// An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
identifier = characterEncoding.replace( "w", "w#" ),
// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
operators = "([*^$|!~]?=)",
attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
"*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",
pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",
combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*",
groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+",
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
rcombinators = new RegExp( "^" + combinators ),
// All simple (non-comma) selectors, excluding insignifant trailing whitespace
rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ),
// A selector, or everything after leading whitespace
// Optionally followed in either case by a ")" for terminating sub-selectors
rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ),
// All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive
rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ),
// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
rsibling = /[\x20\t\r\n\f]*[+~]/,
rendsWithNot = /:not\($/,
rheader = /h\d/i,
rinputs = /input|select|textarea|button/i,
rbackslash = /\\(?!\\)/g,
matchExpr = {
"ID": new RegExp( "^#(" + characterEncoding + ")" ),
"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
"NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
"TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ),
"ATTR": new RegExp( "^" + attributes ),
"PSEUDO": new RegExp( "^" + pseudos ),
"CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace +
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
"POS": new RegExp( pos, "ig" ),
// For use in libraries implementing .is()
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
},
classCache = {},
cachedClasses = [],
compilerCache = {},
cachedSelectors = [],
// Mark a function for use in filtering
markFunction = function( fn ) {
fn.sizzleFilter = true;
return fn;
},
// Returns a function to use in pseudos for input types
createInputFunction = function( type ) {
return function( elem ) {
// Check the input's nodeName and type
return elem.nodeName.toLowerCase() === "input" && elem.type === type;
};
},
// Returns a function to use in pseudos for buttons
createButtonFunction = function( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase();
return (name === "input" || name === "button") && elem.type === type;
};
},
// Used for testing something on an element
assert = function( fn ) {
var pass = false,
div = document.createElement("div");
try {
pass = fn( div );
} catch (e) {}
// release memory in IE
div = null;
return pass;
},
// Check if attributes should be retrieved by attribute nodes
assertAttributes = assert(function( div ) {
div.innerHTML = "<select></select>";
var type = typeof div.lastChild.getAttribute("multiple");
// IE8 returns a string for some attributes even when not present
return type !== "boolean" && type !== "string";
}),
// Check if getElementById returns elements by name
// Check if getElementsByName privileges form controls or returns elements by ID
assertUsableName = assert(function( div ) {
// Inject content
div.id = expando + 0;
div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
docElem.insertBefore( div, docElem.firstChild );
// Test
var pass = document.getElementsByName &&
// buggy browsers will return fewer than the correct 2
document.getElementsByName( expando ).length ===
// buggy browsers will return more than the correct 0
2 + document.getElementsByName( expando + 0 ).length;
assertGetIdNotName = !document.getElementById( expando );
// Cleanup
docElem.removeChild( div );
return pass;
}),
// Check if the browser returns only elements
// when doing getElementsByTagName("*")
assertTagNameNoComments = assert(function( div ) {
div.appendChild( document.createComment("") );
return div.getElementsByTagName("*").length === 0;
}),
// Check if getAttribute returns normalized href attributes
assertHrefNotNormalized = assert(function( div ) {
div.innerHTML = "<a href='#'></a>";
return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
div.firstChild.getAttribute("href") === "#";
}),
// Check if getElementsByClassName can be trusted
assertUsableClassName = assert(function( div ) {
// Opera can't find a second classname (in 9.6)
div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
return false;
}
// Safari caches class attributes, doesn't catch changes (in 3.2)
div.lastChild.className = "e";
return div.getElementsByClassName("e").length !== 1;
});
var Sizzle = function( selector, context, results, seed ) {
results = results || [];
context = context || document;
var match, elem, xml, m,
nodeType = context.nodeType;
if ( nodeType !== 1 && nodeType !== 9 ) {
return [];
}
if ( !selector || typeof selector !== "string" ) {
return results;
}
xml = isXML( context );
if ( !xml && !seed ) {
if ( (match = rquickExpr.exec( selector )) ) {
// Speed-up: Sizzle("#ID")
if ( (m = match[1]) ) {
if ( nodeType === 9 ) {
elem = context.getElementById( m );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE, Opera, and Webkit return items
// by name instead of ID
if ( elem.id === m ) {
results.push( elem );
return results;
}
} else {
return results;
}
} else {
// Context is not a document
if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
contains( context, elem ) && elem.id === m ) {
results.push( elem );
return results;
}
}
// Speed-up: Sizzle("TAG")
} else if ( match[2] ) {
push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
return results;
// Speed-up: Sizzle(".CLASS")
} else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
return results;
}
}
}
// All others
return select( selector, context, results, seed, xml );
};
var Expr = Sizzle.selectors = {
// Can be adjusted by the user
cacheLength: 50,
match: matchExpr,
order: [ "ID", "TAG" ],
attrHandle: {},
createPseudo: markFunction,
find: {
"ID": assertGetIdNotName ?
function( id, context, xml ) {
if ( typeof context.getElementById !== strundefined && !xml ) {
var m = context.getElementById( id );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
return m && m.parentNode ? [m] : [];
}
} :
function( id, context, xml ) {
if ( typeof context.getElementById !== strundefined && !xml ) {
var m = context.getElementById( id );
return m ?
m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
[m] :
undefined :
[];
}
},
"TAG": assertTagNameNoComments ?
function( tag, context ) {
if ( typeof context.getElementsByTagName !== strundefined ) {
return context.getElementsByTagName( tag );
}
} :
function( tag, context ) {
var results = context.getElementsByTagName( tag );
// Filter out possible comments
if ( tag === "*" ) {
var elem,
tmp = [],
i = 0;
for ( ; (elem = results[i]); i++ ) {
if ( elem.nodeType === 1 ) {
tmp.push( elem );
}
}
return tmp;
}
return results;
}
},
relative: {
">": { dir: "parentNode", first: true },
" ": { dir: "parentNode" },
"+": { dir: "previousSibling", first: true },
"~": { dir: "previousSibling" }
},
preFilter: {
"ATTR": function( match ) {
match[1] = match[1].replace( rbackslash, "" );
// Move the given value to match[3] whether quoted or unquoted
match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
if ( match[2] === "~=" ) {
match[3] = " " + match[3] + " ";
}
return match.slice( 0, 4 );
},
"CHILD": function( match ) {
/* matches from matchExpr.CHILD
1 type (only|nth|...)
2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
3 xn-component of xn+y argument ([+-]?\d*n|)
4 sign of xn-component
5 x of xn-component
6 sign of y-component
7 y of y-component
*/
match[1] = match[1].toLowerCase();
if ( match[1] === "nth" ) {
// nth-child requires argument
if ( !match[2] ) {
Sizzle.error( match[0] );
}
// numeric x and y parameters for Expr.filter.CHILD
// remember that false/true cast respectively to 0/1
match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
// other types prohibit arguments
} else if ( match[2] ) {
Sizzle.error( match[0] );
}
return match;
},
"PSEUDO": function( match ) {
var argument,
unquoted = match[4];
if ( matchExpr["CHILD"].test( match[0] ) ) {
return null;
}
// Relinquish our claim on characters in `unquoted` from a closing parenthesis on
if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) {
match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 );
unquoted = argument[0].slice( 0, -1 );
}
// Quoted or unquoted, we have the full argument
// Return only captures needed by the pseudo filter method (type and argument)
match.splice( 2, 3, unquoted || match[3] );
return match;
}
},
filter: {
"ID": assertGetIdNotName ?
function( id ) {
id = id.replace( rbackslash, "" );
return function( elem ) {
return elem.getAttribute("id") === id;
};
} :
function( id ) {
id = id.replace( rbackslash, "" );
return function( elem ) {
var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
return node && node.value === id;
};
},
"TAG": function( nodeName ) {
if ( nodeName === "*" ) {
return function() { return true; };
}
nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
return function( elem ) {
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
};
},
"CLASS": function( className ) {
var pattern = classCache[ className ];
if ( !pattern ) {
pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" );
cachedClasses.push( className );
// Avoid too large of a cache
if ( cachedClasses.length > Expr.cacheLength ) {
delete classCache[ cachedClasses.shift() ];
}
}
return function( elem ) {
return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
};
},
"ATTR": function( name, operator, check ) {
if ( !operator ) {
return function( elem ) {
return Sizzle.attr( elem, name ) != null;
};
}
return function( elem ) {
var result = Sizzle.attr( elem, name ),
value = result + "";
if ( result == null ) {
return operator === "!=";
}
switch ( operator ) {
case "=":
return value === check;
case "!=":
return value !== check;
case "^=":
return check && value.indexOf( check ) === 0;
case "*=":
return check && value.indexOf( check ) > -1;
case "$=":
return check && value.substr( value.length - check.length ) === check;
case "~=":
return ( " " + value + " " ).indexOf( check ) > -1;
case "|=":
return value === check || value.substr( 0, check.length + 1 ) === check + "-";
}
};
},
"CHILD": function( type, argument, first, last ) {
if ( type === "nth" ) {
var doneName = done++;
return function( elem ) {
var parent, diff,
count = 0,
node = elem;
if ( first === 1 && last === 0 ) {
return true;
}
parent = elem.parentNode;
if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) {
for ( node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType === 1 ) {
node.sizset = ++count;
if ( node === elem ) {
break;
}
}
}
parent[ expando ] = doneName;
}
diff = elem.sizset - last;
if ( first === 0 ) {
return diff === 0;
} else {
return ( diff % first === 0 && diff / first >= 0 );
}
};
}
return function( elem ) {
var node = elem;
switch ( type ) {
case "only":
case "first":
while ( (node = node.previousSibling) ) {
if ( node.nodeType === 1 ) {
return false;
}
}
if ( type === "first" ) {
return true;
}
node = elem;
/* falls through */
case "last":
while ( (node = node.nextSibling) ) {
if ( node.nodeType === 1 ) {
return false;
}
}
return true;
}
};
},
"PSEUDO": function( pseudo, argument, context, xml ) {
// pseudo-class names are case-insensitive
// http://www.w3.org/TR/selectors/#pseudo-classes
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ];
if ( !fn ) {
Sizzle.error( "unsupported pseudo: " + pseudo );
}
// The user may set fn.sizzleFilter to indicate
// that arguments are needed to create the filter function
// just as Sizzle does
if ( !fn.sizzleFilter ) {
return fn;
}
return fn( argument, context, xml );
}
},
pseudos: {
"not": markFunction(function( selector, context, xml ) {
// Trim the selector passed to compile
// to avoid treating leading and trailing
// spaces as combinators
var matcher = compile( selector.replace( rtrim, "$1" ), context, xml );
return function( elem ) {
return !matcher( elem );
};
}),
"enabled": function( elem ) {
return elem.disabled === false;
},
"disabled": function( elem ) {
return elem.disabled === true;
},
"checked": function( elem ) {
// In CSS3, :checked should return both checked and selected elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
var nodeName = elem.nodeName.toLowerCase();
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
},
"selected": function( elem ) {
// Accessing this property makes selected-by-default
// options in Safari work properly
if ( elem.parentNode ) {
elem.parentNode.selectedIndex;
}
return elem.selected === true;
},
"parent": function( elem ) {
return !Expr.pseudos["empty"]( elem );
},
"empty": function( elem ) {
// http://www.w3.org/TR/selectors/#empty-pseudo
// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
// not comment, processing instructions, or others
// Thanks to Diego Perini for the nodeName shortcut
// Greater than "@" means alpha characters (specifically not starting with "#" or "?")
var nodeType;
elem = elem.firstChild;
while ( elem ) {
if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
return false;
}
elem = elem.nextSibling;
}
return true;
},
"contains": markFunction(function( text ) {
return function( elem ) {
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
};
}),
"has": markFunction(function( selector ) {
return function( elem ) {
return Sizzle( selector, elem ).length > 0;
};
}),
"header": function( elem ) {
return rheader.test( elem.nodeName );
},
"text": function( elem ) {
var type, attr;
// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
// use getAttribute instead to test this case
return elem.nodeName.toLowerCase() === "input" &&
(type = elem.type) === "text" &&
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
},
// Input types
"radio": createInputFunction("radio"),
"checkbox": createInputFunction("checkbox"),
"file": createInputFunction("file"),
"password": createInputFunction("password"),
"image": createInputFunction("image"),
"submit": createButtonFunction("submit"),
"reset": createButtonFunction("reset"),
"button": function( elem ) {
var name = elem.nodeName.toLowerCase();
return name === "input" && elem.type === "button" || name === "button";
},
"input": function( elem ) {
return rinputs.test( elem.nodeName );
},
"focus": function( elem ) {
var doc = elem.ownerDocument;
return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href);
},
"active": function( elem ) {
return elem === elem.ownerDocument.activeElement;
}
},
setFilters: {
"first": function( elements, argument, not ) {
return not ? elements.slice( 1 ) : [ elements[0] ];
},
"last": function( elements, argument, not ) {
var elem = elements.pop();
return not ? elements : [ elem ];
},
"even": function( elements, argument, not ) {
var results = [],
i = not ? 1 : 0,
len = elements.length;
for ( ; i < len; i = i + 2 ) {
results.push( elements[i] );
}
return results;
},
"odd": function( elements, argument, not ) {
var results = [],
i = not ? 0 : 1,
len = elements.length;
for ( ; i < len; i = i + 2 ) {
results.push( elements[i] );
}
return results;
},
"lt": function( elements, argument, not ) {
return not ? elements.slice( +argument ) : elements.slice( 0, +argument );
},
"gt": function( elements, argument, not ) {
return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 );
},
"eq": function( elements, argument, not ) {
var elem = elements.splice( +argument, 1 );
return not ? elements : elem;
}
}
};
// Deprecated
Expr.setFilters["nth"] = Expr.setFilters["eq"];
// Back-compat
Expr.filters = Expr.pseudos;
// IE6/7 return a modified href
if ( !assertHrefNotNormalized ) {
Expr.attrHandle = {
"href": function( elem ) {
return elem.getAttribute( "href", 2 );
},
"type": function( elem ) {
return elem.getAttribute("type");
}
};
}
// Add getElementsByName if usable
if ( assertUsableName ) {
Expr.order.push("NAME");
Expr.find["NAME"] = function( name, context ) {
if ( typeof context.getElementsByName !== strundefined ) {
return context.getElementsByName( name );
}
};
}
// Add getElementsByClassName if usable
if ( assertUsableClassName ) {
Expr.order.splice( 1, 0, "CLASS" );
Expr.find["CLASS"] = function( className, context, xml ) {
if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
return context.getElementsByClassName( className );
}
};
}
// If slice is not available, provide a backup
try {
slice.call( docElem.childNodes, 0 )[0].nodeType;
} catch ( e ) {
slice = function( i ) {
var elem, results = [];
for ( ; (elem = this[i]); i++ ) {
results.push( elem );
}
return results;
};
}
var isXML = Sizzle.isXML = function( elem ) {
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
// Element contains another
var contains = Sizzle.contains = docElem.compareDocumentPosition ?
function( a, b ) {
return !!( a.compareDocumentPosition( b ) & 16 );
} :
docElem.contains ?
function( a, b ) {
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b.parentNode;
return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
} :
function( a, b ) {
while ( (b = b.parentNode) ) {
if ( b === a ) {
return true;
}
}
return false;
};
/**
* Utility function for retrieving the text value of an array of DOM nodes
* @param {Array|Element} elem
*/
var getText = Sizzle.getText = function( elem ) {
var node,
ret = "",
i = 0,
nodeType = elem.nodeType;
if ( nodeType ) {
if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
// Use textContent for elements
// innerText usage removed for consistency of new lines (see #11153)
if ( typeof elem.textContent === "string" ) {
return elem.textContent;
} else {
// Traverse its children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
ret += getText( elem );
}
}
} else if ( nodeType === 3 || nodeType === 4 ) {
return elem.nodeValue;
}
// Do not include comment or processing instruction nodes
} else {
// If no nodeType, this is expected to be an array
for ( ; (node = elem[i]); i++ ) {
// Do not traverse comment nodes
ret += getText( node );
}
}
return ret;
};
Sizzle.attr = function( elem, name ) {
var attr,
xml = isXML( elem );
if ( !xml ) {
name = name.toLowerCase();
}
if ( Expr.attrHandle[ name ] ) {
return Expr.attrHandle[ name ]( elem );
}
if ( assertAttributes || xml ) {
return elem.getAttribute( name );
}
attr = elem.getAttributeNode( name );
return attr ?
typeof elem[ name ] === "boolean" ?
elem[ name ] ? name : null :
attr.specified ? attr.value : null :
null;
};
Sizzle.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
// Check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
// Thus far that includes Google Chrome.
[0, 0].sort(function() {
return (baseHasDuplicate = 0);
});
if ( docElem.compareDocumentPosition ) {
sortOrder = function( a, b ) {
if ( a === b ) {
hasDuplicate = true;
return 0;
}
return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
a.compareDocumentPosition :
a.compareDocumentPosition(b) & 4
) ? -1 : 1;
};
} else {
sortOrder = function( a, b ) {
// The nodes are identical, we can exit early
if ( a === b ) {
hasDuplicate = true;
return 0;
// Fallback to using sourceIndex (in IE) if it's available on both nodes
} else if ( a.sourceIndex && b.sourceIndex ) {
return a.sourceIndex - b.sourceIndex;
}
var al, bl,
ap = [],
bp = [],
aup = a.parentNode,
bup = b.parentNode,
cur = aup;
// If the nodes are siblings (or identical) we can do a quick check
if ( aup === bup ) {
return siblingCheck( a, b );
// If no parents were found then the nodes are disconnected
} else if ( !aup ) {
return -1;
} else if ( !bup ) {
return 1;
}
// Otherwise they're somewhere else in the tree so we need
// to build up a full list of the parentNodes for comparison
while ( cur ) {
ap.unshift( cur );
cur = cur.parentNode;
}
cur = bup;
while ( cur ) {
bp.unshift( cur );
cur = cur.parentNode;
}
al = ap.length;
bl = bp.length;
// Start walking down the tree looking for a discrepancy
for ( var i = 0; i < al && i < bl; i++ ) {
if ( ap[i] !== bp[i] ) {
return siblingCheck( ap[i], bp[i] );
}
}
// We ended someplace up the tree so do a sibling check
return i === al ?
siblingCheck( a, bp[i], -1 ) :
siblingCheck( ap[i], b, 1 );
};
siblingCheck = function( a, b, ret ) {
if ( a === b ) {
return ret;
}
var cur = a.nextSibling;
while ( cur ) {
if ( cur === b ) {
return -1;
}
cur = cur.nextSibling;
}
return 1;
};
}
// Document sorting and removing duplicates
Sizzle.uniqueSort = function( results ) {
var elem,
i = 1;
if ( sortOrder ) {
hasDuplicate = baseHasDuplicate;
results.sort( sortOrder );
if ( hasDuplicate ) {
for ( ; (elem = results[i]); i++ ) {
if ( elem === results[ i - 1 ] ) {
results.splice( i--, 1 );
}
}
}
}
return results;
};
function multipleContexts( selector, contexts, results, seed ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
Sizzle( selector, contexts[i], results, seed );
}
}
function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) {
var results,
fn = Expr.setFilters[ posfilter.toLowerCase() ];
if ( !fn ) {
Sizzle.error( posfilter );
}
if ( selector || !(results = seed) ) {
multipleContexts( selector || "*", contexts, (results = []), seed );
}
return results.length > 0 ? fn( results, argument, not ) : [];
}
function handlePOS( selector, context, results, seed, groups ) {
var match, not, anchor, ret, elements, currentContexts, part, lastIndex,
i = 0,
len = groups.length,
rpos = matchExpr["POS"],
// This is generated here in case matchExpr["POS"] is extended
rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ),
// This is for making sure non-participating
// matching groups are represented cross-browser (IE6-8)
setUndefined = function() {
var i = 1,
len = arguments.length - 2;
for ( ; i < len; i++ ) {
if ( arguments[i] === undefined ) {
match[i] = undefined;
}
}
};
for ( ; i < len; i++ ) {
// Reset regex index to 0
rpos.exec("");
selector = groups[i];
ret = [];
anchor = 0;
elements = seed;
while ( (match = rpos.exec( selector )) ) {
lastIndex = rpos.lastIndex = match.index + match[0].length;
if ( lastIndex > anchor ) {
part = selector.slice( anchor, match.index );
anchor = lastIndex;
currentContexts = [ context ];
if ( rcombinators.test(part) ) {
if ( elements ) {
currentContexts = elements;
}
elements = seed;
}
if ( (not = rendsWithNot.test( part )) ) {
part = part.slice( 0, -5 ).replace( rcombinators, "$&*" );
}
if ( match.length > 1 ) {
match[0].replace( rposgroups, setUndefined );
}
elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not );
}
}
if ( elements ) {
ret = ret.concat( elements );
if ( (part = selector.slice( anchor )) && part !== ")" ) {
if ( rcombinators.test(part) ) {
multipleContexts( part, ret, results, seed );
} else {
Sizzle( part, context, results, seed ? seed.concat(elements) : elements );
}
} else {
push.apply( results, ret );
}
} else {
Sizzle( selector, context, results, seed );
}
}
// Do not sort if this is a single filter
return len === 1 ? results : Sizzle.uniqueSort( results );
}
function tokenize( selector, context, xml ) {
var tokens, soFar, type,
groups = [],
i = 0,
// Catch obvious selector issues: terminal ")"; nonempty fallback match
// rselector never fails to match *something*
match = rselector.exec( selector ),
matched = !match.pop() && !match.pop(),
selectorGroups = matched && selector.match( rgroups ) || [""],
preFilters = Expr.preFilter,
filters = Expr.filter,
checkContext = !xml && context !== document;
for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) {
groups.push( tokens = [] );
// Need to make sure we're within a narrower context if necessary
// Adding a descendant combinator will generate what is needed
if ( checkContext ) {
soFar = " " + soFar;
}
while ( soFar ) {
matched = false;
// Combinators
if ( (match = rcombinators.exec( soFar )) ) {
soFar = soFar.slice( match[0].length );
// Cast descendant combinators to space
matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match });
}
// Filters
for ( type in filters ) {
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
(match = preFilters[ type ]( match, context, xml )) ) ) {
soFar = soFar.slice( match.shift().length );
matched = tokens.push({ part: type, captures: match });
}
}
if ( !matched ) {
break;
}
}
}
if ( !matched ) {
Sizzle.error( selector );
}
return groups;
}
function addCombinator( matcher, combinator, context ) {
var dir = combinator.dir,
doneName = done++;
if ( !matcher ) {
// If there is no matcher to check, check against the context
matcher = function( elem ) {
return elem === context;
};
}
return combinator.first ?
function( elem, context ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 ) {
return matcher( elem, context ) && elem;
}
}
} :
function( elem, context ) {
var cache,
dirkey = doneName + "." + dirruns,
cachedkey = dirkey + "." + cachedruns;
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 ) {
if ( (cache = elem[ expando ]) === cachedkey ) {
return elem.sizset;
} else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
if ( elem.sizset ) {
return elem;
}
} else {
elem[ expando ] = cachedkey;
if ( matcher( elem, context ) ) {
elem.sizset = true;
return elem;
}
elem.sizset = false;
}
}
}
};
}
function addMatcher( higher, deeper ) {
return higher ?
function( elem, context ) {
var result = deeper( elem, context );
return result && higher( result === true ? elem : result, context );
} :
deeper;
}
// ["TAG", ">", "ID", " ", "CLASS"]
function matcherFromTokens( tokens, context, xml ) {
var token, matcher,
i = 0;
for ( ; (token = tokens[i]); i++ ) {
if ( Expr.relative[ token.part ] ) {
matcher = addCombinator( matcher, Expr.relative[ token.part ], context );
} else {
token.captures.push( context, xml );
matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) );
}
}
return matcher;
}
function matcherFromGroupMatchers( matchers ) {
return function( elem, context ) {
var matcher,
j = 0;
for ( ; (matcher = matchers[j]); j++ ) {
if ( matcher(elem, context) ) {
return true;
}
}
return false;
};
}
var compile = Sizzle.compile = function( selector, context, xml ) {
var tokens, group, i,
cached = compilerCache[ selector ];
// Return a cached group function if already generated (context dependent)
if ( cached && cached.context === context ) {
return cached;
}
// Generate a function of recursive functions that can be used to check each element
group = tokenize( selector, context, xml );
for ( i = 0; (tokens = group[i]); i++ ) {
group[i] = matcherFromTokens( tokens, context, xml );
}
// Cache the compiled function
cached = compilerCache[ selector ] = matcherFromGroupMatchers( group );
cached.context = context;
cached.runs = cached.dirruns = 0;
cachedSelectors.push( selector );
// Ensure only the most recent are cached
if ( cachedSelectors.length > Expr.cacheLength ) {
delete compilerCache[ cachedSelectors.shift() ];
}
return cached;
};
Sizzle.matches = function( expr, elements ) {
return Sizzle( expr, null, null, elements );
};
Sizzle.matchesSelector = function( elem, expr ) {
return Sizzle( expr, null, null, [ elem ] ).length > 0;
};
var select = function( selector, context, results, seed, xml ) {
// Remove excessive whitespace
selector = selector.replace( rtrim, "$1" );
var elements, matcher, i, len, elem, token,
type, findContext, notTokens,
match = selector.match( rgroups ),
tokens = selector.match( rtokens ),
contextNodeType = context.nodeType;
// POS handling
if ( matchExpr["POS"].test(selector) ) {
return handlePOS( selector, context, results, seed, match );
}
if ( seed ) {
elements = slice.call( seed, 0 );
// To maintain document order, only narrow the
// set if there is one group
} else if ( match && match.length === 1 ) {
// Take a shortcut and set the context if the root selector is an ID
if ( tokens.length > 1 && contextNodeType === 9 && !xml &&
(match = matchExpr["ID"].exec( tokens[0] )) ) {
context = Expr.find["ID"]( match[1], context, xml )[0];
if ( !context ) {
return results;
}
selector = selector.slice( tokens.shift().length );
}
findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context;
// Get the last token, excluding :not
notTokens = tokens.pop();
token = notTokens.split(":not")[0];
for ( i = 0, len = Expr.order.length; i < len; i++ ) {
type = Expr.order[i];
if ( (match = matchExpr[ type ].exec( token )) ) {
elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml );
if ( elements == null ) {
continue;
}
if ( token === notTokens ) {
selector = selector.slice( 0, selector.length - notTokens.length ) +
token.replace( matchExpr[ type ], "" );
if ( !selector ) {
push.apply( results, slice.call(elements, 0) );
}
}
break;
}
}
}
// Only loop over the given elements once
// If selector is empty, we're already done
if ( selector ) {
matcher = compile( selector, context, xml );
dirruns = matcher.dirruns++;
if ( elements == null ) {
elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context );
}
for ( i = 0; (elem = elements[i]); i++ ) {
cachedruns = matcher.runs++;
if ( matcher(elem, context) ) {
results.push( elem );
}
}
}
return results;
};
if ( document.querySelectorAll ) {
(function() {
var disconnectedMatch,
oldSelect = select,
rescape = /'|\\/g,
rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
rbuggyQSA = [],
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
// A support test would require too much code (would include document ready)
// just skip matchesSelector for :active
rbuggyMatches = [":active"],
matches = docElem.matchesSelector ||
docElem.mozMatchesSelector ||
docElem.webkitMatchesSelector ||
docElem.oMatchesSelector ||
docElem.msMatchesSelector;
// Build QSA regex
// Regex strategy adopted from Diego Perini
assert(function( div ) {
div.innerHTML = "<select><option selected></option></select>";
// IE8 - Some boolean attributes are not treated correctly
if ( !div.querySelectorAll("[selected]").length ) {
rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
}
// Webkit/Opera - :checked should return selected option elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
// IE8 throws error here (do not put tests after this one)
if ( !div.querySelectorAll(":checked").length ) {
rbuggyQSA.push(":checked");
}
});
assert(function( div ) {
// Opera 10-12/IE9 - ^= $= *= and empty values
// Should not select anything
div.innerHTML = "<p test=''></p>";
if ( div.querySelectorAll("[test^='']").length ) {
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
}
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
// IE8 throws error here (do not put tests after this one)
div.innerHTML = "<input type='hidden'>";
if ( !div.querySelectorAll(":enabled").length ) {
rbuggyQSA.push(":enabled", ":disabled");
}
});
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
select = function( selector, context, results, seed, xml ) {
// Only use querySelectorAll when not filtering,
// when this is not xml,
// and when no QSA bugs apply
if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
if ( context.nodeType === 9 ) {
try {
push.apply( results, slice.call(context.querySelectorAll( selector ), 0) );
return results;
} catch(qsaError) {}
// qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
// and working up from there (Thanks to Andrew Dupont for the technique)
// IE 8 doesn't work on object elements
} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
var old = context.getAttribute("id"),
nid = old || expando,
newContext = rsibling.test( selector ) && context.parentNode || context;
if ( old ) {
nid = nid.replace( rescape, "\\$&" );
} else {
context.setAttribute( "id", nid );
}
try {
push.apply( results, slice.call( newContext.querySelectorAll(
selector.replace( rgroups, "[id='" + nid + "'] $&" )
), 0 ) );
return results;
} catch(qsaError) {
} finally {
if ( !old ) {
context.removeAttribute("id");
}
}
}
}
return oldSelect( selector, context, results, seed, xml );
};
if ( matches ) {
assert(function( div ) {
// Check to see if it's possible to do matchesSelector
// on a disconnected node (IE 9)
disconnectedMatch = matches.call( div, "div" );
// This should fail with an exception
// Gecko does not error, returns false instead
try {
matches.call( div, "[test!='']:sizzle" );
rbuggyMatches.push( Expr.match.PSEUDO );
} catch ( e ) {}
});
// rbuggyMatches always contains :active, so no need for a length check
rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
Sizzle.matchesSelector = function( elem, expr ) {
// Make sure that attribute selectors are quoted
expr = expr.replace( rattributeQuotes, "='$1']" );
// rbuggyMatches always contains :active, so no need for an existence check
if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) {
try {
var ret = matches.call( elem, expr );
// IE 9's matchesSelector returns false on disconnected nodes
if ( ret || disconnectedMatch ||
// As well, disconnected nodes are said to be in a document
// fragment in IE 9
elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
} catch(e) {}
}
return Sizzle( expr, null, null, [ elem ] ).length > 0;
};
}
})();
}
// Override sizzle attribute retrieval
Sizzle.attr = jQuery.attr;
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos;
jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;
})( window );
var runtil = /Until$/,
rparentsprev = /^(?:parents|prev(?:Until|All))/,
isSimple = /^.[^:#\[\.,]*$/,
rneedsContext = jQuery.expr.match.needsContext,
// methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
contents: true,
next: true,
prev: true
};
jQuery.fn.extend({
find: function( selector ) {
var i, l, length, n, r, ret,
self = this;
if ( typeof selector !== "string" ) {
return jQuery( selector ).filter(function() {
for ( i = 0, l = self.length; i < l; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
});
}
ret = this.pushStack( "", "find", selector );
for ( i = 0, l = this.length; i < l; i++ ) {
length = ret.length;
jQuery.find( selector, this[i], ret );
if ( i > 0 ) {
// Make sure that the results are unique
for ( n = length; n < ret.length; n++ ) {
for ( r = 0; r < length; r++ ) {
if ( ret[r] === ret[n] ) {
ret.splice(n--, 1);
break;
}
}
}
}
}
return ret;
},
has: function( target ) {
var i,
targets = jQuery( target, this ),
len = targets.length;
return this.filter(function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( this, targets[i] ) ) {
return true;
}
}
});
},
not: function( selector ) {
return this.pushStack( winnow(this, selector, false), "not", selector);
},
filter: function( selector ) {
return this.pushStack( winnow(this, selector, true), "filter", selector );
},
is: function( selector ) {
return !!selector && (
typeof selector === "string" ?
// If this is a positional/relative selector, check membership in the returned set
// so $("p:first").is("p:last") won't return true for a doc with two "p".
rneedsContext.test( selector ) ?
jQuery( selector, this.context ).index( this[0] ) >= 0 :
jQuery.filter( selector, this ).length > 0 :
this.filter( selector ).length > 0 );
},
closest: function( selectors, context ) {
var cur,
i = 0,
l = this.length,
ret = [],
pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
jQuery( selectors, context || this.context ) :
0;
for ( ; i < l; i++ ) {
cur = this[i];
while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
ret.push( cur );
break;
}
cur = cur.parentNode;
}
}
ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
return this.pushStack( ret, "closest", selectors );
},
// Determine the position of an element within
// the matched set of elements
index: function( elem ) {
// No argument, return index in parent
if ( !elem ) {
return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
}
// index in selector
if ( typeof elem === "string" ) {
return jQuery.inArray( this[0], jQuery( elem ) );
}
// Locate the position of the desired element
return jQuery.inArray(
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[0] : elem, this );
},
add: function( selector, context ) {
var set = typeof selector === "string" ?
jQuery( selector, context ) :
jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
all = jQuery.merge( this.get(), set );
return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
all :
jQuery.unique( all ) );
},
addBack: function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter(selector)
);
}
});
jQuery.fn.andSelf = jQuery.fn.addBack;
// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
return !node || !node.parentNode || node.parentNode.nodeType === 11;
}
function sibling( cur, dir ) {
do {
cur = cur[ dir ];
} while ( cur && cur.nodeType !== 1 );
return cur;
}
jQuery.each({
parent: function( elem ) {
var parent = elem.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function( elem ) {
return jQuery.dir( elem, "parentNode" );
},
parentsUntil: function( elem, i, until ) {
return jQuery.dir( elem, "parentNode", until );
},
next: function( elem ) {
return sibling( elem, "nextSibling" );
},
prev: function( elem ) {
return sibling( elem, "previousSibling" );
},
nextAll: function( elem ) {
return jQuery.dir( elem, "nextSibling" );
},
prevAll: function( elem ) {
return jQuery.dir( elem, "previousSibling" );
},
nextUntil: function( elem, i, until ) {
return jQuery.dir( elem, "nextSibling", until );
},
prevUntil: function( elem, i, until ) {
return jQuery.dir( elem, "previousSibling", until );
},
siblings: function( elem ) {
return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
},
children: function( elem ) {
return jQuery.sibling( elem.firstChild );
},
contents: function( elem ) {
return jQuery.nodeName( elem, "iframe" ) ?
elem.contentDocument || elem.contentWindow.document :
jQuery.merge( [], elem.childNodes );
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
var ret = jQuery.map( this, fn, until );
if ( !runtil.test( name ) ) {
selector = until;
}
if ( selector && typeof selector === "string" ) {
ret = jQuery.filter( selector, ret );
}
ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
if ( this.length > 1 && rparentsprev.test( name ) ) {
ret = ret.reverse();
}
return this.pushStack( ret, name, core_slice.call( arguments ).join(",") );
};
});
jQuery.extend({
filter: function( expr, elems, not ) {
if ( not ) {
expr = ":not(" + expr + ")";
}
return elems.length === 1 ?
jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
jQuery.find.matches(expr, elems);
},
dir: function( elem, dir, until ) {
var matched = [],
cur = elem[ dir ];
while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
if ( cur.nodeType === 1 ) {
matched.push( cur );
}
cur = cur[dir];
}
return matched;
},
sibling: function( n, elem ) {
var r = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType === 1 && n !== elem ) {
r.push( n );
}
}
return r;
}
});
// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {
// Can't pass null or undefined to indexOf in Firefox 4
// Set to 0 to skip string check
qualifier = qualifier || 0;
if ( jQuery.isFunction( qualifier ) ) {
return jQuery.grep(elements, function( elem, i ) {
var retVal = !!qualifier.call( elem, i, elem );
return retVal === keep;
});
} else if ( qualifier.nodeType ) {
return jQuery.grep(elements, function( elem, i ) {
return ( elem === qualifier ) === keep;
});
} else if ( typeof qualifier === "string" ) {
var filtered = jQuery.grep(elements, function( elem ) {
return elem.nodeType === 1;
});
if ( isSimple.test( qualifier ) ) {
return jQuery.filter(qualifier, filtered, !keep);
} else {
qualifier = jQuery.filter( qualifier, filtered );
}
}
return jQuery.grep(elements, function( elem, i ) {
return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
});
}
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment();
if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}
var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
rleadingWhitespace = /^\s+/,
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
rtagName = /<([\w:]+)/,
rtbody = /<tbody/i,
rhtml = /<|&#?\w+;/,
rnoInnerhtml = /<(?:script|style|link)/i,
rnocache = /<(?:script|object|embed|option|style)/i,
rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
rcheckableType = /^(?:checkbox|radio)$/,
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
rscriptType = /\/(java|ecma)script/i,
rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
area: [ 1, "<map>", "</map>" ],
_default: [ 0, "", "" ]
},
safeFragment = createSafeFragment( document ),
fragmentDiv = safeFragment.appendChild( document.createElement("div") );
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
// unless wrapped in a div with non-breaking characters in front of it.
if ( !jQuery.support.htmlSerialize ) {
wrapMap._default = [ 1, "X<div>", "</div>" ];
}
jQuery.fn.extend({
text: function( value ) {
return jQuery.access( this, function( value ) {
return value === undefined ?
jQuery.text( this ) :
this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
}, null, value, arguments.length );
},
wrapAll: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each(function(i) {
jQuery(this).wrapAll( html.call(this, i) );
});
}
if ( this[0] ) {
// The elements to wrap the target around
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
if ( this[0].parentNode ) {
wrap.insertBefore( this[0] );
}
wrap.map(function() {
var elem = this;
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
elem = elem.firstChild;
}
return elem;
}).append( this );
}
return this;
},
wrapInner: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each(function(i) {
jQuery(this).wrapInner( html.call(this, i) );
});
}
return this.each(function() {
var self = jQuery( this ),
contents = self.contents();
if ( contents.length ) {
contents.wrapAll( html );
} else {
self.append( html );
}
});
},
wrap: function( html ) {
var isFunction = jQuery.isFunction( html );
return this.each(function(i) {
jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
});
},
unwrap: function() {
return this.parent().each(function() {
if ( !jQuery.nodeName( this, "body" ) ) {
jQuery( this ).replaceWith( this.childNodes );
}
}).end();
},
append: function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 ) {
this.appendChild( elem );
}
});
},
prepend: function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 ) {
this.insertBefore( elem, this.firstChild );
}
});
},
before: function() {
if ( !isDisconnected( this[0] ) ) {
return this.domManip(arguments, false, function( elem ) {
this.parentNode.insertBefore( elem, this );
});
}
if ( arguments.length ) {
var set = jQuery.clean( arguments );
return this.pushStack( jQuery.merge( set, this ), "before", this.selector );
}
},
after: function() {
if ( !isDisconnected( this[0] ) ) {
return this.domManip(arguments, false, function( elem ) {
this.parentNode.insertBefore( elem, this.nextSibling );
});
}
if ( arguments.length ) {
var set = jQuery.clean( arguments );
return this.pushStack( jQuery.merge( this, set ), "after", this.selector );
}
},
// keepData is for internal use only--do not document
remove: function( selector, keepData ) {
var elem,
i = 0;
for ( ; (elem = this[i]) != null; i++ ) {
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
if ( !keepData && elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName("*") );
jQuery.cleanData( [ elem ] );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
}
return this;
},
empty: function() {
var elem,
i = 0;
for ( ; (elem = this[i]) != null; i++ ) {
// Remove element nodes and prevent memory leaks
if ( elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName("*") );
}
// Remove any remaining nodes
while ( elem.firstChild ) {
elem.removeChild( elem.firstChild );
}
}
return this;
},
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map( function () {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
});
},
html: function( value ) {
return jQuery.access( this, function( value ) {
var elem = this[0] || {},
i = 0,
l = this.length;
if ( value === undefined ) {
return elem.nodeType === 1 ?
elem.innerHTML.replace( rinlinejQuery, "" ) :
undefined;
}
// See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
value = value.replace( rxhtmlTag, "<$1></$2>" );
try {
for (; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if ( elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName( "*" ) );
elem.innerHTML = value;
}
}
elem = 0;
// If using innerHTML throws an exception, use the fallback method
} catch(e) {}
}
if ( elem ) {
this.empty().append( value );
}
}, null, value, arguments.length );
},
replaceWith: function( value ) {
if ( !isDisconnected( this[0] ) ) {
// Make sure that the elements are removed from the DOM before they are inserted
// this can help fix replacing a parent with child elements
if ( jQuery.isFunction( value ) ) {
return this.each(function(i) {
var self = jQuery(this), old = self.html();
self.replaceWith( value.call( this, i, old ) );
});
}
if ( typeof value !== "string" ) {
value = jQuery( value ).detach();
}
return this.each(function() {
var next = this.nextSibling,
parent = this.parentNode;
jQuery( this ).remove();
if ( next ) {
jQuery(next).before( value );
} else {
jQuery(parent).append( value );
}
});
}
return this.length ?
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
this;
},
detach: function( selector ) {
return this.remove( selector, true );
},
domManip: function( args, table, callback ) {
// Flatten any nested arrays
args = [].concat.apply( [], args );
var results, first, fragment, iNoClone,
i = 0,
value = args[0],
scripts = [],
l = this.length;
// We can't cloneNode fragments that contain checked, in WebKit
if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
return this.each(function() {
jQuery(this).domManip( args, table, callback );
});
}
if ( jQuery.isFunction(value) ) {
return this.each(function(i) {
var self = jQuery(this);
args[0] = value.call( this, i, table ? self.html() : undefined );
self.domManip( args, table, callback );
});
}
if ( this[0] ) {
results = jQuery.buildFragment( args, this, scripts );
fragment = results.fragment;
first = fragment.firstChild;
if ( fragment.childNodes.length === 1 ) {
fragment = first;
}
if ( first ) {
table = table && jQuery.nodeName( first, "tr" );
// Use the original fragment for the last item instead of the first because it can end up
// being emptied incorrectly in certain situations (#8070).
// Fragments from the fragment cache must always be cloned and never used in place.
for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
callback.call(
table && jQuery.nodeName( this[i], "table" ) ?
findOrAppend( this[i], "tbody" ) :
this[i],
i === iNoClone ?
fragment :
jQuery.clone( fragment, true, true )
);
}
}
// Fix #11809: Avoid leaking memory
fragment = first = null;
if ( scripts.length ) {
jQuery.each( scripts, function( i, elem ) {
if ( elem.src ) {
if ( jQuery.ajax ) {
jQuery.ajax({
url: elem.src,
type: "GET",
dataType: "script",
async: false,
global: false,
"throws": true
});
} else {
jQuery.error("no ajax");
}
} else {
jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
});
}
}
return this;
}
});
function findOrAppend( elem, tag ) {
return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
}
function cloneCopyEvent( src, dest ) {
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
return;
}
var type, i, l,
oldData = jQuery._data( src ),
curData = jQuery._data( dest, oldData ),
events = oldData.events;
if ( events ) {
delete curData.handle;
curData.events = {};
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
// make the cloned public data object a copy from the original
if ( curData.data ) {
curData.data = jQuery.extend( {}, curData.data );
}
}
function cloneFixAttributes( src, dest ) {
var nodeName;
// We do not need to do anything for non-Elements
if ( dest.nodeType !== 1 ) {
return;
}
// clearAttributes removes the attributes, which we don't want,
// but also removes the attachEvent events, which we *do* want
if ( dest.clearAttributes ) {
dest.clearAttributes();
}
// mergeAttributes, in contrast, only merges back on the
// original attributes, not the events
if ( dest.mergeAttributes ) {
dest.mergeAttributes( src );
}
nodeName = dest.nodeName.toLowerCase();
if ( nodeName === "object" ) {
// IE6-10 improperly clones children of object elements using classid.
// IE10 throws NoModificationAllowedError if parent is null, #12132.
if ( dest.parentNode ) {
dest.outerHTML = src.outerHTML;
}
// This path appears unavoidable for IE9. When cloning an object
// element in IE9, the outerHTML strategy above is not sufficient.
// If the src has innerHTML and the destination does not,
// copy the src.innerHTML into the dest.innerHTML. #10324
if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) {
dest.innerHTML = src.innerHTML;
}
} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
// IE6-8 fails to persist the checked state of a cloned checkbox
// or radio button. Worse, IE6-7 fail to give the cloned element
// a checked appearance if the defaultChecked value isn't also set
dest.defaultChecked = dest.checked = src.checked;
// IE6-7 get confused and end up setting the value of a cloned
// checkbox/radio button to an empty string instead of "on"
if ( dest.value !== src.value ) {
dest.value = src.value;
}
// IE6-8 fails to return the selected option to the default selected
// state when cloning options
} else if ( nodeName === "option" ) {
dest.selected = src.defaultSelected;
// IE6-8 fails to set the defaultValue to the correct value when
// cloning other types of input fields
} else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
// IE blanks contents when cloning scripts
} else if ( nodeName === "script" && dest.text !== src.text ) {
dest.text = src.text;
}
// Event data gets referenced instead of copied if the expando
// gets copied too
dest.removeAttribute( jQuery.expando );
}
jQuery.buildFragment = function( args, context, scripts ) {
var fragment, cacheable, cachehit,
first = args[ 0 ];
// Set context from what may come in as undefined or a jQuery collection or a node
context = context || document;
context = (context[0] || context).ownerDocument || context[0] || context;
// Ensure that an attr object doesn't incorrectly stand in as a document object
// Chrome and Firefox seem to allow this to occur and will throw exception
// Fixes #8950
if ( typeof context.createDocumentFragment === "undefined" ) {
context = document;
}
// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
// Cloning options loses the selected state, so don't cache them
// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document &&
first.charAt(0) === "<" && !rnocache.test( first ) &&
(jQuery.support.checkClone || !rchecked.test( first )) &&
(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
// Mark cacheable and look for a hit
cacheable = true;
fragment = jQuery.fragments[ first ];
cachehit = fragment !== undefined;
}
if ( !fragment ) {
fragment = context.createDocumentFragment();
jQuery.clean( args, context, fragment, scripts );
// Update the cache, but only store false
// unless this is a second parsing of the same content
if ( cacheable ) {
jQuery.fragments[ first ] = cachehit && fragment;
}
}
return { fragment: fragment, cacheable: cacheable };
};
jQuery.fragments = {};
jQuery.each({
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
insertAfter: "after",
replaceAll: "replaceWith"
}, function( name, original ) {
jQuery.fn[ name ] = function( selector ) {
var elems,
i = 0,
ret = [],
insert = jQuery( selector ),
l = insert.length,
parent = this.length === 1 && this[0].parentNode;
if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) {
insert[ original ]( this[0] );
return this;
} else {
for ( ; i < l; i++ ) {
elems = ( i > 0 ? this.clone(true) : this ).get();
jQuery( insert[i] )[ original ]( elems );
ret = ret.concat( elems );
}
return this.pushStack( ret, name, insert.selector );
}
};
});
function getAll( elem ) {
if ( typeof elem.getElementsByTagName !== "undefined" ) {
return elem.getElementsByTagName( "*" );
} else if ( typeof elem.querySelectorAll !== "undefined" ) {
return elem.querySelectorAll( "*" );
} else {
return [];
}
}
// Used in clean, fixes the defaultChecked property
function fixDefaultChecked( elem ) {
if ( rcheckableType.test( elem.type ) ) {
elem.defaultChecked = elem.checked;
}
}
jQuery.extend({
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var srcElements,
destElements,
i,
clone;
if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
clone = elem.cloneNode( true );
// IE<=8 does not properly clone detached, unknown element nodes
} else {
fragmentDiv.innerHTML = elem.outerHTML;
fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
}
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
// IE copies events bound via attachEvent when using cloneNode.
// Calling detachEvent on the clone will also remove the events
// from the original. In order to get around this, we use some
// proprietary methods to clear the events. Thanks to MooTools
// guys for this hotness.
cloneFixAttributes( elem, clone );
// Using Sizzle here is crazy slow, so we use getElementsByTagName instead
srcElements = getAll( elem );
destElements = getAll( clone );
// Weird iteration because IE will replace the length property
// with an element if you are cloning the body and one of the
// elements on the page has a name or id of "length"
for ( i = 0; srcElements[i]; ++i ) {
// Ensure that the destination node is not null; Fixes #9587
if ( destElements[i] ) {
cloneFixAttributes( srcElements[i], destElements[i] );
}
}
}
// Copy the events from the original to the clone
if ( dataAndEvents ) {
cloneCopyEvent( elem, clone );
if ( deepDataAndEvents ) {
srcElements = getAll( elem );
destElements = getAll( clone );
for ( i = 0; srcElements[i]; ++i ) {
cloneCopyEvent( srcElements[i], destElements[i] );
}
}
}
srcElements = destElements = null;
// Return the cloned set
return clone;
},
clean: function( elems, context, fragment, scripts ) {
var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
i = 0,
ret = [];
// Ensure that context is a document
if ( !context || typeof context.createDocumentFragment === "undefined" ) {
context = document;
}
// Use the already-created safe fragment if context permits
for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) {
if ( typeof elem === "number" ) {
elem += "";
}
if ( !elem ) {
continue;
}
// Convert html string into DOM nodes
if ( typeof elem === "string" ) {
if ( !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
} else {
// Ensure a safe container in which to render the html
safe = safe || createSafeFragment( context );
div = div || safe.appendChild( context.createElement("div") );
// Fix "XHTML"-style tags in all browsers
elem = elem.replace(rxhtmlTag, "<$1></$2>");
// Go to html and back, then peel off extra wrappers
tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
wrap = wrapMap[ tag ] || wrapMap._default;
depth = wrap[0];
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
while ( depth-- ) {
div = div.lastChild;
}
// Remove IE's autoinserted <tbody> from table fragments
if ( !jQuery.support.tbody ) {
// String was a <table>, *may* have spurious <tbody>
hasBody = rtbody.test(elem);
tbody = tag === "table" && !hasBody ?
div.firstChild && div.firstChild.childNodes :
// String was a bare <thead> or <tfoot>
wrap[1] === "<table>" && !hasBody ?
div.childNodes :
[];
for ( j = tbody.length - 1; j >= 0 ; --j ) {
if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
tbody[ j ].parentNode.removeChild( tbody[ j ] );
}
}
}
// IE completely kills leading whitespace when innerHTML is used
if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
}
elem = div.childNodes;
// Remember the top-level container for proper cleanup
div = safe.lastChild;
}
}
if ( elem.nodeType ) {
ret.push( elem );
} else {
ret = jQuery.merge( ret, elem );
}
}
// Fix #11356: Clear elements from safeFragment
if ( div ) {
safe.removeChild( div );
elem = div = safe = null;
}
// Reset defaultChecked for any radios and checkboxes
// about to be appended to the DOM in IE 6/7 (#8060)
if ( !jQuery.support.appendChecked ) {
for ( i = 0; (elem = ret[i]) != null; i++ ) {
if ( jQuery.nodeName( elem, "input" ) ) {
fixDefaultChecked( elem );
} else if ( typeof elem.getElementsByTagName !== "undefined" ) {
jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
}
}
}
// Append elements to a provided document fragment
if ( fragment ) {
// Special handling of each script element
handleScript = function( elem ) {
// Check if we consider it executable
if ( !elem.type || rscriptType.test( elem.type ) ) {
// Detach the script and store it in the scripts array (if provided) or the fragment
// Return truthy to indicate that it has been handled
return scripts ?
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
fragment.appendChild( elem );
}
};
for ( i = 0; (elem = ret[i]) != null; i++ ) {
// Check if we're done after handling an executable script
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
// Append to fragment and handle embedded scripts
fragment.appendChild( elem );
if ( typeof elem.getElementsByTagName !== "undefined" ) {
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
// Splice the scripts into ret after their former ancestor and advance our index beyond them
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
i += jsTags.length;
}
}
}
}
return ret;
},
cleanData: function( elems, /* internal */ acceptData ) {
var data, id, elem, type,
i = 0,
internalKey = jQuery.expando,
cache = jQuery.cache,
deleteExpando = jQuery.support.deleteExpando,
special = jQuery.event.special;
for ( ; (elem = elems[i]) != null; i++ ) {
if ( acceptData || jQuery.acceptData( elem ) ) {
id = elem[ internalKey ];
data = id && cache[ id ];
if ( data ) {
if ( data.events ) {
for ( type in data.events ) {
if ( special[ type ] ) {
jQuery.event.remove( elem, type );
// This is a shortcut to avoid jQuery.event.remove's overhead
} else {
jQuery.removeEvent( elem, type, data.handle );
}
}
}
// Remove cache only if it was not already removed by jQuery.event.remove
if ( cache[ id ] ) {
delete cache[ id ];
// IE does not allow us to delete expando properties from nodes,
// nor does it have a removeAttribute function on Document nodes;
// we must handle all of these cases
if ( deleteExpando ) {
delete elem[ internalKey ];
} else if ( elem.removeAttribute ) {
elem.removeAttribute( internalKey );
} else {
elem[ internalKey ] = null;
}
jQuery.deletedIds.push( id );
}
}
}
}
}
});
// Limit scope pollution from any deprecated API
(function() {
var matched, browser;
// Use of jQuery.browser is frowned upon.
// More details: http://api.jquery.com/jQuery.browser
// jQuery.uaMatch maintained for back-compat
jQuery.uaMatch = function( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
matched = jQuery.uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
// Deprecated, use jQuery.browser.webkit instead
// Maintained for back-compat only
if ( browser.webkit ) {
browser.safari = true;
}
jQuery.browser = browser;
jQuery.sub = function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, this );
jQuerySub.superclass = this;
jQuerySub.fn = jQuerySub.prototype = this();
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.sub = this.sub;
jQuerySub.fn.init = function init( selector, context ) {
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
context = jQuerySub( context );
}
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
return jQuerySub;
};
})();
var curCSS, iframe, iframeDoc,
ralpha = /alpha\([^)]*\)/i,
ropacity = /opacity=([^)]*)/,
rposition = /^(top|right|bottom|left)$/,
rmargin = /^margin/,
rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
elemdisplay = {},
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: 0,
fontWeight: 400,
lineHeight: 1
},
cssExpand = [ "Top", "Right", "Bottom", "Left" ],
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
eventsToggle = jQuery.fn.toggle;
// return a css property mapped to a potentially vendor prefixed property
function vendorPropName( style, name ) {
// shortcut for names that are not vendor prefixed
if ( name in style ) {
return name;
}
// check for vendor prefixed names
var capName = name.charAt(0).toUpperCase() + name.slice(1),
origName = name,
i = cssPrefixes.length;
while ( i-- ) {
name = cssPrefixes[ i ] + capName;
if ( name in style ) {
return name;
}
}
return origName;
}
function isHidden( elem, el ) {
elem = el || elem;
return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
}
function showHide( elements, show ) {
var elem, display,
values = [],
index = 0,
length = elements.length;
for ( ; index < length; index++ ) {
elem = elements[ index ];
if ( !elem.style ) {
continue;
}
values[ index ] = jQuery._data( elem, "olddisplay" );
if ( show ) {
// Reset the inline display of this element to learn if it is
// being hidden by cascaded rules or not
if ( !values[ index ] && elem.style.display === "none" ) {
elem.style.display = "";
}
// Set elements which have been overridden with display: none
// in a stylesheet to whatever the default browser style is
// for such an element
if ( elem.style.display === "" && isHidden( elem ) ) {
values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
}
} else {
display = curCSS( elem, "display" );
if ( !values[ index ] && display !== "none" ) {
jQuery._data( elem, "olddisplay", display );
}
}
}
// Set the display of most of the elements in a second loop
// to avoid the constant reflow
for ( index = 0; index < length; index++ ) {
elem = elements[ index ];
if ( !elem.style ) {
continue;
}
if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
elem.style.display = show ? values[ index ] || "" : "none";
}
}
return elements;
}
jQuery.fn.extend({
css: function( name, value ) {
return jQuery.access( this, function( elem, name, value ) {
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
},
show: function() {
return showHide( this, true );
},
hide: function() {
return showHide( this );
},
toggle: function( state, fn2 ) {
var bool = typeof state === "boolean";
if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) {
return eventsToggle.apply( this, arguments );
}
return this.each(function() {
if ( bool ? state : isHidden( this ) ) {
jQuery( this ).show();
} else {
jQuery( this ).hide();
}
});
}
});
jQuery.extend({
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
}
}
}
},
// Exclude the following css properties to add px
cssNumber: {
"fillOpacity": true,
"fontWeight": true,
"lineHeight": true,
"opacity": true,
"orphans": true,
"widows": true,
"zIndex": true,
"zoom": true
},
// Add in properties whose names you wish to fix before
// setting or getting the value
cssProps: {
// normalize float css property
"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
},
// Get and set the style property on a DOM Node
style: function( elem, name, value, extra ) {
// Don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
}
// Make sure that we're working with the right name
var ret, type, hooks,
origName = jQuery.camelCase( name ),
style = elem.style;
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
// gets hook for the prefixed version
// followed by the unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// Check if we're setting a value
if ( value !== undefined ) {
type = typeof value;
// convert relative number strings (+= or -=) to relative numbers. #7345
if ( type === "string" && (ret = rrelNum.exec( value )) ) {
value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
// Fixes bug #9237
type = "number";
}
// Make sure that NaN and null values aren't set. See: #7116
if ( value == null || type === "number" && isNaN( value ) ) {
return;
}
// If a number was passed in, add 'px' to the (except for certain CSS properties)
if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
value += "px";
}
// If a hook was provided, use that value, otherwise just set the specified value
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
// Fixes bug #5509
try {
style[ name ] = value;
} catch(e) {}
}
} else {
// If a hook was provided get the non-computed value from there
if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
return ret;
}
// Otherwise just get the value from the style object
return style[ name ];
}
},
css: function( elem, name, numeric, extra ) {
var val, num, hooks,
origName = jQuery.camelCase( name );
// Make sure that we're working with the right name
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
// gets hook for the prefixed version
// followed by the unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// If a hook was provided get the computed value from there
if ( hooks && "get" in hooks ) {
val = hooks.get( elem, true, extra );
}
// Otherwise, if a way to get the computed value exists, use that
if ( val === undefined ) {
val = curCSS( elem, name );
}
//convert "normal" to computed value
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
}
// Return, converting to number if forced or a qualifier was provided and val looks numeric
if ( numeric || extra !== undefined ) {
num = parseFloat( val );
return numeric || jQuery.isNumeric( num ) ? num || 0 : val;
}
return val;
},
// A method for quickly swapping in/out CSS properties to get correct calculations
swap: function( elem, options, callback ) {
var ret, name,
old = {};
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.call( elem );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
return ret;
}
});
// NOTE: To any future maintainer, we've used both window.getComputedStyle
// and getComputedStyle here to produce a better gzip size
if ( window.getComputedStyle ) {
curCSS = function( elem, name ) {
var ret, width, minWidth, maxWidth,
computed = getComputedStyle( elem, null ),
style = elem.style;
if ( computed ) {
ret = computed[ name ];
if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
ret = jQuery.style( elem, name );
}
// A tribute to the "awesome hack by Dean Edwards"
// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
width = style.width;
minWidth = style.minWidth;
maxWidth = style.maxWidth;
style.minWidth = style.maxWidth = style.width = ret;
ret = computed.width;
style.width = width;
style.minWidth = minWidth;
style.maxWidth = maxWidth;
}
}
return ret;
};
} else if ( document.documentElement.currentStyle ) {
curCSS = function( elem, name ) {
var left, rsLeft,
ret = elem.currentStyle && elem.currentStyle[ name ],
style = elem.style;
// Avoid setting ret to empty string here
// so we don't default to auto
if ( ret == null && style && style[ name ] ) {
ret = style[ name ];
}
// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
// but not position css attributes, as those are proportional to the parent element instead
// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
// Remember the original values
left = style.left;
rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
// Put in the new values to get a computed value out
if ( rsLeft ) {
elem.runtimeStyle.left = elem.currentStyle.left;
}
style.left = name === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px";
// Revert the changed values
style.left = left;
if ( rsLeft ) {
elem.runtimeStyle.left = rsLeft;
}
}
return ret === "" ? "auto" : ret;
};
}
function setPositiveNumber( elem, value, subtract ) {
var matches = rnumsplit.exec( value );
return matches ?
Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
value;
}
function augmentWidthOrHeight( elem, name, extra, isBorderBox ) {
var i = extra === ( isBorderBox ? "border" : "content" ) ?
// If we already have the right measurement, avoid augmentation
4 :
// Otherwise initialize for horizontal or vertical properties
name === "width" ? 1 : 0,
val = 0;
for ( ; i < 4; i += 2 ) {
// both box models exclude margin, so add it if we want it
if ( extra === "margin" ) {
// we use jQuery.css instead of curCSS here
// because of the reliableMarginRight CSS hook!
val += jQuery.css( elem, extra + cssExpand[ i ], true );
}
// From this point on we use curCSS for maximum performance (relevant in animations)
if ( isBorderBox ) {
// border-box includes padding, so remove it if we want content
if ( extra === "content" ) {
val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
}
// at this point, extra isn't border nor margin, so remove border
if ( extra !== "margin" ) {
val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
}
} else {
// at this point, extra isn't content, so add padding
val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
// at this point, extra isn't content nor padding, so add border
if ( extra !== "padding" ) {
val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
}
}
}
return val;
}
function getWidthOrHeight( elem, name, extra ) {
// Start with offset property, which is equivalent to the border-box value
var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
valueIsBorderBox = true,
isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
if ( val <= 0 ) {
// Fall back to computed then uncomputed css if necessary
val = curCSS( elem, name );
if ( val < 0 || val == null ) {
val = elem.style[ name ];
}
// Computed unit is not pixels. Stop here and return.
if ( rnumnonpx.test(val) ) {
return val;
}
// we need the check for style in case a browser which returns unreliable values
// for getComputedStyle silently falls back to the reliable elem.style
valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
// Normalize "", auto, and prepare for extra
val = parseFloat( val ) || 0;
}
// use the active box-sizing model to add/subtract irrelevant styles
return ( val +
augmentWidthOrHeight(
elem,
name,
extra || ( isBorderBox ? "border" : "content" ),
valueIsBorderBox
)
) + "px";
}
// Try to determine the default display value of an element
function css_defaultDisplay( nodeName ) {
if ( elemdisplay[ nodeName ] ) {
return elemdisplay[ nodeName ];
}
var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ),
display = elem.css("display");
elem.remove();
// If the simple way fails,
// get element's real default display by attaching it to a temp iframe
if ( display === "none" || display === "" ) {
// Use the already-created iframe if possible
iframe = document.body.appendChild(
iframe || jQuery.extend( document.createElement("iframe"), {
frameBorder: 0,
width: 0,
height: 0
})
);
// Create a cacheable copy of the iframe document on first call.
// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
// document to it; WebKit & Firefox won't allow reusing the iframe document.
if ( !iframeDoc || !iframe.createElement ) {
iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
iframeDoc.write("<!doctype html><html><body>");
iframeDoc.close();
}
elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) );
display = curCSS( elem, "display" );
document.body.removeChild( iframe );
}
// Store the correct default display
elemdisplay[ nodeName ] = display;
return display;
}
jQuery.each([ "height", "width" ], function( i, name ) {
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) {
return getWidthOrHeight( elem, name, extra );
} else {
return jQuery.swap( elem, cssShow, function() {
return getWidthOrHeight( elem, name, extra );
});
}
}
},
set: function( elem, value, extra ) {
return setPositiveNumber( elem, value, extra ?
augmentWidthOrHeight(
elem,
name,
extra,
jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"
) : 0
);
}
};
});
if ( !jQuery.support.opacity ) {
jQuery.cssHooks.opacity = {
get: function( elem, computed ) {
// IE uses filters for opacity
return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
computed ? "1" : "";
},
set: function( elem, value ) {
var style = elem.style,
currentStyle = elem.currentStyle,
opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
filter = currentStyle && currentStyle.filter || style.filter || "";
// IE has trouble with opacity if it does not have layout
// Force it by setting the zoom level
style.zoom = 1;
// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
style.removeAttribute ) {
// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
// if "filter:" is present at all, clearType is disabled, we want to avoid this
// style.removeAttribute is IE Only, but so apparently is this code path...
style.removeAttribute( "filter" );
// if there there is no filter style applied in a css rule, we are done
if ( currentStyle && !currentStyle.filter ) {
return;
}
}
// otherwise, set new filter values
style.filter = ralpha.test( filter ) ?
filter.replace( ralpha, opacity ) :
filter + " " + opacity;
}
};
}
// These hooks cannot be added until DOM ready because the support test
// for it is not run until after DOM ready
jQuery(function() {
if ( !jQuery.support.reliableMarginRight ) {
jQuery.cssHooks.marginRight = {
get: function( elem, computed ) {
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
// Work around by temporarily setting element display to inline-block
return jQuery.swap( elem, { "display": "inline-block" }, function() {
if ( computed ) {
return curCSS( elem, "marginRight" );
}
});
}
};
}
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// getComputedStyle returns percent when specified for top/left/bottom/right
// rather than make the css module depend on the offset module, we just check for it here
if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
jQuery.each( [ "top", "left" ], function( i, prop ) {
jQuery.cssHooks[ prop ] = {
get: function( elem, computed ) {
if ( computed ) {
var ret = curCSS( elem, prop );
// if curCSS returns percentage, fallback to offset
return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret;
}
}
};
});
}
});
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.hidden = function( elem ) {
return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none");
};
jQuery.expr.filters.visible = function( elem ) {
return !jQuery.expr.filters.hidden( elem );
};
}
// These hooks are used by animate to expand properties
jQuery.each({
margin: "",
padding: "",
border: "Width"
}, function( prefix, suffix ) {
jQuery.cssHooks[ prefix + suffix ] = {
expand: function( value ) {
var i,
// assumes a single number if not a string
parts = typeof value === "string" ? value.split(" ") : [ value ],
expanded = {};
for ( i = 0; i < 4; i++ ) {
expanded[ prefix + cssExpand[ i ] + suffix ] =
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
}
return expanded;
}
};
if ( !rmargin.test( prefix ) ) {
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
}
});
var r20 = /%20/g,
rbracket = /\[\]$/,
rCRLF = /\r?\n/g,
rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
rselectTextarea = /^(?:select|textarea)/i;
jQuery.fn.extend({
serialize: function() {
return jQuery.param( this.serializeArray() );
},
serializeArray: function() {
return this.map(function(){
return this.elements ? jQuery.makeArray( this.elements ) : this;
})
.filter(function(){
return this.name && !this.disabled &&
( this.checked || rselectTextarea.test( this.nodeName ) ||
rinput.test( this.type ) );
})
.map(function( i, elem ){
var val = jQuery( this ).val();
return val == null ?
null :
jQuery.isArray( val ) ?
jQuery.map( val, function( val, i ){
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}) :
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}).get();
}
});
//Serialize an array of form elements or a set of
//key/values into a query string
jQuery.param = function( a, traditional ) {
var prefix,
s = [],
add = function( key, value ) {
// If value is a function, invoke it and return its value
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
};
// Set traditional to true for jQuery <= 1.3.2 behavior.
if ( traditional === undefined ) {
traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
}
// If an array was passed in, assume that it is an array of form elements.
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
// Serialize the form elements
jQuery.each( a, function() {
add( this.name, this.value );
});
} else {
// If traditional, encode the "old" way (the way 1.3.2 or older
// did it), otherwise encode params recursively.
for ( prefix in a ) {
buildParams( prefix, a[ prefix ], traditional, add );
}
}
// Return the resulting serialization
return s.join( "&" ).replace( r20, "+" );
};
function buildParams( prefix, obj, traditional, add ) {
var name;
if ( jQuery.isArray( obj ) ) {
// Serialize array item.
jQuery.each( obj, function( i, v ) {
if ( traditional || rbracket.test( prefix ) ) {
// Treat each array item as a scalar.
add( prefix, v );
} else {
// If array item is non-scalar (array or object), encode its
// numeric index to resolve deserialization ambiguity issues.
// Note that rack (as of 1.0.0) can't currently deserialize
// nested arrays properly, and attempting to do so may cause
// a server error. Possible fixes are to modify rack's
// deserialization algorithm or to provide an option or flag
// to force array serialization to be shallow.
buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
}
});
} else if ( !traditional && jQuery.type( obj ) === "object" ) {
// Serialize object item.
for ( name in obj ) {
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
}
} else {
// Serialize scalar item.
add( prefix, obj );
}
}
var // Document location
ajaxLocation,
// Document location segments
ajaxLocParts,
rhash = /#.*$/,
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
// #7653, #8125, #8152: local protocol detection
rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
rquery = /\?/,
rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
rts = /([?&])_=[^&]*/,
rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
// Keep a copy of the old load method
_load = jQuery.fn.load,
/* Prefilters
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
* 2) These are called:
* - BEFORE asking for a transport
* - AFTER param serialization (s.data is a string if s.processData is true)
* 3) key is the dataType
* 4) the catchall symbol "*" can be used
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
*/
prefilters = {},
/* Transports bindings
* 1) key is the dataType
* 2) the catchall symbol "*" can be used
* 3) selection will start with transport dataType and THEN go to "*" if needed
*/
transports = {},
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
allTypes = ["*/"] + ["*"];
// #8138, IE may throw an exception when accessing
// a field from window.location if document.domain has been set
try {
ajaxLocation = location.href;
} catch( e ) {
// Use the href attribute of an A element
// since IE will modify it given document.location
ajaxLocation = document.createElement( "a" );
ajaxLocation.href = "";
ajaxLocation = ajaxLocation.href;
}
// Segment location into parts
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {
// dataTypeExpression is optional and defaults to "*"
return function( dataTypeExpression, func ) {
if ( typeof dataTypeExpression !== "string" ) {
func = dataTypeExpression;
dataTypeExpression = "*";
}
var dataType, list, placeBefore,
dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ),
i = 0,
length = dataTypes.length;
if ( jQuery.isFunction( func ) ) {
// For each dataType in the dataTypeExpression
for ( ; i < length; i++ ) {
dataType = dataTypes[ i ];
// We control if we're asked to add before
// any existing element
placeBefore = /^\+/.test( dataType );
if ( placeBefore ) {
dataType = dataType.substr( 1 ) || "*";
}
list = structure[ dataType ] = structure[ dataType ] || [];
// then we add to the structure accordingly
list[ placeBefore ? "unshift" : "push" ]( func );
}
}
};
}
// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
dataType /* internal */, inspected /* internal */ ) {
dataType = dataType || options.dataTypes[ 0 ];
inspected = inspected || {};
inspected[ dataType ] = true;
var selection,
list = structure[ dataType ],
i = 0,
length = list ? list.length : 0,
executeOnly = ( structure === prefilters );
for ( ; i < length && ( executeOnly || !selection ); i++ ) {
selection = list[ i ]( options, originalOptions, jqXHR );
// If we got redirected to another dataType
// we try there if executing only and not done already
if ( typeof selection === "string" ) {
if ( !executeOnly || inspected[ selection ] ) {
selection = undefined;
} else {
options.dataTypes.unshift( selection );
selection = inspectPrefiltersOrTransports(
structure, options, originalOptions, jqXHR, selection, inspected );
}
}
}
// If we're only executing or nothing was selected
// we try the catchall dataType if not done already
if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
selection = inspectPrefiltersOrTransports(
structure, options, originalOptions, jqXHR, "*", inspected );
}
// unnecessary when only executing (prefilters)
// but it'll be ignored by the caller in that case
return selection;
}
// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
var key, deep,
flatOptions = jQuery.ajaxSettings.flatOptions || {};
for ( key in src ) {
if ( src[ key ] !== undefined ) {
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
}
}
if ( deep ) {
jQuery.extend( true, target, deep );
}
}
jQuery.fn.load = function( url, params, callback ) {
if ( typeof url !== "string" && _load ) {
return _load.apply( this, arguments );
}
// Don't do a request if no elements are being requested
if ( !this.length ) {
return this;
}
var selector, type, response,
self = this,
off = url.indexOf(" ");
if ( off >= 0 ) {
selector = url.slice( off, url.length );
url = url.slice( 0, off );
}
// If it's a function
if ( jQuery.isFunction( params ) ) {
// We assume that it's the callback
callback = params;
params = undefined;
// Otherwise, build a param string
} else if ( typeof params === "object" ) {
type = "POST";
}
// Request the remote document
jQuery.ajax({
url: url,
// if "type" variable is undefined, then "GET" method will be used
type: type,
dataType: "html",
data: params,
complete: function( jqXHR, status ) {
if ( callback ) {
self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
}
}
}).done(function( responseText ) {
// Save response for use in complete callback
response = arguments;
// See if a selector was specified
self.html( selector ?
// Create a dummy div to hold the results
jQuery("<div>")
// inject the contents of the document in, removing the scripts
// to avoid any 'Permission Denied' errors in IE
.append( responseText.replace( rscript, "" ) )
// Locate the specified elements
.find( selector ) :
// If not, just inject the full result
responseText );
});
return this;
};
// Attach a bunch of functions for handling common AJAX events
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
jQuery.fn[ o ] = function( f ){
return this.on( o, f );
};
});
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
// shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
return jQuery.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
});
};
});
jQuery.extend({
getScript: function( url, callback ) {
return jQuery.get( url, undefined, callback, "script" );
},
getJSON: function( url, data, callback ) {
return jQuery.get( url, data, callback, "json" );
},
// Creates a full fledged settings object into target
// with both ajaxSettings and settings fields.
// If target is omitted, writes into ajaxSettings.
ajaxSetup: function( target, settings ) {
if ( settings ) {
// Building a settings object
ajaxExtend( target, jQuery.ajaxSettings );
} else {
// Extending ajaxSettings
settings = target;
target = jQuery.ajaxSettings;
}
ajaxExtend( target, settings );
return target;
},
ajaxSettings: {
url: ajaxLocation,
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
global: true,
type: "GET",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
processData: true,
async: true,
/*
timeout: 0,
data: null,
dataType: null,
username: null,
password: null,
cache: null,
throws: false,
traditional: false,
headers: {},
*/
accepts: {
xml: "application/xml, text/xml",
html: "text/html",
text: "text/plain",
json: "application/json, text/javascript",
"*": allTypes
},
contents: {
xml: /xml/,
html: /html/,
json: /json/
},
responseFields: {
xml: "responseXML",
text: "responseText"
},
// List of data converters
// 1) key format is "source_type destination_type" (a single space in-between)
// 2) the catchall symbol "*" can be used for source_type
converters: {
// Convert anything to text
"* text": window.String,
// Text to html (true = no transformation)
"text html": true,
// Evaluate text as a json expression
"text json": jQuery.parseJSON,
// Parse text as xml
"text xml": jQuery.parseXML
},
// For options that shouldn't be deep extended:
// you can add your own custom options here if
// and when you create one that shouldn't be
// deep extended (see ajaxExtend)
flatOptions: {
context: true,
url: true
}
},
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
// Main method
ajax: function( url, options ) {
// If url is an object, simulate pre-1.5 signature
if ( typeof url === "object" ) {
options = url;
url = undefined;
}
// Force options to be an object
options = options || {};
var // ifModified key
ifModifiedKey,
// Response headers
responseHeadersString,
responseHeaders,
// transport
transport,
// timeout handle
timeoutTimer,
// Cross-domain detection vars
parts,
// To know if global events are to be dispatched
fireGlobals,
// Loop variable
i,
// Create the final options object
s = jQuery.ajaxSetup( {}, options ),
// Callbacks context
callbackContext = s.context || s,
// Context for global events
// It's the callbackContext if one was provided in the options
// and if it's a DOM node or a jQuery collection
globalEventContext = callbackContext !== s &&
( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
jQuery( callbackContext ) : jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks( "once memory" ),
// Status-dependent callbacks
statusCode = s.statusCode || {},
// Headers (they are sent all at once)
requestHeaders = {},
requestHeadersNames = {},
// The jqXHR state
state = 0,
// Default abort message
strAbort = "canceled",
// Fake xhr
jqXHR = {
readyState: 0,
// Caches the header
setRequestHeader: function( name, value ) {
if ( !state ) {
var lname = name.toLowerCase();
name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
requestHeaders[ name ] = value;
}
return this;
},
// Raw string
getAllResponseHeaders: function() {
return state === 2 ? responseHeadersString : null;
},
// Builds headers hashtable if needed
getResponseHeader: function( key ) {
var match;
if ( state === 2 ) {
if ( !responseHeaders ) {
responseHeaders = {};
while( ( match = rheaders.exec( responseHeadersString ) ) ) {
responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
}
}
match = responseHeaders[ key.toLowerCase() ];
}
return match === undefined ? null : match;
},
// Overrides response content-type header
overrideMimeType: function( type ) {
if ( !state ) {
s.mimeType = type;
}
return this;
},
// Cancel the request
abort: function( statusText ) {
statusText = statusText || strAbort;
if ( transport ) {
transport.abort( statusText );
}
done( 0, statusText );
return this;
}
};
// Callback for when everything is done
// It is defined here because jslint complains if it is declared
// at the end of the function (which would be more logical and readable)
function done( status, nativeStatusText, responses, headers ) {
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;
// Called once
if ( state === 2 ) {
return;
}
// State is "done" now
state = 2;
// Clear timeout if it exists
if ( timeoutTimer ) {
clearTimeout( timeoutTimer );
}
// Dereference transport for early garbage collection
// (no matter how long the jqXHR object will be used)
transport = undefined;
// Cache response headers
responseHeadersString = headers || "";
// Set readyState
jqXHR.readyState = status > 0 ? 4 : 0;
// Get response data
if ( responses ) {
response = ajaxHandleResponses( s, jqXHR, responses );
}
// If successful, handle type chaining
if ( status >= 200 && status < 300 || status === 304 ) {
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
modified = jqXHR.getResponseHeader("Last-Modified");
if ( modified ) {
jQuery.lastModified[ ifModifiedKey ] = modified;
}
modified = jqXHR.getResponseHeader("Etag");
if ( modified ) {
jQuery.etag[ ifModifiedKey ] = modified;
}
}
// If not modified
if ( status === 304 ) {
statusText = "notmodified";
isSuccess = true;
// If we have data
} else {
isSuccess = ajaxConvert( s, response );
statusText = isSuccess.state;
success = isSuccess.data;
error = isSuccess.error;
isSuccess = !error;
}
} else {
// We extract error from statusText
// then normalize statusText and status for non-aborts
error = statusText;
if ( !statusText || status ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
}
}
}
// Set data for the fake xhr object
jqXHR.status = status;
jqXHR.statusText = "" + ( nativeStatusText || statusText );
// Success/Error
if ( isSuccess ) {
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
} else {
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
}
// Status-dependent callbacks
jqXHR.statusCode( statusCode );
statusCode = undefined;
if ( fireGlobals ) {
globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
[ jqXHR, s, isSuccess ? success : error ] );
}
// Complete
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
jQuery.event.trigger( "ajaxStop" );
}
}
}
// Attach deferreds
deferred.promise( jqXHR );
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
jqXHR.complete = completeDeferred.add;
// Status-dependent callbacks
jqXHR.statusCode = function( map ) {
if ( map ) {
var tmp;
if ( state < 2 ) {
for ( tmp in map ) {
statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
}
} else {
tmp = map[ jqXHR.status ];
jqXHR.always( tmp );
}
}
return this;
};
// Remove hash character (#7531: and string promotion)
// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
// We also use the url parameter if available
s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
// Extract dataTypes list
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace );
// Determine if a cross-domain request is in order
if ( s.crossDomain == null ) {
parts = rurl.exec( s.url.toLowerCase() );
s.crossDomain = !!( parts &&
( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
);
}
// Convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param( s.data, s.traditional );
}
// Apply prefilters
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
// If request was aborted inside a prefilter, stop there
if ( state === 2 ) {
return jqXHR;
}
// We can fire global events as of now if asked to
fireGlobals = s.global;
// Uppercase the type
s.type = s.type.toUpperCase();
// Determine if request has content
s.hasContent = !rnoContent.test( s.type );
// Watch for a new set of requests
if ( fireGlobals && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}
// More options handling for requests with no content
if ( !s.hasContent ) {
// If data is available, append data to url
if ( s.data ) {
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}
// Get ifModifiedKey before adding the anti-cache parameter
ifModifiedKey = s.url;
// Add anti-cache in url if needed
if ( s.cache === false ) {
var ts = jQuery.now(),
// try replacing _= if it is there
ret = s.url.replace( rts, "$1_=" + ts );
// if nothing was replaced, add timestamp to the end
s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
}
}
// Set the correct header, if data is being sent
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
jqXHR.setRequestHeader( "Content-Type", s.contentType );
}
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
ifModifiedKey = ifModifiedKey || s.url;
if ( jQuery.lastModified[ ifModifiedKey ] ) {
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
}
if ( jQuery.etag[ ifModifiedKey ] ) {
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
}
}
// Set the Accepts header for the server, depending on the dataType
jqXHR.setRequestHeader(
"Accept",
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
s.accepts[ "*" ]
);
// Check for headers option
for ( i in s.headers ) {
jqXHR.setRequestHeader( i, s.headers[ i ] );
}
// Allow custom headers/mimetypes and early abort
if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
// Abort if not done already and return
return jqXHR.abort();
}
// aborting is no longer a cancellation
strAbort = "abort";
// Install callbacks on deferreds
for ( i in { success: 1, error: 1, complete: 1 } ) {
jqXHR[ i ]( s[ i ] );
}
// Get transport
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
// If no transport, we auto-abort
if ( !transport ) {
done( -1, "No Transport" );
} else {
jqXHR.readyState = 1;
// Send global event
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
}
// Timeout
if ( s.async && s.timeout > 0 ) {
timeoutTimer = setTimeout( function(){
jqXHR.abort( "timeout" );
}, s.timeout );
}
try {
state = 1;
transport.send( requestHeaders, done );
} catch (e) {
// Propagate exception as error if not done
if ( state < 2 ) {
done( -1, e );
// Simply rethrow otherwise
} else {
throw e;
}
}
}
return jqXHR;
},
// Counter for holding the number of active queries
active: 0,
// Last-Modified header cache for next request
lastModified: {},
etag: {}
});
/* Handles responses to an ajax request:
* - sets all responseXXX fields accordingly
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
function ajaxHandleResponses( s, jqXHR, responses ) {
var ct, type, finalDataType, firstDataType,
contents = s.contents,
dataTypes = s.dataTypes,
responseFields = s.responseFields;
// Fill responseXXX fields
for ( type in responseFields ) {
if ( type in responses ) {
jqXHR[ responseFields[type] ] = responses[ type ];
}
}
// Remove auto dataType and get content-type in the process
while( dataTypes[ 0 ] === "*" ) {
dataTypes.shift();
if ( ct === undefined ) {
ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
}
}
// Check if we're dealing with a known content-type
if ( ct ) {
for ( type in contents ) {
if ( contents[ type ] && contents[ type ].test( ct ) ) {
dataTypes.unshift( type );
break;
}
}
}
// Check to see if we have a response for the expected dataType
if ( dataTypes[ 0 ] in responses ) {
finalDataType = dataTypes[ 0 ];
} else {
// Try convertible dataTypes
for ( type in responses ) {
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
finalDataType = type;
break;
}
if ( !firstDataType ) {
firstDataType = type;
}
}
// Or just use first one
finalDataType = finalDataType || firstDataType;
}
// If we found a dataType
// We add the dataType to the list if needed
// and return the corresponding response
if ( finalDataType ) {
if ( finalDataType !== dataTypes[ 0 ] ) {
dataTypes.unshift( finalDataType );
}
return responses[ finalDataType ];
}
}
// Chain conversions given the request and the original response
function ajaxConvert( s, response ) {
var conv, conv2, current, tmp,
// Work with a copy of dataTypes in case we need to modify it for conversion
dataTypes = s.dataTypes.slice(),
prev = dataTypes[ 0 ],
converters = {},
i = 0;
// Apply the dataFilter if provided
if ( s.dataFilter ) {
response = s.dataFilter( response, s.dataType );
}
// Create converters map with lowercased keys
if ( dataTypes[ 1 ] ) {
for ( conv in s.converters ) {
converters[ conv.toLowerCase() ] = s.converters[ conv ];
}
}
// Convert to each sequential dataType, tolerating list modification
for ( ; (current = dataTypes[++i]); ) {
// There's only work to do if current dataType is non-auto
if ( current !== "*" ) {
// Convert response if prev dataType is non-auto and differs from current
if ( prev !== "*" && prev !== current ) {
// Seek a direct converter
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
// If none found, seek a pair
if ( !conv ) {
for ( conv2 in converters ) {
// If conv2 outputs current
tmp = conv2.split(" ");
if ( tmp[ 1 ] === current ) {
// If prev can be converted to accepted input
conv = converters[ prev + " " + tmp[ 0 ] ] ||
converters[ "* " + tmp[ 0 ] ];
if ( conv ) {
// Condense equivalence converters
if ( conv === true ) {
conv = converters[ conv2 ];
// Otherwise, insert the intermediate dataType
} else if ( converters[ conv2 ] !== true ) {
current = tmp[ 0 ];
dataTypes.splice( i--, 0, current );
}
break;
}
}
}
}
// Apply converter (if not an equivalence)
if ( conv !== true ) {
// Unless errors are allowed to bubble, catch and return them
if ( conv && s["throws"] ) {
response = conv( response );
} else {
try {
response = conv( response );
} catch ( e ) {
return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
}
}
}
}
// Update prev for next iteration
prev = current;
}
}
return { state: "success", data: response };
}
var oldCallbacks = [],
rquestion = /\?/,
rjsonp = /(=)\?(?=&|$)|\?\?/,
nonce = jQuery.now();
// Default jsonp settings
jQuery.ajaxSetup({
jsonp: "callback",
jsonpCallback: function() {
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
this[ callback ] = true;
return callback;
}
});
// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
var callbackName, overwritten, responseContainer,
data = s.data,
url = s.url,
hasCallback = s.jsonp !== false,
replaceInUrl = hasCallback && rjsonp.test( url ),
replaceInData = hasCallback && !replaceInUrl && typeof data === "string" &&
!( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") &&
rjsonp.test( data );
// Handle iff the expected data type is "jsonp" or we have a parameter to set
if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) {
// Get callback name, remembering preexisting value associated with it
callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
s.jsonpCallback() :
s.jsonpCallback;
overwritten = window[ callbackName ];
// Insert callback into url or form data
if ( replaceInUrl ) {
s.url = url.replace( rjsonp, "$1" + callbackName );
} else if ( replaceInData ) {
s.data = data.replace( rjsonp, "$1" + callbackName );
} else if ( hasCallback ) {
s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
}
// Use data converter to retrieve json after script execution
s.converters["script json"] = function() {
if ( !responseContainer ) {
jQuery.error( callbackName + " was not called" );
}
return responseContainer[ 0 ];
};
// force json dataType
s.dataTypes[ 0 ] = "json";
// Install callback
window[ callbackName ] = function() {
responseContainer = arguments;
};
// Clean-up function (fires after converters)
jqXHR.always(function() {
// Restore preexisting value
window[ callbackName ] = overwritten;
// Save back as free
if ( s[ callbackName ] ) {
// make sure that re-using the options doesn't screw things around
s.jsonpCallback = originalSettings.jsonpCallback;
// save the callback name for future use
oldCallbacks.push( callbackName );
}
// Call if it was a function and we have a response
if ( responseContainer && jQuery.isFunction( overwritten ) ) {
overwritten( responseContainer[ 0 ] );
}
responseContainer = overwritten = undefined;
});
// Delegate to script
return "script";
}
});
// Install script dataType
jQuery.ajaxSetup({
accepts: {
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
},
contents: {
script: /javascript|ecmascript/
},
converters: {
"text script": function( text ) {
jQuery.globalEval( text );
return text;
}
}
});
// Handle cache's special case and global
jQuery.ajaxPrefilter( "script", function( s ) {
if ( s.cache === undefined ) {
s.cache = false;
}
if ( s.crossDomain ) {
s.type = "GET";
s.global = false;
}
});
// Bind script tag hack transport
jQuery.ajaxTransport( "script", function(s) {
// This transport only deals with cross domain requests
if ( s.crossDomain ) {
var script,
head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
return {
send: function( _, callback ) {
script = document.createElement( "script" );
script.async = "async";
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
}
script.src = s.url;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function( _, isAbort ) {
if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
// Remove the script
if ( head && script.parentNode ) {
head.removeChild( script );
}
// Dereference the script
script = undefined;
// Callback if not abort
if ( !isAbort ) {
callback( 200, "success" );
}
}
};
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore( script, head.firstChild );
},
abort: function() {
if ( script ) {
script.onload( 0, 1 );
}
}
};
}
});
var xhrCallbacks,
// #5280: Internet Explorer will keep connections alive if we don't abort on unload
xhrOnUnloadAbort = window.ActiveXObject ? function() {
// Abort all pending requests
for ( var key in xhrCallbacks ) {
xhrCallbacks[ key ]( 0, 1 );
}
} : false,
xhrId = 0;
// Functions to create xhrs
function createStandardXHR() {
try {
return new window.XMLHttpRequest();
} catch( e ) {}
}
function createActiveXHR() {
try {
return new window.ActiveXObject( "Microsoft.XMLHTTP" );
} catch( e ) {}
}
// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject ?
/* Microsoft failed to properly
* implement the XMLHttpRequest in IE7 (can't request local files),
* so we use the ActiveXObject when it is available
* Additionally XMLHttpRequest can be disabled in IE7/IE8 so
* we need a fallback.
*/
function() {
return !this.isLocal && createStandardXHR() || createActiveXHR();
} :
// For all other browsers, use the standard XMLHttpRequest object
createStandardXHR;
// Determine support properties
(function( xhr ) {
jQuery.extend( jQuery.support, {
ajax: !!xhr,
cors: !!xhr && ( "withCredentials" in xhr )
});
})( jQuery.ajaxSettings.xhr() );
// Create transport if the browser can provide an xhr
if ( jQuery.support.ajax ) {
jQuery.ajaxTransport(function( s ) {
// Cross domain only allowed if supported through XMLHttpRequest
if ( !s.crossDomain || jQuery.support.cors ) {
var callback;
return {
send: function( headers, complete ) {
// Get a new xhr
var handle, i,
xhr = s.xhr();
// Open the socket
// Passing null username, generates a login popup on Opera (#2865)
if ( s.username ) {
xhr.open( s.type, s.url, s.async, s.username, s.password );
} else {
xhr.open( s.type, s.url, s.async );
}
// Apply custom fields if provided
if ( s.xhrFields ) {
for ( i in s.xhrFields ) {
xhr[ i ] = s.xhrFields[ i ];
}
}
// Override mime type if needed
if ( s.mimeType && xhr.overrideMimeType ) {
xhr.overrideMimeType( s.mimeType );
}
// X-Requested-With header
// For cross-domain requests, seeing as conditions for a preflight are
// akin to a jigsaw puzzle, we simply never set it to be sure.
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
if ( !s.crossDomain && !headers["X-Requested-With"] ) {
headers[ "X-Requested-With" ] = "XMLHttpRequest";
}
// Need an extra try/catch for cross domain requests in Firefox 3
try {
for ( i in headers ) {
xhr.setRequestHeader( i, headers[ i ] );
}
} catch( _ ) {}
// Do send the request
// This may raise an exception which is actually
// handled in jQuery.ajax (so no try/catch here)
xhr.send( ( s.hasContent && s.data ) || null );
// Listener
callback = function( _, isAbort ) {
var status,
statusText,
responseHeaders,
responses,
xml;
// Firefox throws exceptions when accessing properties
// of an xhr when a network error occurred
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
try {
// Was never called and is aborted or complete
if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
// Only called once
callback = undefined;
// Do not keep as active anymore
if ( handle ) {
xhr.onreadystatechange = jQuery.noop;
if ( xhrOnUnloadAbort ) {
delete xhrCallbacks[ handle ];
}
}
// If it's an abort
if ( isAbort ) {
// Abort it manually if needed
if ( xhr.readyState !== 4 ) {
xhr.abort();
}
} else {
status = xhr.status;
responseHeaders = xhr.getAllResponseHeaders();
responses = {};
xml = xhr.responseXML;
// Construct response list
if ( xml && xml.documentElement /* #4958 */ ) {
responses.xml = xml;
}
// When requesting binary data, IE6-9 will throw an exception
// on any attempt to access responseText (#11426)
try {
responses.text = xhr.responseText;
} catch( _ ) {
}
// Firefox throws an exception when accessing
// statusText for faulty cross-domain requests
try {
statusText = xhr.statusText;
} catch( e ) {
// We normalize with Webkit giving an empty statusText
statusText = "";
}
// Filter status for non standard behaviors
// If the request is local and we have data: assume a success
// (success with no data won't get notified, that's the best we
// can do given current implementations)
if ( !status && s.isLocal && !s.crossDomain ) {
status = responses.text ? 200 : 404;
// IE - #1450: sometimes returns 1223 when it should be 204
} else if ( status === 1223 ) {
status = 204;
}
}
}
} catch( firefoxAccessException ) {
if ( !isAbort ) {
complete( -1, firefoxAccessException );
}
}
// Call complete if needed
if ( responses ) {
complete( status, statusText, responses, responseHeaders );
}
};
if ( !s.async ) {
// if we're in sync mode we fire the callback
callback();
} else if ( xhr.readyState === 4 ) {
// (IE6 & IE7) if it's in cache and has been
// retrieved directly we need to fire the callback
setTimeout( callback, 0 );
} else {
handle = ++xhrId;
if ( xhrOnUnloadAbort ) {
// Create the active xhrs callbacks list if needed
// and attach the unload handler
if ( !xhrCallbacks ) {
xhrCallbacks = {};
jQuery( window ).unload( xhrOnUnloadAbort );
}
// Add to list of active xhrs callbacks
xhrCallbacks[ handle ] = callback;
}
xhr.onreadystatechange = callback;
}
},
abort: function() {
if ( callback ) {
callback(0,1);
}
}
};
}
});
}
var fxNow, timerId,
rfxtypes = /^(?:toggle|show|hide)$/,
rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
rrun = /queueHooks$/,
animationPrefilters = [ defaultPrefilter ],
tweeners = {
"*": [function( prop, value ) {
var end, unit, prevScale,
tween = this.createTween( prop, value ),
parts = rfxnum.exec( value ),
target = tween.cur(),
start = +target || 0,
scale = 1;
if ( parts ) {
end = +parts[2];
unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
// We need to compute starting value
if ( unit !== "px" && start ) {
// Iteratively approximate from a nonzero starting point
// Prefer the current property, because this process will be trivial if it uses the same units
// Fallback to end or a simple constant
start = jQuery.css( tween.elem, prop, true ) || end || 1;
do {
// If previous iteration zeroed out, double until we get *something*
// Use a string for doubling factor so we don't accidentally see scale as unchanged below
prevScale = scale = scale || ".5";
// Adjust and apply
start = start / scale;
jQuery.style( tween.elem, prop, start + unit );
// Update scale, tolerating zeroes from tween.cur()
scale = tween.cur() / target;
// Stop looping if we've hit the mark or scale is unchanged
} while ( scale !== 1 && scale !== prevScale );
}
tween.unit = unit;
tween.start = start;
// If a +=/-= token was provided, we're doing a relative animation
tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
}
return tween;
}]
};
// Animations created synchronously will run synchronously
function createFxNow() {
setTimeout(function() {
fxNow = undefined;
}, 0 );
return ( fxNow = jQuery.now() );
}
function createTweens( animation, props ) {
jQuery.each( props, function( prop, value ) {
var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
index = 0,
length = collection.length;
for ( ; index < length; index++ ) {
if ( collection[ index ].call( animation, prop, value ) ) {
// we're done with this property
return;
}
}
});
}
function Animation( elem, properties, options ) {
var result,
index = 0,
tweenerIndex = 0,
length = animationPrefilters.length,
deferred = jQuery.Deferred().always( function() {
// don't match elem in the :animated selector
delete tick.elem;
}),
tick = function() {
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
percent = 1 - ( remaining / animation.duration || 0 ),
index = 0,
length = animation.tweens.length;
for ( ; index < length ; index++ ) {
animation.tweens[ index ].run( percent );
}
deferred.notifyWith( elem, [ animation, percent, remaining ]);
if ( percent < 1 && length ) {
return remaining;
} else {
deferred.resolveWith( elem, [ animation ] );
return false;
}
},
animation = deferred.promise({
elem: elem,
props: jQuery.extend( {}, properties ),
opts: jQuery.extend( true, { specialEasing: {} }, options ),
originalProperties: properties,
originalOptions: options,
startTime: fxNow || createFxNow(),
duration: options.duration,
tweens: [],
createTween: function( prop, end, easing ) {
var tween = jQuery.Tween( elem, animation.opts, prop, end,
animation.opts.specialEasing[ prop ] || animation.opts.easing );
animation.tweens.push( tween );
return tween;
},
stop: function( gotoEnd ) {
var index = 0,
// if we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;
for ( ; index < length ; index++ ) {
animation.tweens[ index ].run( 1 );
}
// resolve when we played the last frame
// otherwise, reject
if ( gotoEnd ) {
deferred.resolveWith( elem, [ animation, gotoEnd ] );
} else {
deferred.rejectWith( elem, [ animation, gotoEnd ] );
}
return this;
}
}),
props = animation.props;
propFilter( props, animation.opts.specialEasing );
for ( ; index < length ; index++ ) {
result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
if ( result ) {
return result;
}
}
createTweens( animation, props );
if ( jQuery.isFunction( animation.opts.start ) ) {
animation.opts.start.call( elem, animation );
}
jQuery.fx.timer(
jQuery.extend( tick, {
anim: animation,
queue: animation.opts.queue,
elem: elem
})
);
// attach callbacks from options
return animation.progress( animation.opts.progress )
.done( animation.opts.done, animation.opts.complete )
.fail( animation.opts.fail )
.always( animation.opts.always );
}
function propFilter( props, specialEasing ) {
var index, name, easing, value, hooks;
// camelCase, specialEasing and expand cssHook pass
for ( index in props ) {
name = jQuery.camelCase( index );
easing = specialEasing[ name ];
value = props[ index ];
if ( jQuery.isArray( value ) ) {
easing = value[ 1 ];
value = props[ index ] = value[ 0 ];
}
if ( index !== name ) {
props[ name ] = value;
delete props[ index ];
}
hooks = jQuery.cssHooks[ name ];
if ( hooks && "expand" in hooks ) {
value = hooks.expand( value );
delete props[ name ];
// not quite $.extend, this wont overwrite keys already present.
// also - reusing 'index' from above because we have the correct "name"
for ( index in value ) {
if ( !( index in props ) ) {
props[ index ] = value[ index ];
specialEasing[ index ] = easing;
}
}
} else {
specialEasing[ name ] = easing;
}
}
}
jQuery.Animation = jQuery.extend( Animation, {
tweener: function( props, callback ) {
if ( jQuery.isFunction( props ) ) {
callback = props;
props = [ "*" ];
} else {
props = props.split(" ");
}
var prop,
index = 0,
length = props.length;
for ( ; index < length ; index++ ) {
prop = props[ index ];
tweeners[ prop ] = tweeners[ prop ] || [];
tweeners[ prop ].unshift( callback );
}
},
prefilter: function( callback, prepend ) {
if ( prepend ) {
animationPrefilters.unshift( callback );
} else {
animationPrefilters.push( callback );
}
}
});
function defaultPrefilter( elem, props, opts ) {
var index, prop, value, length, dataShow, tween, hooks, oldfire,
anim = this,
style = elem.style,
orig = {},
handled = [],
hidden = elem.nodeType && isHidden( elem );
// handle queue: false promises
if ( !opts.queue ) {
hooks = jQuery._queueHooks( elem, "fx" );
if ( hooks.unqueued == null ) {
hooks.unqueued = 0;
oldfire = hooks.empty.fire;
hooks.empty.fire = function() {
if ( !hooks.unqueued ) {
oldfire();
}
};
}
hooks.unqueued++;
anim.always(function() {
// doing this makes sure that the complete handler will be called
// before this completes
anim.always(function() {
hooks.unqueued--;
if ( !jQuery.queue( elem, "fx" ).length ) {
hooks.empty.fire();
}
});
});
}
// height/width overflow pass
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
// Make sure that nothing sneaks out
// Record all 3 overflow attributes because IE does not
// change the overflow attribute when overflowX and
// overflowY are set to the same value
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
// Set display property to inline-block for height/width
// animations on inline elements that are having width/height animated
if ( jQuery.css( elem, "display" ) === "inline" &&
jQuery.css( elem, "float" ) === "none" ) {
// inline-level elements accept inline-block;
// block-level elements need to be inline with layout
if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
style.display = "inline-block";
} else {
style.zoom = 1;
}
}
}
if ( opts.overflow ) {
style.overflow = "hidden";
if ( !jQuery.support.shrinkWrapBlocks ) {
anim.done(function() {
style.overflow = opts.overflow[ 0 ];
style.overflowX = opts.overflow[ 1 ];
style.overflowY = opts.overflow[ 2 ];
});
}
}
// show/hide pass
for ( index in props ) {
value = props[ index ];
if ( rfxtypes.exec( value ) ) {
delete props[ index ];
if ( value === ( hidden ? "hide" : "show" ) ) {
continue;
}
handled.push( index );
}
}
length = handled.length;
if ( length ) {
dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
if ( hidden ) {
jQuery( elem ).show();
} else {
anim.done(function() {
jQuery( elem ).hide();
});
}
anim.done(function() {
var prop;
jQuery.removeData( elem, "fxshow", true );
for ( prop in orig ) {
jQuery.style( elem, prop, orig[ prop ] );
}
});
for ( index = 0 ; index < length ; index++ ) {
prop = handled[ index ];
tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
if ( !( prop in dataShow ) ) {
dataShow[ prop ] = tween.start;
if ( hidden ) {
tween.end = tween.start;
tween.start = prop === "width" || prop === "height" ? 1 : 0;
}
}
}
}
}
function Tween( elem, options, prop, end, easing ) {
return new Tween.prototype.init( elem, options, prop, end, easing );
}
jQuery.Tween = Tween;
Tween.prototype = {
constructor: Tween,
init: function( elem, options, prop, end, easing, unit ) {
this.elem = elem;
this.prop = prop;
this.easing = easing || "swing";
this.options = options;
this.start = this.now = this.cur();
this.end = end;
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
},
cur: function() {
var hooks = Tween.propHooks[ this.prop ];
return hooks && hooks.get ?
hooks.get( this ) :
Tween.propHooks._default.get( this );
},
run: function( percent ) {
var eased,
hooks = Tween.propHooks[ this.prop ];
this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration );
this.now = ( this.end - this.start ) * eased + this.start;
if ( this.options.step ) {
this.options.step.call( this.elem, this.now, this );
}
if ( hooks && hooks.set ) {
hooks.set( this );
} else {
Tween.propHooks._default.set( this );
}
return this;
}
};
Tween.prototype.init.prototype = Tween.prototype;
Tween.propHooks = {
_default: {
get: function( tween ) {
var result;
if ( tween.elem[ tween.prop ] != null &&
(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
return tween.elem[ tween.prop ];
}
// passing any value as a 4th parameter to .css will automatically
// attempt a parseFloat and fallback to a string if the parse fails
// so, simple values such as "10px" are parsed to Float.
// complex values such as "rotate(1rad)" are returned as is.
result = jQuery.css( tween.elem, tween.prop, false, "" );
// Empty strings, null, undefined and "auto" are converted to 0.
return !result || result === "auto" ? 0 : result;
},
set: function( tween ) {
// use step hook for back compat - use cssHook if its there - use .style if its
// available and use plain properties where available
if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween );
} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
} else {
tween.elem[ tween.prop ] = tween.now;
}
}
}
};
// Remove in 2.0 - this supports IE8's panic based approach
// to setting things on disconnected nodes
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
set: function( tween ) {
if ( tween.elem.nodeType && tween.elem.parentNode ) {
tween.elem[ tween.prop ] = tween.now;
}
}
};
jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = jQuery.fn[ name ];
jQuery.fn[ name ] = function( speed, easing, callback ) {
return speed == null || typeof speed === "boolean" ||
// special check for .toggle( handler, handler, ... )
( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ?
cssFn.apply( this, arguments ) :
this.animate( genFx( name, true ), speed, easing, callback );
};
});
jQuery.fn.extend({
fadeTo: function( speed, to, easing, callback ) {
// show any hidden elements after setting opacity to 0
return this.filter( isHidden ).css( "opacity", 0 ).show()
// animate to the value specified
.end().animate({ opacity: to }, speed, easing, callback );
},
animate: function( prop, speed, easing, callback ) {
var empty = jQuery.isEmptyObject( prop ),
optall = jQuery.speed( speed, easing, callback ),
doAnimation = function() {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
// Empty animations resolve immediately
if ( empty ) {
anim.stop( true );
}
};
return empty || optall.queue === false ?
this.each( doAnimation ) :
this.queue( optall.queue, doAnimation );
},
stop: function( type, clearQueue, gotoEnd ) {
var stopQueue = function( hooks ) {
var stop = hooks.stop;
delete hooks.stop;
stop( gotoEnd );
};
if ( typeof type !== "string" ) {
gotoEnd = clearQueue;
clearQueue = type;
type = undefined;
}
if ( clearQueue && type !== false ) {
this.queue( type || "fx", [] );
}
return this.each(function() {
var dequeue = true,
index = type != null && type + "queueHooks",
timers = jQuery.timers,
data = jQuery._data( this );
if ( index ) {
if ( data[ index ] && data[ index ].stop ) {
stopQueue( data[ index ] );
}
} else {
for ( index in data ) {
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
stopQueue( data[ index ] );
}
}
}
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
timers[ index ].anim.stop( gotoEnd );
dequeue = false;
timers.splice( index, 1 );
}
}
// start the next in the queue if the last step wasn't forced
// timers currently will call their complete callbacks, which will dequeue
// but only if they were gotoEnd
if ( dequeue || !gotoEnd ) {
jQuery.dequeue( this, type );
}
});
}
});
// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
var which,
attrs = { height: type },
i = 0;
// if we include width, step value is 1 to do all cssExpand values,
// if we don't include width, step value is 2 to skip over Left and Right
for( ; i < 4 ; i += 2 - includeWidth ) {
which = cssExpand[ i ];
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
}
if ( includeWidth ) {
attrs.opacity = attrs.width = type;
}
return attrs;
}
// Generate shortcuts for custom animations
jQuery.each({
slideDown: genFx("show"),
slideUp: genFx("hide"),
slideToggle: genFx("toggle"),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
jQuery.fn[ name ] = function( speed, easing, callback ) {
return this.animate( props, speed, easing, callback );
};
});
jQuery.speed = function( speed, easing, fn ) {
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
// normalize opt.queue - true/undefined/null -> "fx"
if ( opt.queue == null || opt.queue === true ) {
opt.queue = "fx";
}
// Queueing
opt.old = opt.complete;
opt.complete = function() {
if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
if ( opt.queue ) {
jQuery.dequeue( this, opt.queue );
}
};
return opt;
};
jQuery.easing = {
linear: function( p ) {
return p;
},
swing: function( p ) {
return 0.5 - Math.cos( p*Math.PI ) / 2;
}
};
jQuery.timers = [];
jQuery.fx = Tween.prototype.init;
jQuery.fx.tick = function() {
var timer,
timers = jQuery.timers,
i = 0;
for ( ; i < timers.length; i++ ) {
timer = timers[ i ];
// Checks the timer has not already been removed
if ( !timer() && timers[ i ] === timer ) {
timers.splice( i--, 1 );
}
}
if ( !timers.length ) {
jQuery.fx.stop();
}
};
jQuery.fx.timer = function( timer ) {
if ( timer() && jQuery.timers.push( timer ) && !timerId ) {
timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
}
};
jQuery.fx.interval = 13;
jQuery.fx.stop = function() {
clearInterval( timerId );
timerId = null;
};
jQuery.fx.speeds = {
slow: 600,
fast: 200,
// Default speed
_default: 400
};
// Back Compat <1.8 extension point
jQuery.fx.step = {};
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.animated = function( elem ) {
return jQuery.grep(jQuery.timers, function( fn ) {
return elem === fn.elem;
}).length;
};
}
var rroot = /^(?:body|html)$/i;
jQuery.fn.offset = function( options ) {
if ( arguments.length ) {
return options === undefined ?
this :
this.each(function( i ) {
jQuery.offset.setOffset( this, options, i );
});
}
var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left,
elem = this[ 0 ],
doc = elem && elem.ownerDocument;
if ( !doc ) {
return;
}
if ( (body = doc.body) === elem ) {
return jQuery.offset.bodyOffset( elem );
}
docElem = doc.documentElement;
// Make sure we're not dealing with a disconnected DOM node
if ( !jQuery.contains( docElem, elem ) ) {
return { top: 0, left: 0 };
}
box = elem.getBoundingClientRect();
win = getWindow( doc );
clientTop = docElem.clientTop || body.clientTop || 0;
clientLeft = docElem.clientLeft || body.clientLeft || 0;
scrollTop = win.pageYOffset || docElem.scrollTop;
scrollLeft = win.pageXOffset || docElem.scrollLeft;
top = box.top + scrollTop - clientTop;
left = box.left + scrollLeft - clientLeft;
return { top: top, left: left };
};
jQuery.offset = {
bodyOffset: function( body ) {
var top = body.offsetTop,
left = body.offsetLeft;
if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
}
return { top: top, left: left };
},
setOffset: function( elem, options, i ) {
var position = jQuery.css( elem, "position" );
// set position first, in-case top/left are set even on static elem
if ( position === "static" ) {
elem.style.position = "relative";
}
var curElem = jQuery( elem ),
curOffset = curElem.offset(),
curCSSTop = jQuery.css( elem, "top" ),
curCSSLeft = jQuery.css( elem, "left" ),
calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
props = {}, curPosition = {}, curTop, curLeft;
// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();
curTop = curPosition.top;
curLeft = curPosition.left;
} else {
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
}
if ( jQuery.isFunction( options ) ) {
options = options.call( elem, i, curOffset );
}
if ( options.top != null ) {
props.top = ( options.top - curOffset.top ) + curTop;
}
if ( options.left != null ) {
props.left = ( options.left - curOffset.left ) + curLeft;
}
if ( "using" in options ) {
options.using.call( elem, props );
} else {
curElem.css( props );
}
}
};
jQuery.fn.extend({
position: function() {
if ( !this[0] ) {
return;
}
var elem = this[0],
// Get *real* offsetParent
offsetParent = this.offsetParent(),
// Get correct offsets
offset = this.offset(),
parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
// Subtract element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
// Add offsetParent borders
parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
// Subtract the two offsets
return {
top: offset.top - parentOffset.top,
left: offset.left - parentOffset.left
};
},
offsetParent: function() {
return this.map(function() {
var offsetParent = this.offsetParent || document.body;
while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent || document.body;
});
}
});
// Create scrollLeft and scrollTop methods
jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
var top = /Y/.test( prop );
jQuery.fn[ method ] = function( val ) {
return jQuery.access( this, function( elem, method, val ) {
var win = getWindow( elem );
if ( val === undefined ) {
return win ? (prop in win) ? win[ prop ] :
win.document.documentElement[ method ] :
elem[ method ];
}
if ( win ) {
win.scrollTo(
!top ? val : jQuery( win ).scrollLeft(),
top ? val : jQuery( win ).scrollTop()
);
} else {
elem[ method ] = val;
}
}, method, val, arguments.length, null );
};
});
function getWindow( elem ) {
return jQuery.isWindow( elem ) ?
elem :
elem.nodeType === 9 ?
elem.defaultView || elem.parentWindow :
false;
}
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
// margin is only for outerHeight, outerWidth
jQuery.fn[ funcName ] = function( margin, value ) {
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
return jQuery.access( this, function( elem, type, value ) {
var doc;
if ( jQuery.isWindow( elem ) ) {
// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
// isn't a whole lot we can do. See pull request at this URL for discussion:
// https://github.com/jquery/jquery/pull/764
return elem.document.documentElement[ "client" + name ];
}
// Get document width or height
if ( elem.nodeType === 9 ) {
doc = elem.documentElement;
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
return Math.max(
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
elem.body[ "offset" + name ], doc[ "offset" + name ],
doc[ "client" + name ]
);
}
return value === undefined ?
// Get width or height on the element, requesting but not forcing parseFloat
jQuery.css( elem, type, value, extra ) :
// Set width or height on the element
jQuery.style( elem, type, value, extra );
}, type, chainable ? margin : undefined, chainable );
};
});
});
// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;
// Expose jQuery as an AMD module, but only for AMD loaders that
// understand the issues with loading multiple versions of jQuery
// in a page that all might call define(). The loader will indicate
// they have special allowances for multiple jQuery versions by
// specifying define.amd.jQuery = true. Register as a named module,
// since jQuery can be concatenated with other files that may use define,
// but not use a proper concatenation script that understands anonymous
// AMD modules. A named AMD is safest and most robust way to register.
// Lowercase jquery is used because AMD module names are derived from
// file names, and jQuery is normally delivered in a lowercase file name.
// Do this after creating the global so that if an AMD module wants to call
// noConflict to hide this version of jQuery, it will work.
if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define( "jquery", [], function () { return jQuery; } );
}
})( window );

View File

@ -1,87 +0,0 @@
/**
* Very basic Class utility. Based on base and jquery.class.
*
* Class definition: var Foo = Base.extend({ init: function(){ Constructor }; method_name: function(){ Method } });
*
* Inheritance: var Bar = Foo.extend({ method_name: function(){ this._super(); } });
*
* new-less Constructor: new Foo(arg) <-same as-> Foo(arg)
*/
var Base;
(function(){
var marker = {}, fnTest = /xyz/.test(function(){var xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
Base = function(){};
Base.addMethod = function(name, func) {
var parent = this._super && this._super.prototype;
if (parent && fnTest.test(func)) {
this.prototype[name] = function(){
var tmp = this._super;
this._super = parent[name];
try {
var ret = func.apply(this, arguments);
}
finally {
this._super = tmp;
}
return ret;
};
}
else this.prototype[name] = func;
};
Base.addMethods = function(props) {
for (var name in props) {
if (typeof props[name] == 'function') this.addMethod(name, props[name]);
else this.prototype[name] = props[name];
}
};
Base.subclassOf = function(parentkls) {
var kls = this;
while (kls) {
if (kls === parentkls) return true;
kls = kls._super;
}
};
// Create a new Class that inherits from this class
Base.extend = function(props) {
// The dummy class constructor
var Kls = function() {
if (arguments[0] === marker) return;
if (this instanceof Kls) {
if (this.init) this.init.apply(this, arguments);
}
else {
var ret = new Kls(marker); if (ret.init) ret.init.apply(ret, arguments); return ret;
}
};
// Add the common class variables and methods
Kls.constructor = Kls;
Kls.extend = Base.extend;
Kls.addMethod = Base.addMethod;
Kls.addMethods = Base.addMethods;
Kls.subclassOf = Base.subclassOf;
Kls._super = this;
// Attach the parent object to the inheritance chain
Kls.prototype = new this(marker);
Kls.prototype.constructor = Kls;
// Copy the properties over onto the new prototype
Kls.addMethods(props);
return Kls;
};
})();

View File

@ -1,188 +0,0 @@
(function($){
var tokens = {
UNICODE: /\\[0-9a-f]{1,6}(?:\r\n|[ \n\r\t\f])?/,
ESCAPE: /(?:UNICODE)|\\[^\n\r\f0-9a-f]/,
NONASCII: /[^\x00-\x7F]/,
NMSTART: /[_a-z]|(?:NONASCII)|(?:ESCAPE)/,
NMCHAR: /[_a-z0-9-]|(?:NONASCII)|(?:ESCAPE)/,
IDENT: /-?(?:NMSTART)(?:NMCHAR)*/,
NL: /\n|\r\n|\r|\f/,
STRING: /(?:STRING1)|(?:STRING2)|(?:STRINGBARE)/,
STRING1: /"(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\"])*"/,
STRING2: /'(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\'])*'/,
STRINGBARE: /(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\]])*/,
FUNCTION: /(?:IDENT)\(\)/,
INTEGER: /[0-9]+/,
WITHN: /([-+])?(INTEGER)?(n)\s*(?:([-+])\s*(INTEGER))?/,
WITHOUTN: /([-+])?(INTEGER)/
};
var rx = {
not: /:not\(/,
not_end: /\)/,
tag: /((?:IDENT)|\*)/,
id: /#(IDENT)/,
cls: /\.(IDENT)/,
attr: /\[\s*(IDENT)\s*(?:([^=]?=)\s*(STRING)\s*)?\]/,
pseudo_el: /(?::(first-line|first-letter|before|after))|(?:::((?:FUNCTION)|(?:IDENT)))/,
pseudo_cls_nth: /:nth-child\(\s*(?:(?:WITHN)|(?:WITHOUTN)|(odd|even))\s*\)/,
pseudo_cls: /:(IDENT)/,
comb: /\s*(\+|~|>)\s*|\s+/,
comma: /\s*,\s*/,
important: /\s+!important\s*$/
};
/* Replace placeholders with actual regex, and mark all as case insensitive */
var token = /[A-Z][A-Z0-9]+/;
for (var k in rx) {
var m, src = rx[k].source;
while (m = src.match(token)) src = src.replace(m[0], tokens[m[0]].source);
rx[k] = new RegExp(src, 'gi');
}
/**
* A string that matches itself against regexii, and keeps track of how much of itself has been matched
*/
var ConsumableString = Base.extend({
init: function(str) {
this.str = str;
this.pos = 0;
},
match: function(rx) {
var m;
rx.lastIndex = this.pos;
if ((m = rx.exec(this.str)) && m.index == this.pos ) {
this.pos = rx.lastIndex ? rx.lastIndex : this.str.length ;
return m;
}
return null;
},
peek: function(rx) {
var m;
rx.lastIndex = this.pos;
if ((m = rx.exec(this.str)) && m.index == this.pos ) return m;
return null;
},
showpos: function() {
return this.str.slice(0,this.pos)+'<HERE>' + this.str.slice(this.pos);
},
done: function() {
return this.pos == this.str.length;
}
});
/* A base class that all Selectors inherit off */
var SelectorBase = Base.extend({});
/**
* A class representing a Simple Selector, as per the CSS3 selector spec
*/
var SimpleSelector = SelectorBase.extend({
init: function() {
this.tag = null;
this.id = null;
this.classes = [];
this.attrs = [];
this.nots = [];
this.pseudo_classes = [];
this.pseudo_els = [];
},
parse: function(selector) {
var m;
/* Pull out the initial tag first, if there is one */
if (m = selector.match(rx.tag)) this.tag = m[1];
/* Then for each selection type, try and find a match */
do {
if (m = selector.match(rx.not)) {
this.nots[this.nots.length] = SelectorsGroup().parse(selector);
if (!(m = selector.match(rx.not_end))) {
throw 'Invalid :not term in selector';
}
}
else if (m = selector.match(rx.id)) this.id = m[1];
else if (m = selector.match(rx.cls)) this.classes[this.classes.length] = m[1];
else if (m = selector.match(rx.attr)) this.attrs[this.attrs.length] = [ m[1], m[2], m[3] ];
else if (m = selector.match(rx.pseudo_el)) this.pseudo_els[this.pseudo_els.length] = m[1] || m[2];
else if (m = selector.match(rx.pseudo_cls_nth)) {
if (m[3]) {
var a = parseInt((m[1]||'')+(m[2]||'1'));
var b = parseInt((m[4]||'')+(m[5]||'0'));
}
else {
var a = m[8] ? 2 : 0;
var b = m[8] ? (4-m[8].length) : parseInt((m[6]||'')+m[7]);
}
this.pseudo_classes[this.pseudo_classes.length] = ['nth-child', [a, b]];
}
else if (m = selector.match(rx.pseudo_cls)) this.pseudo_classes[this.pseudo_classes.length] = [m[1]];
} while(m && !selector.done());
return this;
}
});
/**
* A class representing a Selector, as per the CSS3 selector spec
*/
var Selector = SelectorBase.extend({
init: function(){
this.parts = [];
},
parse: function(cons){
this.parts[this.parts.length] = SimpleSelector().parse(cons);
while (!cons.done() && !cons.peek(rx.comma) && (m = cons.match(rx.comb))) {
this.parts[this.parts.length] = m[1] || ' ';
this.parts[this.parts.length] = SimpleSelector().parse(cons);
}
return this.parts.length == 1 ? this.parts[0] : this;
}
});
/**
* A class representing a sequence of selectors, as per the CSS3 selector spec
*/
var SelectorsGroup = SelectorBase.extend({
init: function(){
this.parts = [];
},
parse: function(cons){
this.parts[this.parts.length] = Selector().parse(cons);
while (!cons.done() && (m = cons.match(rx.comma))) {
this.parts[this.parts.length] = Selector().parse(cons);
}
return this.parts.length == 1 ? this.parts[0] : this;
}
});
$.selector = function(s){
var cons = ConsumableString(s);
var res = SelectorsGroup().parse(cons);
res.selector = s;
if (!cons.done()) throw 'Could not parse selector - ' + cons.showpos() ;
else return res;
};
$.selector.SelectorBase = SelectorBase;
$.selector.SimpleSelector = SimpleSelector;
$.selector.Selector = Selector;
$.selector.SelectorsGroup = SelectorsGroup;
})(jQuery);

View File

@ -1,346 +0,0 @@
/*
This attempts to do the opposite of Sizzle.
Sizzle is good for finding elements for a selector, but not so good for telling if an individual element matches a selector
*/
(function($) {
/**** CAPABILITY TESTS ****/
var div = document.createElement('div');
div.innerHTML = '<form id="test"><input name="id" type="text"/></form>';
// In IE 6-7, getAttribute often does the wrong thing (returns similar to el.attr), so we need to use getAttributeNode on that browser
var getAttributeDodgy = div.firstChild.getAttribute('id') !== 'test';
// Does browser support Element.firstElementChild, Element.previousElementSibling, etc.
var hasElementTraversal = div.firstElementChild && div.firstElementChild.tagName == 'FORM';
// Does browser support Element.children
var hasChildren = div.children && div.children[0].tagName == 'FORM';
/**** INTRO ****/
var GOOD = /GOOD/g;
var BAD = /BAD/g;
var STARTS_WITH_QUOTES = /^['"]/g;
var join = function(js) {
return js.join('\n');
};
var join_complex = function(js) {
var code = new String(js.join('\n')); // String objects can have properties set. strings can't
code.complex = true;
return code;
};
/**** ATTRIBUTE ACCESSORS ****/
// Not all attribute names can be used as identifiers, so we encode any non-acceptable characters as hex
var varForAttr = function(attr) {
return '_' + attr.replace(/^[^A-Za-z]|[^A-Za-z0-9]/g, function(m){ return '_0x' + m.charCodeAt(0).toString(16) + '_'; });
};
var getAttr;
// Good browsers
if (!getAttributeDodgy) {
getAttr = function(attr){ return 'var '+varForAttr(attr)+' = el.getAttribute("'+attr+'");' ; };
}
// IE 6, 7
else {
// On IE 6 + 7, getAttribute still has to be called with DOM property mirror name, not attribute name. Map attributes to those names
var getAttrIEMap = { 'class': 'className', 'for': 'htmlFor' };
getAttr = function(attr) {
var ieattr = getAttrIEMap[attr] || attr;
return 'var '+varForAttr(attr)+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
};
}
/**** ATTRIBUTE COMPARITORS ****/
var attrchecks = {
'-': '!K',
'=': 'K != "V"',
'!=': 'K == "V"',
'~=': '_WS_K.indexOf(" V ") == -1',
'^=': '!K || K.indexOf("V") != 0',
'*=': '!K || K.indexOf("V") == -1',
'$=': '!K || K.substr(K.length-"V".length) != "V"'
};
/**** STATE TRACKER ****/
var State = $.selector.State = Base.extend({
init: function(){
this.reset();
},
reset: function() {
this.attrs = {}; this.wsattrs = {};
},
prev: function(){
this.reset();
if (hasElementTraversal) return 'el = el.previousElementSibling';
return 'while((el = el.previousSibling) && el.nodeType != 1) {}';
},
next: function() {
this.reset();
if (hasElementTraversal) return 'el = el.nextElementSibling';
return 'while((el = el.nextSibling) && el.nodeType != 1) {}';
},
prevLoop: function(body){
this.reset();
if (hasElementTraversal) return join([ 'while(el = el.previousElementSibling){', body]);
return join([
'while(el = el.previousSibling){',
'if (el.nodeType != 1) continue;',
body
]);
},
parent: function() {
this.reset();
return 'el = el.parentNode;';
},
parentLoop: function(body) {
this.reset();
return join([
'while((el = el.parentNode) && el.nodeType == 1){',
body,
'}'
]);
},
uses_attr: function(attr) {
if (this.attrs[attr]) return;
this.attrs[attr] = true;
return getAttr(attr);
},
uses_wsattr: function(attr) {
if (this.wsattrs[attr]) return;
this.wsattrs[attr] = true;
return join([this.uses_attr(attr), 'var _WS_'+varForAttr(attr)+' = " "+'+varForAttr(attr)+'+" ";']);
},
uses_jqueryFilters: function() {
if (this.jqueryFiltersAdded) return;
this.jqueryFiltersAdded = true;
return 'var _$filters = jQuery.find.selectors.filters;';
},
save: function(lbl) {
return 'var el'+lbl+' = el;';
},
restore: function(lbl) {
this.reset();
return 'el = el'+lbl+';';
}
});
/**** PSEUDO-CLASS DETAILS ****/
var pseudoclschecks = {
'first-child': join([
'var cel = el;',
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }'
]),
'last-child': join([
'var cel = el;',
'while(cel = cel.nextSibling){ if (cel.nodeType === 1) BAD; }'
]),
'nth-child': function(a,b) {
var get_i = join([
'var i = 1, cel = el;',
'while(cel = cel.previousSibling){',
'if (cel.nodeType === 1) i++;',
'}'
]);
if (a == 0) return join([
get_i,
'if (i- '+b+' != 0) BAD;'
]);
else if (b == 0 && a >= 0) return join([
get_i,
'if (i%'+a+' != 0 || i/'+a+' < 0) BAD;'
]);
else if (b == 0 && a < 0) return join([
'BAD;'
]);
else return join([
get_i,
'if ((i- '+b+')%'+a+' != 0 || (i- '+b+')/'+a+' < 0) BAD;'
]);
}
};
// Needs to refence contents of object, so must be injected after definition
pseudoclschecks['only-child'] = join([
pseudoclschecks['first-child'],
pseudoclschecks['last-child']
]);
/**** SimpleSelector ****/
$.selector.SimpleSelector.addMethod('compile', function(el) {
var js = [];
/* Check against element name */
if (this.tag && this.tag != '*') {
js[js.length] = 'if (el.tagName != "'+this.tag.toUpperCase()+'") BAD;';
}
/* Check against ID */
if (this.id) {
js[js.length] = el.uses_attr('id');
js[js.length] = 'if (_id !== "'+this.id+'") BAD;';
}
/* Build className checking variable */
if (this.classes.length) {
js[js.length] = el.uses_wsattr('class');
/* Check against class names */
$.each(this.classes, function(i, cls){
js[js.length] = 'if (_WS__class.indexOf(" '+cls+' ") == -1) BAD;';
});
}
/* Check against attributes */
$.each(this.attrs, function(i, attr){
js[js.length] = (attr[1] == '~=') ? el.uses_wsattr(attr[0]) : el.uses_attr(attr[0]);
var check = attrchecks[ attr[1] || '-' ];
check = check.replace( /K/g, varForAttr(attr[0])).replace( /V/g, attr[2] && attr[2].match(STARTS_WITH_QUOTES) ? attr[2].slice(1,-1) : attr[2] );
js[js.length] = 'if ('+check+') BAD;';
});
/* Check against nots */
$.each(this.nots, function(i, not){
var lbl = ++lbl_id;
var func = join([
'l'+lbl+':{',
not.compile(el).replace(BAD, 'break l'+lbl).replace(GOOD, 'BAD'),
'}'
]);
if (!(not instanceof $.selector.SimpleSelector)) func = join([
el.save(lbl),
func,
el.restore(lbl)
]);
js[js.length] = func;
});
/* Check against pseudo-classes */
$.each(this.pseudo_classes, function(i, pscls){
var check = pseudoclschecks[pscls[0]];
if (check) {
js[js.length] = ( typeof check == 'function' ? check.apply(this, pscls[1]) : check );
}
else if (check = $.find.selectors.filters[pscls[0]]) {
js[js.length] = el.uses_jqueryFilters();
js[js.length] = 'if (!_$filters.'+pscls[0]+'(el)) BAD;';
}
});
js[js.length] = 'GOOD';
/* Pass */
return join(js);
});
var lbl_id = 0;
/** Turns an compiled fragment into the first part of a combination */
function as_subexpr(f) {
if (f.complex)
return join([
'l'+(++lbl_id)+':{',
f.replace(GOOD, 'break l'+lbl_id),
'}'
]);
else
return f.replace(GOOD, '');
}
var combines = {
' ': function(el, f1, f2) {
return join_complex([
f2,
'while(true){',
el.parent(),
'if (!el || el.nodeType !== 1) BAD;',
f1.compile(el).replace(BAD, 'continue'),
'}'
]);
},
'>': function(el, f1, f2) {
return join([
f2,
el.parent(),
'if (!el || el.nodeType !== 1) BAD;',
f1.compile(el)
]);
},
'~': function(el, f1, f2) {
return join_complex([
f2,
el.prevLoop(),
f1.compile(el).replace(BAD, 'continue'),
'}',
'BAD;'
]);
},
'+': function(el, f1, f2) {
return join([
f2,
el.prev(),
'if (!el) BAD;',
f1.compile(el)
]);
}
};
$.selector.Selector.addMethod('compile', function(el) {
var l = this.parts.length;
var expr = this.parts[--l].compile(el);
while (l) {
var combinator = this.parts[--l];
expr = combines[combinator](el, this.parts[--l], as_subexpr(expr));
}
return expr;
});
$.selector.SelectorsGroup.addMethod('compile', function(el) {
var expr = [], lbl = ++lbl_id;
for (var i=0; i < this.parts.length; i++) {
expr[expr.length] = join([
i == 0 ? el.save(lbl) : el.restore(lbl),
'l'+lbl+'_'+i+':{',
this.parts[i].compile(el).replace(BAD, 'break l'+lbl+'_'+i),
'}'
]);
}
expr[expr.length] = 'BAD;';
return join(expr);
});
$.selector.SelectorBase.addMethod('matches', function(el){
this.matches = new Function('el', join([
'if (!el) return false;',
this.compile(new State()).replace(BAD, 'return false').replace(GOOD, 'return true')
]));
return this.matches(el);
});
})(jQuery);

View File

@ -1,42 +0,0 @@
(function($) {
$.selector.SimpleSelector.addMethod('specifity', function() {
if (this.spec) return this.spec;
var spec = [
this.id ? 1 : 0,
this.classes.length + this.attrs.length + this.pseudo_classes.length,
((this.tag && this.tag != '*') ? 1 : 0) + this.pseudo_els.length
];
$.each(this.nots, function(i,not){
var ns = not.specifity(); spec[0] += ns[0]; spec[1] += ns[1]; spec[2] += ns[2];
});
return this.spec = spec;
});
$.selector.Selector.addMethod('specifity', function(){
if (this.spec) return this.spec;
var spec = [0,0,0];
$.each(this.parts, function(i,part){
if (i%2) return;
var ps = part.specifity(); spec[0] += ps[0]; spec[1] += ps[1]; spec[2] += ps[2];
});
return this.spec = spec;
});
$.selector.SelectorsGroup.addMethod('specifity', function(){
if (this.spec) return this.spec;
var spec = [0,0,0];
$.each(this.parts, function(i,part){
var ps = part.specifity(); spec[0] += ps[0]; spec[1] += ps[1]; spec[2] += ps[2];
});
return this.spec = spec;
});
})(jQuery);

View File

@ -1,8 +0,0 @@
---
format: 1
handler:
commit: 8fe63b186e349433b6da1cd6ec4c9a751fefb13e
branch: master
lock: false
repository_class: Piston::Git::Repository
repository_url: git://github.com/visionmedia/jspec.git

View File

@ -1,552 +0,0 @@
=== 2.11.7 / 2009-10-15
* Fixed minor grammar issues for windows users [thanks Tony]
* Fixes installation issue when XCode is not present; changed dependency json -> json_pure [thanks esbie]
* Fixed Chrome#visit; latest builds of Chrome for the mac are now "Google Chrome"
=== 2.11.6 / 2009-10-12
* Added Tony to contributor list
* Removed JSpec.paramsFor()
* Removed module contexts [#72]
* Fixed some css styling issues in IE8 [#71]
* Fixed; DOM formatter supporting \r\n \r \n for EOL in the body source [Thanks Tony]
* Fixed "Access is denied" error in IE
* Fixed some css support for older browsers [Thanks Tony]
=== 2.11.5 / 2009-10-10
* Fixed dependencies (created by github's gem builder removal)
=== 2.11.4 / 2009-10-10
* Updated installation docs
* Removed namespaced dependencies (thanks alot github...)
=== 2.11.3 / 2009-09-30
* Updated to mock timers 1.0.1
fixes an issue where setTimeout(function(){}, 0); tick(100) is never called
=== 2.11.2 / 2009-09-21
* Fixed example path in rails template
=== 2.11.1 / 2009-09-10
* Fixed JSpec root when using --symlink, --freeze [#36]
* Added __END__ to the grammar (works like Ruby's __END__)
=== 2.11.0 / 2009-09-04
* Added --symlink switch (links the current version of JSpec to ./spec/lib) [#4]
* Added --freeze switch (copies the current version of JSpec to ./spec/lib) [#4]
=== 2.10.1 / 2009-09-02
* Added `jspec shell` sub command (interactive Rhino shell through JSpec)
* Added jspec.shell.js
=== 2.10.0 / 2009-08-27
* Added Async support via mock timers (lib/jspec.timers.js) [#19]
* IRC channel up and running! irc://irc.freenode.net#jspec
=== 2.9.1 / 2009-08-21
* Added module support for formatters
=== 2.9.0 / 2009-08-21
* Server output matching Rhino when using verbose or failuresOnly options
* Added mock_request() and unmock_request() as aliases for mockRequest() and unmockRequest()
* Added JSpec.JSON.encode()
* Added default Sinatra routes /slow/NUMBER and /status/NUMBER for simulating
slow reponses and HTTP status codes.
* Added server support for loading spec/jspec.rb (or jspec/jspec.rb for rails)
Allowing additional browser support to be plugged in, as well as Sinatra routes.
* Added dependency for Sinatra (new server)
* Added a new Ruby server
* Added support for --bind and --server on various platforms
* Added Google Chrome support
* Added Internet Explorer support
* Change; --server without --browsers defaults to all supported browsers
* Removed JSpec.reportToServer()
Now utilizes JSpec.formatters.Server to handle this
functionality.
* Fixed Server output escaping (removed html escaping from puts()) [#13]
* Fixed JSpec.load(); returns responseText when 2xx or 0 (for file://)
=== 2.8.4 / 2009-08-02
* Fixed error thrown when a module has no utilities
=== 2.8.3 / 2009-07-30
* Added JSpec.evalHook()
* Added JSpec.paramsFor()
* Refactored jspec.xhr.js
* Fixed mock xhr HEAD method
* Fixed node.js print() newline issue
* Fixed specs preventing spec/spec.node.js from running
=== 2.8.2 / 2009-07-29
* Added JSpec.tryLoading()
* Added JSpec.request used to reference the original XMLHttpRequest; used to fix [#149]
* Fixed Mock XHR issue messing up JSpec request related utilities such as fixture() [#149]
=== 2.8.1 / 2009-07-27
* Added Lawrence Pit as a contributor
* Fixed object hash equality [#146]
{ a : '1', b : '2' } is now the same as:
{ b : '2', a : '1' }
=== 2.8.0 / 2009-07-27
* Give readFile precendence over xhr so that fixtures work with mockRequest when using Rhino
* Give XMLHttpRequest precedence over microsoft crap
* Added Mock Ajax Support
* Added mockRequest(), unmockRequest() utilities
* Added jspec.xhr.js
* Fixed be_visible, and be_hidden. Now implement the jQuery <= 1.3.1 method
=== 2.7.2 / 2009-07-24
* Fixed "end" in spec bodies when using the grammar
* Fixed "it" in spec bodies when using the grammar [#142]
* Changed; HTML entities in descriptions are now escaped for DOM formatter [#141]
* Added enno84@gmx.net as a contributor (thanks for the bug reports)
=== 2.7.1 / 2009-07-17
* Changed; hash() now accepts null
* Fixed should_receive issue with validating boolean args or return values
* Fixed --server-only switch
* Fixed jQuery dependency error message when jQuery is not available
when using jspec.jquery.js
=== 2.7.0 / 2009-07-14
* Added fixture() utility function
* Templates initialize with example paths to lib
=== 2.6.0 / 2009-07-09
* Added Ruby on Rails support
* Added exporting of JSpec (node.js etc)
* Added be_undefined matcher [#134]
=== 2.5.1 / 2009-07-07
* Added intermediate node.js support
* Fixed; grammar now allows foo.bar.baz.stub() etc to convert to stub(foo.bar.baz)
=== 2.5.0 / 2009-07-03
* Added contrib in README (thanks to anyone who has helped)
* Added more shared behavior specs
* Added Module.DSLs support for extending / adding new DSLs (DSL exchange not yet fully implemented)
* Added spec to make sure methods like end() will not fail due to the grammar
* Changed; giving hook precedence to suite hooks (before_each, etc) over module hooks (beforeSuite, etc) ; (thanks mpd)
* Changed; calls to stub() without and_return() now simply stub an arbitrary method with no return value
* Changed JSpec.include(); now returns JSpec allowing chaining
* Fixed having "end" in descriptions which would be replaced with '});'
* Fixed negation of should.receive('foo') matcher
* Fixed shared behavior assertion count issue
=== 2.4.3 / 2009-07-02
* Fixed matcher semicolon matcher issue when using the JSpec grammar
* Added pass() util; Spec#pass() and Spec#fail() (thanks gisikw)
* Removing Object.prototype.stubby() after specs are finished to prevent pollution
=== 2.4.2 / 2009-06-30
* Fixed trailing comma (thanks Kevin)
=== 2.4.1 / 2009-06-30
* Moved beforeSpec and afterSpec hook into proper positions
allowing for additional assertions within afterSpec.
=== 2.4.0 / 2009-06-30
* Added hook() and hookImmutable()
* Added support for matcher lists ('be enabled disabled selected') == be_enabled, be_disabled etc
* Added JSpec.include()
* Added several hooks
* Added Module support
* Added grammar conversion of Foo.stub('method') to stub(Foo, 'method')
* Added grammar conversion of Foo.destub() to destub(Foo)
* Require bind gem
* Fixed `jspec` bin docs
=== 2.3.1 / 2009-06-25
* Fixed; all stubs generated with stub() are restored
to their original methods after each 'it' block. See
README for details.
=== 2.3.0 / 2009-06-25
* Added stub()
* Added destub()
* Changed; Server responses utilize Rack::Mime now for arbitrary requests
=== 2.2.1 / 2009-06-22
* Changed; reportToServer() now accepts url arg
* Fixed be_empty matcher; now considers {} empty, however { foo : bar } is not
* Fixed throw_error error messages for Opera
* Fixed throw_error in Rhino (Opera is broken now)
* Fixed stray console.log() call
* Fixed some tab issues.
When using the JSpec grammar option you should
use the 'soft tabs' feature of your IDE or text editor.
A patch for tabs is pending and should be available soon,
however be aware that a 'parse error' may occur otherwise.
=== 2.2.0 / 2009-06-18
* Added link to JSpec in JSMag June 2009
* Added Github gem source location to docs
* Changed throw_error matcher; now accepts two arguments
* Changed --server; serves from current working directory.
This allows files in ../lib/* to be served rather than ./spec/* only.
* Refactored argumentsToArray()
=== 2.1.0 / 2009-06-12
* Changed `jspec init` to utilize a single template
which allows for all three suite running capabilities
within a single template. Now after initializing a
project you may `jspec run --server`, `jspec run --rhino`
etc at any time without modifications.
=== 2.0.3 / 2009-05-15
* Table should span full width
(Very week release I know, but improperly styled things bug me :) )
=== 2.0.2 / 2009-05-11
* Added rails integration link http://github.com/bhauman/jspec-rails
* Changed; puts() now displays constructor name when available
* Fixed Terminal output which was not displaying due to a recent commit
* fixed IE bug : DOM elements don't have valueOf() method
=== 2.0.1 / 2009-05-01
* Added better failure messages for throw_error matcher
* Renamed print() to puts() [#108]
=== 2.0.0 / 2009-04-27
* Added DOM loading indicator [#105]
* Added wait() helper for additional async support
* Added shared behavior support using should_behave_like('Another Suite')
* Added CSS body toggling [#1]
* Added receive matcher for Proxy Assertins
* Added grammar-less support
* Added an_instance_of() helper
* Removed .this literal
* Removed deprecated be_a_TYPE_input matchers
* Added ProxyAssertion
* Added select() util
* Added does() util for report-less assertions
* Added find() util
* Added JSpec.contentsOf()
* Added matchers to body evaluation [#90]
=== 1.1.7 / 2009-04-22
* Removed trailing commas causing issues with IE (what a suprise ;) )
=== 1.1.6 / 2009-04-22
* Fixed typo in requires()
* Added expect()
=== 1.1.5 / 2009-04-17
* Strengthened specs for cascading hooks
* Fixed cascading hooks
=== 1.1.4 / 2009-04-17
* Added rhino and server template files
* Added JSpec.hasXhr()
* Added JSpec.xhr()
* Added Ruby javascript testing server
* Added support for options passed to run()
* Added failuresOnly for Terminal formatter
* Added terminal assertion graphs
* Addec color() utility
* Added main.puts() since we use print() as a utility
* Added rhino support
* Added fail() utility function
* Added JSpec.Assertion
* Added normalizeMatcherMessage()
* Added normalizeMatcherBody()
* Added have_classes [#19]
* Added extend() utility
* Added be_an_instance_of matcher
* Added constructor checking support for throw_error matcher [#72]
* Added file support for exception messages, making them much easier to debug
* Added catching of exceptions throw within specs [#46]
* Changed; executable aborts when template does not exist
* Changed; matchers now normalized upon creation, accepts function, hash, or string.
* Changed be() matcher to be strict [#57]
* Changed error() to conditionally show line number when available
* Renamed Jspec.addSuite to JSpec.describe and Suite#addSpec to Suite#it
* Refactored be_a_TYPE_input matchers so that the deprication warning is logged only when calling the method
* Fixed JSpec.requires() now works with latest version of JSpec.error()
* Fixed error() now displays exceptions throw that do not respond to .message
* Fixed commenting bug [#37]
* Removed JSpec.main, now just using local main
=== 1.1.3 / 2009-04-14
* Removed /test used for the executable, causing gem to fail building
=== 1.1.2 / 2009-04-14
* Added `jspec update` sub-command [#63]
=== 1.1.1 / 2009-04-12
* Added gemspec
=== 1.1.0 / 2009-04-12
* jspec executable fully functional
=== 1.0.4 / 2009-04-09
* Added `jspec bind`
* Added `jspec run`
* Added `jspec init`
* Added `jspec` executable
* Added gemspec and manifest
* Added command-line usage docs
* Added custom matchers documentation
* Removed double negation
=== 1.0.3 / 2009-04-08
* Added have_prop matcher, have_property is now strict [#56]
=== 1.0.2 / 2009-04-08
* Added be_selected, be_checked matchers
* Added string support to each() each('some foo bar', ...)
* Added have_ATTR matchers [#51]
* Deprected be_a_TYPE_input matchers [#50]
=== 1.0.1 / 2009-04-07
* Added have_property matcher [#53]
=== 1.0.0 / 2009-04-06
* Added option() which gives the query string option precedence [#39]
* Changed; Using JSpec.options.formatter not JSpec.formatter [#44]
* Fixed Console formatter, now displays nested suites
* Check out http://visionmedia.github.com/jspec for additional documentation!
=== 0.9.6 / 2009-04-03
* Added nesting support
* Added printing of nested specs
* Added assertion graphs to DOM formatter
* Refactored preprocess()
* Refactored most of the specs
* Renamed preProcess() to preprocess()
* Removed running of a single suite via ?suite= for now
=== 0.9.5 / 2009-04-02
* Added support for printing of function bodies and regexps [#27]
* Added support for strings / regexp with should_throw_error [#26]
* Added have_within matcher
* Added have_at_most matcher
* Added have_at_least matcher
* Added have matcher [#24]
=== 0.9.4 / 2009-04-02
* Added be_a_TYPE_input matchers (be_a_checkbox_input, be_a_text_input, etc)
* Added be_disabled matcher [#21]
* Added be_enabled matcher [#20]
* Refactored be_visible and be_hidden with $(elem).is()
=== 0.9.2 / 2009-04-02
* Added support for multi-arg failure messages [#2]
* Better printing of jQuery objects [#15]
=== 0.9.1 / 2009-04-02
* Added support for dotted negation of assertions (foo.should.not.equal bar)
* Added support for dot-style assertions [#17] (foo.should_not.equal bar)
=== 0.9.0 / 2009-04-01
* Added spec for strip()
* Added strip()
* Added any() util
* Added new improved include matcher
* Added have_many and have_one matchers
* Added have_attr matcher [#14]
* Added map() util
* Added inject() util
* Added escape() util
* Added recursive array and object printing
* Added DOM formatter option failuresOnly
* Added support for running of a single squite via ?suite=...
* Added query() util
* Added last() util
* Added be_within matcher, accepts a range literal
* Added inclusive range literal n..n
* Added row hover
* Refactored range()
* Refactored setMessage()
* Refactored hash()
* Changed; preprocessor passing array of args (multi-arg matcher support)
* Changed jQuery to $ for internal usage
=== 0.8.0 / 2009-02-27
* Added a new style for the DOM formatter (not finished yet)
=== 0.7.0 / 2009-02-27
* Added Console formatter (anything implementing the console object. Firebug, Safari 4, etc)
* Added JSpec.options.profile for optional profiling of specs
* Added this. literal alternative (view readme)
* Moved formatters into JSpec.formatters
* Added error() util
* Added savings raketask
* Fixed parse error bug in Safari 4
=== 0.6.3 / 2009-02-26
* Added minification for jspec.jquery.js when packaging before release
* Added compression of css when packaging before release
=== 0.6.2 / 2009-02-26
* Changed; using $ in jspec.jquery.js for JSpec, take that jQuery ;)
* Added addMatchers, print, hash, and each as 'utility functions' this allows
JSpec to do each(...) internally instead of JSpec.each(...), while still preventing
pollution of the global scope.
=== 0.6.1 / 2009-02-26
* Added closrue literal -{ (view README)
* Added option to DOM formatter, now allows you to specify which element id to output to
=== 0.6.0 / 2009-02-24
* Added JSpec.hash
* Added be_null matcher
* Allow recursive composite matching using should_eql and should_not_eql
For example [1, 2, [3]].should_eql([1, 2, [3]]) is true, works with object
'hashes' as well.
=== 0.5.1 / 2009-02-24
* Damn auto-release messed up
=== 0.5.0 / 2009-02-24
* Added async support for jQuery
* Added JSpec.requires for dependencies
* Added JSpec.throw
* Added JSpec.runSpec
* Refactored jspec.jquery.js
* Fixed evalBody exceptions, previously was not showing exception message
* Fixed bug of JSpec interpreting // in a string such as http:// to be a comment.
=== 0.4.1 / 2009-02-22
* Added elements() alias of element()
* Added support for string passed to runSuite; runSuite('Matchers') is the same as
runSuite(JSpec.suites['Matchers']).
* Fixed some documentation
=== 0.4.0 / 2009-02-20
* Added comment literal (//)
* Added pre-processor for convering matchers.
For example 'test'.should_be_true becomes JSpec.match('test', 'should_be', 'true'),
preventing pollution of core prototypes.
=== 0.3.2 / 2009-02-19
* Added TM bundle (go checkout my jspec.tmbundle repo on github)
* Renamed have_length_of to have_length
=== 0.3.1 / 2009-02-19
* Added jquery js to package
=== 0.3.0 / 2009-02-19
* Added JSpec.match
* Added options to report() which are passed to formatter
* Added sandbox helpers (reg / jquery)
* Added have_child and have_children
* Added have_tag and have_tags
* Changed exec to only load / eval file
* Fixed parser token issue, was previously matching things like end() as literal end
=== 0.2.3 / 2009-02-18
* Changed test dir to spec
* Changed test.js to core.spec.js
=== 0.2.2 / 2009-02-18
* Added contexts
=== 0.2.0 / 2009-02-18
* Added release rake task
* Added package with minified alternative
=== 0.1.0 / 2009-02-18
* Added new sexy syntax (warning: you will have to re-write your specs)
* Added pre-processor for optional matcher parens
* Added several new matchers
* Added matcher aliasing
* Added simple matcher declarations
* Added __END__
* Added yet-to-be-implemented specs
* Added loading of suites via JSpec.load
=== 0.0.4 / 2008-11-03
* Added ability to pass only a description to it(), meaning not yet implemented
=== 0.0.3 / 2008-10-28
* Added should_fail
* Added should_match
* Added should_not_match
* Added should_be and should_not_be
=== 0.0.2 / 2008-10-28
* Fixed typo in documentation for pointing to the master repo
=== 0.0.1 / 2008-10-28
* Initial release

View File

@ -1,57 +0,0 @@
History.rdoc
Manifest
README.rdoc
Rakefile
bin/jspec
jspec.gemspec
lib/images/bg.png
lib/images/hr.png
lib/images/loading.gif
lib/images/sprites.bg.png
lib/images/sprites.png
lib/images/vr.png
lib/jspec.css
lib/jspec.jquery.js
lib/jspec.js
lib/jspec.shell.js
lib/jspec.timers.js
lib/jspec.xhr.js
server/browsers.rb
server/helpers.rb
server/routes.rb
server/server.rb
spec/async
spec/env.js
spec/fixtures/test.html
spec/fixtures/test.json
spec/fixtures/test.xml
spec/helpers.js
spec/server.rb
spec/spec.dom.html
spec/spec.fixtures.js
spec/spec.grammar-less.js
spec/spec.grammar.js
spec/spec.jquery.js
spec/spec.jquery.xhr.js
spec/spec.js
spec/spec.matchers.js
spec/spec.modules.js
spec/spec.node.js
spec/spec.rhino.js
spec/spec.server.html
spec/spec.shared-behaviors.js
spec/spec.utils.js
spec/spec.xhr.js
templates/default/History.rdoc
templates/default/README.rdoc
templates/default/lib/yourlib.core.js
templates/default/spec/server.rb
templates/default/spec/spec.core.js
templates/default/spec/spec.dom.html
templates/default/spec/spec.rhino.js
templates/default/spec/spec.server.html
templates/rails/server.rb
templates/rails/spec.application.js
templates/rails/spec.dom.html
templates/rails/spec.rhino.js
templates/rails/spec.server.html

View File

@ -1,825 +0,0 @@
= JSpec
JSpec is a minimalistic JavaScript behavior driven development framework,
providing simple installation, extremely low learning curve, absolutely no pollution
to core prototypes, async request support, and incredibly sexy syntax, tons of matchers
and much more.
== Features
* Highly readable
* Framework / DOM independent
* Modular via JSpec Module's and hooks
* Mock Ajax Requests
* Rhino support
* Node.js support
* Async support
* Fixture support
* Ruby JavaScript testing server
* Nested describes
* Does not pollute core object prototypes
* Cascading before/after/before_each/after_each hooks
* Extremely simple and intuitive matcher declaration
* Over 45 core matchers
* Allows parens to be optional when using matchers to increase readability
* Several helpful formatters (DOM, Console, Terminal, ...)
* Assertion graphs displaying how many, and which assertions pass or failed
* Default / customizable evaluation contexts
* DOM sandbox support
* Great looking default DOM theme
* `jspec` command-line utility for auto-running specs, and initializing project templates
* Proxy or 'Spy' assertions
* Method Stubbing
* Shared behaviors
* Profiling
* Interactive Shell
* Ruby on Rails Integration
* Tiny (15 kb compressed, 1300-ish LOC)
== Installation
Simply download JSpec and include JSpec.css and JSpec.js in your markup.
Head over to the downloads section on Github, clone this public repo, or
add JSpec as a git submodule with in your project. Alternatively JSpec is
also available as a Ruby Gem (though this is not required), which also
provides the `jspec` executable. First install [Gemcutter](http://gemcutter.org/) then execute:
$ sudo gem install jspec
At which point you may:
$ jspec init myproject
By default, the command above will use absolute path for all JSpec library files.
This behavior can be a problem when you're working across different computers or
operating systems. You can freeze the library or symlink it.
$ jspec init myproject --freeze
$ jspec init myproject --symlink
JSpec scripts should NOT be referenced via the <script> tag, they should be
loaded using the exec method (unless you are using the grammar-less alternative).
Below is an example:
...
<script>
function runSuites() {
JSpec
.exec('spec.core.js')
.exec('spec.jquery.js')
.run({ failuresOnly : true })
.report()
}
</script>
<body onLoad="runSuites()">
...
You may optionally want to use sources in the /pkg directory
for your project, since it includes compressed alternatives generated
each release.
== Example
describe 'ShoppingCart'
before_each
cart = new ShoppingCart
end
describe 'addProducts'
it 'should add several products'
cart.addProduct('cookie')
cart.addProduct('icecream')
cart.should.have 2, 'products'
end
end
describe 'checkout'
it 'should throw an error when checking out with no products'
-{ cart.clear().checkout() }.should.throw_error EmptyCart
end
end
end
== Grammar-less Example
JSpec's grammar is optional, you may also use the equivalent grammar-less
alternative below using pure JavaScript (when using the JSpec grammar you
may also use grammar-less assertions):
JSpec.describe('ShoppingCart', function(){
before_each(function{
cart = new ShoppingCart
})
describe('addProducts', function(){
it ('should add several products', function(){
cart.addProducts('cookie')
cart.addProducts('icecream')
expect(cart).to(have, 2, 'products')
})
})
describe('checkout', function(){
it ('should throw an error when checking out with no products', function(){
expect(function(){ cart.clear().checkout() }).to(throw_error, EmptyCart)
})
})
})
== Options
You may alter the way JSpec operates by assigning options via the
JSpec.options hash, by passing string-based option values via the
query string, or passing a hash to run(). For example
JSpec.options.failuresOnly = true, and ?failuresOnly=1 will both work.
* profile {bool} when enabled, uses console.time() in order to display performance information in your console log as specs are completed. (DOM, Console)
* failuresOnly {bool} displays only failing specs, making them quick to discover and fix (DOM, Terminal, Server)
* reportToId {string} an element id to report to when using the DOM formatter (DOM)
* verbose {bool} verbose server output, defaults to false (Server)
== Matchers
* Core
- equal, be ===
- be_a, be_an have constructor of x
- be_an_instance_of instanceof x
- be_at_least >=
- be_at_most <=
- be_null == null
- be_empty length < 0 or {}
- be_true == true
- be_false == false
- be_type be type of x
- be_greater_than >
- be_less_than <
- be_undefined check if variable passed is undefined
- throw_error should throw an error, optionally supply the error string or regexp for message comparison
- have object should have n of property (person.should.have(2, 'pets'))
- have_at_least object should have at least n of property
- have_at_most object should have a maximum n of property
- have_within object should have within n..n of property (person.should.have_within(1..3, 'pets')
- have_length length of n
- have_prop object should have property x, optionally supplying an expected value
- have_property strict version of have_prop
- be_within checks if n is within the range passed
- include include substring, array element, or hash key
- match string should match regexp x
- respond_to property x should be a function
- eql matches simple literals (strings, numbers) with ==
However composites like arrays or 'hashes' are recursively matched,
meaning that [1, 2, [3]].should_eql([1, 2, [3]]) will be true.
* jQuery
- have_tag, have_one have exactly one tag
- have_tags, have_many have more than one tag
- have_child have exactly one child
- have_children have more than one child
- have_text have plain text
- have_attr have an attribute, with optional value
- have_type
- have_id
- have_title
- have_alt
- have_href
- have_rel
- have_rev
- have_name
- have_target
- have_value
- have_class
- have_classes
- be_visible
- be_hidden
- be_enabled
- be_disabled
- be_selected
- be_checked
== Async Support With Mock Timers
The javascript mock timers library is available at http://github.com/visionmedia/js-mock-timers
although it is already bundled with JSpec at lib/jspec.timers.js
Timers return ids and may be passed to clearInterval(), however
they do not execute in threads, they must be manually scheduled and
controlled via the tick() function.
setTimeout(function(){
alert('Wahoo!')
}, 400)
tick(200) // Nothing happens
tick(400) // Wahoo!
setInterval() works as expected, although it persists, where as setTimeout()
is destroyed after a single call. As conveyed by the last tick() call below,
a large increment in milliseconds may cause the callbacks to be called several times
to 'catch up'.
progress = ''
var id = setInterval(function(){
progress += '.'
}, 100)
tick(50), print(progress) // ''
tick(50), print(progress) // '.'
tick(100), print(progress) // '..'
tick(100), print(progress) // '...'
tick(300), print(progress) // '......'
clearInterval(id)
tick(800) // Nothing happens
You may also reset at any time using resetTimers()
== Proxy Assertions
Proxy or 'Spy' assertions allow you to assert that a method is called n number
of times, with x arguments, returning x value. For example:
person = { getPets : function(species){ return ['izzy'] }}
person.should.receive('getPets', 'twice').with_args(an_instance_of(String))and_return(['izzy'])
person.getPets('dog') // This will pass
person.getPets() // This will fail because we asked an instance of String
This is a useful mechanism for testing the behavior of your object, as well as
how other methods may interact with it. Below is another example:
array = ['foo', 'bar']
array.should.receive('toString').and_return('foo,bar')
'array: ' + array // This line causes the spec to pass due to calling toString()
For more examples view spec/spec.matchers.js
== Method Stubbing
JSpec currently provides very simple stubbing support shown below:
person = { toString : function(){ return '<Person>' } }
stub(person, 'toString').and_return('Ive been stubbed!')
After each spec all stubs are restored to their original methods so
there is no reason to explicitly call destub(). To persist stubs,
use a before_each hook:
before_each
stub(someObject, 'method').and_return({ some : thing })
end
To destub a method simply call destub() at any time:
destub(person, 'toString')
If you would like to whipe an object clear of stubs simply pass it
to destub() without an additional method argument:
destub(person)
Alternatively both these utility functions may be called as methods
on any object when using the JSpec grammar:
someObject.stub('method').and_return('whatever')
// Converted to stub(someObject, 'method').and_return('whatever')
== Helpers
* Core
- an_instance_of used in conjunction with the 'receive' matcher
- mockRequest, mock_request mock a request (requires jspec.xhr.js)
- unmockRequest, unmock_request unmock requests (requests jspec.xhr.js)
* jQuery
- sandbox used to generate new DOM sandbox, using jQuery object
- element same as invoking jQuery, just reads better and no need to worry about $ collisions
- elements alias of element
== Shared Behaviors
JSpec's support for shared behaviors allows multiple suites or describe blocks to share
common functionality. For example an Admin, would inherit all specs of User:
describe 'User'
before
User = function(name) { this.name = name }
user = new User('joe')
end
it 'should have a name'
user.should.have_property 'name'
end
describe 'Administrator'
should_behave_like('User')
before
Admin = function(name) { this.name = name }
Admin.prototype.may = function(perm){ return true }
user = new Admin('tj')
end
it 'should have access to all permissions'
user.may('edit pages').should.be_true
end
end
end
NOTE: both User and Administrator's before hooks implement the 'user' variable
== Mock Ajax Requests
JSpec supports generic Ajax mocking which is usable with any JavaScript framework via 'jspec.xhr.js'. The
API is comprised of two functions, mockRequest() and unmockRequest(). unmockRequest() is
automatically called after each specification to restore the default functionality of XMLHttpRequest,
so it is uncommon to call unmockRequest() directly. Below is a jQuery example:
it 'should mock requests'
mockRequest().and_return('{ foo : "bar" }', 'application/json')
$.getJSON('foo', function(response, statusText){
response.foo.should.eql 'bar'
})
end
The mockRequest().and_return signature is as follows:
mockRequest().and_return(<data>, [content-type], [response-status-code], [headers-hash])
At the moment mockRequest() itself does not accept any arguments, however in the future
this will be used to target specific uris for mocking.
NOTE: works with Rhino as well
== Hooks
Currently the following hooks are supported, and may be utilized any number of times as they
are simply pushed to a stack. So for instance you may have two before_each blocks within the same
scope, they will both run, but this can help keep your specs readable.
* before run once before the suite is executed
* after run once after the suite is executed
* before_each run before each specification
* after_each run after each specification
== Custom Contexts
Custom contexts can be applied to supply helper
methods or properties to all subsequent bodies (other hooks, or specs).
Keep in mind that when replacing the default context you will loose
functionality provided by it, unless you manually merge it with your
custom context.
To reset the context simply assign null to obtain the original context.
...
before
JSpec.context = { foo : 'bar' }
end
after
JSpec.context = null
end
it 'will work ;)'
foo.should_equal 'bar'
end
...
== Async Support
Currently only jspec.jquery.js supports async requests. JSpec uses jQuery.ajaxSetup and sets all
requests to sync, which preserves execution order, and reports correctly.
it 'should load mah cookies (textfile)'
$.post('async', function(text){
text.should_eql 'cookies!'
})
end
== Pre-processor
The pre-processing capability of JSpec is extremely powerful. Your JavaScript
code is not necessarily what it seems. For example when you seemingly invoke a
object's prototype like below:
'foobar'.should.include 'bar'
First parens are added:
'foobar'.should.include('bar')
Secondly the matcher invocation is converted to a non-polluting match() call:
JSpec.match('foobar', 'should', 'include', 'bar')
This also means instead of:
var object = { foo : 'bar' }
object.should.include 'foo'
We can do:
{ foo : 'bar' }.should.include 'foo'
=== Closure Literal
These are equivalent:
-{ throw 'test' }.should.throw_error
function() { throw 'test' }.should.throw_error
=== Inclusive Range Literal
The following expands to the array of [1,2,3,4,5]
n.should.be_within 1..5
== Formatters
To change a formatter simply alter the options hash like below, assigning
a new constructor, or pass it within the hash to run():
JSpec.options.formatter = JSpec.formatters.Console
OR
JSpec
.exec('...')
.run({ formatter : JSpec.formatters.Terminal })
.report()
== Fixtures
The fixture() utility function may be used in order to load arbitrary file contents
for use with your specifications. JSpec will resolve fixture('data') in the following
manor:
- 'data'
- 'spec/data'
- 'spec/fixtures/data'
- 'spec/fixtures/data.html'
So if the file 'spec/fixtures/data.html' exists, we can simply use fixture('data'),
where as 'spec/fixtures/xml/data.xml' must be specified with fixture('xml/data.xml').
If you prefer not to store fixtures in the 'fixtures' directory you must be more specific
with the path supplied.
== Testing DOM Elements
When using jQuery testing DOM elements is very easy. Many may think they require specific
sandbox divs in their html, however you do not. Using the fixture support mentioned above
you may simply load some HTML, and use the 'elements()' utility which is an alias of jQuery:
describe 'JSpec DOM testing'
describe 'is so easy'
before_each
list = elements(fixture('users-list'))
// or list = jQuery(fixture('users-list'))
// or list = $(fixture('users-list'))
end
it 'should have users'
list.should.have_tag 'ul'
end
end
end
You may also use simple strings, since jQuery's constructor will convert them to DOM elements:
describe 'Something'
before_each
html = elements('<p>Foo</p>')
// or html = $('<p>Foo</p>') ...
end
it 'should do something'
html.should.have_text 'Foo'
end
end
== Custom Matchers
First lets create a simple equality matcher. In the case below JSpec is smart enough to realize
this is simply a binary operator, and simply transforms this into 'actual === expected'
JSpec.addMatchers({
equal : '==='
})
To alias a method to keep your specs readable you may alias them like below:
JSpec.addMatchers({
be : 'alias equal'
})
'foo'.should.equal 'foo'
true.should.be true
Matchers with string bodies implicitly return the expression value.
The expanded version of the equal matcher would then be:
JSpec.addMatchers({
equal : 'actual === expected'
})
Large matchers or those which require several parameters may wish
to utilize the hash method:
JSpec.addMatchers({
equal : { match : function(actual, expected){
return actual === expected
}}
})
To keep JSpec tiny, JSpec will default to generating failure messages
for you, how ever this can be explicitly defined:
JSpec.addMatchers({
equal : {
match : function(actual, expected){
return actual === expected
},
message : function(actual, expected, negate) {
return 'a message here'
}
}
})
When defining matchers that are extremely similar in functionality, however
require different names, you may use a prefixed list of words like below which
defines be_disabled, be_selected, be_checked, and have_type, have_id, etc. Each
function must return the matcher body which will be used.
JSpec.addMatchers({
'be disabled selected checked' : function(attr) {
return 'jQuery(actual).attr("' + attr + '")'
},
'have type id title alt href src sel rev name target' : function(attr) {
return function(actual, value) {
return value ? jQuery(actual).attr(attr) == value:
jQuery(actual).attr(attr)
}
}
})
== Extending Or Hooking Into JSpec
JSpec provides a hook architecture for extending or analyzing various
points in its execution, through the use of 'Modules'. For a Module
example view lib/jspec.jquery.js.
The following methods or properties are utilized by JSpec:
- name : module name string
- init : called to initialize a module
- formatters : hash of formatters merged with JSpec.formatters
- utilities : hash of utility functions merged with JSpec.defaultContext
- matchers : hash of matchers merged with JSpec's core matchers via JSpec.addMatchers()
- DSLs : hash of DSL methods; for example DSLs.snake contains before_each, after_each, etc.
Where as DSLs.camel may contain beforeEach, afterEach, etc.
Below is a list of hooks, descriptions, and valid return values which
may simply be implemented as module methods. beforeSuite, afterSuite, beforeSpec, and afterSpec have lower
precedence than before_each, after_each etc within the specs themselves, allowing them to override or undo
anything that has been done by a Module.
- running(options) : started running JSpec with the options passed : returning 'stop' will halt running
- loading(file) : loading a file : returning 'stop' will prevent loading
- executing(file) : executing a file : returning 'stop' will prevent execution
- posting(data, url) : posting data to a url : returning 'stop' will prevent request
- preprocessing(input) : before input string is preprocessed : return input string for next hook to preprocess
- stubbing(object, method, result) : called when stubbing an object's method, and return value (result). : (no return value)
- requiring(dependency, message) : requiring a dependency : (no return value)
- beforeAssertion(assertion) : before an assertion has been made : (no return value)
- afterAssertion(assertion) : after an assertion has been made : (no return value)
- addingMatcher(name, body) : unprocessed matcher name and body : (no return value)
- addingSuite(suite) : adding Suite instance to JSpec : (no return value)
- beforeSuite(suite) : before running of suite (describe block) : (no return value)
- afterSuite(suite) : after running of suite (describe block) : (no return value)
- beforeSpec(spec) : before running of spec (it block) : (no return value)
- afterSpec(spec) : after running of spec (it block) : (no return value)
- reporting(options) : called before reporting : (no return value)
- evaluatingBody(dsl, matchers, context, contents) : evaluating body contents, with the given context, matchers and dsl. : (no return value)
For example you may wish to proxy files which are being executed, simply implement the
executing method like below. This example will stop execution of any file matching /matchers/.
MyModule = {
executing : function(file) {
if (file.match(/matchers/))
return 'stop'
}
}
JSpec.include(MyModule)
Immutable values may also be passed to hooks using hookImmutable() internally. This allows
for simple numbers, strings, etc to be utilized or altered within a hook implementation. Below
is an example module which adds functionality to the JSpec grammar by converting SomeObject.stub('method')
to stub(SomeObject, 'method'):
JSpec.include({
preprocessing : function(input) {
return input.replace(/(\w+)\.(stub|destub)\((.*?)\)$/gm, '$2($1, $3)')
}
})
== JSpec Command-line Utility
When installed as a Ruby Gem, the `jspec` executable will become available,
allowing you to initialize project templates quickly, as well as auto-testing
specifications when a file is altered.
Initialize JSpec-driven project template in directory 'myproject':
$ jspec init myproject
Once within 'myproject' start testing by executing:
$ jspec
For additional usage execute:
$ jspec help
Or for specific usage:
$ jspec help run
== Rhino
JSpec provides transparent support for Rhino, while using the Terminal formatter.
Simply create a JavaScript file with contents similar to below, and then execute
the command following it:
load('lib/jspec.js')
JSpec
.exec('spec/spec.grammar.js')
.exec('spec/spec.core.js')
.run({ formatter : JSpec.formatters.Terminal, failuresOnly : true })
.report()
Initialize project with:
$ jspec init myproject
Run with:
$ jspec run --rhino
Or bind (automated testing):
$ jspec --rhino
== Server
The Ruby JavaScript testing server included with JSpec simply runs
the spec suites within each browser you specify, while reporting result
back to the terminal. It is essentially the same as using the DOM formatter
and auto-testing each browser, however results are centralized to the terminal,
removing the need to manually view each browser's output.
When utilizing the server if a file named spec/jspec.rb (or jspec/jspec.rb for rails)
is present, then it will be loaded before the server is started. This allows you to
add Sinatra routes, support additional Browsers, etc.
Run with all supported browsers:
$ jspec run --server
Run with specific browsers:
$ jspec run --browsers Safari,Firefox,Chrome,Explorer
Run with alternative browser names:
$ jspec run --browsers safari,ff,chrome,ie
Browsers supported in core:
Browser::Safari
Browser::Chrome
Browser::Opera
Browser::Firefox
Browser::IE
Supplied routes:
/slow/NUMBER
/status/NUMBER
For example $.get('/slow/4', function(){}) will take 4 seconds
to reply, where as $.get('/status/404', function(){}) will respond
with an 404 status code. Add additional Sinatra routes to the jspec.rb
file to add your own functionality.
== Interactive Shell
JSpec provides an interactive shell through Rhino, utilize with:
$ jspec shell
Or to specify additional files to load:
$ jspec shell lib/*.js
Or view additional shell help
$ jspec help shell
== Ruby on Rails
No additional gems are required for JSpec to work with rails, although
http://github.com/bhauman/jspec-rails has been created by 'bhauman'. JSpec
supports Rails out of the box, simply execute:
$ jspec init --rails
Then while still in the root directory of your Rails project, run the following
command which will bind to, and refresh your browsers automatically when any changes
are made to ./public/javascripts/*.js or ./jspec/*.js
$ jspec
Or just like regular JSpec applications, run once:
$ jspec run
Or run via the terminal using Rhino:
$ jspec run --rhino
== Support Browsers
Browsers below are supported and can be found in server/browsers.rb, however
your spec/server.rb file may support additional browsers.
* Safari
* Chrome
* Firefox
* Opera
* Internet Explorer
== Known Issues
* Tabs may cause a parse error. To prevent this use 'soft tabs' (setting in your IDE/Editor)
or use JSpec's grammar-less alternative (mentioned above).
* The preprocessor is not (yet) capable of multiline conversions. For example the following is invalid
object.stub('getContentsOfURL').and_return(function(url){
return 'html'
})
In cases such as this, you may always revert to utilizing JSpec in a grammar-less form as follows:
stub(object, 'getContentsOfURL').and_return(function(url){
return 'html'
})
== Additional JSpec Modules
* JSocka stubbing http://github.com/gisikw/jsocka/tree/master
== More Information
* IRC Channel irc://irc.freenode.net#jspec
* Featured article in JSMag: http://www.jsmag.com/main.issues.description/id=21/
* Syntax comparison with other frameworks http://gist.github.com/92283
* Get the TextMate bundle at https://github.com/visionmedia/jspec.tmbundle/tree
* For more information consult the JSpec source code documentation or visit http://visionmedia.github.com/jspec
* jQuery + HTML fixture example http://gist.github.com/147831
== Contributors
Many ideas and bug reports were contributed by
the following developers, thankyou for making
JSpec more enjoyable, and bug free ;)
* Lawrence Pit
* mpd@jesters-court.ne
* kevin.gisi@gmail.com
* tony_t_tubbs@yahoo.com
* enno84@gmx.net
* fnando
== License
(The MIT License)
Copyright (c) 2008 - 2009 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,75 +0,0 @@
require 'rubygems'
require 'rake'
require 'echoe'
def version
$1 if File.read('lib/jspec.js').match /version *: *'(.*?)'/
end
Echoe.new "jspec", version do |p|
p.author = "TJ Holowaychuk"
p.email = "tj@vision-media.ca"
p.summary = "JavaScript BDD Testing Framework"
p.url = "http://visionmedia.github.com/jspec"
p.runtime_dependencies << "sinatra"
p.runtime_dependencies << "json_pure"
p.runtime_dependencies << "commander >=4.0.0"
p.runtime_dependencies << "bind >=0.2.8"
end
namespace :pkg do
desc 'Build package'
task :build => ['pkg:clear'] do
begin
sh 'mkdir pkg'
sh 'cp -fr lib/* pkg'
minify 'lib/jspec.js', 'pkg/jspec.min.js'
minify 'lib/jspec.jquery.js', 'pkg/jspec.jquery.min.js'
compress 'lib/jspec.css', 'pkg/jspec.min.css'
sh 'git add pkg/.'
rescue Exception => e
puts "Failed to package: #{e}."
else
puts "Packaging of JSpec-#{version} completed."
end
end
desc 'Clear packaging'
task :clear do
if File.directory? 'pkg'
sh 'rm -fr pkg/*'
sh 'rmdir pkg'
end
end
desc 'Display compression savings of last release'
task :savings do
totals = Hash.new { |h, k| h[k] = 0 }
format = '%-20s : %0.3f kb'
totals = %w( pkg/jspec.min.js pkg/jspec.jquery.min.js pkg/jspec.min.css ).inject totals do |total, file|
uncompressed = File.size(file.sub('.min', '')).to_f / 1024
compressed = File.size(file).to_f / 1024
saved = uncompressed - compressed
puts format % [file.sub('pkg/', ''), saved]
totals[:saved] += saved
totals[:uncompressed] += uncompressed
totals[:compressed] += compressed
totals
end
puts
puts format % ['total uncompressed', totals[:uncompressed]]
puts format % ['total compressed', totals[:compressed]]
puts format % ['total saved', totals[:saved]]
end
end
def minify from, to
sh "jsmin < #{from} > #{to}"
end
def compress from, to
File.open(to, 'w+') do |file|
file.write File.read(from).gsub(/(^[\t ]*)|\n/, '')
end
end

View File

@ -1,305 +0,0 @@
#!/usr/bin/env ruby
JSPEC_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
$:.unshift JSPEC_ROOT
require 'rubygems'
require 'commander/import'
require 'bind'
require 'fileutils'
require 'server/server'
RHINO = 'java org.mozilla.javascript.tools.shell.Main'
program :name, 'JSpec'
program :version, '2.11.7'
program :description, 'JavaScript BDD Testing Framework'
default_command :bind
command :init do |c|
c.syntax = 'jspec init [dest]'
c.summary = 'Initialize a JSpec project template'
c.description = 'Initialize a JSpec project template. Defaults to the current directory
when [dest] is not specified. The template includes several files for
running via Rhino, DOM, and the JSpec Rack server.
Additional switches --freeze, and --symlink are available in order
to preserve the version of JSpec at the time of initialization. Otherwise
incompatibilities from later versions may prevent your suite from
running properly.'
c.option '-R', '--rails', 'Initialize rails template from rails root directory'
c.option '-f', '--freeze', 'Copy the JSpec library'
c.option '-s', '--symlink', 'Symlink the JSpec library instead of copying it'
c.example 'Create a directory foo, initialized with a jspec template', 'jspec init foo'
c.when_called do |args, options|
dest = args.shift || '.'
if options.rails
initialize_rails_at dest, options
else
initialize_at dest, options
end
say "Template initialized at `#{dest}'"
end
end
command :shell do |c|
c.syntax = 'jspec shell [path ...]'
c.summary = 'JSpec interactive shell'
c.description = 'Launch interactive shell with jspec.js, jspec.shell.js,
and any [path]s given. Simply type "quit" or "exit" to
terminate the shell.'
c.example 'Run shell', 'jspec shell'
c.example 'Run shell with glob of files', 'jspec shell lib/*.js'
c.example 'Run shell with list of files', 'jspec shell lib/foo.js lib/bar.js'
c.when_called do |args, options|
paths = ['jspec.js', 'jspec.shell.js'] | args
paths.map! do |path|
if path.include? 'jspec'
"-f #{JSPEC_ROOT}/lib/#{path}"
else
"-f #{path}"
end
end
say "JSpec #{program(:version)}"
`#{RHINO} #{paths.join(' ')} -f -`
end
end
command :update do |c|
c.syntax = 'jspec update [path ...]'
c.summary = 'Update JSpec releases'
c.description = 'Update JSpec release in [paths], this will allow you to utilize
the latest JSpec features. Execute from JSpec project root without [paths] to
update the default template spec files.'
c.when_called do |args, options|
if args.empty?
if rails?
paths = 'jspec/spec.dom.html', 'jspec/spec.rhino.js'
else
paths = 'spec/spec.dom.html', 'spec/spec.rhino.js'
end
else
paths = args
end
update_version_in *paths
end
end
command :run do |c|
c.syntax = 'jspec run [path] [options]'
c.summary = 'Run specifications'
c.description = 'Run specifications, defaulting [path] to spec/spec.dom.html.
You will need to supply [path] if your specs do not reside
in this location. `run --bind` is the default sub-command of
jspec so you may simply execute `jspec` in order to bind execution
of your specs when a file is altered.
JSpec supports Rhino execution when installed. The [path] is assumed
to be spec/spec.rhino.js unless specified. See examples below for
using the --rhino switch.
JSpec\'s server is also available via --server, which defaults
the [path] to spec/server.html'
c.example 'Run once in Safari', 'jspec run'
c.example 'Run once in Safari and Firefox', 'jspec run --browsers Safari,Firefox'
c.example 'Run once in Opera, Firefox, and Chrome', 'jspec run --browsers opera,ff,chrome'
c.example 'Run custom spec file', 'jspec run foo.html'
c.example 'Auto-run browsers when a file is altered', 'jspec run --bind --browsers Safari,Firefox'
c.example 'Shortcut for the previous example', 'jspec --browsers Safari,Firefox'
c.example 'Auto-run rhino when a file is altered', 'jspec --rhino'
c.example 'Run Rhino specs at spec/rhino.js', 'jspec run --rhino'
c.example 'Run Rhino specs once', 'jspec run specs/something.js --rhino'
c.option '-b', '--browsers BROWSERS', Array, 'Specify browsers to test'
c.option '-p', '--paths PATHS', Array, 'Specify paths when binding, defaults to javascript within ./lib and ./spec'
c.option '-B', '--bind', 'Auto-run specs when source files or specs are altered'
c.option '-R', '--rhino', 'Run specs using Rhino'
c.option '-S', '--server', 'Run specs using the JSpec server'
c.option '-P', '--port NUMBER', Integer, 'Start JSpec server using the given port number'
c.when_called do |args, options|
# Rails
if rails?
options.default :paths => ['public/javascripts/**/*.js', 'jspec/**/*.js'], :port => 4444
else
options.default :paths => ['lib/**/*.js', 'spec/**/*.js'], :port => 4444
end
# Actions
if options.rhino
suite = args.shift || path_to('spec.rhino.js')
action = lambda { rhino suite }
elsif options.server
raise 'Cannot use --server with --bind' if options.bind
suite = args.shift || path_to('spec.server.html')
action = lambda { start_server suite, options }
else
suite = args.shift || path_to('spec.dom.html')
browsers = browsers_for options.browsers || ['safari']
action = lambda do
browsers.each do |browser|
browser.visit File.expand_path(suite)
end
end
end
# Binding
if options.bind
listener = Bind::Listener.new :paths => options.paths, :interval => 1, :actions => [action], :debug => $stdout
listener.run!
else
action.call File.new(suite)
end
end
end
alias_command :bind, :run, '--bind'
##
# Initialize template at _dest_.
def initialize_at dest, options
unless Dir[dest + '/*'].empty?
abort unless agree "'#{dest}' is not empty; continue? "
end
copy_template_to 'default', dest
setup_lib_dir dest, options
replace_root_in dest, 'spec/spec.dom.html', 'spec/spec.rhino.js'
end
##
# Initialize rails template at _dest_.
def initialize_rails_at dest, options
unless looks_like_rails_root?(dest)
abort unless agree "'#{dest}' does not look like root of a rails project; continue? "
end
copy_template_to 'rails', "#{dest}/jspec"
setup_lib_dir "#{dest}/jspec", options
replace_root_in "#{dest}/jspec", 'spec.dom.html', 'spec.rhino.js'
end
##
# Copy template _name_ to _dest_.
def copy_template_to name, dest
FileUtils.mkdir_p dest
FileUtils.cp_r path_to_template(name), dest
end
##
# Return path to template _name_.
def path_to_template name
File.join JSPEC_ROOT, 'templates', name, '.'
end
##
# Resolve path to _file_. Supports rails and unbound projects.
def path_to file
rails? ? "jspec/#{file}" : "spec/#{file}"
end
##
# Execute _file_ with Rhino.
def rhino file
raise "#{file} not found" unless File.exists? file
system "#{RHINO} #{file}"
end
##
# Start server with _suite_ html and _options_.
def start_server suite, options
set :port, options.port
set :server, 'Mongrel'
enable :sessions
disable :logging
hook = File.expand_path path_to('server.rb')
load hook if File.exists? hook
JSpec::Server.new(suite, options.port).start(options.browsers ? browsers_for(options.browsers) : nil)
end
##
# Return array of browser instances for the given _names_.
def browsers_for names
names.map do |name|
begin
Browser.subclasses.find do |browser|
browser.matches_name? name
end.new
rescue
raise "Unsupported browser `#{name}'"
end
end
end
##
# Check if the current directory looks like a rails app.
def rails?
File.directory? 'jspec'
end
##
# Replace JSPEC_ROOT placeholder in _paths_ relative to _dest_.
def replace_root_in dest, *paths
if rails? && File.exist?("#{dest}/jspec/lib")
root = './jspec'
elsif File.exist?("#{dest}/spec/lib")
root = "./spec"
else
root = JSPEC_ROOT
end
paths.each do |path|
path = File.join dest, path
contents = File.read(path).gsub 'JSPEC_ROOT', root
File.open(path, 'w') { |file| file.write contents }
end
end
##
# Update JSpec version in _paths_. Matches jspec-TRIPLE
def update_version_in *paths
paths.each do |path|
next unless File.exists? path
contents = File.read(path).gsub /jspec-(\d+\.\d+\.\d+)/, "jspec-#{program(:version)}"
File.open(path, 'r+'){ |file| file.write contents }
say "Updated #{path}; #{$1} -> #{program(:version)}"
end
say "Finished updating JSpec"
end
##
# Check if _path_ looks like a rails root directory.
def looks_like_rails_root? path = '.'
File.directory? "#{path}/vendor"
end
##
# Copy or symlink library to the specified path.
def setup_lib_dir dest, options
return unless options.symlink || options.freeze
if rails?
dest = File.join dest, "lib"
else
dest = File.join dest, "spec", "lib"
end
from = File.join JSPEC_ROOT, "lib"
if options.symlink
FileUtils.symlink from, dest, :force => true
else
FileUtils.cp_r from, dest
end
end

View File

@ -1,44 +0,0 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{jspec}
s.version = "2.11.7"
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
s.authors = ["TJ Holowaychuk"]
s.date = %q{2009-10-15}
s.default_executable = %q{jspec}
s.description = %q{JavaScript BDD Testing Framework}
s.email = %q{tj@vision-media.ca}
s.executables = ["jspec"]
s.extra_rdoc_files = ["README.rdoc", "bin/jspec", "lib/images/bg.png", "lib/images/hr.png", "lib/images/loading.gif", "lib/images/sprites.bg.png", "lib/images/sprites.png", "lib/images/vr.png", "lib/jspec.css", "lib/jspec.jquery.js", "lib/jspec.js", "lib/jspec.shell.js", "lib/jspec.timers.js", "lib/jspec.xhr.js"]
s.files = ["History.rdoc", "Manifest", "README.rdoc", "Rakefile", "bin/jspec", "jspec.gemspec", "lib/images/bg.png", "lib/images/hr.png", "lib/images/loading.gif", "lib/images/sprites.bg.png", "lib/images/sprites.png", "lib/images/vr.png", "lib/jspec.css", "lib/jspec.jquery.js", "lib/jspec.js", "lib/jspec.shell.js", "lib/jspec.timers.js", "lib/jspec.xhr.js", "server/browsers.rb", "server/helpers.rb", "server/routes.rb", "server/server.rb", "spec/async", "spec/env.js", "spec/fixtures/test.html", "spec/fixtures/test.json", "spec/fixtures/test.xml", "spec/helpers.js", "spec/server.rb", "spec/spec.dom.html", "spec/spec.fixtures.js", "spec/spec.grammar-less.js", "spec/spec.grammar.js", "spec/spec.jquery.js", "spec/spec.jquery.xhr.js", "spec/spec.js", "spec/spec.matchers.js", "spec/spec.modules.js", "spec/spec.node.js", "spec/spec.rhino.js", "spec/spec.server.html", "spec/spec.shared-behaviors.js", "spec/spec.utils.js", "spec/spec.xhr.js", "templates/default/History.rdoc", "templates/default/README.rdoc", "templates/default/lib/yourlib.core.js", "templates/default/spec/server.rb", "templates/default/spec/spec.core.js", "templates/default/spec/spec.dom.html", "templates/default/spec/spec.rhino.js", "templates/default/spec/spec.server.html", "templates/rails/server.rb", "templates/rails/spec.application.js", "templates/rails/spec.dom.html", "templates/rails/spec.rhino.js", "templates/rails/spec.server.html"]
s.homepage = %q{http://visionmedia.github.com/jspec}
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Jspec", "--main", "README.rdoc"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{jspec}
s.rubygems_version = %q{1.3.5}
s.summary = %q{JavaScript BDD Testing Framework}
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<sinatra>, [">= 0"])
s.add_runtime_dependency(%q<json_pure>, [">= 0"])
s.add_runtime_dependency(%q<commander>, [">= 4.0.0"])
s.add_runtime_dependency(%q<bind>, [">= 0.2.8"])
else
s.add_dependency(%q<sinatra>, [">= 0"])
s.add_dependency(%q<json_pure>, [">= 0"])
s.add_dependency(%q<commander>, [">= 4.0.0"])
s.add_dependency(%q<bind>, [">= 0.2.8"])
end
else
s.add_dependency(%q<sinatra>, [">= 0"])
s.add_dependency(%q<json_pure>, [">= 0"])
s.add_dependency(%q<commander>, [">= 4.0.0"])
s.add_dependency(%q<bind>, [">= 0.2.8"])
end
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

View File

@ -1,147 +0,0 @@
body.jspec {
margin: 45px 0;
font: 12px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
background: #efefef url(images/bg.png) top left repeat-x;
text-align: center;
}
#jspec {
margin: 0 auto;
padding-top: 30px;
width: 1008px;
background: url(images/vr.png) top left repeat-y;
text-align: left;
}
#jspec-top {
position: relative;
margin: 0 auto;
width: 1008px;
height: 40px;
background: url(images/sprites.bg.png) top left no-repeat;
}
#jspec-bottom {
margin: 0 auto;
width: 1008px;
height: 15px;
background: url(images/sprites.bg.png) bottom left no-repeat;
}
#jspec .loading {
margin-top: -45px;
width: 1008px;
height: 80px;
background: url(images/loading.gif) 50% 50% no-repeat;
}
#jspec-title {
position: absolute;
top: 15px;
left: 20px;
width: 160px;
font-size: 22px;
font-weight: normal;
background: url(images/sprites.png) 0 -126px no-repeat;
text-align: center;
}
#jspec-title em {
font-size: 10px;
font-style: normal;
color: #BCC8D1;
}
#jspec-report * {
margin: 0;
padding: 0;
background: none;
border: none;
}
#jspec-report {
padding: 15px 40px;
font: 11px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
color: #7B8D9B;
}
#jspec-report.has-failures {
padding-bottom: 30px;
}
#jspec-report .hidden {
display: none;
}
#jspec-report .heading {
margin-bottom: 15px;
}
#jspec-report .heading span {
padding-right: 10px;
}
#jspec-report .heading .passes em {
color: #0ea0eb;
}
#jspec-report .heading .failures em {
color: #FA1616;
}
#jspec-report table {
font-size: 11px;
border-collapse: collapse;
}
#jspec-report td {
padding: 8px;
text-indent: 30px;
color: #7B8D9B;
}
#jspec-report tr.body {
display: none;
}
#jspec-report tr.body pre {
margin: 0;
padding: 0 0 5px 25px;
}
#jspec-report tr.even:hover + tr.body,
#jspec-report tr.odd:hover + tr.body {
display: block;
}
#jspec-report tr td:first-child em {
font-style: normal;
font-weight: normal;
color: #7B8D9B;
}
#jspec-report tr.even:hover,
#jspec-report tr.odd:hover {
text-shadow: 1px 1px 1px #fff;
background: #F2F5F7;
}
#jspec-report td + td {
padding-right: 0;
width: 15px;
}
#jspec-report td.pass {
background: url(images/sprites.png) 3px -7px no-repeat;
}
#jspec-report td.fail {
background: url(images/sprites.png) 3px -47px no-repeat;
font-weight: bold;
color: #FC0D0D;
}
#jspec-report td.requires-implementation {
background: url(images/sprites.png) 3px -87px no-repeat;
}
#jspec-report tr.description td {
margin-top: 25px;
padding-top: 25px;
font-size: 12px;
font-weight: bold;
text-indent: 0;
color: #1a1a1a;
}
#jspec-report tr.description:first-child td {
border-top: none;
}
#jspec-report .assertion {
display: block;
float: left;
margin: 0 0 0 1px;
padding: 0;
width: 1px;
height: 5px;
background: #7B8D9B;
}
#jspec-report .assertion.failed {
background: red;
}
.jspec-sandbox {
display: none;
}

View File

@ -1,71 +0,0 @@
// JSpec - jQuery - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
JSpec
.requires('jQuery', 'when using jspec.jquery.js')
.include({
name: 'jQuery',
// --- Initialize
init : function() {
jQuery.ajaxSetup({ async: false })
},
// --- Utilities
utilities : {
element: jQuery,
elements: jQuery,
sandbox : function() {
return jQuery('<div class="sandbox"></div>')
}
},
// --- Matchers
matchers : {
have_tag : "jQuery(expected, actual).length == 1",
have_one : "alias have_tag",
have_tags : "jQuery(expected, actual).length > 1",
have_many : "alias have_tags",
have_child : "jQuery(actual).children(expected).length == 1",
have_children : "jQuery(actual).children(expected).length > 1",
have_text : "jQuery(actual).text() == expected",
have_value : "jQuery(actual).val() == expected",
be_enabled : "!jQuery(actual).attr('disabled')",
have_class : "jQuery(actual).hasClass(expected)",
be_visible : function(actual) {
return jQuery(actual).css('display') != 'none' &&
jQuery(actual).css('visibility') != 'hidden' &&
jQuery(actual).attr('type') != 'hidden'
},
be_hidden : function(actual) {
return !JSpec.does(actual, 'be_visible')
},
have_classes : function(actual) {
return !JSpec.any(JSpec.argumentsToArray(arguments, 1), function(arg){
return !JSpec.does(actual, 'have_class', arg)
})
},
have_attr : function(actual, attr, value) {
return value ? jQuery(actual).attr(attr) == value:
jQuery(actual).attr(attr)
},
'be disabled selected checked' : function(attr) {
return 'jQuery(actual).attr("' + attr + '")'
},
'have type id title alt href src sel rev name target' : function(attr) {
return function(actual, value) {
return JSpec.does(actual, 'have_attr', attr, value)
}
}
}
})

View File

@ -1,1776 +0,0 @@
// JSpec - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
(function(){
JSpec = {
version : '2.11.7',
cache : {},
suites : [],
modules : [],
allSuites : [],
matchers : {},
stubbed : [],
request : 'XMLHttpRequest' in this ? XMLHttpRequest : null,
stats : { specs: 0, assertions: 0, failures: 0, passes: 0, specsFinished: 0, suitesFinished: 0 },
options : { profile: false },
/**
* Default context in which bodies are evaluated.
*
* Replace context simply by setting JSpec.context
* to your own like below:
*
* JSpec.context = { foo : 'bar' }
*
* Contexts can be changed within any body, this can be useful
* in order to provide specific helper methods to specific suites.
*
* To reset (usually in after hook) simply set to null like below:
*
* JSpec.context = null
*
*/
defaultContext : {
/**
* Return an object used for proxy assertions.
* This object is used to indicate that an object
* should be an instance of _object_, not the constructor
* itself.
*
* @param {function} constructor
* @return {hash}
* @api public
*/
an_instance_of : function(constructor) {
return { an_instance_of : constructor }
},
/**
* Load fixture at _path_. This utility function
* supplies the means to resolve, and cache fixture contents
* via the DOM or Rhino.
*
* Fixtures are resolved as:
*
* - <path>
* - fixtures/<path>
* - fixtures/<path>.html
*
* @param {string} path
* @return {string}
* @api public
*/
fixture : function(path) {
if (JSpec.cache[path]) return JSpec.cache[path]
return JSpec.cache[path] =
JSpec.tryLoading(path) ||
JSpec.tryLoading('fixtures/' + path) ||
JSpec.tryLoading('fixtures/' + path + '.html') ||
JSpec.tryLoading('spec/' + path) ||
JSpec.tryLoading('spec/fixtures/' + path) ||
JSpec.tryLoading('spec/fixtures/' + path + '.html')
}
},
// --- Objects
formatters : {
/**
* Report to server.
*
* Options:
* - uri specific uri to report to.
* - verbose weither or not to output messages
* - failuresOnly output failure messages only
*
* @api public
*/
Server : function(results, options) {
var uri = options.uri || 'http://' + window.location.host + '/results'
JSpec.post(uri, {
stats: JSpec.stats,
options: options,
results: map(results.allSuites, function(suite) {
if (suite.hasSpecs())
return {
description: suite.description,
specs: map(suite.specs, function(spec) {
return {
description: spec.description,
message: !spec.passed() ? spec.failure().message : null,
status: spec.requiresImplementation() ? 'pending' :
spec.passed() ? 'pass' :
'fail',
assertions: map(spec.assertions, function(assertion){
return {
passed: assertion.passed
}
})
}
})
}
})
})
if ('close' in main) main.close()
},
/**
* Default formatter, outputting to the DOM.
*
* Options:
* - reportToId id of element to output reports to, defaults to 'jspec'
* - failuresOnly displays only suites with failing specs
*
* @api public
*/
DOM : function(results, options) {
var id = option('reportToId') || 'jspec'
var report = document.getElementById(id)
var failuresOnly = option('failuresOnly')
var classes = results.stats.failures ? 'has-failures' : ''
if (!report) throw 'JSpec requires the element #' + id + ' to output its reports'
function bodyContents(body) {
return JSpec.
escape(JSpec.contentsOf(body)).
replace(/^ */gm, function(a){ return (new Array(Math.round(a.length / 3))).join(' ') }).
replace(/\r\n|\r|\n/gm, '<br/>')
}
report.innerHTML = '<div id="jspec-report" class="' + classes + '"><div class="heading"> \
<span class="passes">Passes: <em>' + results.stats.passes + '</em></span> \
<span class="failures">Failures: <em>' + results.stats.failures + '</em></span> \
</div><table class="suites">' + map(results.allSuites, function(suite) {
var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
if (displaySuite && suite.hasSpecs())
return '<tr class="description"><td colspan="2">' + escape(suite.description) + '</td></tr>' +
map(suite.specs, function(i, spec) {
return '<tr class="' + (i % 2 ? 'odd' : 'even') + '">' +
(spec.requiresImplementation() ?
'<td class="requires-implementation" colspan="2">' + escape(spec.description) + '</td>' :
(spec.passed() && !failuresOnly) ?
'<td class="pass">' + escape(spec.description)+ '</td><td>' + spec.assertionsGraph() + '</td>' :
!spec.passed() ?
'<td class="fail">' + escape(spec.description) + ' <em>' + escape(spec.failure().message) + '</em>' + '</td><td>' + spec.assertionsGraph() + '</td>' :
'') +
'<tr class="body"><td colspan="2"><pre>' + bodyContents(spec.body) + '</pre></td></tr>'
}).join('') + '</tr>'
}).join('') + '</table></div>'
},
/**
* Terminal formatter.
*
* @api public
*/
Terminal : function(results, options) {
failuresOnly = option('failuresOnly')
print(color("\n Passes: ", 'bold') + color(results.stats.passes, 'green') +
color(" Failures: ", 'bold') + color(results.stats.failures, 'red') + "\n")
function indent(string) {
return string.replace(/^(.)/gm, ' $1')
}
each(results.allSuites, function(suite) {
var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
if (displaySuite && suite.hasSpecs()) {
print(color(' ' + suite.description, 'bold'))
each(suite.specs, function(spec){
var assertionsGraph = inject(spec.assertions, '', function(graph, assertion){
return graph + color('.', assertion.passed ? 'green' : 'red')
})
if (spec.requiresImplementation())
print(color(' ' + spec.description, 'blue') + assertionsGraph)
else if (spec.passed() && !failuresOnly)
print(color(' ' + spec.description, 'green') + assertionsGraph)
else if (!spec.passed())
print(color(' ' + spec.description, 'red') + assertionsGraph +
"\n" + indent(spec.failure().message) + "\n")
})
print("")
}
})
},
/**
* Console formatter.
*
* @api public
*/
Console : function(results, options) {
console.log('')
console.log('Passes: ' + results.stats.passes + ' Failures: ' + results.stats.failures)
each(results.allSuites, function(suite) {
if (suite.ran) {
console.group(suite.description)
each(suite.specs, function(spec){
var assertionCount = spec.assertions.length + ':'
if (spec.requiresImplementation())
console.warn(spec.description)
else if (spec.passed())
console.log(assertionCount + ' ' + spec.description)
else
console.error(assertionCount + ' ' + spec.description + ', ' + spec.failure().message)
})
console.groupEnd()
}
})
}
},
Assertion : function(matcher, actual, expected, negate) {
extend(this, {
message: '',
passed: false,
actual: actual,
negate: negate,
matcher: matcher,
expected: expected,
// Report assertion results
report : function() {
this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++
return this
},
// Run the assertion
run : function() {
// TODO: remove unshifting
expected.unshift(actual)
this.result = matcher.match.apply(this, expected)
this.passed = negate ? !this.result : this.result
if (!this.passed) this.message = matcher.message.call(this, actual, expected, negate, matcher.name)
return this
}
})
},
ProxyAssertion : function(object, method, times, negate) {
var self = this
var old = object[method]
// Proxy
object[method] = function(){
args = argumentsToArray(arguments)
result = old.apply(object, args)
self.calls.push({ args : args, result : result })
return result
}
// Times
this.times = {
once : 1,
twice : 2
}[times] || times || 1
extend(this, {
calls: [],
message: '',
defer: true,
passed: false,
negate: negate,
object: object,
method: method,
// Proxy return value
and_return : function(result) {
this.expectedResult = result
return this
},
// Proxy arguments passed
with_args : function() {
this.expectedArgs = argumentsToArray(arguments)
return this
},
// Check if any calls have failing results
anyResultsFail : function() {
return any(this.calls, function(call){
return self.expectedResult.an_instance_of ?
call.result.constructor != self.expectedResult.an_instance_of:
hash(self.expectedResult) != hash(call.result)
})
},
// Check if any calls have passing results
anyResultsPass : function() {
return any(this.calls, function(call){
return self.expectedResult.an_instance_of ?
call.result.constructor == self.expectedResult.an_instance_of:
hash(self.expectedResult) == hash(call.result)
})
},
// Return the passing result
passingResult : function() {
return this.anyResultsPass().result
},
// Return the failing result
failingResult : function() {
return this.anyResultsFail().result
},
// Check if any arguments fail
anyArgsFail : function() {
return any(this.calls, function(call){
return any(self.expectedArgs, function(i, arg){
if (arg == null) return call.args[i] == null
return arg.an_instance_of ?
call.args[i].constructor != arg.an_instance_of:
hash(arg) != hash(call.args[i])
})
})
},
// Check if any arguments pass
anyArgsPass : function() {
return any(this.calls, function(call){
return any(self.expectedArgs, function(i, arg){
return arg.an_instance_of ?
call.args[i].constructor == arg.an_instance_of:
hash(arg) == hash(call.args[i])
})
})
},
// Return the passing args
passingArgs : function() {
return this.anyArgsPass().args
},
// Return the failing args
failingArgs : function() {
return this.anyArgsFail().args
},
// Report assertion results
report : function() {
this.passed ? ++JSpec.stats.passes : ++JSpec.stats.failures
return this
},
// Run the assertion
run : function() {
var methodString = 'expected ' + object.toString() + '.' + method + '()' + (negate ? ' not' : '' )
function times(n) {
return n > 2 ? n + ' times' : { 1: 'once', 2: 'twice' }[n]
}
if (this.expectedResult != null && (negate ? this.anyResultsPass() : this.anyResultsFail()))
this.message = methodString + ' to return ' + puts(this.expectedResult) +
' but ' + (negate ? 'it did' : 'got ' + puts(this.failingResult()))
if (this.expectedArgs && (negate ? !this.expectedResult && this.anyArgsPass() : this.anyArgsFail()))
this.message = methodString + ' to be called with ' + puts.apply(this, this.expectedArgs) +
' but was' + (negate ? '' : ' called with ' + puts.apply(this, this.failingArgs()))
if (negate ? !this.expectedResult && !this.expectedArgs && this.calls.length == this.times : this.calls.length != this.times)
this.message = methodString + ' to be called ' + times(this.times) +
', but ' + (this.calls.length == 0 ? ' was not called' : ' was called ' + times(this.calls.length))
if (!this.message.length)
this.passed = true
return this
}
})
},
/**
* Specification Suite block object.
*
* @param {string} description
* @param {function} body
* @api private
*/
Suite : function(description, body) {
var self = this
extend(this, {
body: body,
description: description,
suites: [],
specs: [],
ran: false,
hooks: { 'before' : [], 'after' : [], 'before_each' : [], 'after_each' : [] },
// Add a spec to the suite
addSpec : function(description, body) {
var spec = new JSpec.Spec(description, body)
this.specs.push(spec)
JSpec.stats.specs++ // TODO: abstract
spec.suite = this
},
// Add a hook to the suite
addHook : function(hook, body) {
this.hooks[hook].push(body)
},
// Add a nested suite
addSuite : function(description, body) {
var suite = new JSpec.Suite(description, body)
JSpec.allSuites.push(suite)
suite.name = suite.description
suite.description = this.description + ' ' + suite.description
this.suites.push(suite)
suite.suite = this
},
// Invoke a hook in context to this suite
hook : function(hook) {
if (this.suite) this.suite.hook(hook)
each(this.hooks[hook], function(body) {
JSpec.evalBody(body, "Error in hook '" + hook + "', suite '" + self.description + "': ")
})
},
// Check if nested suites are present
hasSuites : function() {
return this.suites.length
},
// Check if this suite has specs
hasSpecs : function() {
return this.specs.length
},
// Check if the entire suite passed
passed : function() {
return !any(this.specs, function(spec){
return !spec.passed()
})
}
})
},
/**
* Specification block object.
*
* @param {string} description
* @param {function} body
* @api private
*/
Spec : function(description, body) {
extend(this, {
body: body,
description: description,
assertions: [],
// Add passing assertion
pass : function(message) {
this.assertions.push({ passed: true, message: message })
++JSpec.stats.passes
},
// Add failing assertion
fail : function(message) {
this.assertions.push({ passed: false, message: message })
++JSpec.stats.failures
},
// Run deferred assertions
runDeferredAssertions : function() {
each(this.assertions, function(assertion){
if (assertion.defer) assertion.run().report(), hook('afterAssertion', assertion)
})
},
// Find first failing assertion
failure : function() {
return find(this.assertions, function(assertion){
return !assertion.passed
})
},
// Find all failing assertions
failures : function() {
return select(this.assertions, function(assertion){
return !assertion.passed
})
},
// Weither or not the spec passed
passed : function() {
return !this.failure()
},
// Weither or not the spec requires implementation (no assertions)
requiresImplementation : function() {
return this.assertions.length == 0
},
// Sprite based assertions graph
assertionsGraph : function() {
return map(this.assertions, function(assertion){
return '<span class="assertion ' + (assertion.passed ? 'passed' : 'failed') + '"></span>'
}).join('')
}
})
},
Module : function(methods) {
extend(this, methods)
},
JSON : {
/**
* Generic sequences.
*/
meta : {
'\b' : '\\b',
'\t' : '\\t',
'\n' : '\\n',
'\f' : '\\f',
'\r' : '\\r',
'"' : '\\"',
'\\' : '\\\\'
},
/**
* Escapable sequences.
*/
escapable : /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
/**
* JSON encode _object_.
*
* @param {mixed} object
* @return {string}
* @api private
*/
encode : function(object) {
var self = this
if (object == undefined || object == null) return 'null'
if (object === true) return 'true'
if (object === false) return 'false'
switch (typeof object) {
case 'number': return object
case 'string': return this.escapable.test(object) ?
'"' + object.replace(this.escapable, function (a) {
return typeof self.meta[a] === 'string' ? self.meta[a] :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)
}) + '"' :
'"' + object + '"'
case 'object':
if (object.constructor == Array)
return '[' + map(object, function(val){
return self.encode(val)
}).join(', ') + ']'
else if (object)
return '{' + map(object, function(key, val){
return self.encode(key) + ':' + self.encode(val)
}).join(', ') + '}'
}
return 'null'
}
},
// --- DSLs
DSLs : {
snake : {
expect : function(actual){
return JSpec.expect(actual)
},
describe : function(description, body) {
return JSpec.currentSuite.addSuite(description, body)
},
it : function(description, body) {
return JSpec.currentSuite.addSpec(description, body)
},
before : function(body) {
return JSpec.currentSuite.addHook('before', body)
},
after : function(body) {
return JSpec.currentSuite.addHook('after', body)
},
before_each : function(body) {
return JSpec.currentSuite.addHook('before_each', body)
},
after_each : function(body) {
return JSpec.currentSuite.addHook('after_each', body)
},
should_behave_like : function(description) {
return JSpec.shareBehaviorsOf(description)
}
}
},
// --- Methods
/**
* Check if _value_ is 'stop'. For use as a
* utility callback function.
*
* @param {mixed} value
* @return {bool}
* @api public
*/
haveStopped : function(value) {
return value === 'stop'
},
/**
* Include _object_ which may be a hash or Module instance.
*
* @param {has, Module} object
* @return {JSpec}
* @api public
*/
include : function(object) {
var module = object.constructor == JSpec.Module ? object : new JSpec.Module(object)
this.modules.push(module)
if ('init' in module) module.init()
if ('utilities' in module) extend(this.defaultContext, module.utilities)
if ('matchers' in module) this.addMatchers(module.matchers)
if ('formatters' in module) extend(this.formatters, module.formatters)
if ('DSLs' in module)
each(module.DSLs, function(name, methods){
JSpec.DSLs[name] = JSpec.DSLs[name] || {}
extend(JSpec.DSLs[name], methods)
})
return this
},
/**
* Add a module hook _name_, which is immediately
* called per module with the _args_ given. An array of
* hook return values is returned.
*
* @param {name} string
* @param {...} args
* @return {array}
* @api private
*/
hook : function(name, args) {
args = argumentsToArray(arguments, 1)
return inject(JSpec.modules, [], function(results, module){
if (typeof module[name] == 'function')
results.push(JSpec.evalHook(module, name, args))
})
},
/**
* Eval _module_ hook _name_ with _args_. Evaluates in context
* to the module itself, JSpec, and JSpec.context.
*
* @param {Module} module
* @param {string} name
* @param {array} args
* @return {mixed}
* @api private
*/
evalHook : function(module, name, args) {
hook('evaluatingHookBody', module, name)
try { return module[name].apply(module, args) }
catch(e) { error('Error in hook ' + module.name + '.' + name + ': ', e) }
},
/**
* Same as hook() however accepts only one _arg_ which is
* considered immutable. This function passes the arg
* to the first module, then passes the return value of the last
* module called, to the following module.
*
* @param {string} name
* @param {mixed} arg
* @return {mixed}
* @api private
*/
hookImmutable : function(name, arg) {
return inject(JSpec.modules, arg, function(result, module){
if (typeof module[name] == 'function')
return JSpec.evalHook(module, name, [result])
})
},
/**
* Find a suite by its description or name.
*
* @param {string} description
* @return {Suite}
* @api private
*/
findSuite : function(description) {
return find(this.allSuites, function(suite){
return suite.name == description || suite.description == description
})
},
/**
* Share behaviors (specs) of the given suite with
* the current suite.
*
* @param {string} description
* @api public
*/
shareBehaviorsOf : function(description) {
if (suite = this.findSuite(description)) this.copySpecs(suite, this.currentSuite)
else throw 'failed to share behaviors. ' + puts(description) + ' is not a valid Suite name'
},
/**
* Copy specs from one suite to another.
*
* @param {Suite} fromSuite
* @param {Suite} toSuite
* @api public
*/
copySpecs : function(fromSuite, toSuite) {
each(fromSuite.specs, function(spec){
spec.assertions = []
toSuite.specs.push(spec)
})
},
/**
* Convert arguments to an array.
*
* @param {object} arguments
* @param {int} offset
* @return {array}
* @api public
*/
argumentsToArray : function(arguments, offset) {
return Array.prototype.slice.call(arguments, offset || 0)
},
/**
* Return ANSI-escaped colored string.
*
* @param {string} string
* @param {string} color
* @return {string}
* @api public
*/
color : function(string, color) {
return "\u001B[" + {
bold : 1,
black : 30,
red : 31,
green : 32,
yellow : 33,
blue : 34,
magenta : 35,
cyan : 36,
white : 37
}[color] + 'm' + string + "\u001B[0m"
},
/**
* Default matcher message callback.
*
* @api private
*/
defaultMatcherMessage : function(actual, expected, negate, name) {
return 'expected ' + puts(actual) + ' to ' +
(negate ? 'not ' : '') +
name.replace(/_/g, ' ') +
' ' + puts.apply(this, expected.slice(1))
},
/**
* Normalize a matcher message.
*
* When no messge callback is present the defaultMatcherMessage
* will be assigned, will suffice for most matchers.
*
* @param {hash} matcher
* @return {hash}
* @api public
*/
normalizeMatcherMessage : function(matcher) {
if (typeof matcher.message != 'function')
matcher.message = this.defaultMatcherMessage
return matcher
},
/**
* Normalize a matcher body
*
* This process allows the following conversions until
* the matcher is in its final normalized hash state.
*
* - '==' becomes 'actual == expected'
* - 'actual == expected' becomes 'return actual == expected'
* - function(actual, expected) { return actual == expected } becomes
* { match : function(actual, expected) { return actual == expected }}
*
* @param {mixed} body
* @return {hash}
* @api public
*/
normalizeMatcherBody : function(body) {
switch (body.constructor) {
case String:
if (captures = body.match(/^alias (\w+)/)) return JSpec.matchers[last(captures)]
if (body.length < 4) body = 'actual ' + body + ' expected'
return { match: function(actual, expected) { return eval(body) }}
case Function:
return { match: body }
default:
return body
}
},
/**
* Get option value. This method first checks if
* the option key has been set via the query string,
* otherwise returning the options hash value.
*
* @param {string} key
* @return {mixed}
* @api public
*/
option : function(key) {
return (value = query(key)) !== null ? value :
JSpec.options[key] || null
},
/**
* Generates a hash of the object passed.
*
* @param {object} object
* @return {string}
* @api private
*/
hash : function(object) {
if (object == null) return 'null'
if (object == undefined) return 'undefined'
function serialize(prefix) {
return inject(object, prefix + ':', function(buffer, key, value){
return buffer += hash(value)
})
}
switch (object.constructor) {
case Array : return serialize('a')
case RegExp: return 'r:' + object.toString()
case Number: return 'n:' + object.toString()
case String: return 's:' + object.toString()
case Object: return 'o:' + inject(object, [], function(array, key, value){
array.push([key, hash(value)])
}).sort()
default: return object.toString()
}
},
/**
* Return last element of an array.
*
* @param {array} array
* @return {object}
* @api public
*/
last : function(array) {
return array[array.length - 1]
},
/**
* Convert object(s) to a print-friend string.
*
* @param {...} object
* @return {string}
* @api public
*/
puts : function(object) {
if (arguments.length > 1) {
return map(argumentsToArray(arguments), function(arg){
return puts(arg)
}).join(', ')
}
if (object === undefined) return ''
if (object === null) return 'null'
if (object === true) return 'true'
if (object === false) return 'false'
if (object.an_instance_of) return 'an instance of ' + object.an_instance_of.name
if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector) + ''
if (object.jquery) return object.html()
if (object.nodeName) return object.outerHTML
switch (object.constructor) {
case String: return "'" + object + "'"
case Number: return object
case Function: return object.name || object
case Array:
return inject(object, '[', function(b, v){
return b + ', ' + puts(v)
}).replace('[,', '[') + ' ]'
case Object:
return inject(object, '{', function(b, k, v) {
return b + ', ' + puts(k) + ' : ' + puts(v)
}).replace('{,', '{') + ' }'
default:
return object.toString()
}
},
/**
* Escape HTML.
*
* @param {string} html
* @return {string}
* @api public
*/
escape : function(html) {
return html.toString()
.replace(/&/gmi, '&amp;')
.replace(/"/gmi, '&quot;')
.replace(/>/gmi, '&gt;')
.replace(/</gmi, '&lt;')
},
/**
* Perform an assertion without reporting.
*
* This method is primarily used for internal
* matchers in order retain DRYness. May be invoked
* like below:
*
* does('foo', 'eql', 'foo')
* does([1,2], 'include', 1, 2)
*
* External hooks are not run for internal assertions
* performed by does().
*
* @param {mixed} actual
* @param {string} matcher
* @param {...} expected
* @return {mixed}
* @api private
*/
does : function(actual, matcher, expected) {
var assertion = new JSpec.Assertion(JSpec.matchers[matcher], actual, argumentsToArray(arguments, 2))
return assertion.run().result
},
/**
* Perform an assertion.
*
* expect(true).to('be', true)
* expect('foo').not_to('include', 'bar')
* expect([1, [2]]).to('include', 1, [2])
*
* @param {mixed} actual
* @return {hash}
* @api public
*/
expect : function(actual) {
assert = function(matcher, args, negate) {
var expected = argumentsToArray(args, 1)
matcher.negate = negate
assertion = new JSpec.Assertion(matcher, actual, expected, negate)
hook('beforeAssertion', assertion)
if (matcher.defer) assertion.run()
else JSpec.currentSpec.assertions.push(assertion.run().report()), hook('afterAssertion', assertion)
return assertion.result
}
to = function(matcher) {
return assert(matcher, arguments, false)
}
not_to = function(matcher) {
return assert(matcher, arguments, true)
}
return {
to : to,
should : to,
not_to: not_to,
should_not : not_to
}
},
/**
* Strim whitespace or chars.
*
* @param {string} string
* @param {string} chars
* @return {string}
* @api public
*/
strip : function(string, chars) {
return string.
replace(new RegExp('[' + (chars || '\\s') + ']*$'), '').
replace(new RegExp('^[' + (chars || '\\s') + ']*'), '')
},
/**
* Call an iterator callback with arguments a, or b
* depending on the arity of the callback.
*
* @param {function} callback
* @param {mixed} a
* @param {mixed} b
* @return {mixed}
* @api private
*/
callIterator : function(callback, a, b) {
return callback.length == 1 ? callback(b) : callback(a, b)
},
/**
* Extend an object with another.
*
* @param {object} object
* @param {object} other
* @api public
*/
extend : function(object, other) {
each(other, function(property, value){
object[property] = value
})
},
/**
* Iterate an object, invoking the given callback.
*
* @param {hash, array, string} object
* @param {function} callback
* @return {JSpec}
* @api public
*/
each : function(object, callback) {
if (typeof object == 'string') object = object.split(' ')
for (key in object)
if (object.hasOwnProperty(key))
callIterator(callback, key, object[key])
},
/**
* Iterate with memo.
*
* @param {hash, array} object
* @param {object} memo
* @param {function} callback
* @return {object}
* @api public
*/
inject : function(object, memo, callback) {
each(object, function(key, value){
memo = (callback.length == 2 ?
callback(memo, value):
callback(memo, key, value)) ||
memo
})
return memo
},
/**
* Destub _object_'s _method_. When no _method_ is passed
* all stubbed methods are destubbed. When no arguments
* are passed every object found in JSpec.stubbed will be
* destubbed.
*
* @param {mixed} object
* @param {string} method
* @api public
*/
destub : function(object, method) {
if (method) {
if (object['__prototype__' + method])
delete object[method]
else
object[method] = object['__original__' + method]
delete object['__prototype__' + method]
delete object['__original____' + method]
}
else if (object) {
for (var key in object)
if (captures = key.match(/^(?:__prototype__|__original__)(.*)/))
destub(object, captures[1])
}
else
while (JSpec.stubbed.length)
destub(JSpec.stubbed.shift())
},
/**
* Stub _object_'s _method_.
*
* stub(foo, 'toString').and_return('bar')
*
* @param {mixed} object
* @param {string} method
* @return {hash}
* @api public
*/
stub : function(object, method) {
hook('stubbing', object, method)
JSpec.stubbed.push(object)
var type = object.hasOwnProperty(method) ? '__original__' : '__prototype__'
object[type + method] = object[method]
object[method] = function(){}
return {
and_return : function(value) {
if (typeof value == 'function') object[method] = value
else object[method] = function(){ return value }
}
}
},
/**
* Map callback return values.
*
* @param {hash, array} object
* @param {function} callback
* @return {array}
* @api public
*/
map : function(object, callback) {
return inject(object, [], function(memo, key, value){
memo.push(callIterator(callback, key, value))
})
},
/**
* Returns the first matching expression or null.
*
* @param {hash, array} object
* @param {function} callback
* @return {mixed}
* @api public
*/
any : function(object, callback) {
return inject(object, null, function(state, key, value){
if (state == undefined)
return callIterator(callback, key, value) ? value : state
})
},
/**
* Returns an array of values collected when the callback
* given evaluates to true.
*
* @param {hash, array} object
* @return {function} callback
* @return {array}
* @api public
*/
select : function(object, callback) {
return inject(object, [], function(selected, key, value){
if (callIterator(callback, key, value))
selected.push(value)
})
},
/**
* Define matchers.
*
* @param {hash} matchers
* @api public
*/
addMatchers : function(matchers) {
each(matchers, function(name, body){
JSpec.addMatcher(name, body)
})
},
/**
* Define a matcher.
*
* @param {string} name
* @param {hash, function, string} body
* @api public
*/
addMatcher : function(name, body) {
hook('addingMatcher', name, body)
if (name.indexOf(' ') != -1) {
var matchers = name.split(/\s+/)
var prefix = matchers.shift()
each(matchers, function(name) {
JSpec.addMatcher(prefix + '_' + name, body(name))
})
}
this.matchers[name] = this.normalizeMatcherMessage(this.normalizeMatcherBody(body))
this.matchers[name].name = name
},
/**
* Add a root suite to JSpec.
*
* @param {string} description
* @param {body} function
* @api public
*/
describe : function(description, body) {
var suite = new JSpec.Suite(description, body)
hook('addingSuite', suite)
this.allSuites.push(suite)
this.suites.push(suite)
},
/**
* Return the contents of a function body.
*
* @param {function} body
* @return {string}
* @api public
*/
contentsOf : function(body) {
return body.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]
},
/**
* Evaluate a JSpec capture body.
*
* @param {function} body
* @param {string} errorMessage (optional)
* @return {Type}
* @api private
*/
evalBody : function(body, errorMessage) {
var dsl = this.DSL || this.DSLs.snake
var matchers = this.matchers
var context = this.context || this.defaultContext
var contents = this.contentsOf(body)
hook('evaluatingBody', dsl, matchers, context, contents)
try { eval('with (dsl){ with (context) { with (matchers) { ' + contents + ' }}}') }
catch(e) { error(errorMessage, e) }
},
/**
* Pre-process a string of JSpec.
*
* @param {string} input
* @return {string}
* @api private
*/
preprocess : function(input) {
if (typeof input != 'string') return
input = hookImmutable('preprocessing', input)
return input.
replace(/\r\n/gm, '\n').
replace(/([\w\.]+)\.(stub|destub)\((.*?)\)$/gm, '$2($1, $3)').
replace(/describe\s+(.*?)$/gm, 'describe($1, function(){').
replace(/^\s+it\s+(.*?)$/gm, ' it($1, function(){').
replace(/^\s*(before_each|after_each|before|after)(?=\s|$)/gm, 'JSpec.currentSuite.addHook("$1", function(){').
replace(/^\s*end(?=\s|$)/gm, '});').
replace(/-\{/g, 'function(){').
replace(/(\d+)\.\.(\d+)/g, function(_, a, b){ return range(a, b) }).
replace(/\.should([_\.]not)?[_\.](\w+)(?: |;|$)(.*)$/gm, '.should$1_$2($3)').
replace(/([\/\s]*)(.+?)\.(should(?:[_\.]not)?)[_\.](\w+)\((.*)\)\s*;?$/gm, '$1 expect($2).$3($4, $5)').
replace(/, \)/gm, ')').
replace(/should\.not/gm, 'should_not').
replace(/__END__.*/m, '')
},
/**
* Create a range string which can be evaluated to a native array.
*
* @param {int} start
* @param {int} end
* @return {string}
* @api public
*/
range : function(start, end) {
var current = parseInt(start), end = parseInt(end), values = [current]
if (end > current) while (++current <= end) values.push(current)
else while (--current >= end) values.push(current)
return '[' + values + ']'
},
/**
* Report on the results.
*
* @api public
*/
report : function() {
hook('reporting', JSpec.options)
new (JSpec.options.formatter || JSpec.formatters.DOM)(JSpec, JSpec.options)
},
/**
* Run the spec suites. Options are merged
* with JSpec options when present.
*
* @param {hash} options
* @return {JSpec}
* @api public
*/
run : function(options) {
if (any(hook('running'), haveStopped)) return this
if (options) extend(this.options, options)
if (option('profile')) console.group('Profile')
each(this.suites, function(suite) { JSpec.runSuite(suite) })
if (option('profile')) console.groupEnd()
return this
},
/**
* Run a suite.
*
* @param {Suite} suite
* @api public
*/
runSuite : function(suite) {
this.currentSuite = suite
this.evalBody(suite.body)
suite.ran = true
hook('beforeSuite', suite), suite.hook('before')
each(suite.specs, function(spec) {
hook('beforeSpec', spec)
suite.hook('before_each')
JSpec.runSpec(spec)
hook('afterSpec', spec)
suite.hook('after_each')
})
if (suite.hasSuites()) {
each(suite.suites, function(suite) {
JSpec.runSuite(suite)
})
}
hook('afterSuite', suite), suite.hook('after')
this.stats.suitesFinished++
},
/**
* Report a failure for the current spec.
*
* @param {string} message
* @api public
*/
fail : function(message) {
JSpec.currentSpec.fail(message)
},
/**
* Report a passing assertion for the current spec.
*
* @param {string} message
* @api public
*/
pass : function(message) {
JSpec.currentSpec.pass(message)
},
/**
* Run a spec.
*
* @param {Spec} spec
* @api public
*/
runSpec : function(spec) {
this.currentSpec = spec
if (option('profile')) console.time(spec.description)
try { this.evalBody(spec.body) }
catch (e) { fail(e) }
if (option('profile')) console.timeEnd(spec.description)
spec.runDeferredAssertions()
destub()
this.stats.specsFinished++
this.stats.assertions += spec.assertions.length
},
/**
* Require a dependency, with optional message.
*
* @param {string} dependency
* @param {string} message (optional)
* @return {JSpec}
* @api public
*/
requires : function(dependency, message) {
hook('requiring', dependency, message)
try { eval(dependency) }
catch (e) { throw 'JSpec depends on ' + dependency + ' ' + message }
return this
},
/**
* Query against the current query strings keys
* or the queryString specified.
*
* @param {string} key
* @param {string} queryString
* @return {string, null}
* @api private
*/
query : function(key, queryString) {
var queryString = (queryString || (main.location ? main.location.search : null) || '').substring(1)
return inject(queryString.split('&'), null, function(value, pair){
parts = pair.split('=')
return parts[0] == key ? parts[1].replace(/%20|\+/gmi, ' ') : value
})
},
/**
* Throw a JSpec related error.
*
* @param {string} message
* @param {Exception} e
* @api public
*/
error : function(message, e) {
throw (message ? message : '') + e.toString() +
(e.line ? ' near line ' + e.line : '')
},
/**
* Ad-hoc POST request for JSpec server usage.
*
* @param {string} uri
* @param {string} data
* @api private
*/
post : function(uri, data) {
if (any(hook('posting', uri, data), haveStopped)) return
var request = this.xhr()
request.open('POST', uri, false)
request.setRequestHeader('Content-Type', 'application/json')
request.send(JSpec.JSON.encode(data))
},
/**
* Instantiate an XMLHttpRequest.
*
* Here we utilize IE's lame ActiveXObjects first which
* allow IE access serve files via the file: protocol, otherwise
* we then default to XMLHttpRequest.
*
* @return {XMLHttpRequest, ActiveXObject}
* @api private
*/
xhr : function() {
return this.ieXhr() || new JSpec.request
},
/**
* Return Microsoft piece of crap ActiveXObject.
*
* @return {ActiveXObject}
* @api public
*/
ieXhr : function() {
function object(str) {
try { return new ActiveXObject(str) } catch(e) {}
}
return object('Msxml2.XMLHTTP.6.0') ||
object('Msxml2.XMLHTTP.3.0') ||
object('Msxml2.XMLHTTP') ||
object('Microsoft.XMLHTTP')
},
/**
* Check for HTTP request support.
*
* @return {bool}
* @api private
*/
hasXhr : function() {
return JSpec.request || 'ActiveXObject' in main
},
/**
* Try loading _file_ returning the contents
* string or null. Chain to locate / read a file.
*
* @param {string} file
* @return {string}
* @api public
*/
tryLoading : function(file) {
try { return JSpec.load(file) }
catch (e) {}
},
/**
* Load a _file_'s contents.
*
* @param {string} file
* @param {function} callback
* @return {string}
* @api public
*/
load : function(file, callback) {
if (any(hook('loading', file), haveStopped)) return
if ('readFile' in main)
return callback ? readFile(file, callback) : readFile(file)
else if (this.hasXhr()) {
var request = this.xhr()
request.open('GET', file, false)
request.send(null)
if (request.readyState == 4 &&
(request.status == 0 ||
request.status.toString().charAt(0) == 2))
return request.responseText
}
else
error("failed to load `" + file + "'")
},
/**
* Load, pre-process, and evaluate a file.
*
* @param {string} file
* @param {JSpec}
* @api public
*/
exec : function(file) {
if (any(hook('executing', file), haveStopped)) return this
if ('node' in main)
this.load(file, function(contents){
eval('with (JSpec){ ' + JSpec.preprocess(contents) + ' }')
})
else
eval('with (JSpec){' + this.preprocess(this.load(file)) + '}')
return this
}
}
// --- Utility functions
var main = this
var find = JSpec.any
var utils = 'haveStopped stub hookImmutable hook destub map any last pass fail range each option inject select \
error escape extend puts hash query strip color does addMatchers callIterator argumentsToArray'.split(/\s+/)
while (utils.length) util = utils.shift(), eval('var ' + util + ' = JSpec.' + util)
if (!main.setTimeout) main.setTimeout = function(callback){ callback() }
// --- Matchers
addMatchers({
equal : "===",
be : "alias equal",
be_greater_than : ">",
be_less_than : "<",
be_at_least : ">=",
be_at_most : "<=",
be_a : "actual.constructor == expected",
be_an : "alias be_a",
be_an_instance_of : "actual instanceof expected",
be_null : "actual == null",
be_true : "actual == true",
be_false : "actual == false",
be_undefined : "typeof actual == 'undefined'",
be_type : "typeof actual == expected",
match : "typeof actual == 'string' ? actual.match(expected) : false",
respond_to : "typeof actual[expected] == 'function'",
have_length : "actual.length == expected",
be_within : "actual >= expected[0] && actual <= last(expected)",
have_length_within : "actual.length >= expected[0] && actual.length <= last(expected)",
eql : function(actual, expected) {
return actual.constructor == Array ||
actual instanceof Object ?
hash(actual) == hash(expected):
actual == expected
},
receive : { defer : true, match : function(actual, method, times) {
proxy = new JSpec.ProxyAssertion(actual, method, times, this.negate)
JSpec.currentSpec.assertions.push(proxy)
return proxy
}},
be_empty : function(actual) {
if (actual.constructor == Object && actual.length == undefined)
for (var key in actual)
return false;
return !actual.length
},
include : function(actual) {
for (state = true, i = 1; i < arguments.length; i++) {
arg = arguments[i]
switch (actual.constructor) {
case String:
case Number:
case RegExp:
case Function:
state = actual.toString().match(arg.toString())
break
case Object:
state = arg in actual
break
case Array:
state = any(actual, function(value){ return hash(value) == hash(arg) })
break
}
if (!state) return false
}
return true
},
throw_error : { match : function(actual, expected, message) {
try { actual() }
catch (e) {
this.e = e
var assert = function(arg) {
switch (arg.constructor) {
case RegExp : return arg.test(e)
case String : return arg == (e.message || e.toString())
case Function : return (e.name || 'Error') == arg.name
}
}
return message ? assert(expected) && assert(message) :
expected ? assert(expected) :
true
}
}, message : function(actual, expected, negate) {
// TODO: refactor when actual is not in expected [0]
var message_for = function(i) {
if (expected[i] == undefined) return 'exception'
switch (expected[i].constructor) {
case RegExp : return 'exception matching ' + puts(expected[i])
case String : return 'exception of ' + puts(expected[i])
case Function : return expected[i].name || 'Error'
}
}
exception = message_for(1) + (expected[2] ? ' and ' + message_for(2) : '')
return 'expected ' + exception + (negate ? ' not ' : '' ) +
' to be thrown, but ' + (this.e ? 'got ' + puts(this.e) : 'nothing was')
}},
have : function(actual, length, property) {
return actual[property].length == length
},
have_at_least : function(actual, length, property) {
return actual[property].length >= length
},
have_at_most :function(actual, length, property) {
return actual[property].length <= length
},
have_within : function(actual, range, property) {
length = actual[property].length
return length >= range.shift() && length <= range.pop()
},
have_prop : function(actual, property, value) {
return actual[property] == null ||
actual[property] instanceof Function ? false:
value == null ? true:
does(actual[property], 'eql', value)
},
have_property : function(actual, property, value) {
return actual[property] == null ||
actual[property] instanceof Function ? false:
value == null ? true:
value === actual[property]
}
})
if ('exports' in main) exports.JSpec = JSpec
})()

View File

@ -1,36 +0,0 @@
// JSpec - Shell - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
;(function(){
var _quit = quit
Shell = {
// --- Global
main: this,
// --- Commands
commands: {
quit: ['Terminate the shell', function(){ _quit() }],
exit: ['Terminate the shell', function(){ _quit() }]
},
/**
* Start the interactive shell.
*
* @api public
*/
start : function() {
for (var name in this.commands)
if (this.commands.hasOwnProperty(name))
this.main.__defineGetter__(name, this.commands[name][1])
}
}
Shell.start()
})()

View File

@ -1,90 +0,0 @@
// JSpec - Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
;(function(){
/**
* Version.
*/
mockTimersVersion = '1.0.1'
/**
* Localized timer stack.
*/
var timers = []
/**
* Set mock timeout with _callback_ and timeout of _ms_.
*
* @param {function} callback
* @param {int} ms
* @return {int}
* @api public
*/
setTimeout = function(callback, ms) {
var id
return id = setInterval(function(){
callback()
clearInterval(id)
}, ms)
}
/**
* Set mock interval with _callback_ and interval of _ms_.
*
* @param {function} callback
* @param {int} ms
* @return {int}
* @api public
*/
setInterval = function(callback, ms) {
callback.step = ms, callback.current = callback.last = 0
return timers[timers.length] = callback, timers.length
}
/**
* Destroy timer with _id_.
*
* @param {int} id
* @return {bool}
* @api public
*/
clearInterval = function(id) {
return delete timers[--id]
}
/**
* Reset timers.
*
* @return {array}
* @api public
*/
resetTimers = function() {
return timers = []
}
/**
* Increment each timers internal clock by _ms_.
*
* @param {int} ms
* @api public
*/
tick = function(ms) {
for (var i = 0, len = timers.length; i < len; ++i)
if (timers[i] && (timers[i].current += ms))
if (timers[i].current - timers[i].last >= timers[i].step) {
var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step)
var remainder = (timers[i].current - timers[i].last) % timers[i].step
timers[i].last = timers[i].current - remainder
while (times-- && timers[i]) timers[i]()
}
}
})()

View File

@ -1,183 +0,0 @@
// JSpec - XHR - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
(function(){
// --- Original XMLHttpRequest
var OriginalXMLHttpRequest = 'XMLHttpRequest' in this ?
XMLHttpRequest :
function(){}
// --- MockXMLHttpRequest
var MockXMLHttpRequest = function() {
this.requestHeaders = {}
}
MockXMLHttpRequest.prototype = {
status: 0,
async: true,
readyState: 0,
responseText: '',
abort: function(){},
onreadystatechange: function(){},
/**
* Return response headers hash.
*/
getAllResponseHeaders : function(){
return this.responseHeaders
},
/**
* Return case-insensitive value for header _name_.
*/
getResponseHeader : function(name) {
return this.responseHeaders[name.toLowerCase()]
},
/**
* Set case-insensitive _value_ for header _name_.
*/
setRequestHeader : function(name, value) {
this.requestHeaders[name.toLowerCase()] = value
},
/**
* Open mock request.
*/
open : function(method, url, async, user, password) {
this.user = user
this.password = password
this.url = url
this.readyState = 1
this.method = method.toUpperCase()
if (async != undefined) this.async = async
if (this.async) this.onreadystatechange()
},
/**
* Send request _data_.
*/
send : function(data) {
this.data = data
this.readyState = 4
if (this.method == 'HEAD') this.responseText = null
this.responseHeaders['content-length'] = (this.responseText || '').length
if(this.async) this.onreadystatechange()
}
}
// --- Response status codes
JSpec.statusCodes = {
100: 'Continue',
101: 'Switching Protocols',
200: 'OK',
201: 'Created',
202: 'Accepted',
203: 'Non-Authoritative Information',
204: 'No Content',
205: 'Reset Content',
206: 'Partial Content',
300: 'Multiple Choice',
301: 'Moved Permanently',
302: 'Found',
303: 'See Other',
304: 'Not Modified',
305: 'Use Proxy',
307: 'Temporary Redirect',
400: 'Bad Request',
401: 'Unauthorized',
402: 'Payment Required',
403: 'Forbidden',
404: 'Not Found',
405: 'Method Not Allowed',
406: 'Not Acceptable',
407: 'Proxy Authentication Required',
408: 'Request Timeout',
409: 'Conflict',
410: 'Gone',
411: 'Length Required',
412: 'Precondition Failed',
413: 'Request Entity Too Large',
414: 'Request-URI Too Long',
415: 'Unsupported Media Type',
416: 'Requested Range Not Satisfiable',
417: 'Expectation Failed',
422: 'Unprocessable Entity',
500: 'Internal Server Error',
501: 'Not Implemented',
502: 'Bad Gateway',
503: 'Service Unavailable',
504: 'Gateway Timeout',
505: 'HTTP Version Not Supported'
}
/**
* Mock XMLHttpRequest requests.
*
* mockRequest().and_return('some data', 'text/plain', 200, { 'X-SomeHeader' : 'somevalue' })
*
* @return {hash}
* @api public
*/
function mockRequest() {
return { and_return : function(body, type, status, headers) {
XMLHttpRequest = MockXMLHttpRequest
status = status || 200
headers = headers || {}
headers['content-type'] = type
JSpec.extend(XMLHttpRequest.prototype, {
responseText: body,
responseHeaders: headers,
status: status,
statusText: JSpec.statusCodes[status]
})
}}
}
/**
* Unmock XMLHttpRequest requests.
*
* @api public
*/
function unmockRequest() {
XMLHttpRequest = OriginalXMLHttpRequest
}
JSpec.include({
name: 'Mock XHR',
// --- Utilities
utilities : {
mockRequest: mockRequest,
unmockRequest: unmockRequest
},
// --- Hooks
afterSpec : function() {
unmockRequest()
},
// --- DSLs
DSLs : {
snake : {
mock_request: mockRequest,
unmock_request: unmockRequest
}
}
})
})()

View File

@ -1,228 +0,0 @@
require 'rbconfig'
#--
# Browser
#++
class Browser
##
# Check if the user agent _string_ matches this browser.
def self.matches_agent? string; end
##
# Check if the browser matches the name _string_.
def self.matches_name? string; end
##
# Subclasses.
def self.subclasses
@subclasses ||= []
end
##
# Stack subclasses.
def self.inherited subclass
subclasses << subclass
end
##
# Weither or not the browser is supported.
def supported?; true end
##
# Server setup.
def setup; end
##
# Server teardown.
def teardown; end
##
# Host environment.
def host
Config::CONFIG['host']
end
##
# Check if we are using macos.
def macos?
host.include? 'darwin'
end
##
# Check if we are using windows.
def windows?
host.include? 'mswin'
end
##
# Check if we are using linux.
def linux?
host.include? 'linux'
end
##
# Run applescript _code_.
def applescript code
raise "Can't run AppleScript on #{host}" unless macos?
system "osascript -e '#{code}' 2>&1 >/dev/null"
end
#--
# Firefox
#++
class Firefox < self
def self.matches_agent? string
string =~ /firefox/i
end
def self.matches_name? string
string =~ /ff|firefox|mozilla/i
end
def visit uri
system "open -g -a Firefox '#{uri}'" if macos?
system "firefox #{uri}" if linux?
system "#{File.join(ENV['ProgramFiles'] || 'c:\Program Files', '\Mozilla Firefox\firefox.exe')} #{uri}" if windows?
end
def to_s
'Firefox'
end
end
#--
# Safari
#++
class Safari < self
def self.matches_agent? string
string =~ /safari/i && string !~ /chrome/i
end
def self.matches_name? string
string =~ /safari/i
end
def supported?
macos?
end
def setup
applescript 'tell application "Safari" to make new document'
end
def visit uri
applescript 'tell application "Safari" to set URL of front document to "' + uri + '"'
end
def matches_agent? string
string =~ /safari/i
end
def to_s
'Safari'
end
end
#--
# Chrome
#++
class Chrome < self
def self.matches_agent? string
string =~ /chrome/i
end
def self.matches_name? string
string =~ /google|chrome/i
end
def supported?
macos?
end
def visit uri
system "open -g -a 'Google Chrome' #{uri}" if macos?
end
def to_s
'Chrome'
end
end
#--
# Internet Explorer
#++
class IE < self
def self.matches_agent? string
string =~ /microsoft/i
end
def self.matches_name? string
string =~ /ie|explorer/i
end
def supported?
windows?
end
def setup
require 'win32ole'
end
def visit uri
ie = WIN32OLE.new 'InternetExplorer.Application'
ie.visible = true
ie.Navigate uri
while ie.ReadyState != 4 do
sleep 1
end
end
def to_s
'Internet Explorer'
end
end
#--
# Opera
#++
class Opera < self
def self.matches_agent? string
string =~ /opera/i
end
def self.matches_name? string
string =~ /opera/i
end
def visit uri
system "open -g -a Opera #{uri}" if macos?
system "c:\Program Files\Opera\Opera.exe #{uri}" if windows?
system "opera #{uri}" if linux?
end
def to_s
'Opera'
end
end
end

View File

@ -1,82 +0,0 @@
helpers do
##
# Return dotted assertion graph for _assertions_.
def assertion_graph_for assertions
return if assertions.empty?
assertions.map do |assertion|
assertion['passed'] ? green('.') : red('.')
end.join
end
##
# Override Sinatra's #send_file to prevent caching.
def send_file path, opts = {}
stat = File.stat(path)
response['Cache-Control'] = 'no-cache'
content_type media_type(opts[:type]) ||
media_type(File.extname(path)) ||
response['Content-Type'] ||
'application/octet-stream'
response['Content-Length'] ||= (opts[:length] || stat.size).to_s
if opts[:disposition] == 'attachment' || opts[:filename]
attachment opts[:filename] || path
elsif opts[:disposition] == 'inline'
response['Content-Disposition'] = 'inline'
end
halt ::Sinatra::Application::StaticFile.open(path, 'rb')
rescue Errno::ENOENT
not_found
end
##
# Find the browser name for the current user agent.
def browser_name
Browser.subclasses.find do |browser|
browser.matches_agent? env['HTTP_USER_AGENT']
end.new
rescue
'Unknown'
end
##
# Wrap _string_ with ansi escape sequence using _code_.
def color string, code
"\e[#{code}m#{string}\e[0m"
end
##
# Bold _string_.
def bold string
color string, 1
end
##
# Color _string_ red.
def red string
color string, 31
end
##
# Color _string_ green.
def green string
color string, 32
end
##
# Color _string_ blue.
def blue string
color string, 34
end
end

View File

@ -1,57 +0,0 @@
get '/jspec/*' do |path|
send_file JSPEC_ROOT + '/lib/' + path
end
post '/results' do
require 'json/pure'
data = JSON.parse request.body.read
if data['options'].include?('verbose') && data['options']['verbose'] ||
data['options'].include?('failuresOnly') && data['options']['failuresOnly']
puts "\n\n %s Passes: %s Failures: %s\n\n" % [
bold(browser_name),
green(data['stats']['passes']),
red(data['stats']['failures'])]
data['results'].compact.each do |suite|
specs = suite['specs'].compact.map do |spec|
case spec['status'].to_sym
when :pass
next if data['options'].include?('failuresOnly') && data['options']['failuresOnly']
' ' + green(spec['description']) + assertion_graph_for(spec['assertions']).to_s + "\n"
when :fail
" #{red(spec['description'])}\n #{spec['message']}\n\n"
else
" #{blue(spec['description'])}\n"
end
end.join
unless specs.strip.empty?
puts "\n " + bold(suite['description'])
puts specs
end
end
else
puts "%20s Passes: %s Failures: %s" % [
bold(browser_name),
green(data['stats']['passes']),
red(data['stats']['failures'])]
end
halt 200
end
get '/*' do |path|
pass unless File.exists?(path)
send_file path
end
#--
# Simulation Routes
#++
get '/slow/*' do |seconds|
sleep seconds.to_i
halt 200
end
get '/status/*' do |code|
halt code.to_i
end

View File

@ -1,88 +0,0 @@
$:.unshift File.dirname(__FILE__)
require 'sinatra'
require 'thread'
require 'browsers'
require 'helpers'
require 'routes'
module JSpec
class Server
##
# Suite HTML.
attr_accessor :suite
##
# Host string.
attr_reader :host
##
# Port number.
attr_reader :port
##
# Server instance.
attr_reader :server
##
# Initialize.
def initialize suite, port
@suite, @port, @host = suite, port, :localhost
end
##
# URI formed by the given host and port.
def uri
'http://%s:%d' % [host, port]
end
##
# Start the server with _browsers_ which defaults to all supported browsers.
def start browsers = nil
browsers ||= Browser.subclasses.map { |browser| browser.new }
browsers.map do |browser|
Thread.new {
sleep 1
if browser.supported?
browser.setup
browser.visit uri + '/' + suite
browser.teardown
end
}
end.push(Thread.new {
start!
}).reverse.each { |thread| thread.join }
end
private
#:nodoc:
def start!
Sinatra::Application.class_eval do
begin
$stderr.puts 'Started JSpec server at http://%s:%d' % [host, port.to_i]
detect_rack_handler.run self, :Host => host, :Port => port do |server|
trap 'INT' do
server.respond_to?(:stop!) ? server.stop! : server.stop
end
end
rescue Errno::EADDRINUSE
raise "Port #{port} already in use"
rescue Errno::EACCES
raise "Permission Denied on port #{port}"
end
end
end
end
end

View File

@ -1 +0,0 @@
cookies!

View File

@ -1,695 +0,0 @@
/*
* Simulated browser environment for Rhino
* By John Resig <http://ejohn.org/>
* Copyright 2007 John Resig, under the MIT License
*/
// The window Object
var window = this;
(function(){
// Browser Navigator
window.navigator = {
get userAgent(){
return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3";
}
};
var curLocation = (new java.io.File("./")).toURL();
window.__defineSetter__("location", function(url){
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = function(){
curLocation = new java.net.URL( curLocation, url );
window.document = xhr.responseXML;
var event = document.createEvent();
event.initEvent("load");
window.dispatchEvent( event );
};
xhr.send();
});
window.__defineGetter__("location", function(url){
return {
get protocol(){
return curLocation.getProtocol() + ":";
},
get href(){
return curLocation.toString();
},
toString: function(){
return this.href;
}
};
});
// Timers
var timers = [];
window.setTimeout = function(fn, time){
var num;
return num = setInterval(function(){
fn();
clearInterval(num);
}, time);
};
window.setInterval = function(fn, time){
var num = timers.length;
timers[num] = new java.lang.Thread(new java.lang.Runnable({
run: function(){
while (true){
java.lang.Thread.currentThread().sleep(time);
fn();
}
}
}));
timers[num].start();
return num;
};
window.clearInterval = function(num){
if ( timers[num] ) {
timers[num].stop();
delete timers[num];
}
};
// Window Events
var events = [{}];
window.addEventListener = function(type, fn){
if ( !this.uuid || this == window ) {
this.uuid = events.length;
events[this.uuid] = {};
}
if ( !events[this.uuid][type] )
events[this.uuid][type] = [];
if ( events[this.uuid][type].indexOf( fn ) < 0 )
events[this.uuid][type].push( fn );
};
window.removeEventListener = function(type, fn){
if ( !this.uuid || this == window ) {
this.uuid = events.length;
events[this.uuid] = {};
}
if ( !events[this.uuid][type] )
events[this.uuid][type] = [];
events[this.uuid][type] =
events[this.uuid][type].filter(function(f){
return f != fn;
});
};
window.dispatchEvent = function(event){
if ( event.type ) {
if ( this.uuid && events[this.uuid][event.type] ) {
var self = this;
events[this.uuid][event.type].forEach(function(fn){
fn.call( self, event );
});
}
if ( this["on" + event.type] )
this["on" + event.type].call( self, event );
}
};
// DOM Document
window.DOMDocument = function(file){
this._file = file;
this._dom = Packages.javax.xml.parsers.
DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(file);
if ( !obj_nodes.containsKey( this._dom ) )
obj_nodes.put( this._dom, this );
};
DOMDocument.prototype = {
createTextNode: function(text){
return makeNode( this._dom.createTextNode(
text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
},
createElement: function(name){
return makeNode( this._dom.createElement(name.toLowerCase()) );
},
getElementsByTagName: function(name){
return new DOMNodeList( this._dom.getElementsByTagName(
name.toLowerCase()) );
},
getElementById: function(id){
var elems = this._dom.getElementsByTagName("*");
for ( var i = 0; i < elems.length; i++ ) {
var elem = elems.item(i);
if ( elem.getAttribute("id") == id )
return makeNode(elem);
}
return null;
},
get body(){
return this.getElementsByTagName("body")[0];
},
get documentElement(){
return makeNode( this._dom.getDocumentElement() );
},
get ownerDocument(){
return null;
},
addEventListener: window.addEventListener,
removeEventListener: window.removeEventListener,
dispatchEvent: window.dispatchEvent,
get nodeName() {
return "#document";
},
importNode: function(node, deep){
return makeNode( this._dom.importNode(node._dom, deep) );
},
toString: function(){
return "Document" + (typeof this._file == "string" ?
": " + this._file : "");
},
get innerHTML(){
return this.documentElement.outerHTML;
},
get defaultView(){
return {
getComputedStyle: function(elem){
return {
getPropertyValue: function(prop){
prop = prop.replace(/\-(\w)/g,function(m,c){
return c.toUpperCase();
});
var val = elem.style[prop];
if ( prop == "opacity" && val == "" )
val = "1";
return val;
}
};
}
};
},
createEvent: function(){
return {
type: "",
initEvent: function(type){
this.type = type;
}
};
}
};
function getDocument(node){
return obj_nodes.get(node);
}
// DOM NodeList
window.DOMNodeList = function(list){
this._dom = list;
this.length = list.getLength();
for ( var i = 0; i < this.length; i++ ) {
var node = list.item(i);
this[i] = makeNode( node );
}
};
DOMNodeList.prototype = {
toString: function(){
return "[ " +
Array.prototype.join.call( this, ", " ) + " ]";
},
get outerHTML(){
return Array.prototype.map.call(
this, function(node){return node.outerHTML;}).join('');
}
};
// DOM Node
window.DOMNode = function(node){
this._dom = node;
};
DOMNode.prototype = {
get nodeType(){
return this._dom.getNodeType();
},
get nodeValue(){
return this._dom.getNodeValue();
},
get nodeName() {
return this._dom.getNodeName();
},
cloneNode: function(deep){
return makeNode( this._dom.cloneNode(deep) );
},
get ownerDocument(){
return getDocument( this._dom.ownerDocument );
},
get documentElement(){
return makeNode( this._dom.documentElement );
},
get parentNode() {
return makeNode( this._dom.getParentNode() );
},
get nextSibling() {
return makeNode( this._dom.getNextSibling() );
},
get previousSibling() {
return makeNode( this._dom.getPreviousSibling() );
},
toString: function(){
return '"' + this.nodeValue + '"';
},
get outerHTML(){
return this.nodeValue;
}
};
// DOM Element
window.DOMElement = function(elem){
this._dom = elem;
this.style = {
get opacity(){ return this._opacity; },
set opacity(val){ this._opacity = val + ""; }
};
// Load CSS info
var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
for ( var i = 0; i < styles.length; i++ ) {
var style = styles[i].split(/\s*:\s*/);
if ( style.length == 2 )
this.style[ style[0] ] = style[1];
}
};
DOMElement.prototype = extend( new DOMNode(), {
get nodeName(){
return this.tagName.toUpperCase();
},
get tagName(){
return this._dom.getTagName();
},
toString: function(){
return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">";
},
get outerHTML(){
var ret = "<" + this.tagName, attr = this.attributes;
for ( var i in attr )
ret += " " + i + "='" + attr[i] + "'";
if ( this.childNodes.length || this.nodeName == "SCRIPT" )
ret += ">" + this.childNodes.outerHTML +
"</" + this.tagName + ">";
else
ret += "/>";
return ret;
},
get attributes(){
var attr = {}, attrs = this._dom.getAttributes();
for ( var i = 0; i < attrs.getLength(); i++ )
attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue;
return attr;
},
get innerHTML(){
return this.childNodes.outerHTML;
},
set innerHTML(html){
html = html.replace(/<\/?([A-Z]+)/g, function(m){
return m.toLowerCase();
});
var nodes = this.ownerDocument.importNode(
new DOMDocument( new java.io.ByteArrayInputStream(
(new java.lang.String("<wrap>" + html + "</wrap>"))
.getBytes("UTF8"))).documentElement, true).childNodes;
while (this.firstChild)
this.removeChild( this.firstChild );
for ( var i = 0; i < nodes.length; i++ )
this.appendChild( nodes[i] );
},
get textContent(){
return nav(this.childNodes);
function nav(nodes){
var str = "";
for ( var i = 0; i < nodes.length; i++ )
if ( nodes[i].nodeType == 3 )
str += nodes[i].nodeValue;
else if ( nodes[i].nodeType == 1 )
str += nav(nodes[i].childNodes);
return str;
}
},
set textContent(text){
while (this.firstChild)
this.removeChild( this.firstChild );
this.appendChild( this.ownerDocument.createTextNode(text));
},
style: {},
clientHeight: 0,
clientWidth: 0,
offsetHeight: 0,
offsetWidth: 0,
get disabled() {
var val = this.getAttribute("disabled");
return val != "false" && !!val;
},
set disabled(val) { return this.setAttribute("disabled",val); },
get checked() {
var val = this.getAttribute("checked");
return val != "false" && !!val;
},
set checked(val) { return this.setAttribute("checked",val); },
get selected() {
if ( !this._selectDone ) {
this._selectDone = true;
if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
var opt = this.parentNode.getElementsByTagName("option");
if ( this == opt[0] ) {
var select = true;
for ( var i = 1; i < opt.length; i++ )
if ( opt[i].selected ) {
select = false;
break;
}
if ( select )
this.selected = true;
}
}
}
var val = this.getAttribute("selected");
return val != "false" && !!val;
},
set selected(val) { return this.setAttribute("selected",val); },
get className() { return this.getAttribute("class") || ""; },
set className(val) {
return this.setAttribute("class",
val.replace(/(^\s*|\s*$)/g,""));
},
get type() { return this.getAttribute("type") || ""; },
set type(val) { return this.setAttribute("type",val); },
get value() { return this.getAttribute("value") || ""; },
set value(val) { return this.setAttribute("value",val); },
get src() { return this.getAttribute("src") || ""; },
set src(val) { return this.setAttribute("src",val); },
get id() { return this.getAttribute("id") || ""; },
set id(val) { return this.setAttribute("id",val); },
getAttribute: function(name){
return this._dom.hasAttribute(name) ?
new String( this._dom.getAttribute(name) ) :
null;
},
setAttribute: function(name,value){
this._dom.setAttribute(name,value);
},
removeAttribute: function(name){
this._dom.removeAttribute(name);
},
get childNodes(){
return new DOMNodeList( this._dom.getChildNodes() );
},
get firstChild(){
return makeNode( this._dom.getFirstChild() );
},
get lastChild(){
return makeNode( this._dom.getLastChild() );
},
appendChild: function(node){
this._dom.appendChild( node._dom );
},
insertBefore: function(node,before){
this._dom.insertBefore( node._dom, before ? before._dom : before );
},
removeChild: function(node){
this._dom.removeChild( node._dom );
},
getElementsByTagName: DOMDocument.prototype.getElementsByTagName,
addEventListener: window.addEventListener,
removeEventListener: window.removeEventListener,
dispatchEvent: window.dispatchEvent,
click: function(){
var event = document.createEvent();
event.initEvent("click");
this.dispatchEvent(event);
},
submit: function(){
var event = document.createEvent();
event.initEvent("submit");
this.dispatchEvent(event);
},
focus: function(){
var event = document.createEvent();
event.initEvent("focus");
this.dispatchEvent(event);
},
blur: function(){
var event = document.createEvent();
event.initEvent("blur");
this.dispatchEvent(event);
},
get elements(){
return this.getElementsByTagName("*");
},
get contentWindow(){
return this.nodeName == "IFRAME" ? {
document: this.contentDocument
} : null;
},
get contentDocument(){
if ( this.nodeName == "IFRAME" ) {
if ( !this._doc )
this._doc = new DOMDocument(
new java.io.ByteArrayInputStream((new java.lang.String(
"<html><head><title></title></head><body></body></html>"))
.getBytes("UTF8")));
return this._doc;
} else
return null;
}
});
// Helper method for extending one object with another
function extend(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g )
a.__defineGetter__(i, g);
if ( s )
a.__defineSetter__(i, s);
} else
a[i] = b[i];
}
return a;
}
// Helper method for generating the right
// DOM objects based upon the type
var obj_nodes = new java.util.HashMap();
function makeNode(node){
if ( node ) {
if ( !obj_nodes.containsKey( node ) )
obj_nodes.put( node, node.getNodeType() ==
Packages.org.w3c.dom.Node.ELEMENT_NODE ?
new DOMElement( node ) : new DOMNode( node ) );
return obj_nodes.get(node);
} else
return null;
}
// XMLHttpRequest
// Originally implemented by Yehuda Katz
window.XMLHttpRequest = function(){
this.headers = {};
this.responseHeaders = {};
};
XMLHttpRequest.prototype = {
open: function(method, url, async, user, password){
this.readyState = 1;
if (async)
this.async = true;
this.method = method || "GET";
this.url = url;
this.onreadystatechange();
},
setRequestHeader: function(header, value){
this.headers[header] = value;
},
getResponseHeader: function(header){ },
send: function(data){
var self = this;
function makeRequest(){
var url = new java.net.URL(curLocation, self.url);
if ( url.getProtocol() == "file" ) {
if ( self.method == "PUT" ) {
var out = new java.io.FileWriter(
new java.io.File( new java.net.URI( url.toString() ) ) ),
text = new java.lang.String( data || "" );
out.write( text, 0, text.length() );
out.flush();
out.close();
} else if ( self.method == "DELETE" ) {
var file = new java.io.File( new java.net.URI( url.toString() ) );
file["delete"]();
} else {
var connection = url.openConnection();
connection.connect();
handleResponse();
}
} else {
var connection = url.openConnection();
connection.setRequestMethod( self.method );
// Add headers to Java connection
for (var header in self.headers)
connection.addRequestProperty(header, self.headers[header]);
connection.connect();
// Stick the response headers into responseHeaders
for (var i = 0; ; i++) {
var headerName = connection.getHeaderFieldKey(i);
var headerValue = connection.getHeaderField(i);
if (!headerName && !headerValue) break;
if (headerName)
self.responseHeaders[headerName] = headerValue;
}
handleResponse();
}
function handleResponse(){
self.readyState = 4;
self.status = parseInt(connection.responseCode) || undefined;
self.statusText = connection.responseMessage || "";
var stream = new java.io.InputStreamReader(connection.getInputStream()),
buffer = new java.io.BufferedReader(stream), line;
while ((line = buffer.readLine()) != null)
self.responseText += line;
self.responseXML = null;
if ( self.responseText.match(/^\s*</) ) {
try {
self.responseXML = new DOMDocument(
new java.io.ByteArrayInputStream(
(new java.lang.String(
self.responseText)).getBytes("UTF8")));
} catch(e) {}
}
}
self.onreadystatechange();
}
if (this.async)
(new java.lang.Thread(new java.lang.Runnable({
run: makeRequest
}))).start();
else
makeRequest();
},
abort: function(){},
onreadystatechange: function(){},
getResponseHeader: function(header){
if (this.readyState < 3)
throw new Error("INVALID_STATE_ERR");
else {
var returnedHeaders = [];
for (var rHeader in this.responseHeaders) {
if (rHeader.match(new Regexp(header, "i")))
returnedHeaders.push(this.responseHeaders[rHeader]);
}
if (returnedHeaders.length)
return returnedHeaders.join(", ");
}
return null;
},
getAllResponseHeaders: function(header){
if (this.readyState < 3)
throw new Error("INVALID_STATE_ERR");
else {
var returnedHeaders = [];
for (var header in this.responseHeaders)
returnedHeaders.push( header + ": " + this.responseHeaders[header] );
return returnedHeaders.join("\r\n");
}
},
async: true,
readyState: 0,
responseText: "",
status: 0
};
})();

View File

@ -1 +0,0 @@
<p>test</p>

View File

@ -1 +0,0 @@
{ users : { tj : { email : 'tj@vision-media.ca' }}}

View File

@ -1,5 +0,0 @@
<users>
<user name="tj">
<email>tj@vision-media.ca</email>
</user>
</users>

View File

@ -1,62 +0,0 @@
JSpec.include({
name: 'Helpers',
utilities : {
mock_it : function(body) {
var spec = new JSpec.Spec('mock', body)
var prev = JSpec.currentSpec
JSpec.runSpec(spec)
JSpec.currentSpec = prev
return spec
}
},
matchers : {
have_failure_message : function(spec, expected) {
return JSpec.any(spec.assertions, function(assertion){
if (assertion.passed) return
switch (expected.constructor) {
case String: return assertion.message == expected
case RegExp: return expected.test(assertion.message)
default : return false
}
})
}
}
})
JSpec.include({
name: 'ExampleModule',
utilities : {
doFoo : function(){ return 'foo' },
doBar : function(){ return 'bar' }
},
randomHook : function(a, b) {
return [a, b]
},
beforeSpec : function() { addedBeforeSpec = true; this.utilities.doFoo() },
afterSpec : function() { addedAfterSpec = true },
beforeSuite : function() { addedBeforeSuite = true },
afterSuite : function() { addedAfterSuite = true },
matchers : {
be_foo_bar : function() {
return true
}
},
DSLs : {
snake : {
some_snake_case_stuff : function(){
return true
}
},
camel : {
someCamelCaseStuff : function() {
return true
}
}
}
})
JSpec.include({
name : 'EmptyModule'
})

View File

@ -1,2 +0,0 @@
puts 'Use spec/jspec.rb to alter anything you like, provide routes, browsers, etc'

View File

@ -1,34 +0,0 @@
<html>
<head>
<link type="text/css" rel="stylesheet" href="../lib/jspec.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="../lib/jspec.js"></script>
<script src="../lib/jspec.jquery.js"></script>
<script src="../lib/jspec.xhr.js"></script>
<script src="../lib/jspec.timers.js"></script>
<script src="helpers.js"></script>
<script src="spec.grammar-less.js"></script>
<script>
function runSuites() {
JSpec
.exec('spec.grammar.js')
.exec('spec.js')
.exec('spec.matchers.js')
.exec('spec.utils.js')
.exec('spec.fixtures.js')
.exec('spec.shared-behaviors.js')
.exec('spec.jquery.js')
.exec('spec.modules.js')
.exec('spec.xhr.js')
.exec('spec.jquery.xhr.js')
.run({ failuresOnly: true })
.report()
}
</script>
</head>
<body class="jspec" onLoad="runSuites();">
<div id="jspec-top"><h2 id="jspec-title">JSpec <em><script>document.write(JSpec.version)</script></em></h2></div>
<div id="jspec"><div class="loading"></div></div>
<div id="jspec-bottom"></div>
</body>
</html>

View File

@ -1,18 +0,0 @@
describe 'Utility'
describe 'fixture()'
it 'should return a files contents'
fixture('fixtures/test.html').should.eql '<p>test</p>'
fixture('test.html').should.eql '<p>test</p>'
fixture('test').should.eql '<p>test</p>'
end
it 'should cache contents'
contents = fixture('test')
JSpec.cache['test'].should.eql contents
JSpec.cache['test'] = 'foo'
fixture('test').should.eql 'foo'
delete JSpec.cache['test']
end
end
end

View File

@ -1,34 +0,0 @@
JSpec.describe('Grammar-less', function(){
before(function(){
n = 1
})
it('should work', function(){
expect(true).to(be, true)
expect(n).to(equal, 1)
})
describe('with nested describes', function(){
before(function(){
hits = []
})
before_each(function(){
n++
hits.push('before_each')
})
it('should work', function(){
expect(true).not_to(be, false)
expect(n).to(eql, 2)
expect(hits).to(eql, ['before_each'])
})
it('should work again', function(){
expect(n).to(eql, 3)
expect(hits).to(eql, ['before_each', 'before_each'])
})
})
})

View File

@ -1,226 +0,0 @@
describe 'Grammar'
it 'should allow "it" spec literal'
true.should.be_true
end
n = 10
it 'should allow literal javascript outside of blocks'
n.should.eql 10
end
it 'should escape <html> in <p>descriptions</p> and body'
'<p></p>'.should.eql '<p></p>'
end
it 'should parse correctly when "it" is within the body'
text = 'Get it at Github'
text.should.include 'it'
end
it 'should parse correctly when "describe" is within the body'
text = 'It should work with describe'
text.should.include 'describe'
end
it 'should parse correctly when "end" is within the body'
text = 'This should not end the parsing :)'
text.should.include 'not'
end
it 'should parse correctly with "before" and "after" within the body'
text = 'This comes before that, which is after the rest'
text.should.include 'before'
end
it 'should allow parens to be optional when no args are passed'
true.should.be_true
true.should.be_true()
end
it 'should not mess up with words like it or append in descriptions'
-{ element.append().end() }.should.throw_error
end
it 'should not mess up "end" in strings'
'foo end bar'.should.not.eql 'foo }); bar'
end
it 'should allow semicolons'
true.should.be_true;
true.should.be_true();
true.should.be_true() ;
end
it 'should allow parens to be optional with args'
'foobar'.should.include 'foo'
'rawr'.should.not_include 'foo'
end
it 'should allow literals without defining variables variables'
{}.should.be_an Object
end
it 'should allow alternative closure literal'
-{ throw 'test' }.should.throw_error
end
it 'should allow grammar-less assertions'
expect(true).to(be, true)
expect([1,2,3]).to(include, 1, 2, 3)
expect(true).not_to(be, false)
end
it 'should allow multi-line expect() assertions'
expect(' \
foo \
bar \
').to(include, 'foo', 'bar')
end
it 'should allow commenting out of conversions'
// -{ throw 'foo' }.should.throw_error
// foo.should.not.eql 'bar'
end
it 'should allow inclusive range literal n..n'
1..5.should.eql [1,2,3,4,5]
3..4.should.eql [3,4]
1..1.should.eql [1]
3..1.should.eql [3,2,1]
end
it 'should allow snakecase style assertions'
'foo'.should_equal('foo')
'foo'.should_equal 'foo'
'bar'.should_not_equal('foo')
'bar'.should_not_equal 'foo'
end
it 'should allow dot style assertions'
'foo'.should.equal('foo')
'foo'.should.equal 'foo'
'bar'.should.not.equal('foo')
'bar'.should.not.equal 'foo'
end
describe 'with nested describe'
it 'should work'
true.should.be_true
end
describe 'nested again'
it 'should still work'
true.should.be_true
end
end
end
describe 'before / after blocks'
before
n = 1
hits = []
hits.push('before')
end
after
n = 0
hits.push('after')
end
it 'should work'
n.should.eql 1
hits.should.eql ['before']
n++
end
it 'should persist'
n.should.eql 2
hits.should.eql ['before']
end
describe 'with nested describe'
it 'should be accessable'
n.should.eql 1
hits.should.eql ['before']
end
end
end
describe 'before_each / after_each blocks'
hits = []
before_each
n = 1
hits.push('before_each')
end
after_each
o = 2
hits.push('after_each')
end
it 'should work'
n.should.eql 1
hits.should.eql ['before_each']
n = 2
end
it 'should not persist'
n.should.eql 1
o.should.eql 2
hits.should.eql ['before_each', 'after_each', 'before_each']
end
describe 'with nested describe'
it 'should be accessable'
n.should.eql 1
o.should.eql 2
hits.should.eql ['before_each', 'after_each', 'before_each', 'after_each', 'before_each']
end
it 'should continue hits'
hits.should.eql ['before_each', 'after_each', 'before_each', 'after_each', 'before_each', 'after_each', 'before_each']
end
describe 'with more hooks'
before_each
hits.push('before_each')
end
after_each
hits.push('after_each')
end
it 'should continue hits, while cascading properly'
hits.should.eql ['before_each', 'after_each', 'before_each', 'after_each', 'before_each', 'after_each', 'before_each', 'after_each', 'before_each', 'before_each']
end
end
describe 'with multiple hooks'
before_each
hits = []
end
before_each
hits.push('before_each')
end
it 'should work'
hits.should.eql ['before_each']
end
end
end
end
end
__END__
describe 'Grammar'
it 'should consider everything below __END__ a comment'
end
end

View File

@ -1,176 +0,0 @@
describe 'jQuery'
describe 'sandbox()'
before
dom = sandbox()
end
it 'should provide an empty DOM sandbox'
dom.prepend('<em>test</em>')
dom.should.have_text 'test'
end
end
describe 'element() / elements()'
it 'should alias jQuery'
element.should.be jQuery
elements.should.be jQuery
end
end
describe 'async'
it 'should load mah cookies (textfile)'
$.get('async', function(text){
text.should_eql 'cookies!'
})
end
it 'should load mah cookies twice (ensure multiple async requests work)'
$.get('async', function(text){
text.should.eql 'cookies!'
})
$.get('async', function(text){
text.should.not.eql 'rawr'
})
end
end
describe 'matchers'
before_each
html = '<p><label><em>Save?</em></label> \
<select class="save form-select" style="display: none;"> \
<option value="0">No</option> \
<option value="1">Yes</option> \
</select> \
<strong>test</strong> \
<strong>test</strong> \
</p>'
elem = $(html)
end
it 'should fail with pretty print of element'
spec = mock_it(function() {
elem.should.not.have_tag 'label'
})
spec.should.have_failure_message(/<label>\s*<em>Save?/i)
end
describe 'have_tag / have_one'
it 'should check if a single child is present'
elem.should.have_tag 'label'
elem.should.have_tag 'em'
elem.should.have_one 'label'
elem.should.not.have_tag 'input'
end
end
describe 'have_tags / have_many'
it 'should check if more than one child is present'
elem.should.have_tags 'option'
elem.should.have_many 'option'
elem.should.not.have_many 'label'
end
end
describe 'have_child'
it 'should check if a direct child is present'
elem.should.have_child 'label'
elem.should.not.have_child 'em'
end
end
describe 'have_children'
it 'should check if more than one direct children are present'
elem.should.have_children 'strong'
elem.should.not.have_children 'select'
end
end
describe 'have_text'
it 'should check for plain text'
elem.children('label').should.have_text 'Save?'
end
end
describe 'have_value'
it 'should check if an element has the given value'
elem.find('option').get(1).should.have_value '1'
end
end
describe 'have_class'
it 'should check if an element has the given class'
elem.children('select').should.have_class 'save'
end
end
describe 'have_classes'
it 'should check if an element has the classes given'
elem.children('select').should.have_classes 'save', 'form-select'
elem.children('select').should.not.have_classes 'save', 'foo'
elem.children('select').should.not.have_classes 'foo', 'save'
end
end
describe 'be_visible'
it 'should check that an element is not hidden or set to display of none'
element('#jspec-report').should.be_visible
'#jspec-report'.should.be_visible
'<input style="visibility: hidden;"/>'.should.not.be_visible
'<input style="display: none;"/>'.should.not.be_visible
'<input />'.should.be_visible
end
end
describe 'be_enabled'
it 'should check that an element is currently enabled'
'<input type="button"/>'.should.be_enabled
'<input type="button" disabled="disabled" />'.should.not.be_enabled
end
end
describe 'be_BOOLATTR'
it 'should check that an element is currently selected, disabled, checked etc'
'<input type="button"/>'.should.not.be_disabled
'<input type="button" disabled="disabled" />'.should.be_disabled
'<option value="foo" selected="selected">Foo</option>'.should.be_selected
end
end
describe 'have_ATTR'
it 'should check if an attribute exists'
'<input type="checkbox"/>'.should.have_type
end
it 'should check if an attribute has a specific value'
'<input type="checkbox"/>'.should.have_type 'checkbox'
end
end
describe 'be_hidden'
it 'should check if an element is hidden'
'<input style="display: none;" />'.should.be_hidden
'<input style="visibility: hidden;" />'.should.be_hidden
'<input />'.should.not.be_hidden
end
end
describe 'have_attr'
before_each
elem = '<input type="button" title="some foo" value="Foo" />'
end
it 'should check that an element has the given attribute'
elem.should.have_attr 'title'
elem.should.not_have_attr 'rawr'
end
it 'should check that the given attribute has a specific value'
elem.should.have_attr 'title', 'some foo'
elem.should.not.have_attr 'some', 'rawr'
elem.should.not.have_attr 'title', 'bar'
end
end
end
end

View File

@ -1,65 +0,0 @@
describe 'jQuery'
describe '.ajax()'
it "should call the success function when 200"
mock_request().and_return('{ foo: "bar" }', 'application/json')
var successCalled = false
$.ajax({
type: "POST",
url: 'foo',
dataType: 'json',
success: function() {
successCalled = true
}
})
successCalled.should.be_true
end
it "should call the error function when 404"
mock_request().and_return('{ foo: "bar" }', 'application/json', 404)
var errorCalled = false
$.ajax({
type: "POST",
url: 'foo',
dataType: 'json',
error: function() {
errorCalled = true
}
})
errorCalled.should.be_true
end
end
describe '.getJSON()'
it 'should work with mockRequest'
mockRequest().and_return('{ foo : "bar" }')
$.getJSON('foo', function(response, statusText){
response.foo.should.eql 'bar'
statusText.should.eql 'success'
})
end
it 'should work with a json fixture'
mockRequest().and_return(fixture('test.json'))
$.getJSON('foo', function(response){
response.users.tj.email.should.eql 'tj@vision-media.ca'
})
end
it 'should not invoke callback when response status is 4xx'
mockRequest().and_return('foo', 'text/plain', 404)
$.getJSON('foo', function(){
fail('callback was invoked')
})
end
end
describe '.post()'
it 'should work with mockRequest'
mockRequest().and_return('<p></p>', 'text/html')
$.post('foo', function(response){
response.should.eql '<p></p>'
})
end
end
end

View File

@ -1,166 +0,0 @@
describe 'Failing specs'
it 'should fail'
spec = mock_it(function(){
'test'.should.not.eql 'test'
})
spec.should.have_failure_message("expected 'test' to not eql 'test'")
end
it 'should fail with one faulty assertion'
spec = mock_it(function() {
'test'.should.equal 'test'
'test'.should.equal 'foo'
})
spec.should.have_failure_message("expected 'test' to be 'foo'")
end
it 'should fail and print array with square braces'
spec = mock_it(function() {
[1,2].should.equal [1,3]
})
spec.should.have_failure_message("expected [ 1, 2 ] to be [ 1, 3 ]")
end
it 'should fail and print nested array'
spec = mock_it(function() {
[1, ['foo']].should.equal [1, ['bar', ['whatever', 1.0, { foo : 'bar', bar : { 1 : 2 } }]]]
})
spec.should.have_failure_message(/^expected \[\s*1,\s*\[\s*'foo'/)
end
it 'should fail with selector for jQuery objects'
spec = mock_it(function() {
elem = { jquery : '1.3.1', selector : '.foobar' }
elem.should.eql 'foo'
})
spec.should.have_failure_message("expected selector '.foobar' to eql 'foo'")
end
it 'should fail with negated message'
spec = mock_it(function(){
'1'.should.not.be_true
})
spec.should.have_failure_message(/expected '1' to not be true/)
end
it 'should fail with positive message'
spec = mock_it(function() {
false.should.be_true
})
spec.should.have_failure_message(/expected false to be true/)
end
it 'should fail saying which error has been thrown'
spec = mock_it(function() {
-{ throw 'foo' }.should.throw_error 'bar'
})
spec.should.have_failure_message("expected exception of 'bar' to be thrown, but got 'foo'")
end
it 'should fail saying no error was thrown'
spec = mock_it(function() {
-{ }.should.throw_error 'foo'
})
spec.should.have_failure_message("expected exception of 'foo' to be thrown, but nothing was")
end
it 'should fail saying no error matching was thrown'
spec = mock_it(function() {
-{ throw 'bar' }.should.throw_error(/foo/)
})
spec.should.have_failure_message("expected exception matching /foo/ to be thrown, but got 'bar'")
end
it 'should fail saying constructors'
spec = mock_it(function() {
-{ throw new TypeError('oh no') }.should.throw_error(Error)
})
spec.should.have_failure_message("expected Error to be thrown, but got TypeError: oh no")
end
it 'should fail saying multiple arg messages'
spec = mock_it(function() {
-{ throw new TypeError('oh no') }.should.throw_error(TypeError, /foo/)
})
spec.should.have_failure_message("expected TypeError and exception matching /foo/ to be thrown, but got TypeError: oh no")
end
it 'should fail with constructor name'
spec = mock_it(function() {
function Foo(){}
function Bar(){}
Bar.prototype.toString = function(){ return 'Bar: oh no' }
-{ throw new Bar }.should.throw_error Foo
})
spec.should.have_failure_message("expected Foo to be thrown, but got Bar: oh no")
end
it 'should fail with constructor name'
spec = mock_it(function() {
function Foo(){ this.toString = function(){ return '<Foo>' }}
foo = new Foo
foo.should.not.be_an_instance_of Foo
})
spec.should.have_failure_message("expected <Foo> to not be an instance of Foo")
end
it 'should fail with message of first failure'
spec = mock_it(function() {
true.should.be_true
'bar'.should.match(/foo/gm)
'bar'.should.include 'foo'
})
spec.should.have_failure_message("expected 'bar' to match /foo/gm")
end
it 'should fail with list'
spec = mock_it(function() {
['foo', 'bar'].should.include 'foo', 'car'
})
spec.should.have_failure_message("expected [ 'foo', 'bar' ] to include 'foo', 'car'")
end
it 'should catch exceptions throw within specs'
spec = mock_it(function() {
throw new Error('Oh noes!')
})
spec.should.have_failure_message(/Error: Oh noes!/)
end
it 'should catch exceptions without constructors'
spec = mock_it(function() {
throw 'oh noes'
})
spec.should.have_failure_message(/oh noes/)
end
it 'should catch indirect exceptions'
spec = mock_it(function() {
iDoNotExist.neitherDoI()
})
spec.should.have_failure_message(/iDoNotExist/)
end
end
describe 'Contexts'
before
JSpec.context = { iLike : 'cookies' }
end
after
JSpec.context = null
end
it 'should be replaceable'
iLike.should.equal 'cookies'
end
end
describe 'Misc'
it 'requires implementation'
end
end

View File

@ -1,493 +0,0 @@
describe 'Matchers'
describe 'eql'
it 'should work with strings'
'test'.should.eql 'test'
'test'.should.not.eql 'foo'
end
it 'should work with numbers'
11.should.eql 11
10.should.not.eql 11
end
it 'should loosely compare numbers as strings'
'11'.should.eql 11
'10'.should.not.eql 11
end
it 'should hash compare arrays'
[1, 2].should.eql [1, 2]
[1, 2].should.not.eql [1, 3]
[1, 2, [3], { foo : 'bar' }].should.eql [1, 2, [3], { foo : 'bar' }]
end
it 'should hash compare objects'
{ foo : 'bar' }.should.eql { foo : 'bar' }
end
it 'should hash compare objects with different orders'
a = { one : 'two', three : 'four' }
b = { three : 'four', one : 'two' }
a.should.eql b
end
it 'should hash compare arbitrary objects'
Foo = function(){}, Bar = function(){}
Bar.prototype = { doSomething : function(){ }}
foo = new Foo, foo2 = new Foo, bar = new Bar
foo.should.eql foo2
foo.should.not.eql bar
end
it 'should work with constructors'
Array.should.eql Array
Array.should.not.eql Object
end
end
describe 'equal'
it 'should perform strict comparisons'
'test'.should.equal 'test'
'1'.should.not.equal 1
true.should.be true
'1'.should.not.be true
end
end
describe 'match'
it 'should match regular expressions'
'foobar'.should.match(/foo/)
'foobar'.should.not.match(/barfoo/)
end
end
describe 'be_empty'
it 'should consider any object with zero length to be empty'
''.should.be_empty
' '.should.not.be_empty
[].should.be_empty
{ length : 0 }.should.be_empty
{}.should.be_empty
'cookies'.should.not.be_empty
[0].should.not.be_empty
{ length : 1 }.should.not.be_empty
{ foo : 'bar' }.should.not.be_empty
end
end
describe 'be_null'
it 'should check if a value is null'
a = 0
b = null
null.should.be_null
0.should.not.be_null
a.should.not.be_null
b.should.be_null
end
end
describe 'be_undefined'
it 'should check if a var is defined'
var foo
foo.should.be_undefined
end
end
describe 'have_length'
it 'should compare the length of an object'
'foo'.should.have_length 3
[1, 2].should.have_length 2
end
end
describe 'have_length_within'
it 'should check if an object has a length within the specified range'
'foo'.should.have_length_within 2..4
'f'.should.not.have_length_within 2..4
end
end
describe 'have_prop'
it 'should check if a property exists'
'foo'.should.have_prop 'length'
end
it 'should check that a property has a specific value'
'foo'.should.have_prop 'length', 3
{ length : '3' }.should.have_prop 'length', 3
end
it 'should check object hashes'
{ foo : 1..3 }.should.have_prop 'foo', 1..3
end
it 'should fail when the property does not exist'
'foo'.should.not.have_prop 'foo'
'foo'.should.not.have_prop 'foo', 'bar'
end
it 'should fail when it is a function'
'foo'.should.not.have_prop 'toString'
end
end
describe 'have_property'
it 'should check if a property exists'
'foo'.should.have_property 'length'
end
it 'should check that a property has a specific value'
'foo'.should.have_property 'length', 3
{ length : '3' }.should.not.have_property 'length', 3
end
it 'should fail when the property does not exist'
'foo'.should.not.have_property 'foo'
'foo'.should.not.have_property 'foo', 'bar'
end
it 'should fail when it is a function'
'foo'.should.not.have_property 'toString'
end
end
describe 'respond_to'
it 'should check if an object contains a method'
'test'.should.respond_to('toString')
'test'.should.not.respond_to('rawr')
end
end
describe 'include'
it 'should check if an object includes a property'
{ hey : 'there' }.should.include 'hey'
{ hey : 'there' }.should.not.include 'foo'
end
it 'should check if a regular expression includes a string'
(/(foo)?bar/).should.include '(foo)'
end
it 'should check if a function body includes a string'
-{ return [foo, bar] }.should.include 'foo', 'bar'
end
it 'should check if an array contains element(s)'
[1,2,3].should.include 1
[1,2,3].should.include 1, 2, 3
[1].should.not.include 0
['foo', 'bar'].should.include 'foo', 'bar'
['foo', 'bar'].should.include 'bar', 'foo'
['foo', 'bar'].should.not.include 'foo', 'rawr'
['foo', 'bar'].should.not.include 'rawr', 'foo'
end
it 'should check hashes of array elements'
[1, [2]].should.include [2]
[1, [2]].should.include [2], 1
[1, { two : 'three' }].should.include { two : 'three' }
end
end
describe 'be_a'
it 'should compare the constructor of an object'
'test'.should.be_a String
[].should.be_an Array
end
end
describe 'throw_error'
it 'should check if an error is thrown'
-{ throw 'error' }.should.throw_error
-{ return 'test' }.should.not.throw_error
end
it 'should check if an error with a specific message is thrown'
-{ throw 'some foo bar' }.should.throw_error('some foo bar')
-{ throw 'some foo bar' }.should.throw_error(/foo bar/)
-{ throw 'some foo bar' }.should.not.throw_error(/rawr/)
-{ throw 'some foo bar' }.should.not.throw_error('rawr')
end
it 'should check if an error of a specific constructor is thrown'
-{ throw new Error('foo') }.should.throw_error(Error)
-{ throw new TypeError('foo') }.should.throw_error(TypeError)
-{ throw 'foo' }.should.throw_error Error
-{ throw 'foo' }.should.not.throw_error TypeError
end
it 'should check if an error with a specific constructor and message is thrown'
-{ throw new TypeError('oh no!') }.should.throw_error(TypeError, 'oh no!')
-{ throw new TypeError('oh no!') }.should.not.throw_error(TypeError, 'foo bar')
-{ throw new TypeError('oh no!') }.should.throw_error(TypeError, /oh no/)
-{ throw new TypeError('oh no!') }.should.not.throw_error(TypeError, /foo bar/)
-{ throw new TypeError('oh no!') }.should.not.throw_error(Error, 'oh no!')
-{ throw new TypeError('oh no!') }.should.not.throw_error(Error, 'foo bar')
end
end
describe 'be_an_instance_of'
it 'should check that an object is an instance of another'
MyObject = function(){}
myInstance = new MyObject()
{}.should.be_an_instance_of Object
[].should.be_an_instance_of Array
MyObject.should.be_an_instance_of Function
myInstance.should.be_an_instance_of MyObject
myInstance.should.be_an_instance_of Object
end
end
describe 'be_type'
it 'should compare the type of an object via typeof'
'hey'.should.be_type 'string'
{}.should.be_type 'object'
end
end
describe 'be_within'
it 'should check if a number is within a range'
5.should.be_within 1..10
15.should.not.be_within 10..5
end
end
describe 'have'
it 'should check the length of a property'
person = { pets : ['izzy', 'niko'] }
person.should.have 2, 'pets'
person.should.not.have 3, 'pets'
end
end
describe 'have_at_least'
it 'should check if a object has at least n of a property'
person = { pets : ['izzy', 'niko'] }
person.should.have_at_least 1, 'pets'
person.should.have_at_least 2, 'pets'
person.should.not.have_at_least 3, 'pets'
end
end
describe 'have_at_most'
it 'should check if an object has at most n of a property'
person = { pets : ['izzy', 'niko'] }
person.should.have_at_most 2, 'pets'
person.should.have_at_most 3, 'pets'
person.should.not.have_at_most 1, 'pets'
end
end
describe 'be_within'
it 'should check that an object has within n..n of a property'
person = { pets : ['izzy', 'niko'] }
person.should.have_within 1..2, 'pets'
person.should.have_within 2..5, 'pets'
person.should.not.have_within 5..10, 'pets'
end
end
describe 'receive'
before_each
person = { toString : function(){ return 'person' }}
personWithPets = {
toString : function(){ return 'personWithPets' },
getPets : function() { return ['izzy'] },
addPet : function(name) { return ['izzy', name] },
addPets : function(a, b) { return ['izzy', a, b] }
}
end
it 'should pass when the method is invoked'
personWithPets.should.receive('getPets')
personWithPets.getPets()
end
it 'should pass and original method should still return its result'
personWithPets.should.receive('getPets')
personWithPets.getPets().should.eql ['izzy']
end
it 'should pass when the proper value is returned'
personWithPets.should.receive('getPets').and_return(['izzy'])
personWithPets.getPets()
end
it 'should pass when invoked the expected number of times'
personWithPets.should.receive('getPets', 'twice').and_return(['izzy'])
personWithPets.getPets()
personWithPets.getPets()
end
it 'should pass when a method is invoked with specific arguments'
personWithPets.should.receive('addPet', 'once').with_args('suki')
personWithPets.addPet('suki')
end
it 'should pass with multiple arguments'
personWithPets.should.receive('addPets').with_args('suki', 'max')
personWithPets.addPets('suki', 'max')
end
it 'should pass with arguments and return value'
personWithPets.should.receive('addPet').with_args('suki').and_return(['izzy', 'suki'])
personWithPets.addPet('suki')
end
it 'should pass when argument is the correct type'
personWithPets.should.receive('addPet').with_args(an_instance_of(String))
personWithPets.addPet('suki')
end
it 'should pass when return type is correct'
personWithPets.should.receive('addPet').and_return(an_instance_of(Array))
personWithPets.addPet('suki')
end
it 'should pass when checking the type of multiple args and return types'
personWithPets.should.receive('addPets').with_args(an_instance_of(String), an_instance_of(String)).and_return(an_instance_of(Array))
personWithPets.addPets('suki', 'max')
end
it 'should pass with negation when a method is not called'
personWithPets.should.not.receive('addPets')
end
it 'should pass with negation with args'
personWithPets.should.not.receive('addPets').with_args('izzy')
personWithPets.addPets('max')
end
it 'should pass with negation with return values'
personWithPets.should.not.receive('addPets').with_args('izzy').and_return('test')
personWithPets.addPets('izzy')
end
it 'should pass with negation with times'
personWithPets.should.not.receive('addPets', 'twice')
personWithPets.addPets('izzy')
end
it 'should pass with boolean args'
foo = { bar : function(arg){ return arg }}
foo.should.receive('bar', 'twice').with_args(true)
foo.bar(true)
foo.bar(true)
end
it 'should pass with null args'
foo = { bar : function(arg){ return arg }}
foo.should.receive('bar').with_args(null)
foo.bar(null)
end
it 'should pass with boolean return value true'
foo = { bar : function(){ return true }}
foo.should.receive('bar').and_return(true)
foo.bar()
end
it 'should pass with boolean return value false'
foo = { bar : function(){ return false }}
foo.should.receive('bar').and_return(false)
foo.bar()
end
it 'should pass with null return value'
foo = { bar : function(){ return null }}
foo.should.receive('bar').and_return(null)
foo.bar()
end
it 'should fail when the method does not exist'
person.should.receive('getPets')
end
it 'should fail when the method is never invoked'
personWithPets.should.receive('getPets')
end
it 'should fail when improper value is returned'
personWithPets.should.receive('getPets').and_return(['niko'])
personWithPets.getPets()
end
it 'should fail when checking the type of multiple args and return types'
personWithPets.should.receive('addPets').with_args(an_instance_of(String), an_instance_of(Array)).and_return(an_instance_of(Array))
personWithPets.addPets('suki', 'max')
end
it 'should fail when not invoked the expected number of times'
personWithPets.should.receive('getPets', 'twice').and_return(['izzy'])
personWithPets.getPets()
end
it 'should fail when not invoked many times'
personWithPets.should.receive('getPets', 3).and_return(['izzy'])
personWithPets.getPets()
personWithPets.getPets()
end
it 'should fail when not invoked with specific arguments'
personWithPets.should.receive('addPet', 'once').with_args('suki')
personWithPets.addPet('niko')
end
it 'should fail when expecting multiple arguments'
personWithPets.should.receive('addPets').with_args('suki', 'max')
personWithPets.addPets('suki')
end
it 'should fail when argument is of the wrong type'
personWithPets.should.receive('addPet').with_args(an_instance_of(String))
personWithPets.addPet(['suki'])
end
it 'should fail when return type is incorrect'
personWithPets.should.receive('addPet').and_return(an_instance_of(String))
personWithPets.addPet('suki')
end
it 'should fail with negation when a method is called'
personWithPets.should.not.receive('addPets')
personWithPets.addPets('izzy')
end
it 'should fail with negation with args'
personWithPets.should.not.receive('addPets').with_args('izzy')
personWithPets.addPets('izzy')
end
it 'should fail with negation with return values'
personWithPets.should.not.receive('addPets').with_args('izzy').and_return(an_instance_of(Array))
personWithPets.addPets('izzy')
end
it 'should fail with negation with times'
personWithPets.should.not.receive('addPets', 'twice')
personWithPets.addPets('izzy')
personWithPets.addPets('max')
end
it 'should fail with boolean args'
foo = { bar : function(arg){ return arg }}
foo.should.receive('bar').with_args(true)
foo.bar(false)
end
it 'should fail with boolean return value true'
foo = { bar : function(){ return true }}
foo.should.receive('bar').and_return(false)
foo.bar()
end
it 'should fail with boolean return value false'
foo = { bar : function(){ return false }}
foo.should.receive('bar').and_return(true)
foo.bar()
end
end
end

View File

@ -1,51 +0,0 @@
describe 'JSpec'
describe 'module'
describe 'hooks'
it 'should run beforeSpec'
addedBeforeSpec.should.be_true
end
it 'should run afterSpec'
addedAfterSpec.should.be_true
end
describe 'with suites'
it 'should run beforeSuite'
addedBeforeSuite.should.be_true
end
end
it 'should run afterSuite'
addedAfterSuite.should.be_true
end
end
describe '.hook()'
it 'should invoke hooks, returning an array of results'
results = hook('randomHook', 'foo', 'bar')
results.should.eql [['foo', 'bar']]
end
end
describe '.utilities'
it 'should be merged with the default utilities'
doFoo().should.eql 'foo'
doBar().should.eql 'bar'
end
end
describe '.matchers'
it 'should be merged with default matchers'
'test'.should.be_foo_bar
end
end
describe '.DSLs'
it 'should be merged with default DSLs'
JSpec.DSLs.snake.some_snake_case_stuff().should.be_true
JSpec.DSLs.camel.someCamelCaseStuff().should.be_true
end
end
end
end

View File

@ -1,46 +0,0 @@
__loading__ = []
__loadDelay__ = 1000
originalPrint = print
print = puts
readFile = function(path, callback) {
__loading__.push(path)
var promise = node.fs.cat(path, "utf8")
promise.addErrback(function(){ throw "failed to read file `" + path + "'" })
promise.addCallback(function(contents){
setTimeout(function(){
if (__loading__[0] == path)
__loading__.shift(), callback(contents)
else
setTimeout(arguments.callee, 50)
}, 50)
})
}
load = function(path) {
readFile(path, function(contents){
eval(contents)
})
}
load('lib/jspec.js')
load('spec/modules.js')
load('spec/spec.grammar-less.js')
setTimeout(function(){
JSpec
.exec('spec/spec.grammar.js')
.exec('spec/spec.js')
.exec('spec/spec.matchers.js')
.exec('spec/spec.utils.js')
.exec('spec/spec.shared-behaviors.js')
setTimeout(function(){
JSpec.run({ formatter : JSpec.formatters.Terminal, failuresOnly : false })
setTimeout(function() {
JSpec.report()
}, __loadDelay__ / 3)
}, __loadDelay__ / 3)
}, __loadDelay__ / 3)

View File

@ -1,17 +0,0 @@
load('lib/jspec.js')
load('lib/jspec.xhr.js')
load('spec/helpers.js')
load('spec/spec.grammar-less.js')
JSpec
.exec('spec/spec.grammar.js')
.exec('spec/spec.js')
.exec('spec/spec.matchers.js')
.exec('spec/spec.utils.js')
.exec('spec/spec.fixtures.js')
.exec('spec/spec.shared-behaviors.js')
.exec('spec/spec.modules.js')
.exec('spec/spec.xhr.js')
.run({ formatter : JSpec.formatters.Terminal, failuresOnly : false })
.report()

View File

@ -1,29 +0,0 @@
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
<script src="/jspec/jspec.js"></script>
<script src="/jspec/jspec.jquery.js"></script>
<script src="/jspec/jspec.xhr.js"></script>
<script src="helpers.js"></script>
<script src="spec.grammar-less.js"></script>
<script>
function runSuites() {
JSpec
.exec('spec.grammar.js')
.exec('spec.js')
.exec('spec.matchers.js')
.exec('spec.utils.js')
.exec('spec.fixtures.js')
.exec('spec.shared-behaviors.js')
.exec('spec.jquery.js')
.exec('spec.modules.js')
.exec('spec.xhr.js')
.exec('spec.jquery.xhr.js')
.run({ formatter : JSpec.formatters.Server })
.report()
}
</script>
</head>
<body class="jspec" onLoad="runSuites();">
</body>
</html>

View File

@ -1,80 +0,0 @@
describe 'Shared Behaviors'
describe 'User'
before
User = function(name) { this.name = name }
user = new User('joe')
end
it 'should have a name'
user.should.have_property 'name'
end
describe 'Administrator'
should_behave_like('User')
before
Admin = function(name) { this.name = name }
Admin.prototype.may = function(perm){ return true }
user = new Admin('tj')
end
it 'should have access to all permissions'
user.may('edit pages').should.be_true
user.may('delete users').should.be_true
end
describe 'Super Administrator'
should_behave_like('Administrator')
before
SuperAdmin = function(name) { this.name = name }
SuperAdmin.prototype.may = function(perm){ return true }
user = new SuperAdmin('tj')
end
end
end
end
describe 'User with toString()'
before
user = { toString : function() { return '<User tj>' }}
end
it 'should return &lt;User NAME&gt;'
user.toString().should.match(/\<User/)
end
end
describe 'Manager'
should_behave_like('User')
should_behave_like('User with toString()')
before
Manager = function(name) { this.name = name }
Manager.prototype.may = function(perm){ return perm == 'hire' || perm == 'fire' }
Manager.prototype.toString = function(){ return '<User ' + this.name + '>' }
user = new Manager('tj')
end
it 'should have access to hire or fire employees'
user.may('hire').should.be_true
user.may('fire').should.be_true
user.may('do anything else').should.be_false
end
end
describe 'findSuite'
it 'should find a suite by full description'
JSpec.findSuite('Shared Behaviors User Administrator').should.be_a JSpec.Suite
end
it 'should find a suite by name'
JSpec.findSuite('User').should.be_a JSpec.Suite
end
it 'should return null when not found'
JSpec.findSuite('Rawr').should.be_null
end
end
end

View File

@ -1,262 +0,0 @@
describe 'Utility'
describe 'fail()'
it 'should fail the current spec'
spec = mock_it(function() {
fail('I failed!')
})
spec.should.have_failure_message('I failed!')
end
end
describe 'pass()'
it 'should pass the current spec'
pass('yay')
pass('wahoo')
end
end
describe 'stubbing'
before_each
Object.prototype.stubby = function() { return 'Not stubbed' }
object = { toString : function() { return '<Im an object>' }}
stub(object, 'stubby').and_return('Im stubbed')
stub(object, 'toString').and_return('<No im not>')
end
after_each
delete Object.prototype.stubby
end
describe 'stub()'
it 'should stub :)'
object.stubby().should.eql 'Im stubbed'
object.toString().should.eql '<No im not>'
end
it 'should allow being called as a core prototype method'
foo = { bar : function(){ return 'baz' }}
foo.stub('bar').and_return('something else')
foo.bar().should.eql 'something else'
foo.destub()
foo.bar().should.eql 'baz'
end
it 'should stub methods starting with an underscore'
object._foo = function(){ return 'bar' }
object.stub('_foo').and_return('something else')
object._foo().should.eql 'something else'
object.destub()
object._foo().should.eql 'bar'
end
it 'should stub methods with whitespace'
object['foo bar'] = function(){ return 'rawr' }
object.stub('foo bar').and_return('baz')
object['foo bar']().should.eql 'baz'
object.destub()
object['foo bar']().should.eql 'rawr'
end
it 'should stub with arbitrary method when no return value is set'
object.stub(' super cool ')
object[' super cool '].should.be_a Function
destub(object)
object[' super cool '].should.be_null
end
it 'should stub sub properties using the JSpec grammar'
object = { foo : { bar : {}}}
object.foo.bar.stub('kitten').and_return('meow')
object.foo.bar.kitten().should.eql 'meow'
object.foo.bar.destub()
object.foo.bar.should.not.respond_to('kitten')
end
it 'should allow functions to be passed as a method'
stub(object, 'post').and_return(function(url, callback){
if (url == 'http://jspec.info')
callback('is awesome')
})
object.post('http://jspec.info', function(text){
text.should_eql 'is awesome'
})
end
end
describe 'destub()'
it 'should restore old methods'
destub(object, 'toString')
destub(object, 'stubby')
object.toString().should.eql '<Im an object>'
object.stubby().should.eql 'Not stubbed'
end
it 'should restore prototypal methods'
Object.prototype.stubby = function() { return 'Oh no im new' }
destub(object, 'stubby')
object.stubby().should.eql 'Oh no im new'
end
it 'should destub all methods stubbed related to the object passed when no method is given'
destub(object)
object.toString().should.eql '<Im an object>'
object.stubby().should.eql 'Not stubbed'
end
describe 'should restore after each spec'
before
a = { toString : function(){ return 'Wahoo' }}
b = { toString : function(){ return 'Wahhhhhooo' }}
end
it 'should stub'
stub(a, 'toString').and_return('Oh no')
stub(b, 'toString').and_return('Oh noooo')
a.toString().should.eql 'Oh no'
b.toString().should.eql 'Oh noooo'
end
it 'should restore'
a.toString().should.eql 'Wahoo'
b.toString().should.eql 'Wahhhhhooo'
end
end
end
end
describe 'query()'
it 'should return a pairs value'
query('suite', '?suite=Positive%20specs').should.equal 'Positive specs'
end
it 'should return null when key is not present'
query('foo', '?suite=Positive%20specs').should.be_null
end
end
describe 'strip()'
it 'should strip whitespace by default'
strip(" foo \n\n").should.equal 'foo'
end
it 'should strip the characters passed'
strip('[foo]', '\\[\\]').should.equal 'foo'
end
end
describe 'each()'
it 'should iterate an array'
result = []
each([1,2,3], function(value){
result.push(value)
})
result.should.eql [1,2,3]
end
it 'should iterate words in a string'
result = []
each('some foo bar', function(value){
result.push(value)
})
result.should.eql ['some', 'foo', 'bar']
end
end
describe 'map()'
it 'should return an array of mapped values'
result = map([1,2,3], function(value){
return value * 2
})
result.should.eql [2,4,6]
end
it 'should inherit the ability to iterate words in a string'
result = map('some foo bar', function(i, value){
return i + '-' + value
})
result.should.eql ['0-some', '1-foo', '2-bar']
end
end
describe 'inject()'
it 'should provide a memo object while iterating, not expecting returning of memo for composits'
result = inject([1,2,3], [], function(memo, value){
memo.push(value)
})
result.should.eql [1,2,3]
end
it 'should require returning of memo for scalar variables'
result = inject([1,2,3], false, function(memo, value){
return memo ? memo : value == 2
})
result.should.be_true
end
end
describe 'any()'
it 'should return null when no matches are found'
result = any('some foo bar', function(value){
return value.length > 5
})
result.should.be_null
end
it 'should return the value of the first matching expression'
result = any('foo some bar', function(value){
return value.length > 3
})
result.should.eql 'some'
end
describe 'haveStopped'
it 'should check if "stop" has been returned by a callback hook'
any([true, 'stop'], haveStopped).should.eql 'stop'
any([true, true], haveStopped).should.be_null
any([true, null], haveStopped).should.be_null
end
end
end
describe 'select()'
it 'should return an array of values when the callback evaluates to true'
result = select('some foo bar baz stuff', function(value){
return value.length > 3
})
result.should.eql ['some', 'stuff']
end
end
describe 'last()'
it 'should return the last element in an array'
last(['foo', 'bar']).should.eql 'bar'
end
end
describe 'argumentsToArray()'
it 'should return an array of arguments'
func = function(){ return argumentsToArray(arguments) }
func('foo', 'bar').should.eql ['foo', 'bar']
end
it 'should return the offset of an arguments array'
func = function(){ return argumentsToArray(arguments, 2) }
func('foo', 'bar', 'baz').should.eql ['baz']
end
end
describe 'does()'
it 'should assert without reporting'
does('foo', 'eql', 'foo')
JSpec.currentSpec.assertions.should.have_length 0
end
end
describe 'contentsOf()'
it 'should return a function body'
JSpec.contentsOf(-{ return 'foo' }).should.include 'return', 'foo'
end
end
end

View File

@ -1,156 +0,0 @@
describe 'JSpec'
describe 'Mock XHR'
before
responseFrom = function(path) {
request = new XMLHttpRequest
request.open('POST', path, false)
request.send(null)
return request.responseText
}
end
it 'should provide snake DSL methods'
mock_request.should.equal mockRequest
unmock_request.should.equal unmockRequest
end
it 'should mock XMLHttpRequests if unmockRequest() is called or the spec block has finished'
original = XMLHttpRequest
mockRequest().and_return('test')
XMLHttpRequest.should.not.equal original
unmockRequest()
XMLHttpRequest.should.equal original
end
it 'should restore original XMLHttpRequest constructor after each spec'
XMLHttpRequest.should.not.eql JSpec.XMLHttpRequest
end
describe 'mock response'
before_each
mockRequest().and_return('bar', 'text/plain', 200, { 'x-foo' : 'bar' })
request = new XMLHttpRequest
request.open('GET', 'path', false, 'foo', 'bar')
request.send('foo=bar')
end
it 'should allow setting response status'
mockRequest().and_return('bar', 'text/plain', 404)
request = new XMLHttpRequest
request.open('GET', 'path', false)
request.send(null)
request.status.should.eql 404
request.statusText.should.eql 'Not Found'
end
it 'should default readyState to 0'
request = new XMLHttpRequest
request.readyState.should.eql 0
end
it 'should populate user'
request.user.should.eql 'foo'
end
it 'should populate password'
request.password.should.eql 'bar'
end
it 'should populate method'
request.method.should.eql 'GET'
end
it 'should populate readyState'
request.readyState.should.eql 4
end
it 'should populate url'
request.url.should.eql 'path'
end
it 'should populate status'
request.status.should.eql 200
end
it 'should populate statusText'
request.statusText.should.eql 'OK'
end
it 'should populate content type response header'
request.getResponseHeader('Content-Type').should.eql 'text/plain'
end
it 'should populate Content-Length response header'
request.getResponseHeader('Content-Length').should.eql 3
end
it 'should populate data'
request.data.should.eql 'foo=bar'
end
it 'should populate responseText'
request.responseText.should.eql 'bar'
end
it 'should populate headers'
request.getResponseHeader('X-Foo').should.eql 'bar'
end
it 'should not interrupt JSpec request related functionality'
mockRequest().and_return('fail')
(JSpec.tryLoading('async') || JSpec.tryLoading('spec/async')).should.eql 'cookies!'
fixture('test').should.eql '<p>test</p>'
fixture('test.json').should.include '{ user'
end
describe '.onreadystatechange()'
before_each
mockRequest().and_return('bar', 'text/plain', 200)
request = new XMLHttpRequest
end
it 'should be called when opening request in context to the request'
request.onreadystatechange = function(){
this.readyState.should.eql 1
}
request.open('GET', 'path')
end
it 'should be called when sending request'
request.open('GET', 'path')
request.onreadystatechange = function(){
this.readyState.should.eql 4
}
request.send(null)
end
end
describe '.setRequestHeader()'
it 'should set request headers'
mockRequest().and_return('bar', 'text/plain', 200)
request.open('GET', 'path', false, 'foo', 'bar')
request.setRequestHeader('Accept', 'foo')
request.send(null)
request.requestHeaders['accept'].should.eql 'foo'
end
end
describe 'HEAD'
it 'should respond with headers only'
mockRequest().and_return('bar', 'text/plain', 200)
request.open('HEAD', 'path', false)
request.send(null)
request.responseText.should.be_null
end
end
describe 'with uri'
it 'should mock only the uri specified'
mockRequest('ilike').and_return('cookies')
responseFrom('async').should.eql 'cookies'
end
end
end
end
end

View File

@ -1,4 +0,0 @@
=== 0.0.1 / YYYY-MM-DD
* Initial release

View File

@ -1,29 +0,0 @@
= YourLib
Description
== License
(The MIT License)
Copyright (c) 2009 Your Name <Your Email>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,2 +0,0 @@
// Your library here

View File

@ -1,4 +0,0 @@
get '/lib/*' do |path|
send_file File.dirname(__FILE__) + '/../lib/' + path
end

View File

@ -1,8 +0,0 @@
describe 'YourLib'
describe '.someMethod()'
it 'should do something'
true.should.be true
end
end
end

View File

@ -1,20 +0,0 @@
<html>
<head>
<link type="text/css" rel="stylesheet" href="JSPEC_ROOT/lib/jspec.css" />
<script src="JSPEC_ROOT/lib/jspec.js"></script>
<script src="../lib/yourlib.core.js"></script>
<script>
function runSuites() {
JSpec
.exec('spec.core.js')
.run()
.report()
}
</script>
</head>
<body class="jspec" onLoad="runSuites();">
<div id="jspec-top"><h2 id="jspec-title">JSpec <em><script>document.write(JSpec.version)</script></em></h2></div>
<div id="jspec"></div>
<div id="jspec-bottom"></div>
</body>
</html>

View File

@ -1,8 +0,0 @@
load('JSPEC_ROOT/lib/jspec.js')
load('lib/yourlib.core.js')
JSpec
.exec('spec/spec.core.js')
.run({ formatter: JSpec.formatters.Terminal })
.report()

View File

@ -1,16 +0,0 @@
<html>
<head>
<script src="/jspec/jspec.js"></script>
<script src="/lib/yourlib.core.js"></script>
<script>
function runSuites() {
JSpec
.exec('spec.core.js')
.run({ formatter: JSpec.formatters.Server, verbose: true, failuresOnly: true })
.report()
}
</script>
</head>
<body class="jspec" onLoad="runSuites();">
</body>
</html>

View File

@ -1,4 +0,0 @@
get '/public/*' do |path|
send_file File.dirname(__FILE__) + '/../public/' + path
end

View File

@ -1,8 +0,0 @@
describe 'YourLib'
describe '.someMethod()'
it 'should do something'
true.should.be true
end
end
end

View File

@ -1,20 +0,0 @@
<html>
<head>
<link type="text/css" rel="stylesheet" href="JSPEC_ROOT/lib/jspec.css" />
<script src="JSPEC_ROOT/lib/jspec.js"></script>
<script src="../public/javascripts/application.js"></script>
<script>
function runSuites() {
JSpec
.exec('spec.application.js')
.run()
.report()
}
</script>
</head>
<body class="jspec" onLoad="runSuites();">
<div id="jspec-top"><h2 id="jspec-title">JSpec <em><script>document.write(JSpec.version)</script></em></h2></div>
<div id="jspec"></div>
<div id="jspec-bottom"></div>
</body>
</html>

View File

@ -1,8 +0,0 @@
load('JSPEC_ROOT/lib/jspec.js')
load('public/javascripts/application.js')
JSpec
.exec('jspec/spec.application.js')
.run({ formatter: JSpec.formatters.Terminal })
.report()

View File

@ -1,16 +0,0 @@
<html>
<head>
<script src="/jspec/jspec.js"></script>
<script src="/public/javascripts/application.js"></script>
<script>
function runSuites() {
JSpec
.exec('spec.application.js')
.run({ formatter: JSpec.formatters.Server, verbose: true, failuresOnly: true })
.report()
}
</script>
</head>
<body class="jspec" onLoad="runSuites();">
</body>
</html>