jazz 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +129 -0
  3. data/bin/jazz +230 -0
  4. data/doc/jasmine/files.html +460 -0
  5. data/doc/jasmine/index.html +322 -0
  6. data/doc/jasmine/symbols/_global_.html +1083 -0
  7. data/doc/jasmine/symbols/jasmine.Block.html +417 -0
  8. data/doc/jasmine/symbols/jasmine.Clock.html +678 -0
  9. data/doc/jasmine/symbols/jasmine.Env.html +1135 -0
  10. data/doc/jasmine/symbols/jasmine.EnvjsReporter.html +328 -0
  11. data/doc/jasmine/symbols/jasmine.JsApiReporter.html +822 -0
  12. data/doc/jasmine/symbols/jasmine.Matchers.html +1106 -0
  13. data/doc/jasmine/symbols/jasmine.MultiReporter.html +394 -0
  14. data/doc/jasmine/symbols/jasmine.NestedResults.html +710 -0
  15. data/doc/jasmine/symbols/jasmine.Reporter.html +574 -0
  16. data/doc/jasmine/symbols/jasmine.Runner.html +710 -0
  17. data/doc/jasmine/symbols/jasmine.Spec.html +1372 -0
  18. data/doc/jasmine/symbols/jasmine.Spy.html +855 -0
  19. data/doc/jasmine/symbols/jasmine.Suite.html +705 -0
  20. data/doc/jasmine/symbols/jasmine.XMLReporter.html +328 -0
  21. data/doc/jasmine/symbols/jasmine.html +1359 -0
  22. data/doc/jasmine/symbols/jasmine.util.html +535 -0
  23. data/doc/jasmine/symbols/src/lib_EnvjsReporter.js.html +149 -0
  24. data/doc/jasmine/symbols/src/lib_TrivialReporter.js.html +127 -0
  25. data/doc/jasmine/symbols/src/lib_XMLReporter.js.html +210 -0
  26. data/doc/jasmine/symbols/src/src_Block.js.html +35 -0
  27. data/doc/jasmine/symbols/src/src_Env.js.html +233 -0
  28. data/doc/jasmine/symbols/src/src_JsApiReporter.js.html +110 -0
  29. data/doc/jasmine/symbols/src/src_Matchers.js.html +399 -0
  30. data/doc/jasmine/symbols/src/src_MultiReporter.js.html +36 -0
  31. data/doc/jasmine/symbols/src/src_NestedResults.js.html +88 -0
  32. data/doc/jasmine/symbols/src/src_PrettyPrinter.js.html +128 -0
  33. data/doc/jasmine/symbols/src/src_Queue.js.html +119 -0
  34. data/doc/jasmine/symbols/src/src_Reporter.js.html +35 -0
  35. data/doc/jasmine/symbols/src/src_Reporters.js.html +51 -0
  36. data/doc/jasmine/symbols/src/src_Runner.js.html +75 -0
  37. data/doc/jasmine/symbols/src/src_Spec.js.html +228 -0
  38. data/doc/jasmine/symbols/src/src_Suite.js.html +77 -0
  39. data/doc/jasmine/symbols/src/src_WaitsBlock.js.html +21 -0
  40. data/doc/jasmine/symbols/src/src_WaitsForBlock.js.html +45 -0
  41. data/doc/jasmine/symbols/src/src_base.js.html +566 -0
  42. data/doc/jasmine/symbols/src/src_mock-timeout.js.html +185 -0
  43. data/doc/jasmine/symbols/src/src_util.js.html +75 -0
  44. data/lib/jazz.rb +0 -0
  45. data/lib/jazz/intro.js +46 -0
  46. data/lib/jazz/jasmine/EnvjsReporter.js +141 -0
  47. data/lib/jazz/jasmine/TrivialReporter.js +155 -0
  48. data/lib/jazz/jasmine/XMLReporter.js +241 -0
  49. data/lib/jazz/jasmine/consolex.js +28 -0
  50. data/lib/jazz/jasmine/jasmine-0.10.0.js +2526 -0
  51. data/lib/jazz/jasmine/jasmine.js +2526 -0
  52. data/lib/jazz/jasmine/json2.js +478 -0
  53. data/lib/jazz/options.rb +26 -0
  54. data/lib/jazz/outro.js +3 -0
  55. data/lib/jazz/qintro.js +113 -0
  56. data/lib/jazz/qoutro.js +3 -0
  57. data/lib/jazz/qunit/qunit.css +17 -0
  58. data/lib/jazz/qunit/qunit.js +1027 -0
  59. data/spec/example/hello_world_spec.js +29 -0
  60. data/spec/example/nested/HelloWorldSpec.js +13 -0
  61. data/spec/example/nested/SpecHelper.js +1 -0
  62. data/spec/example/plain_spec.js +8 -0
  63. data/spec/example/spec_helper.js +1 -0
  64. data/spec/spec_helper.js +18 -0
  65. data/spec/spec_runner.js +143 -0
  66. data/test/jazz_test.rb +7 -0
  67. data/test/test_helper.rb +10 -0
  68. data/vendor/jasmine/MIT.LICENSE +20 -0
  69. data/vendor/jasmine/README.markdown +479 -0
  70. data/vendor/jasmine/Rakefile +155 -0
  71. data/vendor/jasmine/Wakefile +68 -0
  72. data/vendor/jasmine/contrib/ruby/jasmine_runner.rb +334 -0
  73. data/vendor/jasmine/contrib/ruby/jasmine_spec_builder.rb +153 -0
  74. data/vendor/jasmine/contrib/ruby/run.html +47 -0
  75. data/vendor/jasmine/contrib/ruby/spec/jasmine_runner_spec.rb +71 -0
  76. data/vendor/jasmine/doc/files.html +460 -0
  77. data/vendor/jasmine/doc/index.html +322 -0
  78. data/vendor/jasmine/doc/symbols/_global_.html +1083 -0
  79. data/vendor/jasmine/doc/symbols/jasmine.Block.html +417 -0
  80. data/vendor/jasmine/doc/symbols/jasmine.Clock.html +678 -0
  81. data/vendor/jasmine/doc/symbols/jasmine.Env.html +1135 -0
  82. data/vendor/jasmine/doc/symbols/jasmine.EnvjsReporter.html +328 -0
  83. data/vendor/jasmine/doc/symbols/jasmine.JsApiReporter.html +822 -0
  84. data/vendor/jasmine/doc/symbols/jasmine.Matchers.html +1106 -0
  85. data/vendor/jasmine/doc/symbols/jasmine.MultiReporter.html +394 -0
  86. data/vendor/jasmine/doc/symbols/jasmine.NestedResults.html +710 -0
  87. data/vendor/jasmine/doc/symbols/jasmine.Reporter.html +574 -0
  88. data/vendor/jasmine/doc/symbols/jasmine.Runner.html +710 -0
  89. data/vendor/jasmine/doc/symbols/jasmine.Spec.html +1372 -0
  90. data/vendor/jasmine/doc/symbols/jasmine.Spy.html +855 -0
  91. data/vendor/jasmine/doc/symbols/jasmine.Suite.html +705 -0
  92. data/vendor/jasmine/doc/symbols/jasmine.XMLReporter.html +328 -0
  93. data/vendor/jasmine/doc/symbols/jasmine.html +1359 -0
  94. data/vendor/jasmine/doc/symbols/jasmine.util.html +535 -0
  95. data/vendor/jasmine/doc/symbols/src/lib_EnvjsReporter.js.html +149 -0
  96. data/vendor/jasmine/doc/symbols/src/lib_TrivialReporter.js.html +127 -0
  97. data/vendor/jasmine/doc/symbols/src/lib_XMLReporter.js.html +210 -0
  98. data/vendor/jasmine/doc/symbols/src/src_Block.js.html +35 -0
  99. data/vendor/jasmine/doc/symbols/src/src_Env.js.html +233 -0
  100. data/vendor/jasmine/doc/symbols/src/src_JsApiReporter.js.html +110 -0
  101. data/vendor/jasmine/doc/symbols/src/src_Matchers.js.html +399 -0
  102. data/vendor/jasmine/doc/symbols/src/src_MultiReporter.js.html +36 -0
  103. data/vendor/jasmine/doc/symbols/src/src_NestedResults.js.html +88 -0
  104. data/vendor/jasmine/doc/symbols/src/src_PrettyPrinter.js.html +128 -0
  105. data/vendor/jasmine/doc/symbols/src/src_Queue.js.html +119 -0
  106. data/vendor/jasmine/doc/symbols/src/src_Reporter.js.html +35 -0
  107. data/vendor/jasmine/doc/symbols/src/src_Reporters.js.html +51 -0
  108. data/vendor/jasmine/doc/symbols/src/src_Runner.js.html +75 -0
  109. data/vendor/jasmine/doc/symbols/src/src_Spec.js.html +228 -0
  110. data/vendor/jasmine/doc/symbols/src/src_Suite.js.html +77 -0
  111. data/vendor/jasmine/doc/symbols/src/src_WaitsBlock.js.html +21 -0
  112. data/vendor/jasmine/doc/symbols/src/src_WaitsForBlock.js.html +45 -0
  113. data/vendor/jasmine/doc/symbols/src/src_base.js.html +566 -0
  114. data/vendor/jasmine/doc/symbols/src/src_mock-timeout.js.html +185 -0
  115. data/vendor/jasmine/doc/symbols/src/src_util.js.html +75 -0
  116. data/vendor/jasmine/examples/html/example_suite.html +27 -0
  117. data/vendor/jasmine/examples/html/spec/example_suite.js +11 -0
  118. data/vendor/jasmine/examples/ruby/Rakefile +33 -0
  119. data/vendor/jasmine/examples/ruby/spec/example/example_spec.js +11 -0
  120. data/vendor/jasmine/examples/ruby/spec/jasmine_helper.rb +41 -0
  121. data/vendor/jasmine/examples/ruby/spec/jasmine_spec.rb +31 -0
  122. data/vendor/jasmine/examples/ruby/spec/saucelabs.yml +24 -0
  123. data/vendor/jasmine/geminstaller.yml +23 -0
  124. data/vendor/jasmine/images/fail-16.png +0 -0
  125. data/vendor/jasmine/images/fail.png +0 -0
  126. data/vendor/jasmine/images/go-16.png +0 -0
  127. data/vendor/jasmine/images/go.png +0 -0
  128. data/vendor/jasmine/images/pending-16.png +0 -0
  129. data/vendor/jasmine/images/pending.png +0 -0
  130. data/vendor/jasmine/images/question-bk.png +0 -0
  131. data/vendor/jasmine/images/questionbk-16.png +0 -0
  132. data/vendor/jasmine/images/spinner.gif +0 -0
  133. data/vendor/jasmine/lib/EnvjsReporter.js +141 -0
  134. data/vendor/jasmine/lib/TrivialReporter.js +155 -0
  135. data/vendor/jasmine/lib/XMLReporter.js +241 -0
  136. data/vendor/jasmine/lib/consolex.js +28 -0
  137. data/vendor/jasmine/lib/jasmine-0.10.0.js +2526 -0
  138. data/vendor/jasmine/lib/jasmine.css +86 -0
  139. data/vendor/jasmine/lib/json2.js +478 -0
  140. data/vendor/jasmine/spec/jasmine_helper.rb +44 -0
  141. data/vendor/jasmine/spec/jasmine_spec.rb +31 -0
  142. data/vendor/jasmine/spec/runner.html +43 -0
  143. data/vendor/jasmine/spec/runner.js +78 -0
  144. data/vendor/jasmine/spec/saucelabs.yml +24 -0
  145. data/vendor/jasmine/spec/suites/EnvSpec.js +71 -0
  146. data/vendor/jasmine/spec/suites/ExceptionsSpec.js +107 -0
  147. data/vendor/jasmine/spec/suites/JsApiReporterSpec.js +82 -0
  148. data/vendor/jasmine/spec/suites/MatchersSpec.js +589 -0
  149. data/vendor/jasmine/spec/suites/MockClockSpec.js +34 -0
  150. data/vendor/jasmine/spec/suites/MultiReporterSpec.js +30 -0
  151. data/vendor/jasmine/spec/suites/NestedResultsSpec.js +54 -0
  152. data/vendor/jasmine/spec/suites/PrettyPrintSpec.js +93 -0
  153. data/vendor/jasmine/spec/suites/QueueSpec.js +23 -0
  154. data/vendor/jasmine/spec/suites/ReporterSpec.js +60 -0
  155. data/vendor/jasmine/spec/suites/RunnerSpec.js +258 -0
  156. data/vendor/jasmine/spec/suites/SpecRunningSpec.js +1117 -0
  157. data/vendor/jasmine/spec/suites/SpecSpec.js +110 -0
  158. data/vendor/jasmine/spec/suites/SpySpec.js +187 -0
  159. data/vendor/jasmine/spec/suites/SuiteSpec.js +101 -0
  160. data/vendor/jasmine/spec/suites/TrivialReporterSpec.js +140 -0
  161. data/vendor/jasmine/spec/suites/UtilSpec.js +23 -0
  162. data/vendor/jasmine/src/Block.js +34 -0
  163. data/vendor/jasmine/src/Env.js +236 -0
  164. data/vendor/jasmine/src/JsApiReporter.js +103 -0
  165. data/vendor/jasmine/src/Matchers.js +326 -0
  166. data/vendor/jasmine/src/MultiReporter.js +28 -0
  167. data/vendor/jasmine/src/NestedResults.js +99 -0
  168. data/vendor/jasmine/src/PrettyPrinter.js +122 -0
  169. data/vendor/jasmine/src/Queue.js +210 -0
  170. data/vendor/jasmine/src/Reporter.js +27 -0
  171. data/vendor/jasmine/src/Reporters.js +43 -0
  172. data/vendor/jasmine/src/Runner.js +68 -0
  173. data/vendor/jasmine/src/Spec.js +254 -0
  174. data/vendor/jasmine/src/Suite.js +70 -0
  175. data/vendor/jasmine/src/WaitsBlock.js +13 -0
  176. data/vendor/jasmine/src/WaitsForBlock.js +38 -0
  177. data/vendor/jasmine/src/base.js +604 -0
  178. data/vendor/jasmine/src/mock-timeout.js +177 -0
  179. data/vendor/jasmine/src/util.js +67 -0
  180. data/vendor/jasmine/src/version.json +5 -0
  181. metadata +292 -0
@@ -0,0 +1,26 @@
1
+ require 'optparse'
2
+
3
+ $jazz_verbose = false
4
+ $jazz_xml = false
5
+ $jazz_deps = nil
6
+ $jazz_qunit = false
7
+
8
+ OptionParser.new do |o|
9
+
10
+ o.on("-v","--verbose") do
11
+ $jazz_verbose = true
12
+ end
13
+
14
+ o.on("-x","--xml") do
15
+ $jazz_xml = true
16
+ end
17
+
18
+ o.on("-q","--qunit") do
19
+ $jazz_qunit = true
20
+ end
21
+
22
+ o.on("--deps PATH") do |path|
23
+ $jazz_deps = path
24
+ end
25
+
26
+ end.parse!
@@ -0,0 +1,3 @@
1
+ if(window.location == "about:blank"){
2
+ window.onload();
3
+ }
@@ -0,0 +1,113 @@
1
+ this.QUnit || load(Ruby.ENV["JAZZ_JS_PATH"]+"/qunit/qunit.js");
2
+
3
+ (function(){
4
+
5
+ var APOS = "'"; QUOTE = '"';
6
+ var ESCAPED_QUOTE = { };
7
+ ESCAPED_QUOTE[QUOTE] = '"';
8
+ ESCAPED_QUOTE[APOS] = ''';
9
+
10
+ function formatAttributes(attributes) {
11
+ var att_value;
12
+ var apos_pos, quot_pos;
13
+ var use_quote, escape, quote_to_escape;
14
+ var att_str;
15
+ var re;
16
+ var result = '';
17
+
18
+ for (var att in attributes) {
19
+ att_value = attributes[att] || "";
20
+
21
+ att_value = att_value.replace(/&/g, "&");
22
+ att_value = att_value.replace(/</g, "&lt;");
23
+ att_value = att_value.replace(/>/g, "&gt;");
24
+
25
+ // Find first quote marks if any
26
+ apos_pos = att_value.indexOf(APOS);
27
+ quot_pos = att_value.indexOf(QUOTE);
28
+
29
+ // Determine which quote type to use around
30
+ // the attribute value
31
+ if (apos_pos == -1 && quot_pos == -1) {
32
+ att_str = ' ' + att + "='" + att_value + "'";
33
+ result += att_str;
34
+ continue;
35
+ }
36
+
37
+ // Prefer the single quote unless forced to use double
38
+ if (quot_pos != -1 && quot_pos < apos_pos) {
39
+ use_quote = APOS;
40
+ }
41
+ else {
42
+ use_quote = QUOTE;
43
+ }
44
+
45
+ // Figure out which kind of quote to escape
46
+ // Use nice dictionary instead of yucky if-else nests
47
+ escape = ESCAPED_QUOTE[use_quote];
48
+
49
+ // Escape only the right kind of quote
50
+ re = new RegExp(use_quote,'g');
51
+ att_str = ' ' + att + '=' + use_quote +
52
+ att_value.replace(re, escape) + use_quote;
53
+ result += att_str;
54
+ }
55
+ return result;
56
+ };
57
+
58
+
59
+ var module;
60
+ var test;
61
+
62
+ var started = false;
63
+
64
+ QUnit.moduleStart = function(m,te) {
65
+ if(!started){
66
+ started = true;
67
+ print("<testsuites>");
68
+ }
69
+ if(module) {
70
+ print(" </testsuite>");
71
+ }
72
+ print(" <testsuite"+formatAttributes({name:m})+">");
73
+ module = m;
74
+ };
75
+
76
+ QUnit.testStart = function(t) {
77
+ test = t;
78
+ };
79
+
80
+ QUnit.log = function(r,m) {
81
+ var name = test + " : " + m;
82
+ var msg;
83
+ if (!r) {
84
+ var match = m.match(/(.*), (expected: .* result: .*)/);
85
+ if(match) {
86
+ name = match[1];
87
+ msg = match[2];
88
+ } else {
89
+ name = test;
90
+ msg = m;
91
+ }
92
+ }
93
+ print(" <testcase"+formatAttributes({name:name})+">");
94
+ if(!r){
95
+ print(" <failure"+formatAttributes({message:msg})+">");
96
+ print(" </failure>");
97
+ }
98
+ print(" </testcase>");
99
+ // var s = ( r ? "PASS (" : "FAIL (" ) + ") " + test_string + m;
100
+ // print(s);
101
+ };
102
+
103
+ QUnit.done = function(f,t) {
104
+ // print((t-f) + " Passed, " + f + " Failed, " + t + " Total Tests" );
105
+ if(module){
106
+ print(" </testsuite>");
107
+ }
108
+ if(started) {
109
+ print("</testsuites>");
110
+ }
111
+ };
112
+
113
+ })(QUnit);
@@ -0,0 +1,3 @@
1
+ if(window.location == "about:blank"){
2
+ window.onload();
3
+ }
@@ -0,0 +1,17 @@
1
+ h1#qunit-header { padding: 15px; font-size: large; background-color: #06b; color: white; font-family: 'trebuchet ms', verdana, arial; margin: 0; }
2
+ h1#qunit-header a { color: white; }
3
+
4
+ h2#qunit-banner { height: 2em; border-bottom: 1px solid white; background-color: #eee; margin: 0; font-family: 'trebuchet ms', verdana, arial; }
5
+ h2#qunit-banner.pass { background-color: green; }
6
+ h2#qunit-banner.fail { background-color: red; }
7
+
8
+ h2#qunit-userAgent { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal; font-family: 'trebuchet ms', verdana, arial; font-size: 10pt; }
9
+
10
+ div#qunit-testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; font-family: 'trebuchet ms', verdana, arial; margin: 0; font-size: 10pt; }
11
+
12
+ ol#qunit-tests { font-family: 'trebuchet ms', verdana, arial; font-size: 10pt; }
13
+ ol#qunit-tests li strong { cursor:pointer; }
14
+ ol#qunit-tests .pass { color: green; }
15
+ ol#qunit-tests .fail { color: red; }
16
+
17
+ p#qunit-testresult { margin-left: 1em; font-size: 10pt; font-family: 'trebuchet ms', verdana, arial; }
@@ -0,0 +1,1027 @@
1
+ /*
2
+ * QUnit - A JavaScript Unit Testing Framework
3
+ *
4
+ * http://docs.jquery.com/QUnit
5
+ *
6
+ * Copyright (c) 2009 John Resig, Jörn Zaefferer
7
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
8
+ * and GPL (GPL-LICENSE.txt) licenses.
9
+ */
10
+
11
+ (function(window) {
12
+
13
+ var QUnit = {
14
+
15
+ // Initialize the configuration options
16
+ init: function() {
17
+ config = {
18
+ stats: { all: 0, bad: 0 },
19
+ moduleStats: { all: 0, bad: 0 },
20
+ started: +new Date,
21
+ blocking: false,
22
+ autorun: false,
23
+ assertions: [],
24
+ filters: [],
25
+ queue: []
26
+ };
27
+
28
+ var tests = id("qunit-tests"),
29
+ banner = id("qunit-banner"),
30
+ result = id("qunit-testresult");
31
+
32
+ if ( tests ) {
33
+ tests.innerHTML = "";
34
+ }
35
+
36
+ if ( banner ) {
37
+ banner.className = "";
38
+ }
39
+
40
+ if ( result ) {
41
+ result.parentNode.removeChild( result );
42
+ }
43
+ },
44
+
45
+ // call on start of module test to prepend name to all tests
46
+ module: function(name, testEnvironment) {
47
+ config.currentModule = name;
48
+
49
+ synchronize(function() {
50
+ if ( config.currentModule ) {
51
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
52
+ }
53
+
54
+ config.currentModule = name;
55
+ config.moduleTestEnvironment = testEnvironment;
56
+ config.moduleStats = { all: 0, bad: 0 };
57
+
58
+ QUnit.moduleStart( name, testEnvironment );
59
+ });
60
+ },
61
+
62
+ asyncTest: function(testName, expected, callback) {
63
+ if ( arguments.length === 2 ) {
64
+ callback = expected;
65
+ expected = 0;
66
+ }
67
+
68
+ QUnit.test(testName, expected, callback, true);
69
+ },
70
+
71
+ test: function(testName, expected, callback, async) {
72
+ var name = testName, testEnvironment, testEnvironmentArg;
73
+
74
+ if ( arguments.length === 2 ) {
75
+ callback = expected;
76
+ expected = null;
77
+ }
78
+ // is 2nd argument a testEnvironment?
79
+ if ( expected && typeof expected === 'object') {
80
+ testEnvironmentArg = expected;
81
+ expected = null;
82
+ }
83
+
84
+ if ( config.currentModule ) {
85
+ name = config.currentModule + " module: " + name;
86
+ }
87
+
88
+ if ( !validTest(name) ) {
89
+ return;
90
+ }
91
+
92
+ synchronize(function() {
93
+ QUnit.testStart( testName );
94
+
95
+ testEnvironment = extend({
96
+ setup: function() {},
97
+ teardown: function() {}
98
+ }, config.moduleTestEnvironment);
99
+ if (testEnvironmentArg) {
100
+ extend(testEnvironment,testEnvironmentArg);
101
+ }
102
+
103
+ // allow utility functions to access the current test environment
104
+ QUnit.current_testEnvironment = testEnvironment;
105
+
106
+ config.assertions = [];
107
+ config.expected = null;
108
+
109
+ if ( arguments.length >= 3 ) {
110
+ config.expected = callback;
111
+ callback = arguments[2];
112
+ }
113
+
114
+ try {
115
+ if ( !config.pollution ) {
116
+ saveGlobal();
117
+ }
118
+
119
+ testEnvironment.setup.call(testEnvironment);
120
+ } catch(e) {
121
+ QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
122
+ }
123
+
124
+ if ( async ) {
125
+ QUnit.stop();
126
+ }
127
+
128
+ try {
129
+ callback.call(testEnvironment);
130
+ } catch(e) {
131
+ fail("Test " + name + " died, exception and test follows", e, callback);
132
+ QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
133
+ // else next test will carry the responsibility
134
+ saveGlobal();
135
+
136
+ // Restart the tests if they're blocking
137
+ if ( config.blocking ) {
138
+ start();
139
+ }
140
+ }
141
+ });
142
+
143
+ synchronize(function() {
144
+ try {
145
+ checkPollution();
146
+ testEnvironment.teardown.call(testEnvironment);
147
+ } catch(e) {
148
+ QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
149
+ }
150
+
151
+ try {
152
+ QUnit.reset();
153
+ } catch(e) {
154
+ fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
155
+ }
156
+
157
+ if ( config.expected && config.expected != config.assertions.length ) {
158
+ QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
159
+ }
160
+
161
+ var good = 0, bad = 0,
162
+ tests = id("qunit-tests");
163
+
164
+ config.stats.all += config.assertions.length;
165
+ config.moduleStats.all += config.assertions.length;
166
+
167
+ if ( tests ) {
168
+ var ol = document.createElement("ol");
169
+ ol.style.display = "none";
170
+
171
+ for ( var i = 0; i < config.assertions.length; i++ ) {
172
+ var assertion = config.assertions[i];
173
+
174
+ var li = document.createElement("li");
175
+ li.className = assertion.result ? "pass" : "fail";
176
+ li.innerHTML = assertion.message || "(no message)";
177
+ ol.appendChild( li );
178
+
179
+ if ( assertion.result ) {
180
+ good++;
181
+ } else {
182
+ bad++;
183
+ config.stats.bad++;
184
+ config.moduleStats.bad++;
185
+ }
186
+ }
187
+
188
+ var b = document.createElement("strong");
189
+ b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
190
+
191
+ addEvent(b, "click", function() {
192
+ var next = b.nextSibling, display = next.style.display;
193
+ next.style.display = display === "none" ? "block" : "none";
194
+ });
195
+
196
+ addEvent(b, "dblclick", function(e) {
197
+ var target = (e || window.event).target;
198
+ if ( target.nodeName.toLowerCase() === "strong" ) {
199
+ var text = "", node = target.firstChild;
200
+
201
+ while ( node.nodeType === 3 ) {
202
+ text += node.nodeValue;
203
+ node = node.nextSibling;
204
+ }
205
+
206
+ text = text.replace(/(^\s*|\s*$)/g, "");
207
+
208
+ if ( window.location ) {
209
+ window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
210
+ }
211
+ }
212
+ });
213
+
214
+ var li = document.createElement("li");
215
+ li.className = bad ? "fail" : "pass";
216
+ li.appendChild( b );
217
+ li.appendChild( ol );
218
+ tests.appendChild( li );
219
+
220
+ if ( bad ) {
221
+ var toolbar = id("qunit-testrunner-toolbar");
222
+ if ( toolbar ) {
223
+ toolbar.style.display = "block";
224
+ id("qunit-filter-pass").disabled = null;
225
+ id("qunit-filter-missing").disabled = null;
226
+ }
227
+ }
228
+
229
+ } else {
230
+ for ( var i = 0; i < config.assertions.length; i++ ) {
231
+ if ( !config.assertions[i].result ) {
232
+ bad++;
233
+ config.stats.bad++;
234
+ config.moduleStats.bad++;
235
+ }
236
+ }
237
+ }
238
+
239
+ QUnit.testDone( testName, bad, config.assertions.length );
240
+
241
+ if ( !window.setTimeout && !config.queue.length ) {
242
+ done();
243
+ }
244
+ });
245
+
246
+ if ( window.setTimeout && !config.doneTimer ) {
247
+ config.doneTimer = window.setTimeout(function(){
248
+ if ( !config.queue.length ) {
249
+ done();
250
+ } else {
251
+ synchronize( done );
252
+ }
253
+ }, 13);
254
+ }
255
+ },
256
+
257
+ /**
258
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
259
+ */
260
+ expect: function(asserts) {
261
+ config.expected = asserts;
262
+ },
263
+
264
+ /**
265
+ * Asserts true.
266
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
267
+ */
268
+ ok: function(a, msg) {
269
+ QUnit.log(a, msg);
270
+
271
+ config.assertions.push({
272
+ result: !!a,
273
+ message: msg
274
+ });
275
+ },
276
+
277
+ /**
278
+ * Checks that the first two arguments are equal, with an optional message.
279
+ * Prints out both actual and expected values.
280
+ *
281
+ * Prefered to ok( actual == expected, message )
282
+ *
283
+ * @example equals( format("Received {0} bytes.", 2), "Received 2 bytes." );
284
+ *
285
+ * @param Object actual
286
+ * @param Object expected
287
+ * @param String message (optional)
288
+ */
289
+ equals: function(actual, expected, message) {
290
+ push(expected == actual, actual, expected, message);
291
+ },
292
+
293
+ same: function(a, b, message) {
294
+ push(QUnit.equiv(a, b), a, b, message);
295
+ },
296
+
297
+ start: function() {
298
+ // A slight delay, to avoid any current callbacks
299
+ if ( window.setTimeout ) {
300
+ window.setTimeout(function() {
301
+ if ( config.timeout ) {
302
+ clearTimeout(config.timeout);
303
+ }
304
+
305
+ config.blocking = false;
306
+ process();
307
+ }, 13);
308
+ } else {
309
+ config.blocking = false;
310
+ process();
311
+ }
312
+ },
313
+
314
+ stop: function(timeout) {
315
+ config.blocking = true;
316
+
317
+ if ( timeout && window.setTimeout ) {
318
+ config.timeout = window.setTimeout(function() {
319
+ QUnit.ok( false, "Test timed out" );
320
+ QUnit.start();
321
+ }, timeout);
322
+ }
323
+ },
324
+
325
+ /**
326
+ * Resets the test setup. Useful for tests that modify the DOM.
327
+ */
328
+ reset: function() {
329
+ if ( window.jQuery ) {
330
+ jQuery("#main").html( config.fixture );
331
+ jQuery.event.global = {};
332
+ jQuery.ajaxSettings = extend({}, config.ajaxSettings);
333
+ }
334
+ },
335
+
336
+ /**
337
+ * Trigger an event on an element.
338
+ *
339
+ * @example triggerEvent( document.body, "click" );
340
+ *
341
+ * @param DOMElement elem
342
+ * @param String type
343
+ */
344
+ triggerEvent: function( elem, type, event ) {
345
+ if ( document.createEvent ) {
346
+ event = document.createEvent("MouseEvents");
347
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
348
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
349
+ elem.dispatchEvent( event );
350
+
351
+ } else if ( elem.fireEvent ) {
352
+ elem.fireEvent("on"+type);
353
+ }
354
+ },
355
+
356
+ // Safe object type checking
357
+ is: function( type, obj ) {
358
+ return Object.prototype.toString.call( obj ) === "[object "+ type +"]";
359
+ },
360
+
361
+ // Logging callbacks
362
+ done: function(failures, total) {},
363
+ log: function(result, message) {},
364
+ testStart: function(name) {},
365
+ testDone: function(name, failures, total) {},
366
+ moduleStart: function(name, testEnvironment) {},
367
+ moduleDone: function(name, failures, total) {}
368
+ };
369
+
370
+ // Maintain internal state
371
+ var config = {
372
+ // The queue of tests to run
373
+ queue: [],
374
+
375
+ // block until document ready
376
+ blocking: true
377
+ };
378
+
379
+ // Load paramaters
380
+ (function() {
381
+ var location = window.location || { search: "", protocol: "file:" },
382
+ GETParams = location.search.slice(1).split('&');
383
+
384
+ for ( var i = 0; i < GETParams.length; i++ ) {
385
+ GETParams[i] = decodeURIComponent( GETParams[i] );
386
+ if ( GETParams[i] === "noglobals" ) {
387
+ GETParams.splice( i, 1 );
388
+ i--;
389
+ config.noglobals = true;
390
+ } else if ( GETParams[i].search('=') > -1 ) {
391
+ GETParams.splice( i, 1 );
392
+ i--;
393
+ }
394
+ }
395
+
396
+ // restrict modules/tests by get parameters
397
+ config.filters = GETParams;
398
+
399
+ // Figure out if we're running the tests from a server or not
400
+ QUnit.isLocal = !!(location.protocol === 'file:');
401
+ })();
402
+
403
+ // Expose the API as global variables, unless an 'exports'
404
+ // object exists, in that case we assume we're in CommonJS
405
+ if ( typeof exports === "undefined" || typeof require === "undefined" ) {
406
+ extend(window, QUnit);
407
+ window.QUnit = QUnit;
408
+ } else {
409
+ extend(exports, QUnit);
410
+ exports.QUnit = QUnit;
411
+ }
412
+
413
+ if ( typeof document === "undefined" || document.readyState === "complete" ) {
414
+ config.autorun = true;
415
+ }
416
+
417
+ addEvent(window, "load", function() {
418
+ // Initialize the config, saving the execution queue
419
+ var oldconfig = extend({}, config);
420
+ QUnit.init();
421
+ extend(config, oldconfig);
422
+
423
+ config.blocking = false;
424
+
425
+ var userAgent = id("qunit-userAgent");
426
+ if ( userAgent ) {
427
+ userAgent.innerHTML = navigator.userAgent;
428
+ }
429
+
430
+ var toolbar = id("qunit-testrunner-toolbar");
431
+ if ( toolbar ) {
432
+ toolbar.style.display = "none";
433
+
434
+ var filter = document.createElement("input");
435
+ filter.type = "checkbox";
436
+ filter.id = "qunit-filter-pass";
437
+ filter.disabled = true;
438
+ addEvent( filter, "click", function() {
439
+ var li = document.getElementsByTagName("li");
440
+ for ( var i = 0; i < li.length; i++ ) {
441
+ if ( li[i].className.indexOf("pass") > -1 ) {
442
+ li[i].style.display = filter.checked ? "none" : "block";
443
+ }
444
+ }
445
+ });
446
+ toolbar.appendChild( filter );
447
+
448
+ var label = document.createElement("label");
449
+ label.setAttribute("for", "qunit-filter-pass");
450
+ label.innerHTML = "Hide passed tests";
451
+ toolbar.appendChild( label );
452
+
453
+ var missing = document.createElement("input");
454
+ missing.type = "checkbox";
455
+ missing.id = "qunit-filter-missing";
456
+ missing.disabled = true;
457
+ addEvent( missing, "click", function() {
458
+ var li = document.getElementsByTagName("li");
459
+ for ( var i = 0; i < li.length; i++ ) {
460
+ if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
461
+ li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
462
+ }
463
+ }
464
+ });
465
+ toolbar.appendChild( missing );
466
+
467
+ label = document.createElement("label");
468
+ label.setAttribute("for", "qunit-filter-missing");
469
+ label.innerHTML = "Hide missing tests (untested code is broken code)";
470
+ toolbar.appendChild( label );
471
+ }
472
+
473
+ var main = id('main');
474
+ if ( main ) {
475
+ config.fixture = main.innerHTML;
476
+ }
477
+
478
+ if ( window.jQuery ) {
479
+ config.ajaxSettings = window.jQuery.ajaxSettings;
480
+ }
481
+
482
+ QUnit.start();
483
+ });
484
+
485
+ function done() {
486
+ if ( config.doneTimer && window.clearTimeout ) {
487
+ window.clearTimeout( config.doneTimer );
488
+ config.doneTimer = null;
489
+ }
490
+
491
+ if ( config.queue.length ) {
492
+ config.doneTimer = window.setTimeout(function(){
493
+ if ( !config.queue.length ) {
494
+ done();
495
+ } else {
496
+ synchronize( done );
497
+ }
498
+ }, 13);
499
+
500
+ return;
501
+ }
502
+
503
+ config.autorun = true;
504
+
505
+ // Log the last module results
506
+ if ( config.currentModule ) {
507
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
508
+ }
509
+
510
+ var banner = id("qunit-banner"),
511
+ tests = id("qunit-tests"),
512
+ html = ['Tests completed in ',
513
+ +new Date - config.started, ' milliseconds.<br/>',
514
+ '<span class="bad">', config.stats.all - config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> passed, ', config.stats.bad,' failed.'].join('');
515
+
516
+ if ( banner ) {
517
+ banner.className += " " + (config.stats.bad ? "fail" : "pass");
518
+ }
519
+
520
+ if ( tests ) {
521
+ var result = id("qunit-testresult");
522
+
523
+ if ( !result ) {
524
+ result = document.createElement("p");
525
+ result.id = "qunit-testresult";
526
+ result.className = "result";
527
+ tests.parentNode.insertBefore( result, tests.nextSibling );
528
+ }
529
+
530
+ result.innerHTML = html;
531
+ }
532
+
533
+ QUnit.done( config.stats.bad, config.stats.all );
534
+ }
535
+
536
+ function validTest( name ) {
537
+ var i = config.filters.length,
538
+ run = false;
539
+
540
+ if ( !i ) {
541
+ return true;
542
+ }
543
+
544
+ while ( i-- ) {
545
+ var filter = config.filters[i],
546
+ not = filter.charAt(0) == '!';
547
+
548
+ if ( not ) {
549
+ filter = filter.slice(1);
550
+ }
551
+
552
+ if ( name.indexOf(filter) !== -1 ) {
553
+ return !not;
554
+ }
555
+
556
+ if ( not ) {
557
+ run = true;
558
+ }
559
+ }
560
+
561
+ return run;
562
+ }
563
+
564
+ function push(result, actual, expected, message) {
565
+ message = message || (result ? "okay" : "failed");
566
+ QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
567
+ }
568
+
569
+ function synchronize( callback ) {
570
+ config.queue.push( callback );
571
+
572
+ if ( config.autorun && !config.blocking ) {
573
+ process();
574
+ }
575
+ }
576
+
577
+ function process() {
578
+ while ( config.queue.length && !config.blocking ) {
579
+ config.queue.shift()();
580
+ }
581
+ }
582
+
583
+ function saveGlobal() {
584
+ config.pollution = [];
585
+
586
+ if ( config.noglobals ) {
587
+ for ( var key in window ) {
588
+ config.pollution.push( key );
589
+ }
590
+ }
591
+ }
592
+
593
+ function checkPollution( name ) {
594
+ var old = config.pollution;
595
+ saveGlobal();
596
+
597
+ var newGlobals = diff( old, config.pollution );
598
+ if ( newGlobals.length > 0 ) {
599
+ ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
600
+ config.expected++;
601
+ }
602
+
603
+ var deletedGlobals = diff( config.pollution, old );
604
+ if ( deletedGlobals.length > 0 ) {
605
+ ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
606
+ config.expected++;
607
+ }
608
+ }
609
+
610
+ // returns a new Array with the elements that are in a but not in b
611
+ function diff( a, b ) {
612
+ var result = a.slice();
613
+ for ( var i = 0; i < result.length; i++ ) {
614
+ for ( var j = 0; j < b.length; j++ ) {
615
+ if ( result[i] === b[j] ) {
616
+ result.splice(i, 1);
617
+ i--;
618
+ break;
619
+ }
620
+ }
621
+ }
622
+ return result;
623
+ }
624
+
625
+ function fail(message, exception, callback) {
626
+ if ( typeof console !== "undefined" && console.error && console.warn ) {
627
+ console.error(message);
628
+ console.error(exception);
629
+ console.warn(callback.toString());
630
+
631
+ } else if ( window.opera && opera.postError ) {
632
+ opera.postError(message, exception, callback.toString);
633
+ }
634
+ }
635
+
636
+ function extend(a, b) {
637
+ for ( var prop in b ) {
638
+ a[prop] = b[prop];
639
+ }
640
+
641
+ return a;
642
+ }
643
+
644
+ function addEvent(elem, type, fn) {
645
+ if ( elem.addEventListener ) {
646
+ elem.addEventListener( type, fn, false );
647
+ } else if ( elem.attachEvent ) {
648
+ elem.attachEvent( "on" + type, fn );
649
+ } else {
650
+ fn();
651
+ }
652
+ }
653
+
654
+ function id(name) {
655
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
656
+ document.getElementById( name );
657
+ }
658
+
659
+ // Test for equality any JavaScript type.
660
+ // Discussions and reference: http://philrathe.com/articles/equiv
661
+ // Test suites: http://philrathe.com/tests/equiv
662
+ // Author: Philippe Rathé <prathe@gmail.com>
663
+ QUnit.equiv = function () {
664
+
665
+ var innerEquiv; // the real equiv function
666
+ var callers = []; // stack to decide between skip/abort functions
667
+
668
+
669
+ // Determine what is o.
670
+ function hoozit(o) {
671
+ if (QUnit.is("String", o)) {
672
+ return "string";
673
+
674
+ } else if (QUnit.is("Boolean", o)) {
675
+ return "boolean";
676
+
677
+ } else if (QUnit.is("Number", o)) {
678
+
679
+ if (isNaN(o)) {
680
+ return "nan";
681
+ } else {
682
+ return "number";
683
+ }
684
+
685
+ } else if (typeof o === "undefined") {
686
+ return "undefined";
687
+
688
+ // consider: typeof null === object
689
+ } else if (o === null) {
690
+ return "null";
691
+
692
+ // consider: typeof [] === object
693
+ } else if (QUnit.is( "Array", o)) {
694
+ return "array";
695
+
696
+ // consider: typeof new Date() === object
697
+ } else if (QUnit.is( "Date", o)) {
698
+ return "date";
699
+
700
+ // consider: /./ instanceof Object;
701
+ // /./ instanceof RegExp;
702
+ // typeof /./ === "function"; // => false in IE and Opera,
703
+ // true in FF and Safari
704
+ } else if (QUnit.is( "RegExp", o)) {
705
+ return "regexp";
706
+
707
+ } else if (typeof o === "object") {
708
+ return "object";
709
+
710
+ } else if (QUnit.is( "Function", o)) {
711
+ return "function";
712
+ } else {
713
+ return undefined;
714
+ }
715
+ }
716
+
717
+ // Call the o related callback with the given arguments.
718
+ function bindCallbacks(o, callbacks, args) {
719
+ var prop = hoozit(o);
720
+ if (prop) {
721
+ if (hoozit(callbacks[prop]) === "function") {
722
+ return callbacks[prop].apply(callbacks, args);
723
+ } else {
724
+ return callbacks[prop]; // or undefined
725
+ }
726
+ }
727
+ }
728
+
729
+ var callbacks = function () {
730
+
731
+ // for string, boolean, number and null
732
+ function useStrictEquality(b, a) {
733
+ if (b instanceof a.constructor || a instanceof b.constructor) {
734
+ // to catch short annotaion VS 'new' annotation of a declaration
735
+ // e.g. var i = 1;
736
+ // var j = new Number(1);
737
+ return a == b;
738
+ } else {
739
+ return a === b;
740
+ }
741
+ }
742
+
743
+ return {
744
+ "string": useStrictEquality,
745
+ "boolean": useStrictEquality,
746
+ "number": useStrictEquality,
747
+ "null": useStrictEquality,
748
+ "undefined": useStrictEquality,
749
+
750
+ "nan": function (b) {
751
+ return isNaN(b);
752
+ },
753
+
754
+ "date": function (b, a) {
755
+ return hoozit(b) === "date" && a.valueOf() === b.valueOf();
756
+ },
757
+
758
+ "regexp": function (b, a) {
759
+ return hoozit(b) === "regexp" &&
760
+ a.source === b.source && // the regex itself
761
+ a.global === b.global && // and its modifers (gmi) ...
762
+ a.ignoreCase === b.ignoreCase &&
763
+ a.multiline === b.multiline;
764
+ },
765
+
766
+ // - skip when the property is a method of an instance (OOP)
767
+ // - abort otherwise,
768
+ // initial === would have catch identical references anyway
769
+ "function": function () {
770
+ var caller = callers[callers.length - 1];
771
+ return caller !== Object &&
772
+ typeof caller !== "undefined";
773
+ },
774
+
775
+ "array": function (b, a) {
776
+ var i;
777
+ var len;
778
+
779
+ // b could be an object literal here
780
+ if ( ! (hoozit(b) === "array")) {
781
+ return false;
782
+ }
783
+
784
+ len = a.length;
785
+ if (len !== b.length) { // safe and faster
786
+ return false;
787
+ }
788
+ for (i = 0; i < len; i++) {
789
+ if ( ! innerEquiv(a[i], b[i])) {
790
+ return false;
791
+ }
792
+ }
793
+ return true;
794
+ },
795
+
796
+ "object": function (b, a) {
797
+ var i;
798
+ var eq = true; // unless we can proove it
799
+ var aProperties = [], bProperties = []; // collection of strings
800
+
801
+ // comparing constructors is more strict than using instanceof
802
+ if ( a.constructor !== b.constructor) {
803
+ return false;
804
+ }
805
+
806
+ // stack constructor before traversing properties
807
+ callers.push(a.constructor);
808
+
809
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
810
+
811
+ aProperties.push(i); // collect a's properties
812
+
813
+ if ( ! innerEquiv(a[i], b[i])) {
814
+ eq = false;
815
+ }
816
+ }
817
+
818
+ callers.pop(); // unstack, we are done
819
+
820
+ for (i in b) {
821
+ bProperties.push(i); // collect b's properties
822
+ }
823
+
824
+ // Ensures identical properties name
825
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
826
+ }
827
+ };
828
+ }();
829
+
830
+ innerEquiv = function () { // can take multiple arguments
831
+ var args = Array.prototype.slice.apply(arguments);
832
+ if (args.length < 2) {
833
+ return true; // end transition
834
+ }
835
+
836
+ return (function (a, b) {
837
+ if (a === b) {
838
+ return true; // catch the most you can
839
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
840
+ return false; // don't lose time with error prone cases
841
+ } else {
842
+ return bindCallbacks(a, callbacks, [b, a]);
843
+ }
844
+
845
+ // apply transition with (1..n) arguments
846
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
847
+ };
848
+
849
+ return innerEquiv;
850
+
851
+ }();
852
+
853
+ /**
854
+ * jsDump
855
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
856
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
857
+ * Date: 5/15/2008
858
+ * @projectDescription Advanced and extensible data dumping for Javascript.
859
+ * @version 1.0.0
860
+ * @author Ariel Flesler
861
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
862
+ */
863
+ QUnit.jsDump = (function() {
864
+ function quote( str ) {
865
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
866
+ };
867
+ function literal( o ) {
868
+ return o + '';
869
+ };
870
+ function join( pre, arr, post ) {
871
+ var s = jsDump.separator(),
872
+ base = jsDump.indent(),
873
+ inner = jsDump.indent(1);
874
+ if ( arr.join )
875
+ arr = arr.join( ',' + s + inner );
876
+ if ( !arr )
877
+ return pre + post;
878
+ return [ pre, inner + arr, base + post ].join(s);
879
+ };
880
+ function array( arr ) {
881
+ var i = arr.length, ret = Array(i);
882
+ this.up();
883
+ while ( i-- )
884
+ ret[i] = this.parse( arr[i] );
885
+ this.down();
886
+ return join( '[', ret, ']' );
887
+ };
888
+
889
+ var reName = /^function (\w+)/;
890
+
891
+ var jsDump = {
892
+ parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
893
+ var parser = this.parsers[ type || this.typeOf(obj) ];
894
+ type = typeof parser;
895
+
896
+ return type == 'function' ? parser.call( this, obj ) :
897
+ type == 'string' ? parser :
898
+ this.parsers.error;
899
+ },
900
+ typeOf:function( obj ) {
901
+ var type;
902
+ if ( obj === null ) {
903
+ type = "null";
904
+ } else if (typeof obj === "undefined") {
905
+ type = "undefined";
906
+ } else if (QUnit.is("RegExp", obj)) {
907
+ type = "regexp";
908
+ } else if (QUnit.is("Date", obj)) {
909
+ type = "date";
910
+ } else if (QUnit.is("Function", obj)) {
911
+ type = "function";
912
+ } else if (QUnit.is("Array", obj)) {
913
+ type = "array";
914
+ } else if (QUnit.is("Window", obj) || QUnit.is("global", obj)) {
915
+ type = "window";
916
+ } else if (QUnit.is("HTMLDocument", obj)) {
917
+ type = "document";
918
+ } else if (QUnit.is("HTMLCollection", obj) || QUnit.is("NodeList", obj)) {
919
+ type = "nodelist";
920
+ } else if (/^\[object HTML/.test(Object.prototype.toString.call( obj ))) {
921
+ type = "node";
922
+ } else {
923
+ type = typeof obj;
924
+ }
925
+ return type;
926
+ },
927
+ separator:function() {
928
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
929
+ },
930
+ indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
931
+ if ( !this.multiline )
932
+ return '';
933
+ var chr = this.indentChar;
934
+ if ( this.HTML )
935
+ chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
936
+ return Array( this._depth_ + (extra||0) ).join(chr);
937
+ },
938
+ up:function( a ) {
939
+ this._depth_ += a || 1;
940
+ },
941
+ down:function( a ) {
942
+ this._depth_ -= a || 1;
943
+ },
944
+ setParser:function( name, parser ) {
945
+ this.parsers[name] = parser;
946
+ },
947
+ // The next 3 are exposed so you can use them
948
+ quote:quote,
949
+ literal:literal,
950
+ join:join,
951
+ //
952
+ _depth_: 1,
953
+ // This is the list of parsers, to modify them, use jsDump.setParser
954
+ parsers:{
955
+ window: '[Window]',
956
+ document: '[Document]',
957
+ error:'[ERROR]', //when no parser is found, shouldn't happen
958
+ unknown: '[Unknown]',
959
+ 'null':'null',
960
+ undefined:'undefined',
961
+ 'function':function( fn ) {
962
+ var ret = 'function',
963
+ name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
964
+ if ( name )
965
+ ret += ' ' + name;
966
+ ret += '(';
967
+
968
+ ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
969
+ return join( ret, this.parse(fn,'functionCode'), '}' );
970
+ },
971
+ array: array,
972
+ nodelist: array,
973
+ arguments: array,
974
+ object:function( map ) {
975
+ var ret = [ ];
976
+ this.up();
977
+ for ( var key in map )
978
+ ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
979
+ this.down();
980
+ return join( '{', ret, '}' );
981
+ },
982
+ node:function( node ) {
983
+ var open = this.HTML ? '&lt;' : '<',
984
+ close = this.HTML ? '&gt;' : '>';
985
+
986
+ var tag = node.nodeName.toLowerCase(),
987
+ ret = open + tag;
988
+
989
+ for ( var a in this.DOMAttrs ) {
990
+ var val = node[this.DOMAttrs[a]];
991
+ if ( val )
992
+ ret += ' ' + a + '=' + this.parse( val, 'attribute' );
993
+ }
994
+ return ret + close + open + '/' + tag + close;
995
+ },
996
+ functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
997
+ var l = fn.length;
998
+ if ( !l ) return '';
999
+
1000
+ var args = Array(l);
1001
+ while ( l-- )
1002
+ args[l] = String.fromCharCode(97+l);//97 is 'a'
1003
+ return ' ' + args.join(', ') + ' ';
1004
+ },
1005
+ key:quote, //object calls it internally, the key part of an item in a map
1006
+ functionCode:'[code]', //function calls it internally, it's the content of the function
1007
+ attribute:quote, //node calls it internally, it's an html attribute value
1008
+ string:quote,
1009
+ date:quote,
1010
+ regexp:literal, //regex
1011
+ number:literal,
1012
+ 'boolean':literal
1013
+ },
1014
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
1015
+ id:'id',
1016
+ name:'name',
1017
+ 'class':'className'
1018
+ },
1019
+ HTML:true,//if true, entities are escaped ( <, >, \t, space and \n )
1020
+ indentChar:' ',//indentation unit
1021
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
1022
+ };
1023
+
1024
+ return jsDump;
1025
+ })();
1026
+
1027
+ })(this);