From 582cbe4ce3bff4da2b50a00c185a75d8e1899081 Mon Sep 17 00:00:00 2001 From: Wouter Groeneveld Date: Fri, 24 Jun 2011 21:11:58 +0200 Subject: [PATCH] initial checkin --- .../junit/jasmine/JasmineDescriptions.class | Bin 0 -> 1844 bytes .../jasmine/JasmineFailingSpecsTest.class | Bin 0 -> 3372 bytes .../jasmine/JasmineFinishedSpecsTest.class | Bin 0 -> 2252 bytes .../jasmine/JasmineJSSuiteConverter.class | Bin 0 -> 3874 bytes .../cegeka/junit/jasmine/JasmineSpec$1.class | Bin 0 -> 998 bytes .../JasmineSpec$JasmineSpecStatus.class | Bin 0 -> 1313 bytes .../be/cegeka/junit/jasmine/JasmineSpec.class | Bin 0 -> 4276 bytes .../jasmine/JasmineSpecFailureException.class | Bin 0 -> 889 bytes ...RunnerGenerator$TemplatePlaceholders.class | Bin 0 -> 1808 bytes .../jasmine/JasmineSpecRunnerGenerator.class | Bin 0 -> 3189 bytes .../cegeka/junit/jasmine/JasmineSuite.class | Bin 0 -> 608 bytes .../JasmineSuiteGeneratesRunnerTest.class | Bin 0 -> 3623 bytes .../JasmineTestRunner$DefaultSuite.class | Bin 0 -> 651 bytes .../junit/jasmine/JasmineTestRunner.class | Bin 0 -> 8913 bytes .../JasmineTestRunnerBeforeAndAfterTest.class | Bin 0 -> 999 bytes ...JasmineSuiteGeneratorClassWithRunner.class | Bin 0 -> 650 bytes ...mineSuiteGeneratorClassWithoutRunner.class | Bin 0 -> 628 bytes ...JasmineTestRunnerBeforeAndAfterClass.class | Bin 0 -> 1950 bytes .../JasmineTestRunnerExceptionInJSCode.class | Bin 0 -> 508 bytes .../JasmineTestRunnerExceptionInSpec.class | Bin 0 -> 500 bytes .../JasmineTestRunnerFailingSpec.class | Bin 0 -> 487 bytes .../JasmineTestRunnerSuccessSpec.class | Bin 0 -> 485 bytes .../cegeka/rhino/ChainedErrorReporter.class | Bin 0 -> 2508 bytes .../be/cegeka/rhino/ClassInJS.class | Bin 0 -> 710 bytes .../be/cegeka/rhino/RhinoContext$1.class | Bin 0 -> 1097 bytes .../be/cegeka/rhino/RhinoContext$2.class | Bin 0 -> 709 bytes .../be/cegeka/rhino/RhinoContext.class | Bin 0 -> 7577 bytes .../RhinoContextClassExportingTest.class | Bin 0 -> 1463 bytes .../rhino/RhinoContextEnvjsLoadingTest.class | Bin 0 -> 1389 bytes .../be/cegeka/rhino/RhinoContextTest$1.class | Bin 0 -> 1092 bytes .../be/cegeka/rhino/RhinoContextTest.class | Bin 0 -> 3249 bytes .../be/cegeka/rhino/RhinoRunnable.class | Bin 0 -> 173 bytes pom.xml | 74 + .../junit/jasmine/JasmineDescriptions.java | 38 + .../jasmine/JasmineJSSuiteConverter.java | 57 + .../be/cegeka/junit/jasmine/JasmineSpec.java | 101 + .../jasmine/JasmineSpecFailureException.java | 19 + .../jasmine/JasmineSpecRunnerGenerator.java | 77 + .../be/cegeka/junit/jasmine/JasmineSuite.java | 20 + .../junit/jasmine/JasmineTestRunner.java | 190 + .../be/cegeka/rhino/ChainedErrorReporter.java | 58 + .../java/be/cegeka/rhino/RhinoContext.java | 154 + .../java/be/cegeka/rhino/RhinoRunnable.java | 6 + .../jasmine/JasmineFailingSpecsTest.java | 67 + .../jasmine/JasmineFinishedSpecsTest.java | 40 + .../JasmineSuiteGeneratesRunnerTest.java | 67 + .../JasmineTestRunnerBeforeAndAfterTest.java | 22 + .../JasmineSuiteGeneratorClassWithRunner.java | 12 + ...smineSuiteGeneratorClassWithoutRunner.java | 8 + .../JasmineTestRunnerBeforeAndAfterClass.java | 50 + .../JasmineTestRunnerExceptionInJSCode.java | 8 + .../JasmineTestRunnerExceptionInSpec.java | 8 + .../classes/JasmineTestRunnerFailingSpec.java | 8 + .../classes/JasmineTestRunnerSuccessSpec.java | 8 + src/test/java/be/cegeka/rhino/ClassInJS.java | 28 + .../rhino/RhinoContextClassExportingTest.java | 23 + .../rhino/RhinoContextEnvjsLoadingTest.java | 28 + .../be/cegeka/rhino/RhinoContextTest.java | 80 + src/test/javascript/envJsOptions.js | 12 + src/test/javascript/lib/blank.html | 0 src/test/javascript/lib/env.rhino.1.2.js | 13989 ++++++++++++++++ src/test/javascript/lib/env.utils.js | 76 + src/test/javascript/lib/es5-shim-0.0.4.min.js | 13 + .../javascript/lib/jasmine-1.0.2/MIT.LICENSE | 20 + .../lib/jasmine-1.0.2/jasmine-html.js | 188 + .../jasmine-1.0.2/jasmine.console_reporter.js | 64 + .../javascript/lib/jasmine-1.0.2/jasmine.css | 166 + .../jasmine.delegator_reporter.js | 53 + .../javascript/lib/jasmine-1.0.2/jasmine.js | 2421 +++ .../jasmine-1.0.2/jasmine.junit_reporter.js | 204 + src/test/javascript/lib/specRunner.tpl | 23 + src/test/javascript/loadTest.js | 1 + src/test/javascript/loadTestTwo.js | 1 + ...neSuiteGeneratorClassWithRunnerRunner.html | 27 + src/test/javascript/sources/source1.js | 1 + src/test/javascript/sources/source2.js | 1 + src/test/javascript/specs/crashingJSCode.js | 4 + src/test/javascript/specs/crashingSpec.js | 5 + src/test/javascript/specs/emptySpec.js | 5 + src/test/javascript/specs/failingSpec.js | 5 + src/test/javascript/specs/spec1.js | 5 + src/test/javascript/specs/spec2.js | 5 + .../junit/jasmine/JasmineDescriptions.class | Bin 0 -> 1844 bytes .../jasmine/JasmineJSSuiteConverter.class | Bin 0 -> 4013 bytes .../cegeka/junit/jasmine/JasmineSpec$1.class | Bin 0 -> 999 bytes .../JasmineSpec$JasmineSpecStatus.class | Bin 0 -> 1291 bytes .../be/cegeka/junit/jasmine/JasmineSpec.class | Bin 0 -> 4380 bytes .../jasmine/JasmineSpecFailureException.class | Bin 0 -> 889 bytes ...RunnerGenerator$TemplatePlaceholders.class | Bin 0 -> 1784 bytes .../jasmine/JasmineSpecRunnerGenerator.class | Bin 0 -> 3177 bytes .../cegeka/junit/jasmine/JasmineSuite.class | Bin 0 -> 608 bytes .../junit/jasmine/JasmineTestRunner$1.class | Bin 0 -> 778 bytes .../JasmineTestRunner$DefaultSuite.class | Bin 0 -> 651 bytes .../junit/jasmine/JasmineTestRunner.class | Bin 0 -> 9482 bytes .../cegeka/rhino/ChainedErrorReporter.class | Bin 0 -> 2461 bytes .../be/cegeka/rhino/RhinoContext$1.class | Bin 0 -> 1108 bytes .../be/cegeka/rhino/RhinoContext.class | Bin 0 -> 6986 bytes .../be/cegeka/rhino/RhinoRunnable.class | Bin 0 -> 173 bytes target/jasminejunitrunner-1.0-SNAPSHOT.jar | Bin 0 -> 23469 bytes target/maven-archiver/pom.properties | 5 + ....junit.jasmine.JasmineFailingSpecsTest.xml | 65 + ...junit.jasmine.JasmineFinishedSpecsTest.xml | 63 + ...asmine.JasmineSuiteGeneratesRunnerTest.xml | 64 + ...ne.JasmineTestRunnerBeforeAndAfterTest.xml | 63 + ...a.rhino.RhinoContextClassExportingTest.xml | 63 + ...eka.rhino.RhinoContextEnvjsLoadingTest.xml | 64 + .../TEST-be.cegeka.rhino.RhinoContextTest.xml | 68 + ....junit.jasmine.JasmineFailingSpecsTest.txt | 4 + ...junit.jasmine.JasmineFinishedSpecsTest.txt | 4 + ...asmine.JasmineSuiteGeneratesRunnerTest.txt | 4 + ...ne.JasmineTestRunnerBeforeAndAfterTest.txt | 4 + ...a.rhino.RhinoContextClassExportingTest.txt | 4 + ...eka.rhino.RhinoContextEnvjsLoadingTest.txt | 4 + .../be.cegeka.rhino.RhinoContextTest.txt | 4 + .../jasmine/JasmineFailingSpecsTest.class | Bin 0 -> 3381 bytes .../jasmine/JasmineFinishedSpecsTest.class | Bin 0 -> 2255 bytes .../JasmineSuiteGeneratesRunnerTest.class | Bin 0 -> 3652 bytes .../JasmineTestRunnerBeforeAndAfterTest.class | Bin 0 -> 1000 bytes ...JasmineSuiteGeneratorClassWithRunner.class | Bin 0 -> 650 bytes ...mineSuiteGeneratorClassWithoutRunner.class | Bin 0 -> 628 bytes ...JasmineTestRunnerBeforeAndAfterClass.class | Bin 0 -> 1946 bytes .../JasmineTestRunnerExceptionInJSCode.class | Bin 0 -> 508 bytes .../JasmineTestRunnerExceptionInSpec.class | Bin 0 -> 500 bytes .../JasmineTestRunnerFailingSpec.class | Bin 0 -> 487 bytes .../JasmineTestRunnerSuccessSpec.class | Bin 0 -> 485 bytes .../be/cegeka/rhino/ClassInJS.class | Bin 0 -> 710 bytes .../RhinoContextClassExportingTest.class | Bin 0 -> 1464 bytes .../rhino/RhinoContextEnvjsLoadingTest.class | Bin 0 -> 1391 bytes .../be/cegeka/rhino/RhinoContextTest$1.class | Bin 0 -> 1091 bytes .../be/cegeka/rhino/RhinoContextTest.class | Bin 0 -> 3252 bytes 130 files changed, 19023 insertions(+) create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineDescriptions.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec$1.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec$JasmineSpecStatus.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecFailureException.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator$TemplatePlaceholders.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSuite.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineSuiteGeneratesRunnerTest.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunner$DefaultSuite.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunner.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunnerBeforeAndAfterTest.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithoutRunner.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInSpec.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.class create mode 100755 eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.class create mode 100755 eclipsecompiled/be/cegeka/rhino/ChainedErrorReporter.class create mode 100755 eclipsecompiled/be/cegeka/rhino/ClassInJS.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContext$1.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContext$2.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContext.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContextClassExportingTest.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContextTest$1.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoContextTest.class create mode 100755 eclipsecompiled/be/cegeka/rhino/RhinoRunnable.class create mode 100755 pom.xml create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineDescriptions.java create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.java create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineSpec.java create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineSpecFailureException.java create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator.java create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineSuite.java create mode 100755 src/main/java/be/cegeka/junit/jasmine/JasmineTestRunner.java create mode 100755 src/main/java/be/cegeka/rhino/ChainedErrorReporter.java create mode 100755 src/main/java/be/cegeka/rhino/RhinoContext.java create mode 100755 src/main/java/be/cegeka/rhino/RhinoRunnable.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/JasmineSuiteGeneratesRunnerTest.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/JasmineTestRunnerBeforeAndAfterTest.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithoutRunner.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInSpec.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.java create mode 100755 src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.java create mode 100755 src/test/java/be/cegeka/rhino/ClassInJS.java create mode 100755 src/test/java/be/cegeka/rhino/RhinoContextClassExportingTest.java create mode 100755 src/test/java/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.java create mode 100755 src/test/java/be/cegeka/rhino/RhinoContextTest.java create mode 100755 src/test/javascript/envJsOptions.js create mode 100755 src/test/javascript/lib/blank.html create mode 100755 src/test/javascript/lib/env.rhino.1.2.js create mode 100755 src/test/javascript/lib/env.utils.js create mode 100755 src/test/javascript/lib/es5-shim-0.0.4.min.js create mode 100755 src/test/javascript/lib/jasmine-1.0.2/MIT.LICENSE create mode 100755 src/test/javascript/lib/jasmine-1.0.2/jasmine-html.js create mode 100755 src/test/javascript/lib/jasmine-1.0.2/jasmine.console_reporter.js create mode 100755 src/test/javascript/lib/jasmine-1.0.2/jasmine.css create mode 100755 src/test/javascript/lib/jasmine-1.0.2/jasmine.delegator_reporter.js create mode 100755 src/test/javascript/lib/jasmine-1.0.2/jasmine.js create mode 100755 src/test/javascript/lib/jasmine-1.0.2/jasmine.junit_reporter.js create mode 100755 src/test/javascript/lib/specRunner.tpl create mode 100755 src/test/javascript/loadTest.js create mode 100755 src/test/javascript/loadTestTwo.js create mode 100755 src/test/javascript/runners/JasmineSuiteGeneratorClassWithRunnerRunner.html create mode 100755 src/test/javascript/sources/source1.js create mode 100755 src/test/javascript/sources/source2.js create mode 100755 src/test/javascript/specs/crashingJSCode.js create mode 100755 src/test/javascript/specs/crashingSpec.js create mode 100755 src/test/javascript/specs/emptySpec.js create mode 100755 src/test/javascript/specs/failingSpec.js create mode 100755 src/test/javascript/specs/spec1.js create mode 100755 src/test/javascript/specs/spec2.js create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineDescriptions.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSpec$1.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSpec$JasmineSpecStatus.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSpec.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSpecFailureException.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator$TemplatePlaceholders.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineSuite.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineTestRunner$1.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineTestRunner$DefaultSuite.class create mode 100755 target/classes/be/cegeka/junit/jasmine/JasmineTestRunner.class create mode 100755 target/classes/be/cegeka/rhino/ChainedErrorReporter.class create mode 100755 target/classes/be/cegeka/rhino/RhinoContext$1.class create mode 100755 target/classes/be/cegeka/rhino/RhinoContext.class create mode 100755 target/classes/be/cegeka/rhino/RhinoRunnable.class create mode 100755 target/jasminejunitrunner-1.0-SNAPSHOT.jar create mode 100755 target/maven-archiver/pom.properties create mode 100755 target/surefire-reports/TEST-be.cegeka.junit.jasmine.JasmineFailingSpecsTest.xml create mode 100755 target/surefire-reports/TEST-be.cegeka.junit.jasmine.JasmineFinishedSpecsTest.xml create mode 100755 target/surefire-reports/TEST-be.cegeka.junit.jasmine.JasmineSuiteGeneratesRunnerTest.xml create mode 100755 target/surefire-reports/TEST-be.cegeka.junit.jasmine.JasmineTestRunnerBeforeAndAfterTest.xml create mode 100755 target/surefire-reports/TEST-be.cegeka.rhino.RhinoContextClassExportingTest.xml create mode 100755 target/surefire-reports/TEST-be.cegeka.rhino.RhinoContextEnvjsLoadingTest.xml create mode 100755 target/surefire-reports/TEST-be.cegeka.rhino.RhinoContextTest.xml create mode 100755 target/surefire-reports/be.cegeka.junit.jasmine.JasmineFailingSpecsTest.txt create mode 100755 target/surefire-reports/be.cegeka.junit.jasmine.JasmineFinishedSpecsTest.txt create mode 100755 target/surefire-reports/be.cegeka.junit.jasmine.JasmineSuiteGeneratesRunnerTest.txt create mode 100755 target/surefire-reports/be.cegeka.junit.jasmine.JasmineTestRunnerBeforeAndAfterTest.txt create mode 100755 target/surefire-reports/be.cegeka.rhino.RhinoContextClassExportingTest.txt create mode 100755 target/surefire-reports/be.cegeka.rhino.RhinoContextEnvjsLoadingTest.txt create mode 100755 target/surefire-reports/be.cegeka.rhino.RhinoContextTest.txt create mode 100755 target/test-classes/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/JasmineSuiteGeneratesRunnerTest.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/JasmineTestRunnerBeforeAndAfterTest.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithoutRunner.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInSpec.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.class create mode 100755 target/test-classes/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.class create mode 100755 target/test-classes/be/cegeka/rhino/ClassInJS.class create mode 100755 target/test-classes/be/cegeka/rhino/RhinoContextClassExportingTest.class create mode 100755 target/test-classes/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.class create mode 100755 target/test-classes/be/cegeka/rhino/RhinoContextTest$1.class create mode 100755 target/test-classes/be/cegeka/rhino/RhinoContextTest.class diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineDescriptions.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineDescriptions.class new file mode 100755 index 0000000000000000000000000000000000000000..5420d006e77a55d18219c203fb62fda8457fe46a GIT binary patch literal 1844 zcmbVMT~8B16g|@x3hh>C!GeMaqS%&?6~xaXh=4H$F#*H-QYK~VvfFI81YUgg?`R?z zd@w%yql{;E3oHaEnx;E<=FUBH?%Xr?_n#j>0Zd^bj)=hMhSW>4EI%50rEZ&^UNLIh zrY-fi!MG@ECD*KareoLQhzWF7j2%O_47;qq->ArvC(z+Kju+Y}FtF^n7l=w%~buKTD$;Z~roeOAL9UQ)=65E#jY z8b;8sijAs=S{N&ySaa%bNxn9foO{n{eiN#Y7-RvWY@d8E>V444sMo>OcG?jnIOiLo z-NJtg*SHpVI?&0LPn^d%b{D=QT^QY`F}9CvVSFFGU%4K|O@6a}bSHPF8J!_Y7k}O8 zqpuLeqaU|8Ba+WU_?BW4@vQ-Jh~hSFjoj3(IJre=4`PU4#YN|+d@Y4<=>9?@;ve4X zFZTF{1;H(i!vyYNn7e|6?)o6p4UhyuvWK`Qa2BaAgp@c&Dqxh6ipCNV73oxA^Z;Xo z={>*$br%60#Tv{+BXgC1HrRZee+rLT2bBq5#Tm%7B1P0Ehjul@o@%*ew4 literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.class new file mode 100755 index 0000000000000000000000000000000000000000..b8d4f026d637a3fc729e71019a2a04bca404d301 GIT binary patch literal 3372 zcmc&$Yf}?f7=8{H6XJS9O1+>4yd{9FAYKY+MGP&JOG^-{wzbRV1Qx?C?rxCSoBaXp zf9XsoGVQeE=l-ZppR*gnVgioS>GVT#_MG!xpZ9kD`un#(0Sw^B7#alhC8?WoSw1!N z)uL_r`l{irS+>+C!*$%S3YNW`U6-aeFFikoCV``?#)hF640~ChU0Ri4SfrGgx_NgL340CPLJ7>F^A!h+#i zYF{~Q@>eXX=%0E=5NN?^Z^bDVa)A@2*?g856{G^I=u+F!i2Dk);TYZ%NWVpmq9hUo zD~9(4M)o2%3x?-OZ#zUgY>{9k(1w!=jZ*?`si~cSjVb2g^g;^+Iy5xnfFeDs;T)30 zlfe?`OGWJG$-d!BFT~I#aB=^DSD;DY0xrdHQQ(xK-wx}jyIfq8wm)X9`;M#OGExHZ zyyFJeGE3`tuq!Wi3n1Lx^sdID`_eOAYh7hv0=?*q;flcVs39u9m}eSvTxFVVNY~1j z1TIDOhbcdtj(}P@ieZ3Ju2H*J<|{A;HC)FHftX3xgWPFL)sdV)KW=IG07FdfyyZ$2 z^sH~VzRU@9)`?fdS4La$k7&3J)=ZVZny%e-_;(pyp$r7|;;x2K+!Htv!ZYJcJFc9t zed!ve!j>h~o_bshk22!|?rX>>kK@bIUoZ+q7H%g#((o}R1P=2sV!1$)Xw(22p%_l! z6HLc2C2&^J<%x@~%EJvT(MPMF8fGvnkO(j5R}6No8+GGaPfi%&P#Sf9hHMOTH1BP+ z8s=3dwOC%}S*JyKF0ghmVx?kKZu3avuWp zrsLsd#o#!;WK()>6$(kC@Z2bQ$vj(C0#B41U+>{YRDz1pk_J;*onVZnrRN#TG7cJj zDznMyz(h>?Zc!$EC%Ggkzu?I}fkR3W^E#|-7Uh0rD{w5gQ=;1}v5E+R%eARcH%-~@ zy|6YSnZg9AWslsmskcu#(IHV<-yRg1eXJg-m0H)RJ5&(T*6(_ChYo-6k-gnz}DaXi-8^wZOn#=}H^Nw9bR+4f14YKCEVA}I_v!gPz z!M0;?&{Q4e!1zYs-oHU=GOHdTtd6WxbWJ%PSktk`E2>Xf!^){m9nOChM+UoDSxJFm zZ{E(Ca2k8TLx_WF@&VsL4pyoQ)7-Q^07r3*JJuAL8>%9Y^NfN-ih`T@{qyf=d)V6k3MaaM#pyE6 zw03Uc{8Ve2|I_Md3q7yV-&@AD*GQLfbLXrlIO{B9xakixK5SGs*)4p?^Rd_HoFNa_ z^ib24GRC(sd9taDPZ!muj0anI*!o2oU#Y#JHaWFX9yJCY4bTtZ481rmjHUiGKPuKm@K4!9gN;oe16}4!4NF5WO2F zf+Ixm_J4-p^D2S|iRW?tHcga*jJ_E_474y2TVD{xovc=7=llKVY>KbUy=51)XwssI20 literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.class new file mode 100755 index 0000000000000000000000000000000000000000..22d3b20dbc0309331287a038567cc0c4ccea3b97 GIT binary patch literal 2252 zcmb7F`%@cL6#i}qT}anL10s}1p|+SnVG(Q922q5f#SoOxAg!;<<|esxvy1zngZ@>{ zI4M&{r$75gIi9<_fi16&lgZx4Ip;g?bN~7G<=+72AvL5J=5~c)in@5ljlIB@zOl!> zrnH5z7Okt&mR>_t%lpFgwuI+vNHg^A@dIvH+^!oNyL-a)8Fbt6Wlaiq-7%jrOcx!u z9z(i;Z41|k7)4NR%ciJEPwrY`$tK>A&tu4jNKHbOzGEnK61cKJ zcKM489l3mkA-(KWMFt&sOGh^{3_V5ip%gTCg}cQGF@!O>RpG8w=lC-1HzcW;FaF;s zkO{+H!wIZv=*8hitt{=jCCY(m3XdRr6aK5P6*Rofkbi?7#Yv%{XlZzdVc{Zn)8d{d zympdK#A5v_TN(6YNQL7DLw~M#lCfnaT*z0t!7!qu6IT@Ln2wtmr+`wn7-n+``|0M= z{N*beZV}d*jIRjKbmhKEcm}sIso@U84aL?@=aO3wn!@&%`M&SCI^IK$p{wS&p^*&6 zIflPh53d6hGMK_$4bu#LNj0i!sCsnFV3vyKK)AAY$S|2ij|#bvPedxd(lAGO136lp)y(ax$BE6!^AmBNQ9J9sN^5$ zC@A^fwtTx~RV+T$v53zY1|yeC&bs4@N476qZmP6Ur4Hnto^@G4-^P-TFO(Nub>UaI z6;O+Pf+azeDtC>X;uw4nk;8+-wf<+={E?e^FS3aL)264 z`4g%2!e@mB#M)zeRY-=$U4d$crXf9*3@J4vY1QbY)-GC8w9->U->Y;oXl1l^PQ8Hs zdq}=UU&Rb$(L-N7Vn8ph(}^A=5>6dM_R$>yvFk{aGT^sA(Z7=&c!9yGKQP?FXm;WV z?-s-Fy1F_-{uPYr7T$k_i55OQxx3rG`y~ArI(9k~rF?`1;{BX>OGH=egY?W1mWR?U zJldXVp>%}J?Bf=;x0U%FQ0C8uz73Jd!x+E_{YEi|F>1)0*rfP8!7Z3HCz`l}UojcF zc`q_Qc5?s%-{S{zcLYD-N7|)GYJ&DZlMWMu;IvC)m$VHKE#fzi`Axb@p-R*gA*uLZ MC0dRCbrX&M0NrtXfdBvi literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.class new file mode 100755 index 0000000000000000000000000000000000000000..08ba281b66d851b70b0ed528ffb5f773e8b42900 GIT binary patch literal 3874 zcmb_fTUQfT7~Ll%nPeQHqETZ}RMdt5rlO@3@IvDSC}L|UmTE6Un8IL~fysoby|?ya zSNkJ;^0i&7f|o9r&;3hXt9GB6Kn6pAy86ImF5mes``c%Khrj-L^aMaBepV0?$V?cS zyfI~5*E2IE%XBj{dU4jYjLeY#JCw_nOxMWT)`H=^xxUz1xSCWp(=ZEt|caX9;WjHEM;*5rVyveqimOG{w zO5EX8vO$@|SqD* zmPuR`7!2<9<=)qDx=}utR!tz^nUth=q~Kf@7+oV)5LMl>Y?qVBwle)Iw;M}O6Gk<> z3vRoZJ~^44HVcyi2R7K!tz%NN-qSFS_XUzQh2G1$1|I&@EVpC*{rkLJZNW8ssNe&E ztrfPCsTw}Q$K>5y$?Y!`IMK?Gt?YHFE^1MZeotBjBIYDBkh8CfA^hlB3LLIQu~j9o zeV%Ss<1Gpz~)q}%!g{> z)-Vr;;%eM5@+H?eU$XL&iUOBv7FO91%f(fCP~J;xZd`8rmP#r$^;Ja?3vxt#Dv+v~ z#HtobS{HFs!!3Nq{ovYu8Ui~~!A#1@Nfv&g;Y)l)H6rDt8dcM%`c2SPxpEoy8x7y$ zJArx%+bRz2XK=ZPY7SV*X*u4?oDRzeYF7EoD`$=5@FpPRKvHvd$;lh%O?e`0s&QOC zDjS9Ulz=)OxC{!;4S0RPCn6r7e;t@GEj&Cc40SvlYAG#9xvP-TFC_Vwmrbh7t`rK z(9phw10#=dc)Y!XkK2~;%5OBN^McoVL3VRdk^%O3fz!T&mB4$EMjL}g7_1!~4AsCS zk0QghuhP>_zF|OG9ix^1t&`tE@=V98pWbnqo@l0TmDc&kI5ED2u93DyyguHeJn4$o zbw%#sTvACyI(x!x$?#L0T*PU9&pyS4o>(&0IGBtr;;p9`5fAWoPrN-DUqr4Wos1>p zOStk7S3|fR5s645diU9*4q2qc6gWa$fqlfRS)N{*W(x=GL1dZUAdhla_*O^CD}I1Y zWO^&b=lLbdvgA9z_!zF1i*M#Yp5Xg1Js!a%3`WS(%O?aW?m?q*rEf0*news-JtK}W z1wui$f+mIgNbr6d_?uaUwwn`be~jX|gsaq}b|lqB+(@bq@p&Dtw9BWj3Fz&pNJJCL z-DiJRLDI!HR%`wUAxh7tbLc@4)|`cc^E@*uoSD<-=F;k*Zpgm4~19)Dsm%Mk8j zv9}3unEtvvFeCJP5Z}{doZffg2mDCJNS^s%%9YDtHiKZM5cj~m;Dbq2m+?GJ^nc>Q H5bpd7^badi literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec$1.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec$1.class new file mode 100755 index 0000000000000000000000000000000000000000..b0ef823209d63c67b9dd5e2beb2983468c7d8ed9 GIT binary patch literal 998 zcma)5+iuf95IviOIx(gR0m7|KDNSiE2veSrf_RB20-087P~ZU`ob4*v;H)cqT~+)Q z5;yU{2k=pd*~C&Tsz|Z4-re!coHJ*}fBydZ4d4kLTF5c%4u#9bNPP0$Nus27Cw@GY zO1Q7*d;e7M#=eCDLuKNh`EKB=k$W_p2(B%xF>EdpL}RH!_t?CT6Q%rNAQ;y4SjLUV zgybzemqK+Z;F%;I&l#G{l_FXLhC(kq5hXBOabTfnBagC!5-JS&rg12HRMTNH9g67f zoLAKgxgQMtNSb?UEEuv3d#eC9_K9phN)*F(mT5+XUZ}J<*WK2@#x2~jaGPOg1r;3J z#Rfys=Ul`y@w_a;a`jqX7>(R%_*n)4HI(`l^GKd*_t4k!Ow8NXEuzj~iF3gdEo|Jw zeGA(R8w+L^YjCiG2I-ha9VCit8B*;>&1IPV8MIM1#q|~g)Yp+zqi!o>N}Y%qpUcKj z&-CFUC6eFnhe^c6fi#m=$&BnH14VRSC?13{LA?=r9G*C+qsHL8Qc6Ui}QQ~lIO zT9?2o6*E5cd*o=9V3YMSou1O&SnPJ^8=UqJtbdvLTs5}Y7Zd#+Rk}MAW31P3opy#B zsHIt65{k)E?zF$c`H7p=&F|QH_kXGnSjWd%s@mK=O+|s&#RE!~#~!80p@|ml1sbh3 MI&?C04LCjj0D(IH?f?J) literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec$JasmineSpecStatus.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpec$JasmineSpecStatus.class new file mode 100755 index 0000000000000000000000000000000000000000..b5785543451a11843bf0ca432833b8de268a41bf GIT binary patch literal 1313 zcmbVMU2hUW6g|@g7UdGq$#O1LFh-amW22;tRpVM(kx4p{wt*q zZ8SDM`=g9^25k4m#J~eHXXoBC=ggkjU%$Uy0CI$U)JvN^clmR>xw^6U9!kT$L2M zRVg1F$k}9R?{IgiR;(VDEQVL_$L5X}?6yM|HyN}{w#E?J?tTzagyUdH7??ql1QbRk zsZ90CpXGaw+sv1G`5#;4v}` zG46T%#O@xQFyw+>_Zux?`}uOf{@+LBpWcj;xBro$5^NhCQFhGNBadLkKo(CZlR@6? zHt+TF0Wp^wT^W<{qwvJ7Zr`)Tjw6pb5eV(7EG5g9({w4m9xVs$$@apSx;JTGqwKoE zQ$ht@jTa1y|B-)&nSjLMz1mu%=xB63LtAN?F@Q#jml`QqKw?hjN>)(PCSg$hH9{T2 z@>l#0R!>f8XP7?4tO7Se3ZxXc6;>b}`9XEs0JBy-G(gI#hX+Vor~UO2R2)#lH!xblTohH{2%>{3FEvXUEdG_IjIO%zk=UyJDKUogS?Ho)HL@sY{^SJ-2ARYLrSeO0Axf^qA%t zH+4@rkGH;H(4T&RM4};yo++9*XBG7bnh{m84Q&F=iJqx#p!X^igu`fwpdB3wb~1A5 z?iOyS*oEEHGN&`#Twx%0+V%OxfXD=u5E_$IGY&> z^br*;XcdT!kVIpZ#aZ2+lrRXyN34QYn$m1TzWX0T&JCk1Ine+O$%!2S#(AJgy*0@E ztO&F*W9tGwnApO30fjP>?gG#Fhqqt{9SR%eajjg|ivoudfgtP~hH0fIA4yqKF3s+-U)$r-`Ip+u9TcS^IRbgSGLj-FtKU5b_Gh;Q_Req!f6G40;d`P`cVZc z&fs~LI zv$>I>K?&`EigTcItwwp!GRZg=KQSN1=M|i1EqH)kx3xw6mSr!bv&@_AsL0`hKtyKI zb|&o#1w)CeJyTNUh>B5+d32K0@Uq234Q-jI2D(cojB&cVxGJ=4_C~B*M2W;+9hkf$ZtQ77EIk9^)l$8aO8#PQd|a|dv0btgK5>;HumUc~kt35@u?hS6hCubw z=ua4SNaMOu@Vcb0C?hj>UB!z?E4abt@<`LFCnbgERV<(+@FZOuHte$NnqG8y=-66; zKAzgr#~NglH*D*cI|Cw^gDFRnCD7+3YF!wCR+R~4r>3B1DvYnN-O#a|qc4^f5XHlf zf-|(G%?T)uD8IUBYv0TXVV{!7{$8;%oT2>~^N(Cflv8 zoK*fzIU>I$a3+!ath4aj0w-#e_i(ARh4|SWS}y4B#u345cwJ%|;U?lS%Y{auYco&0 z4Z{V7y<4pb<%;X)NOcK`)XpgQG23<>;KIzmT#2(p`@lkjcn~Hi2KOSiw8YBa;h z{Yge?$NK;D-N{i|W4u3q<&yGy6@S3H{vazz=);^5T(1IC@Hy!r6P}Y>>A8~Zw=9DlffL@Glzh26GZ|&)F6;V$~T_oUGP*(@^3hNj}M-K zR`=sUSE1@1@D&R5;#q!?o(F|v8-=^-3P0xxN#PNiYT`YXWUNQ;j_qI_hB_TAd3xxc>V-bOWZ$MQ9=(KU&DHo1!IM;J<` z9^m3=syBXV6_?j=Wfjx?z40&hy2+DoeW8xf3Y7c!(!G5v*v2UDqV+!dC0JgR`QJjC3z;!J02N9g!i@3U)IUd5~Y^&4ww zKdYoVl>n^oAo>umO?N5}@SS_FheSuHqvgF%|0Om8Ie-`!w{8p)!eN}}-(|jE!^HrQ zGgY@|e79p5!*}sL2H8z|e;+@f>wN_EhYUb*f!u@UPjLW>0-<0+;jj{X_z`eSvY30F zAM^kvC8ljD0vU_H;l|uv1JWb)r2vR+Rd3pSZ-iVueSL*@;D?uvPqSBPIn`lh2VYO_ literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecFailureException.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecFailureException.class new file mode 100755 index 0000000000000000000000000000000000000000..e05e09c2d4329f32d8068d0c63d3adaa289f7c61 GIT binary patch literal 889 zcmbVKO>fgc5Pg#`r>;rUB!q8hDNrYsums{1#062Q$g~ova^IMh*)sfCuVEt53RM_Pu2`|H|V z^@@om`}9gCiSW6yp1s<6=~olG1S2dkCVJT{?h)F58_QbbD2+XNsIo41{_)u!W?byD zOI7~1>_}!6pDKJd(ByT4qZ8CP19XR9VGa*Emk!R+x`k!*}RbE@UgvroNma%Y+ zbNzyb>$t%Y3*aVhu_)m-?v&yq<`Lg*4?m;d*~!*(+`YiwM^09dNjGvpJD0Qya4E_5 I=BNk10K?Gf6aWAK literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator$TemplatePlaceholders.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator$TemplatePlaceholders.class new file mode 100755 index 0000000000000000000000000000000000000000..7d128bb2f9d34680d9fe85b400e6a57b80a1fe3a GIT binary patch literal 1808 zcmb_cYflqF6g|WC&5F2a6~qUE+OF36eo+yuD^x2GwlrysA;U73#qE}Cw

4MU6(I z@v}e5cxR~62!1eWKg@Jy@8jGv=iVPbKYs&o9gpMaW0+kPc}LX6Yo6a|`)-)u;H`%1 zi~Q5w-QE<=Qrq`MFe_-`VKbPhh{mSJL$T;_N31u!H4(Jph%gLn@GYMAxL?m(e!IbN zXvr$iR7zEAWpSo5$51NwDBUE(aeHBTsc5Y{DU~gIrLwS6nlF}@A6pE^>_w}1z)<29mkMnh!r}%naqCNrTtggYLdK9=!hbgKs$H$f2Cc_U_qI)F?OOxWO>krIzhhC>lC$;Wk5(2La!9nw#4UW_MK!s~f@zC%fO~ z_f<(ge_R1xc*XFt+pQzTY|oS@X}_=I4oKd&x-%6$-fB(m=dzn#*~a9T+EWd~nSYOl zE0QGQ#CGdG58D9=;YC*h8LiN>!lnqAUXr6pRU&8xJz}{2{}YBZb1=pBx$<8Z_n zQO8krJRLR8sN-1dD_LthG~a5G9gNzw=nls0cNl+5q55#1Rs#`Q`zeWz)08krATFq{ z(t_qi2f!S`mzKJDY4js5nz;`!_o57_;*L-u2E`gu5z^#O_PDIdlmBFa8pX@uN+)Wb zc1BiF^F7QrDy;++Qt5h$cPu^c={%^Dg&&?sK1e@BH@H&%Xc|!dDt13PVLR zT{4%=D@J;?Zd+b@)u>f0+f1Jip0ic6G*h>2)15T=V|b3Mp+#Zms&UOomkoP4oiDDM zB~PKXR<}G;;c)IzHf7(if*#%_chnSiznZ&mbk=h%dzqVJPTi~4y=lW+QHVF&u|3#v z)+(D*Muh;{Ml5d>)EVM}k{Ts!EE4h>Nm zb?RtEn~WaQ(TI@8M*Nw_=f@qmRVi z7%fs5T@FG=oC*mY`*DEemmOoVU{_4RAX&hE~+%>tiWX_m8U|lmM zAholOo3n~UcDT3kbQ6Q^=tWXPpTgv$G}7qFp>?#=f@8%gFPd&mM+*I9b~b-;W+Jn2 zHk-@LE)?<$*{O-##WNX&?Em1b=}p5if*;h87WTF;o8BfEQ5<1R2h)S=e-*>B)7QW(LZXsz z{YH@}IksooUQJf1K+m#SF&sOFB9?_m7V=~hRyKhtthml~xxmM>%4+K4A?$2^1BfuR zQNI*Hbp{q5+{NVBHtQLsD;JEaUrnV3Rdrkyv2B~ljnXOk1r!hwer&_wT1e9A(#IiTw_Czfa{VLM)8$*J3m`w42+uTgRbh57H_ z41>ZFGd3$<5));kRuc|7npJe{XI)*puvPxsAQwb2Wl)+2h+y@Q(d#$p?7;Aa>&ry4dU< z=lapW687N>*h4(3unpyv(- zlJRGfKceF&3@NPP#2t*t$_xHVhAZ)K@*XDV?;$(SsXce`;u`YtnL8-(buS-x@bVg7 zP2I(7-(bgudnnGw7yH++^y~LTaEiHR!Xg6kc8DwieMFQb(iHjZr{5|1I>6B&+syz^ z9N~!}EHMeL;yIs%MBqWlLMtk`LO&JvY(<%G5!kf58P_%~nRR8=b z?U!S1TaLAUgCkv9XY0_ZmH}CeUn6xXQs&dw)gq%C0fYR#^iiwoZ0&6O`tRQd$f*Dd zSbLH&2S#|wD1nSo6Q}t$#>O{_^BCWxll%tIJl^sdA}qYklM((;;vKw8oBOD*_k5iQ zYx{(?PDBING~Co!XB5f12}UEr_#6lw{Wet6NtN5A2+D^HhO)R7ctbth#Rs_!J$&Np zA@v;%MOgJx8-m#5%R9r_NzR_52(mbi7dHj{Wav_a^Fh%28-t!|2>NIAEP~JR1)rjn KUjBdieD^<5OdcEn literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSuite.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineSuite.class new file mode 100755 index 0000000000000000000000000000000000000000..1352c1114b14fe3cdedbacac39ff7d454376bc73 GIT binary patch literal 608 zcmah`%TB{E5L`Eu&_YX}K;ZxfRJ9i@apiaj@1qnwcH1U*Dcz0AL@sY$!0;b&-4M0rDWTg1v_mx2@&`uPYflL^*di}FpFf@r&{sDt}&L7~t zNJGP*sS}SI)LEjb&|V^ALaRDT6AyF8Mn;yz`NE~AuImXz`?(l^<#L|utG zOGBA}<#}L*fC^M+j4@8a%$P8B5CP*J+{|KyXx-B zhQ6gu(wC%d+O$dgxu5bar#+{~=9JU?fc}7<(?8SnnVpp^uzi}g2hi^9+`04I=RSAl z^7nuJ^)mox@dpDbfmar#<;WFz*S6N$o*P+fcGz@1Y2DDzTHB4}HR;K~j$}C7_V_j@ z!^l8J;ORAc-L@LGw_?pKu1O~n$j{DKt5;`hcV_12UZ0=4Gj)BIAE&nsYf<2OD;0r( zN#6@2+lv1@WGtC184fEj1hmqTq3vTExHsocGwy|BP@F`DCdUYe;Qr@|sf7~S>69VZ% zaX}z6=`YC~(#V^55>E*{HBFkT?dBp0vFR~(5IAEZhbNTjITK&T z%hXfQ_5{j>o>2IOx!qg7ig?zliLc zSNYegD>+=nH3P2^=x%#FVr=58s>%#vv>PE~+oukOm|21SJ=)Y{Q^}e{O$UYdXxsva zrv2XPyx;0n=$nr_8{e~5o&Qcxl?hgFX(c&5cj)KxawOxj=7Fg4$@=}ez|>y)`(m5x zN>NPLOw554GR<>Ao5g(s3np&i8!V$h+Dj_;bG|;01x`F(mp!Z`XSR~aZI%8v1jc%m zmdx)i0X>;0Ad7DbjIZgtrA!@P_0|i;vc0r4D_ed*J_?@P80r|z1@5|QH@b7hA~kde zwt;U84DF_&-rY$K%o?cb2xzVp-s1*(!JbHfd{Z$VI!=verT?^xJ_W z&y?4~ELOjO<=NPBjR$e;Flc(H@WY@Lb6BP zizISXuHG{7Bm9^(z+_5~B#!nXObmCfO~6#Lct_v~9c+0uYBrS5pP2Zm0+Efn#dB~6 zzYIHz_sGb&ZexZb9yk|=BYCg4xfvc}$8&Kwi(hb?;fZle8?))i1@=ZaeSOOm0-J~f zyQG_)iJB!Rwa9kv-n3hB<6+?>_y|DXAi!hysHILJTX;@AL#IK&ZU#l>kn!}knFhr7<7 z#P_kAr#Ero0VXyvrM61PQ5+&2AU$aw%Xyq6<`?;PD&BTTyGyoBV+hxAgSej|VPC^E zA>8Cz6}z6R@=ai7kJvjf|4EuNTsM<{{Xf8*J^cXl)zJs2=il7Kw{De2jlaREr}MH_ z&*WEX^}f7YtM}*c*0#{x4rwgTVTqtd7}6-=mKoAZ80P;r&fpx*v;UdE%b3I%FZWj% z$~jco(x^n1G_-EW)7_AjoeFsv1$>7gqzJzF5X@nuK4)eO1Hyn~;6n($ ad_x}dL2)aH1 literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunner$DefaultSuite.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunner$DefaultSuite.class new file mode 100755 index 0000000000000000000000000000000000000000..d4b64a3be779b68343804e34d5f20c93759717ea GIT binary patch literal 651 zcmb7C!AiqG5Ph4}#>Qx4)oK;QgGg(k5fKp-K`Me$6m02zQ`fpN-9WPOzdVTG!4L4G z#M$aW@nAjdym`yazMZ%G_Wtq;U>9o+EQbA11OqV?_dJMlC3O(-Y$TNkEi_6# z^cf26;zds~4$UB=p1oM4kpvhp7fzyN~Vtd3aLU+6QMBy3UBQXnQibbjc j*5On1#<`1mREXJFplD$cON6GbO1MnRrJP{}tFS%*Qj@Q7 literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunner.class b/eclipsecompiled/be/cegeka/junit/jasmine/JasmineTestRunner.class new file mode 100755 index 0000000000000000000000000000000000000000..66439d366e874064b80588912f244d25e318d6c0 GIT binary patch literal 8913 zcmb7K349dyb^e|tm}MC-NE`-ZyfzqgAT7oi+Xxc`5?Hb%Fe^k5j`3)BBrU9V#Oy9t zOj2KQoY+p|q)Bj+Hi=^^&508ual}WjxJ{eh=|QjbcJI4Q8#n6rW@dLsLR7^3e(di5 zde`^9_x^wU?H^uz4ZsHZkbw$8UB4Yq+Jp8HD}K0;P3Pl>t=w=rYsWkM&mKFM-&@FL zZP!4RV5#E{1`AzpH11CdmLxjc+V&jkY42(~)YabEo@m>#ySp_Zkaoem9Zoivx3c+O zD^sv5J^8qdwQ~F)N<2vV-wN-c4r*nf9CbVT*=XsiO>zq8jxFciba)N~+8@(Z&PoxL4R=(iUj73xDx72Ut zlG$6*jLufh*G^r~T-VFMTrsTsbf#*Dld_|z#0nEjaigHJwyt*$1UH$e!J;U?-E86( ztfE1Kc0P!^r+V4govt&iPza2ut*yH@+f~l3CKjT4F4m&XK&@c)3~};Ao2W;FU{=cR zFARD*_vu-UCa%MRDB`%yzy2~&BO-WE|{NmZ7XlL>PdsPD`=wjisNDDR63I( z@CiB}8u7g2WO8v&D3`{&taP?nJ#>eOO}JA*VCVOZc*sa3oe{<>HpvxND#7h{quIb_ zLH)H0HL*oQWu%<#RQ?DBcQPrv3&Z`k+hg@-D7d=QNm`j+%T4R=V6ZAblqSd;W{OTZ zt%zO0{K=2^NQuAFQnF)u7#PVlT)*rWdpT*hG76 z$UD;ntghFD(WFoB=MDmWmUd=jUB7Q9b?JDDxiFd2Db5%yJGu=;+MQ~aW z4Qfc!;hY-vUNwrIenfC%aVBMF>_IEgqgKK4Id0c#`3?iH;5eb`mzG31q;duCUCX6ntRL0`vU1X_e1e?l~I<3#k)UmqN9(>EV%#-E9rC8vO)5Zs22rRZ5B0h?N{-8{!NPvowdx|Gs=WlQZ!NoM9Fh zvPo+sowqXSQ>4F{d=$7Xf=?2os&fRN=C=f)rD^(8CO(7D5+w|3#!B+Q)=3^4vfPAy zv|wkGc5^5Jc7(^n4lRj$fyIgdVd}Uxd55?-oZFwyrkvvmnrTPy68o9s-au1^46dz2 z?4H=#2)@APz-x5+*#I4B8p;o6){>o?h(y7ZFq9EtlDPt6=%xqKK0>w4@AiJ%F1t!q=od}=lJ+Re2W{RC z*kEaD`L}`gfo|JQ*(ufbmreW%zT;DGOD3a>=&I|B^}WChkMD3Y8P-2$Li1ew8h*pT zud@a4O6Zh%6TgYyV$~urDbiu5uw>Fn?ZG(D`7VCf!0*uN@;Sv>6TgSwCmCeD&VO>R z5pb)4KOj5J;A5Xm1b<}WkM+Q%ey6Ey<56zAcj-ym2ENCZpd8}u_JHG(1qFX*;?MCH zg0%x_*Y2|OLr#ipkss2N>3lm?X6N>Smh8zXycZ}NCMX}qjL>ELm5FcS)hOP=-x~NE zW_($L0AyDSv5CLK-?JpER%#8qIp!+MJbR}r4hbVwp>Y}iXyTu=@iOcacCwK7Ed3V~ z|Eh4Ad)!LrTRPMEe1_wf@$V-7Lp%N1>0GOm^_KpZiSOgTi7db1dbqN4EHph%5rcxn zG@4w^oG@if%abZ1fb|bdd>%I%_+Oe|HnnAdz*0<2@H(pM8bemDoA6=RAQh%ms%cgB zi8ODL5nm0xX*68vt*h$D{W+?^`_fDt_P`OL( z8FHQDdXZq&mg`Jepm?6k9;Sq0sb)mV8<^?&^swD_B58Y9>WD02AG$BAXTYdsVgVb$y21#@B(e;C8a}pp_vB$lsn}vwu0=6T9Ujp<g3G3N-|xVxtbVt8v1 z*KqF^3~9`^o3cY%nJ?*F3l-$640Y7UkLe#?`XaKEZOav2NI7rkP;qa$A{9)Br>pOM?^Y!K@Oa}Ii{9(n$o4MwLy1j zQ_W_ij7K`e4+!HQ0&EEYUa$!H`IB`ZSi`>Z-OSgI&=KC)HD!SzyhYy-K5vS6L-z94 zAn!EgfKn>klc|k_AqNE;uAvJ1ea9~U0LP8Uy9n#JU*&QUIYch=mw0V;RQkkHUg3@U zq1v#9MPivrq;|&5A+Hqom6IkIQE2x`$`o5GM5JgUb2ezdmCOn7nrXCPd6cv%hvkT$ zqij%v8eCRyy7!AdmV6mDC95@jL9vGKGQ!h5!<-PkhGFY)yD?M?2|$cCoI+ySID@(TzHSUnT{^q*9M*;A3{KqjGS8^OJ^Z_#+JX94@!@$6R`G%ORz60r!A*Qc zSj*Ws)}a}Vcn802<;s{ZpTD>97d6qRYwB9VH7(dq{dREF) zYHJM1F%0^{hjno_w2r%jb#Aau7mg#Z%g$0BaZ=^z-Xv>{^nY+ug zdWo-EV08pZoM80W#pt_cV8FwH0b6|W<2V^ee%O~hhWAXJ`LXg$^`m2We80xU*QlDO zfp5>tsozG*ZKkKy|Gp+$O8(zc(uDtT5NML&8S2WFv~^|m+A+NU4Xo{KcoXxhpDzDY z>nlC$eOWt*%vQ#~4J)uKBx_|LYaZtmtA0EqkhihIU`Q+U)i99!2tBBhw=`V9vx3*2 zM^n|S=sQpuL~i96K71Y@t$x1xQ)Bqaz(1e!y^uKTZz}6G-^1E{L}(}O;A`{r_Lp_4 zgxo>#yfp;s^w5b4#5HupI#r?iMMB1hiifLY^=L5!VdqCZBla>C5}r^W&T9fkROl0C zAYms}R0%7}&@4l4u77qJW=ae|Z|KYwr8D`a5S)3E6rxUCPes4o4Ku1DYD^#_{#s+?>x)E~7Yh!q0su{_U8Ij;f!7t!j{(jldBQ>i|bN`$E8Q;EuUlnwZ;$Y(i z{I=i?T<+q`A8xLyUshH9C*%0j2C~y%j^VGBvH0~LMqzNlKlAIqotgN4eFLrjPY(Rg zC>Cs)jnw#9*PJ5|YhYvB_OR}D-Zy1-2uQyhW$sL@z zd$Y03AeGE(Y>+XzXa6Yr`Mc^fSXCWgW>jt%la@1B+SpL_szeV|YTy(8vS$CVHa%>! zQFhEOI);eyz0yvvP{@70bCwzEoyV(Wan<5kpPhI>@w1F>c#J0c1#>4!5O|8CPt!@y z&`Hm-SbUfS{TvJ6M@XF?#r=F%PvK)k%O|+^lXwE3;*L+_%ltgcZx{LGtz@>|FA2qM^AY-2_PmrF>j=%N_=a#Z~T?y$sqD?9nvbpd`v_ z3*na@h1o5kQG-_(fBbDMH>7vX1c|o1sWiqpj7`5M_-#;Cnxq^Q(kb_ZoT7pBa~j#w4lb(TD3Af)sdxjmGB* zxfih+FOic+>G_xVZ)z_xYrnvMTliuKz6S#@FXrWPKn4T&GE;xRg%$eF71%M#Owb;y z!{;CwI)nK>ElFk+n}Sj245}M~@9vl!8)XR~bp6abx&2AKLSS*EQa-|+&a)7+>vW6>gc?|FG-6!SbH zV6Hz&@rtO~m{Ur2zdoF&4=*t07YUYchCH<>5Fh1^50ny}Ox8{$%;Ep5@Exvz#fjdI4!1{{PHfyoU7$5lCrXAY8q59RLCXOWG_o@P4V4ZGerg~sfGYr{}xkX+ouv#EZiE6S~T67jHJT>I~ zT%gwN4Fu{t@u6;_hGh?nXbPPos&w*6?1k~^VF*|;^Mk`>o?u_n;_XErXb2)sHkJ+Mu5I&Z24mnJ$`x8iLGbh`bs z`4+c+Z?Fh~>mC|du&Fma+`?_j&)EuWb!Xne2p8x4Y1?@<58^xt^lM`$)19N06=us4 z64>~=4+Z~VvLjBRaiYT9;{CBOC7rZb94^rAd+rTuNYTd~zNyClLcp;Pqjl+7dx6%W zk nu5NzDwJ*4F25QSdm0MVw0d7~o4tZO4cMIqxg5BeHKfr@u1|bcX literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.class b/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.class new file mode 100755 index 0000000000000000000000000000000000000000..e7f47ba290f0702643149ee7c56ce43d616ce5d9 GIT binary patch literal 650 zcmb_a%T59@6g}lNhzN*Jl#LrAE@)({F)R=ju-6=|?nMUaX`DGIIBgQs*2ZPs>EHrf6!Pl5-3fImu{ z?5^NN@ZjamyqC$$8|LHl?HxcHJ4Iv|x+BRwIhN0Y`%$1Q_l23MfW)aVMjC#T@Ij=k z?8-of!s@W&9v_sQ=*ae?fYc(T^D1fPmv%0qG#&-QA~7CwAb<3V(hCV0 slnLFl!)3xsoaZU7#P8J@Yp7FnZC9yr;}IEyHG_3*#ObEN7PbwVUyQJ>m;e9( literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.class b/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.class new file mode 100755 index 0000000000000000000000000000000000000000..45e197e142f8573566819df2054dca5ee72aead8 GIT binary patch literal 1950 zcmb_cYg5}s6g_Jj9E9TV2qf+!F-;*h5R|0p)0Ebb&=?GEF(pGY(~K}{SYt~WNv7pz zb*4>dJIxR1kLvWSq+r81Z9nvb<-K=z@44sPd-u=3etQMrK5A(s1Rm~5t1b`Zk!>|Q zjtZ=%?YEUfXUq0|>04`&y)FGX0@boA$`6VHLp62a*g?mW0@D|^7b82&r0fJF=M|TDXK+!G;F3TxU)W*r6?b16 zNMhW?6^x`YAu!$rDtVrLqR|Xo#rP1jyl!F`rofd7_1WyS_oTON@3ol0SjDZ|tsUD_ z+K!#6;7~F7)yn^&uuh+1Y^bI{mUReJTka@d5w7GoZeRzBx`vr}2XQ5%LKO{6;Z_>& z3EXhG*I*$nU0N@^VwKL8Cf>)ifDvtOAKI+o{rm-Si-k(RC|al}67g=MkVgIuc-@mG zW-%g=R{o>*^Wen5JQmWpBQVhQMULTbStS5 zO?-%tSb2MYUtl68)zhoR!gp+{Na3n`BruilshfAG9M{^?U$$=`e+-I+9nJGI6Gbet z(d%^E%JHjC>qOvo{%KEg(KJxFF0I%_M*1S-QLKN)6Bv%N3#X16g=L6FHgpv=_hl0+ zn&+S=+wL(tGt+Y^*(;T|6XdPeD4 zW(2|ik=d6RoBbVEcVA-i7hL-(Je}n?6XJ{@g$ezDFh0U~yo0y#4lRLqxlZ5)*E*A% z{MWJ9>C>^Zvp?h7DRM6`qgTmO%>9ac2|T$7l7+$W*BQ18l05_Y7@zb3u}MEckm(pC z^#_u>NsUo^flr@kZ|aSJH!+DE--D?Ta54%M12QB&#}XL`d~uH7mxR;&z9+QiHy=X} zbfI@s8uToKh;pe9<%j1ezsBuP`5a(GxgX#hDbJJgoqwVHh?Jui vc@Rp#(vGd3;&HcTMkv=^ig2$d`N25(1U4y60@biBGK}#xf8RWX@Uitb8aTAS literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.class b/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.class new file mode 100755 index 0000000000000000000000000000000000000000..e5b1fbe0408a6def4f89acf37a0473b384e37394 GIT binary patch literal 508 zcmbtRyG{c!5F97D9E6Y;G?X;FiddorA@P)mB9KUwhRSDFiI0mfI{Og6MTJDc2k=pd zy-Qj|LE%}??s|82{q_Cv3E&vpAu0kF5lKx`dR8*dt?@EeZf-0)6XhH^Iau;BIscGb zOWF0SriC}Dy|shUW%@)RY66{Dy(pO|JC*lQOxg?7PYoA56Q~{>P6TR2ZUa@UHxZyN z&>nK1yL=u|HdawW0=;3XRWebTDfr4+^E2ZFu7>|tdLqymrFo|5#uWYb{~oSi%q6hH zvwJhAiE)Odom-oFRV;y(?ft53ReqEkPux3j3)1|ct25}>&Fhe;5G5LfGsDY v&KNS2B?p3|cdWg!qk;xw5iW3pv02^&wwqa+LF@8i74bemh7f;MIH`8|Bn|^-1e*iebRs$7*)0m{DDLpBf6xMi|C^t8jlc{o!oV@wrV{-n! zu$J=67flOqGJ9=D3(^hL1iFcORx(v~D(~Wiv=^u!8-DIYpt^rB5vW~ckJLmJt1U#R z3v`Cu<+hl|l#f-Ml0a{mX_Zb?ZUSE>Ykp>&!1?gMItK#HQC8%du1x5*`!I#+IH>@-ZSpE&G*2gKh2j(iMt u#s)K4av(Za=rmu=x#t+J^oB literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.class b/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.class new file mode 100755 index 0000000000000000000000000000000000000000..47b79c81cdbe7081b93dae06446347b68fa44765 GIT binary patch literal 487 zcmbtRu}%U(5Pb_Ar-*=PV@YGwf=z5CB*uio5KV;8SnZu7&Ux&a+dclv%EZDC@S}`# zCyA9d7W-!3%YFH`*ef(gETzT@_2ZL;LgO;KrxxniZX-Zbp*xih z*TpKLd~TwY6#COFHtE9TT=I>x;UC#4jHmz6c&^ZzWknv-gv(BYzXlqXvnU+Oq@Gu_ zV8m$)O?uI_=@-74Oxu#2A9j>Pul^zWb?_P+q`l7V;t literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.class b/eclipsecompiled/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.class new file mode 100755 index 0000000000000000000000000000000000000000..4ba7fee1ce637956889459126105357ce3e0c91d GIT binary patch literal 485 zcmbtQu};G<5Pfc&6iR7JVPWiofT5OHsVX5P1{8rrsxC~9ITeS*sbU9-&tgJi-~;$5 z#3givg~9Lq?(DmF@AK>Z1Hc&$x@ZZ^5|Wx$^rU23S>t7@Ty88UGvypPdHur|E}x?JN9W52lv9Cw@gpur(V90y$6<1@a8aM=F_86bfu literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/ChainedErrorReporter.class b/eclipsecompiled/be/cegeka/rhino/ChainedErrorReporter.class new file mode 100755 index 0000000000000000000000000000000000000000..e38fdaf9b718158d56341b231ba916595a94d4e4 GIT binary patch literal 2508 zcmb7`Z&MRj6vm$$lHDY%q6n0wVx>h)Kv`=PX=43{D8v{op;)Z#%o0{uO|r~p{9soqrXfA*W!K*DjJEY$TyBQliCCwp;0J7YcEu>zbuTB7DA{W@(`&ev!1O!Q z7YqB@DR+rsl#6!F_AUveQ~O(#UJ{7TIIC6?UFgx!jY9%msq~VHUV$UKd0us0^SMkm ziNokgK%ifPig-6Zg05mv;NY&a^wThej~UBcU8QfTSyKzcT>8F>VS&jG#d(fXsT+&@ zZ3CLXCm2z2ysayx=XKAjYWNhNaYxH_xnpxf+cECCcFik!u4PtpNgTxqS>>33p1S{D zABm)=KqV9#)fLNKG*>EYN^ij_o0TQgwdFW4M!j{L{TwUoM@nqZK%j-|)!bEZhA80Kq}pI_jNfR z*mK=Dhba~3iD0+EJF^-tV44c5SXe+$Pe!?U1-!iyK2ooD_a|$?bMREjBB!OGXjIHl`pQl&QsZtoK);Ab>E5O6SLBg zb%rsSL)EI+%{9NdyL$)d1d?^9;g+qUS*1s`LO}?KdD`V;$)5`bcOE{hTdY4~JrkJd z*vdUAu%B@^IB2LjPZm?V_S`>*W*O>0$urB3Z<`yw+*Fj>MelcAKyw3HO=VcEd_GJW zACS51>OBpM_*&qwYw_UX$=Q;+`qXr56s7e0R>LwT$*KwMhArPG{e7qHq-+C@^Kj|n z72_3=XAJKN9^4Tm5#_xb8Z8I-`KwcpD>r-Vc1= zVwiUkH*k{?nI-11%Bm?*L8ZH1Gag}?wwN+le5xoo4f3F*jYRXb#Gv>0IDs(J`!Nhzl%N9 z0sE2y$^0$UHt>H*@QSXy5kIl4R@5gr8Y6&{Y<7zOGo&%a@fD6{34e}2q(qvi^C9Yd zh&msl&WEV;A?kdH`euk)4^W>bamAT#W>=!>3k>UO zC{Z#9C3;`sU-Uqk|HxOR$)(p9$$5%yinX67lWCv99Q(%5A%jfFAQLjkgbXqvgG|6+ eh_9a%nc_?9C?eZ5#M>3nl!nf79&oP+zWWczkt}}z literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/ClassInJS.class b/eclipsecompiled/be/cegeka/rhino/ClassInJS.class new file mode 100755 index 0000000000000000000000000000000000000000..fefb5b5510bc8e6c8d8d1b79b25bcf0929423c07 GIT binary patch literal 710 zcmZ`#O;6iE5PcgvA9kEjK3kxz#0iL0R^o<0T#!JZh$00c^+Y%BVm3JIXzg&|H*o+7 zgw#WS06z*b>qI6+?O}IzX6L>?p0WT?S`u{fvJ0 zl3&t?gL;4}Y91IG0m`T_OtqDk$HRVCno~>0Fw;uXX8Y(6f!*`-PumfQaoyUh?N z9U3W8d6Elh^wRyI4l|YL^9#)|x3=E426!xV#5P3GzLDBGbrqv*Gu z=s1rE?kOvwNp~|xdT^=VgO4ey1*2|!z%*sFrGjaTx-C<^_2U77`|~dIKa#<_K&BeWPe;oSFGM3L_TXf7+P+TfZKQA`3Z2j05ASy?$Z0Y OOB2wyxu5d^UtR%tt8w@M literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/RhinoContext$1.class b/eclipsecompiled/be/cegeka/rhino/RhinoContext$1.class new file mode 100755 index 0000000000000000000000000000000000000000..09342dca1a6fce266431af51983452335b8a7fc4 GIT binary patch literal 1097 zcmah}TXWJ-5dKa;LLn_Fv{fsm(4um)wEBp4R7PidXG^Dgpk&>V zzBu#qJ37J)<}n}gYM;w)b-#TqEMG^2A$hfXFp!eB`+_0j_iQh}O>rBu0@oOfA@Aqi ziR1co`*CD)h&;8W?e8)?FHE-`UAi{?bP}o9VhGorj+g^O!hnvbnk^cbLo9|6QU>B! zVh9zKX`*3Eu{U_v7Vgnyj>(2&@qUZDwpx!i!zyux>~!!6pOi<4l8)gX)^wy9(z9qX zkij}blv|eY0$O)($h|ldzZORhn>sca)~4c)NiuL3d4}9gXf2h<0|O5gUtw`(`&4-; zPOmr7OYVuzzI^M7q3sNaqxnOhTPIEaKA=uVnIU!6OGiD|IlUx0cIXUTOT4yKXDwcj zxuxu>Hm{`BcRX8mo5Jro9Ru6gA-;&=7v2YHF>L%NgK?rYRbu0fl)|m|x#tNFS!#w5 zy|H8#m$xfS{k;z1=|3T27 z;)5tY_yhb=;+?u+^;MY5DKKn@~zA&smttDeoTdnuq4p^iykyu%e*3iB{x-d{{icc7YRRR<`bordn&Lw zSWMkM5(r0TLLCTPN)X{fi~uVMI!FbAfhVktm8O@?EGPT=kCX1$6tX&!R{4GohTfh) zZ{ZjFL$(*#M#s30n-OmOlfdD-+R-e*E!<{bbgCSe!Jan}ADYG%^g{V0R?i2y>$75) z&vj9mTIq71+|*1W^aR!x1(o0~?g=axmZYO+ls9EbR$zCqJvO$?X6C)BDw%oxy0Gev z%bYP)olWM{Y+owP|C8)#O?Fhtx~3XEjxylYhDcMNDBp+{uMT2HFY@jY_a2FN?tekD z^A*dV&p4|dJ3H~yAJFAK;Tex!#ucstSCP(D9&+_(?cf`({V(tlAwHcGXwL-#tno+- Tcd*Vi#0ECe=bg9a#rXLR#N41j literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/RhinoContext.class b/eclipsecompiled/be/cegeka/rhino/RhinoContext.class new file mode 100755 index 0000000000000000000000000000000000000000..f0352f2f117f96ac50222d66eabe8c109ad6e019 GIT binary patch literal 7577 zcmbVR30NHE8Ge7*WjD*@fB=C+lg(v-C9F9N8gi&P6a*3jMN!i@EE8C=%+i@%a%dZ` zR$HsRyqcc2+SJ;^w7Q#!XAfW47>mFUGMvS-~SKK zy!`NE09K1L0w@wVtyhc2w0>=$8Z`#udNR68KDQ+Gly)E$fKOn~pgN*P6RO@H-O)R! z#Zm$@22E#$K)5Yw^hbx1hvJEZ8kK9!m=PaNMV%GR0)auZGnO3I1eO+B+-dDmdlMSh zmu!gZ@zf@P;@Y}y0pFHnpB6$fW-6G0PzVCE70f}Iz`U5DsVS}1)#{qHq_(b*t}(-A zP|#cjew0X&l?tjbPhinRk(TM(lZGq0y>=?e1y!e#$%Gj-2ed>YdO;%Dt0tPI6*US1 z2-2;#xUO}ihk7-mOU6Q=ye%116Wyv2m*1U1Uuqz33M_0p6?Tl{83hgXguAXggfNx_ zu$U504W)vmSVr`9ZT}b(E}WK%Lhh$sdCM^3eH1Fz;C8hgOxx!Yq`S2nL-Kk zS{qRlt(_Jza~e8RMqKZ2uJb6h+0`7x1>9s>r9qOkML{brBEC{int5+;70{={LXUh$ z<>ZkT&yZt89=imJ2FZ$Y&tgX+Q`lzImV|1WExL4egEySkIDMUxF2m&lGyAnvXMAWlp>?Q3G_-;VlUwNoM?$z;){s{VT=xGVHjThF2XLjpifIOz zrpF{yUCC`$6a>mVhTCY7gLcIen1+5AxT^7`n>ETQ-&GSe*toFW5gFoPm$hNdNF5Y7 z$BRcn-g+dC(UzbI>{GB6+X5J3dgkzGNhGv>HPM-33T-pDLj zPxNU<5U&w9J88B5a4H!#w3rqj(Za(9+dAzG$IY;w4ChL;ZAG{@oeHbr5OkQbxUgVU z=JBVlJBSeh$R2+{!9g5iVIiX&O3oceCL0qe@@fUI#p{TUIy|iDeF7`<$@YY1oJ-6B z9oHzhR`NHPO4^elBw&WH2RA5qJ>Eb}hSRjVHIL+}6S3K&+l7Tew&U29++|0RJV9G9dhrs-tRqQ&c_)w0VA>59;B!k{5Q0>Kn z?J~LFZKdzxfi5S+rM7@zBr82=xKqrxjh^vW9t|E(6G@fitM!^?hr0Q4k7#E|M(Xo*g&^VU#-4=H$`OeNp2ni{Z9*W2R>jSXpT9(_!YK~v5La90J2=q<^P{-QIzIx5cP4A1Ndfm;d&&pnqFFwG-;8jepd&V)Yc+}}#}>NemrRHHvV#Dnrg_Bhz^ z__0^tnT+!`Xb9{m=uggGXX9itc**P{FYpBg$M8uz@U6L9Wr#Smj@=pqlCsCQD>g(??p(9abBZqpZGz=GM3oz_;1*3qUmaDi^|Ym?-#+PHVTO<2 zYbpDMf?vvew?fKjhOwc}^H~1|NemuO$Kn}$Zsj`B!X(Jjl!B^X2-!p%&;165r3CmFDrOS z-o0koSB$M%Z@Rx<=4E4Hhi%gIIZLDM3}$mc@V!rc0m9_j5EMSHT?DH zGj6?;@zq`?6E-*&Re^>=Smuc)PaHut7Sl{~*_i^oq)lYJ_e}(Q+9{`b#urNzL_txZ z&Sct%X|mT7F0YhEc_w1gw&*&OR$g~B6N`C0DCUd6BL46dnDvP-q4>LkGknj+XDPq! z;3}TYQB$9VQqRY%hfrQ$U;iM=v#59o)yJ%@^Z6`?kIy-LmO} zT!+?Rts`S6*A;PH#VF3|8AVf1eI$!>ve=Np=3Jm=S#~XDs2Ulfs3o(?-sjp{f%CD2 zQiZ(1InuW|(#vG@rG=65?LLvgg%izO?Gah#iY!AL+AWbCgtZ7eE$1$_V7{6rNhIb= zgLk>|Gw9CXiYKtAy+P_IwnAZ>-$dG+&7hy-3H5we*L`P0sD zOY&^8lA^=)r~@}z(E~bg6F*6qJMc!liE;zD05|iKkNZP-GyV1B7S6ZA_Yx`sC_YKo z{Q-yoZngdwa}32nRPcWQ`bkQdH0^Vzxn&0R@pTQKHfnFRP`gn|p`I#>49D@dqnOz~ zirae{vbgi{V~i;1Z7Gh>vRsC?aHN$uZ&Ro@|cq#(St$qG#u^oO>@N zOaJ&Mgo^?=G6UE0O7eaiKpdqqnVV}Hde)abw$5L?&UX|`YDy}7t2^o?c#-3{oA419 ziB<;p-ry6JzDobyC!f#3WEYd2%#Vwiw>z;0otCNflup^MscWfEl3I>^828cCxs3Hk zI96<#Sc9UIn2Eqx@b72I4B&oPHHh~p$LLOqm545|EG+*h?IZoJD*yPHk%O1y@;78H z?Pf?XwQRC!y}-3;0Uoey67p>8D7c4|@KZrkq=AAz<>7Vq2m^i@krLozc-pbJg&~pTDy@$+6hDgM3_dTd@Rq|q4|_^o&84p9Qb)7EGwca= zLy7XYw8}3%oG5U>5@-|6?+6t5A|A=Jxq9N}MBdHMx)|T>V7%MQ!tyVTA$;$+;jiQ$ z{#yRwZ@9xbmdHW|80<|Z>wJo3B~8diEF*2k>~=%88{e`RQ$+60b9|M_F5^FY6wmc! z@g4TV48CjCVH*Rx4j&|%hsf}&JXp+j1<$4tvULTSlF#FZ6j>zybmpjtI}ura94}<> z^R`G)2EU4w;f@S`7a7HiJ=FN8EdG|kKQD>o!fktYm?E!XQMi^FcOCog^&ZcbI|c-p zX0`!B9$p=_tLc@bfbTf|n~Rs7RkEbrvfw1Q*c3YKn7w9Hh@QEkI4k^Zkx^07 zQ=b*Vj3{M+c_AZaMKYp1QdV?nnRqrMDkHv(sPQ;qA0TdKExd&xzm108&Rn{Ke?qzw zt8kacnKh0HrKlCB3!Yu(1jQl|c8poh-!`AKVsS1;_IY8UB}S%RkyvUymx<;4T}~L9 N_?!QPJbUrq{{U3Up1}YB literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/RhinoContextClassExportingTest.class b/eclipsecompiled/be/cegeka/rhino/RhinoContextClassExportingTest.class new file mode 100755 index 0000000000000000000000000000000000000000..cc08b235f39ca9d19f3db6a7d013a5b3e30cbf49 GIT binary patch literal 1463 zcmb7ETT>HB6#hCyCyArNhN3jX?%92WqgRH=COKwO%lzPQ~R&S|>5!gE$=)l|&7%G*Q1+w$e zJ5|6C@-FsZufV}tpw-j%T3y9UvK}e{uNF0AxGdwq-h0BVSq&0_OSS)psvgxn%OSJ)YU3sP4#jzIs8HAzqtu|@I!MgDmyPM@E<+xJ7 zC{DOIiBkfFR`N)hx9f4V-le=+z-gRuP!t%qc{Q1l&)O*#j_LYy{iBPsI7bJma%okv zcxOx16vp;vRc+Fj41OLL983tD+R1<4&_&6*&j-oEhqertq8uiPX+y@vsNO2xE^76$ z*k`0vu2``pZQ8{}%&?Kvh74`-Cbn|5XkwO@WDV%s!pbEVmu-`|fwq(<>N$DI;i^E6 z-e)XJmY?f3_ZtE?wtDWl**X7I*{9$Zesl0Edu@P%iF0^j7ZuD3IKw$acBJMi2S1#R^)Rr*eQx((WX9sh8L)Tx6#*HZ z_)Tzic=Ndn?t3ObBllNVUEpffpus+_Zfd}NKW_pDsLkMD&uX}92mD7_mghHrW8}?e z9I8!uqaBR>i_s_39UR}p_)rJGyqfaL9ZXUB^kN78kD4pgY~osW6E{1!P1F0SzY>}9L8&mb-_=jpnBkQc!7s_#3Vefztb|qmzVLF Nry)xJpx+E?-vQSQekcF{ literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.class b/eclipsecompiled/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.class new file mode 100755 index 0000000000000000000000000000000000000000..7d4145d47f07693f9e97f2c778300a3bb2c5ee79 GIT binary patch literal 1389 zcmb7EYflqF6g^XsuBB=z$irtr5h~dAg%4^>0IR`NNGO5$ak?Ga!Rbuhoq~_}qx=F! z6Muj|%6O;SKx2^ThrM_1%+9&zp1pT}{`&Ron1EC ziubmpcXy();Wer28zQnv^f6?1_%8Pq*L8obx+4P1(En6wX`eBin#pf6^evm3NZ}OD zq;VSk4Cl*Ii`90sD#8t3Re~W~HUU?gJd`f(ZuZ%Rj2H^#|KU`m8Wd3^u9b#qt6D|a zEvai}uhQaySk$#8QL4-@n`TRKsfq3QdRtrB6q_=VlzdTZW4V<^Q|?UJgmr(XP38Em zViGCKaQP%cDGcI_hYJitQ5g7^Zuw54CyUT%uB34l*Jw-Za`mdhaPzopJxKBQD5fxh>q$&9Ty@oKJ4QT;MA#|PUp!o< zaRXBfsrYcC!AYHmy*avo`Hm`o;>3qB8tF96kay{t=A%@K_h{f-V^riv4WX3(Qkg1O zDdaJm#4U#0aTI%@)0o3;hO~@UbY!^>#M(B)d@s#qMHLkPfu#qZGREkIAQaq+nNK!q z(uWm7NL5Tb48#lRW^dx85ihvDr2e58Qk klR4t^h*I~YJl7Fqj8cwMH5YqQWe!t$hpC2N76g`uKx-o{B0A*`STilQZ>V{27K}c0pHU*IC5S}N_5WBczu$>A%iw73* zzz6VAh&zteMp2YJjA!P|opbIs{`>Fu9{~68P(zMkt1oO<48=!oN1iW3`#^o$p-jY= zq$}dYYHBDjn1}qB+X0tD`)&VFxQT`(hP9cu4@Oe*ejpf@63>sVU6Sd{w4Bgsk@XW_ z`pHvAzxJnrH(Jfo6%8UMBTAR=7+AwPr9m9?;FZHr zsdi4Y?j(^fhppNKG%iF-#|E}EY%;8e(a`=tMYDMvizx9!8QXg&O9QuHG3evNuE!IG zN0S;EVXZTZXM8wjBh3n`8g4UeEV4CFL!F`M$NQg0Jm`i~ft`q+#+pG4nmcYp3Tjv`k)^Htwnp6=ouMNa*&FWn%FDUq*5;)MeZO^RS%P1F-Ga9_2QMRnhcze@LA zEaI*w9DXDmk4IwgJP7+daNO_{X&W!46j3`+S&peR)G##8fSIOhQhIwi8b#=Yo~6}e z+ABn_H@?HD|HS!ksm%q2r6=lk1!dYBbVs2VafxP%6Dt|Zi;Tr=l&}22wO_cY=I!^> pTy>PtNV!&0ZZqQoOv3LFTON0bJBJ z`w9I6{gQIZX-_}*_w;j5?~@c;&O)(|{iJz%Gk0e0T>I~TfBzG}A^e;`i-2B~xst5N z+eXfvGHoaKhWbA5*uI?e$E4>c&??X|ZOj@u%djiC(c-i$`2wp?nYQV_DzGY(9T#Xl z@04W*Y0K}3#UDsXd z*IZjan&hrnniDD89j%g5lYj5vio=t*F&z&3?*lFiB)o+sU)lezx-Wf~b| z1ybSW*pxwr9*b8cDnT~Dx7bg(8G6gFKAYrx@Rh;=qW=Y_#+sz@G7btPSpS+F zofKG~xezaS_*6cH!#JA25dnQU`0=o59K&&T$Mi1VA&tkJMP04qZ!|hGC2@jO2#L4) zY*&b#*h=9Hvvkj#EzVWTG>1Z4+7QmRQ=I19J$F+DcDpsZ-@9j*u6fcMo00`%Mi!k9dC;o z@J|Y37*F6@6Me>}TxpckxQ;gk+B{3jDz!5+s3f#q{Gb5)A5Ec5YL`vxpaR#<8Zo~)OU)BiU4rD}Lz&Pq3lcZndnED{9O zsG33X}jReD6vX{v$L_G(hqdwq~2rnJj^TEOW=;ct`$UYguf88b-|+! zP(?&Bg(_y#xQjUsL`Bjzuv|(j_-qL2a+1sz7&bwZmn#if92AH3MawbD!!^q{tCk!r zTrw@`CGk+8%X3RPUnyiv#uIqIiGN|WllYKbQjQee`=;sOvA_!phOxU2ZK|W6r12>} zBRSNTKxUb|Z!Ya+c07qMs7dOOET`}lzDeNgCQhAm97`Iu;?%c_Q#azAiZ;pE@5$KE z3o%hO3Qo-}NtH7tckw@!K9#pXdcd}&d)`t%1s-;QO$$ac!7KhV;dg@fIj(|h+rHnB z{FN6i)O!Tmz#6pkIvqa1buI5$AMUnbUG!83SLNszx^Lxr;VC*Ne#47HTGw#z{&{S; z-m7iq@)x>CdJkyZ=Al2q?k?M_q4U`*LP+%8P?xw%JjMvA4=K^#aLT`0+n=uif6Sz^YV>^*_ z@N=_-TS3CNA`smT5O0O0d`B}{pP)34sYZA$D8ONcKf>@w8U9!-bay>;S5z1QYvs^G zQRt3(Xdy&XxEBHZpfOT~Iv`n5l z9tT$7Oas(=ZGYg=#47EB!bGd~QDGh*_iCRLC^4}OUj_u$zH2rthB-)>R|s*K|D#68 f$kABE&eUNZk6^ao2iBzpKjJ5@DT2Msm9PH*SNkNb literal 0 HcmV?d00001 diff --git a/eclipsecompiled/be/cegeka/rhino/RhinoRunnable.class b/eclipsecompiled/be/cegeka/rhino/RhinoRunnable.class new file mode 100755 index 0000000000000000000000000000000000000000..4c229a91c7b878fc494cd534dbd84ff36d9b65d7 GIT binary patch literal 173 zcmX^0Z`VEs1_mPrPId++Mh4lWRQ=@C^wjJ`{i2M_ynOv25E)dOmzS87lgiG(!pI + + 4.0.0 + + + be.cegeka + jasminejunitrunner + 1.0-SNAPSHOT + Jasmine Junit Runner + + + + rhino + js + 1.7R2 + + + junit + junit + 4.8.2 + + + commons-io + commons-io + 1.4 + + + commons-lang + commons-lang + 2.4 + + + + org.mockito + mockito-all + 1.8.5 + test + + + org.easytesting + fest-assert + 1.4 + test + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + eclipsecompiled + true + true + + 2.5.1 + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + true + true + UTF-8 + + + + + + diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineDescriptions.java b/src/main/java/be/cegeka/junit/jasmine/JasmineDescriptions.java new file mode 100755 index 0000000..9e37dc0 --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineDescriptions.java @@ -0,0 +1,38 @@ +package be.cegeka.junit.jasmine; + +import java.util.Collection; +import java.util.Map; + +import org.junit.runner.Description; + +import be.cegeka.rhino.RhinoContext; + +class JasmineDescriptions { + + private final Description rootDescription; + private final Map specsMap; + private final RhinoContext rhinoContext; + + JasmineDescriptions(Description rootDescription, Map specsMap, RhinoContext context) { + this.rootDescription = rootDescription; + this.specsMap = specsMap; + this.rhinoContext = context; + } + + public Description getRootDescription() { + return rootDescription; + } + + public Collection getAllSpecs() { + return specsMap.values(); + } + + public void executeSpec(Description description) { + getSpec(description).execute(rhinoContext); + } + + public JasmineSpec getSpec(Description description) { + return specsMap.get(description.getDisplayName()); + } + +} diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.java b/src/main/java/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.java new file mode 100755 index 0000000..6b74cb0 --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineJSSuiteConverter.java @@ -0,0 +1,57 @@ +package be.cegeka.junit.jasmine; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; + +import org.junit.runner.Description; +import org.mozilla.javascript.NativeArray; +import org.mozilla.javascript.NativeObject; + +import be.cegeka.rhino.RhinoContext; + +class JasmineJSSuiteConverter { + + private final NativeArray baseSuites; + private final RhinoContext context; + + JasmineJSSuiteConverter(NativeArray baseSuites, RhinoContext context) { + this.baseSuites = baseSuites; + this.context = context; + } + + public JasmineDescriptions convertToJunitDescriptions(Class testClass) { + Description rootDescription = Description.createSuiteDescription(testClass); + Map specsMap = convertSuiteArrayToDescriptions(this.baseSuites, rootDescription); + return new JasmineDescriptions(rootDescription, specsMap, context); + } + + private Map convertSuiteArrayToDescriptions(NativeArray suiteArray, Description rootDescription) { + Map specsMap = new HashMap(); + for (Object idObj : suiteArray.getIds()) { + NativeObject suite = (NativeObject) suiteArray.get((Integer) idObj, suiteArray); + + Description suiteDescription = Description + .createSuiteDescription((String) suite.get("description", suite), (Annotation[]) null); + rootDescription.addChild(suiteDescription); + specsMap.putAll(convertToJunitDescription(suite, suiteDescription)); + } + + return specsMap; + } + + private Map convertToJunitDescription(NativeObject suite, Description description) { + Map specsMap = new HashMap(); + NativeArray specsArray = (NativeArray) context.executeFunction(suite, "specs"); + for (Object idObj : specsArray.getIds()) { + NativeObject spec = (NativeObject) specsArray.get((Integer) idObj, specsArray); + + JasmineSpec jasmineSpec = new JasmineSpec(spec); + specsMap.put(jasmineSpec.toString(), jasmineSpec); + description.addChild(jasmineSpec.getDescription()); + } + + return specsMap; + } + +} diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineSpec.java b/src/main/java/be/cegeka/junit/jasmine/JasmineSpec.java new file mode 100755 index 0000000..5f3763e --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineSpec.java @@ -0,0 +1,101 @@ +package be.cegeka.junit.jasmine; + +import static junit.framework.Assert.assertTrue; + +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.mozilla.javascript.NativeArray; +import org.mozilla.javascript.NativeObject; + +import be.cegeka.rhino.RhinoContext; +import be.cegeka.rhino.RhinoRunnable; + +// TODO rhinoContext als field zetten ipv altijd mee te geven? +class JasmineSpec { + + public enum JasmineSpecStatus { + PASSED, + FAILED, + SKIPPED + } + + private final Description description; + private final NativeObject spec; + + JasmineSpec(NativeObject spec) { + this.spec = spec; + String descriptionString = (String) spec.get("description", spec); + this.description = Description.createSuiteDescription(descriptionString); + } + + public Description getDescription() { + return description; + } + + public NativeObject getSpec() { + return spec; + } + + public boolean isPassed(RhinoContext context) { + return getSpecResultStatus(context) == JasmineSpecStatus.PASSED; + } + + public boolean isFailed(RhinoContext context) { + return getSpecResultStatus(context) == JasmineSpecStatus.FAILED; + } + + public JasmineSpecStatus getSpecResultStatus(RhinoContext context) { + assertTrue(isDone()); + + NativeObject results = getSpecResults(context); + boolean passed = (Boolean) context.executeFunction(results, "passed"); + boolean skipped = (Boolean) results.get("skipped", results); + + if (skipped) { + return JasmineSpecStatus.SKIPPED; + } + return passed ? JasmineSpecStatus.PASSED : JasmineSpecStatus.FAILED; + } + + public Failure getJunitFailure(RhinoContext context) { + assertTrue(isFailed(context)); + return new Failure(description, getFirstFailedStacktrace(context)); + } + + private Throwable getFirstFailedStacktrace(RhinoContext context) { + NativeArray resultItems = (NativeArray) context.executeFunction(getSpecResults(context), "getItems"); + for (Object resultItemId : resultItems.getIds()) { + NativeObject resultItem = (NativeObject) resultItems.get((Integer) resultItemId, resultItems); + + if (!((Boolean) context.executeFunction(resultItem, "passed"))) { + return new JasmineSpecFailureException(resultItem); + } + } + + return null; + } + + private NativeObject getSpecResults(RhinoContext context) { + return (NativeObject) context.executeFunction(spec, "results"); + } + + public boolean isDone() { + Object doneResult = spec.get("done", spec); + return doneResult instanceof Boolean && ((Boolean) doneResult); + } + + public void execute(RhinoContext baseContext) { + baseContext.runAsync(new RhinoRunnable() { + + @Override + public void run(RhinoContext context) { + context.executeFunction(spec, "execute"); + } + }); + } + + @Override + public String toString() { + return description.getDisplayName(); + } +} diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineSpecFailureException.java b/src/main/java/be/cegeka/junit/jasmine/JasmineSpecFailureException.java new file mode 100755 index 0000000..d60c63b --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineSpecFailureException.java @@ -0,0 +1,19 @@ +package be.cegeka.junit.jasmine; + +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.ScriptableObject; + +public class JasmineSpecFailureException extends Exception { + + private final ScriptableObject trace; + + public JasmineSpecFailureException(NativeObject specResultItem) { + this.trace = (ScriptableObject) specResultItem.get("trace", specResultItem); + } + + @Override + public String getMessage() { + return (String) trace.get("message", trace); + } + +} diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator.java b/src/main/java/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator.java new file mode 100755 index 0000000..e6f2088 --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineSpecRunnerGenerator.java @@ -0,0 +1,77 @@ +package be.cegeka.junit.jasmine; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; + +public class JasmineSpecRunnerGenerator { + + private enum TemplatePlaceholders { + RELATIVE_PATH(""), + SOURCE_FILES_TO_INCLUDE(""), + SPEC_FILES_TO_INCLUDE(""); + + private final String placeholder; + + private TemplatePlaceholders(String placeholder) { + this.placeholder = placeholder; + } + + public String getPlaceholder() { + return placeholder; + } + + } + + private final JasmineSuite suite; + private final String[] jasmineSpecs; + private final String outputPath; + private final String outputFileName; + + public JasmineSpecRunnerGenerator(String[] jasmineSpecs, JasmineSuite suite, String outputPath, String outputFileName) { + this.jasmineSpecs = jasmineSpecs; + this.suite = suite; + this.outputPath = outputPath; + this.outputFileName = outputFileName; + } + + public void generate() { + // TODO hardcoded relative path stuff wat configureerbaar maken + String template = loadTemplate(); + template = replaceRelativePathsForLibs(template); + template = template.replaceAll(TemplatePlaceholders.SOURCE_FILES_TO_INCLUDE.getPlaceholder(), + getJavascriptFileIncludes("./../../../main/webapp/js", suite.sources())); + template = template.replaceAll(TemplatePlaceholders.SPEC_FILES_TO_INCLUDE.getPlaceholder(), + getJavascriptFileIncludes("./../specs", jasmineSpecs)); + + try { + FileUtils.writeStringToFile(new File(outputPath + "/" + outputFileName), template); + } catch (IOException e) { + throw new RuntimeException("unable to write spec runner contents to destination", e); + } + } + + private String replaceRelativePathsForLibs(String template) { + return template.replaceAll(TemplatePlaceholders.RELATIVE_PATH.getPlaceholder(), suite.jsRootDir()); + } + + private String getJavascriptFileIncludes(String path, String[] jsFiles) { + StringBuilder sourceFileIncludes = new StringBuilder(); + for (String sourceFile : jsFiles) { + sourceFileIncludes.append("\t\t\r\n"); + } + return sourceFileIncludes.toString(); + } + + private String loadTemplate() { + String template = null; + try { + template = FileUtils.readFileToString(new File(suite.jsRootDir() + "/lib/specRunner.tpl")); + } catch (IOException e) { + throw new RuntimeException("spec runner template file not found!", e); + } + return template; + } +} diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineSuite.java b/src/main/java/be/cegeka/junit/jasmine/JasmineSuite.java new file mode 100755 index 0000000..2135dcf --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineSuite.java @@ -0,0 +1,20 @@ +package be.cegeka.junit.jasmine; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface JasmineSuite { + + String jsRootDir() default "src/test/javascript"; + + String sourcesRootDir() default "src/main/webapp/js"; + + String[] specs() default {}; + + String[] sources() default {}; + + boolean generateSpecRunner() default false; + + boolean debug() default false; +} diff --git a/src/main/java/be/cegeka/junit/jasmine/JasmineTestRunner.java b/src/main/java/be/cegeka/junit/jasmine/JasmineTestRunner.java new file mode 100755 index 0000000..d562bdf --- /dev/null +++ b/src/main/java/be/cegeka/junit/jasmine/JasmineTestRunner.java @@ -0,0 +1,190 @@ +package be.cegeka.junit.jasmine; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; +import org.mozilla.javascript.NativeArray; +import org.mozilla.javascript.tools.debugger.Main; + +import be.cegeka.rhino.RhinoContext; + +public class JasmineTestRunner extends Runner { + + private static final int SLEEP_TIME_MILISECONDS = 50; + private static final String JASMINE_LIB_DIR = "/lib/jasmine-1.0.2/"; + + private JasmineDescriptions jasmineSuite; + + private final RhinoContext rhinoContext; + private final JasmineSuite suiteAnnotation; + private final Class testClass; + + @JasmineSuite + private class DefaultSuite { + } + + public JasmineTestRunner(Class testClass) { + this.testClass = testClass; + this.suiteAnnotation = getJasmineSuiteAnnotationFromTestClass(); + + Main debugger = null; + if (this.suiteAnnotation.debug()) { + debugger = this.rhinoContext.createDebugger(); + } + + this.rhinoContext = setUpRhinoScope(); + + if (this.suiteAnnotation.debug()) { + debugger.doBreak(); + } + } + + private RhinoContext setUpRhinoScope() { + RhinoContext context = new RhinoContext(); + context.loadEnv(suiteAnnotation.jsRootDir()); + setUpJasmine(context); + + context.load(suiteAnnotation.sourcesRootDir() + "/", suiteAnnotation.sources()); + context.load(suiteAnnotation.jsRootDir() + "/specs/", getJasmineSpecs(suiteAnnotation)); + return context; + } + + private void setUpJasmine(RhinoContext context) { + context.load(getJsLibDir() + "jasmine.js"); + context.load(getJsLibDir() + "jasmine.delegator_reporter.js"); + + context.evalJS("jasmine.getEnv().addReporter(new jasmine.DelegatorJUnitReporter());"); + } + + private JasmineSuite getJasmineSuiteAnnotationFromTestClass() { + JasmineSuite suiteAnnotation = testClass.getAnnotation(JasmineSuite.class); + if (suiteAnnotation == null) { + suiteAnnotation = DefaultSuite.class.getAnnotation(JasmineSuite.class); + } + return suiteAnnotation; + } + + private String[] getJasmineSpecs(JasmineSuite suiteAnnotation) { + if (suiteAnnotation.specs().length == 0) { + return new String[] { StringUtils.uncapitalize(testClass.getSimpleName()).replace("Test", "Spec") + ".js" }; + } + return suiteAnnotation.specs(); + } + + private void resetEnvjsWindowSpace() { + this.rhinoContext.evalJS("window.location = '" + suiteAnnotation.jsRootDir() + "/lib/blank.html';"); + } + + private String getJsLibDir() { + return suiteAnnotation.jsRootDir() + JASMINE_LIB_DIR; + } + + private JasmineDescriptions getJasmineDescriptions() { + if (this.jasmineSuite == null) { + NativeArray baseSuites = (NativeArray) rhinoContext.evalJS("jasmine.getEnv().currentRunner().suites()"); + this.jasmineSuite = new JasmineJSSuiteConverter(baseSuites, rhinoContext).convertToJunitDescriptions(testClass); + } + return this.jasmineSuite; + } + + @Override + public Description getDescription() { + return getJasmineDescriptions().getRootDescription(); + } + + @Override + public void run(RunNotifier notifier) { + generateSpecRunnerIfNeeded(); + + for (JasmineSpec spec : getJasmineDescriptions().getAllSpecs()) { + Object testClassInstance = createTestClassInstance(); + fireMethodsWithSpecifiedAnnotationIfAny(testClassInstance, Before.class); + + try { + notifier.fireTestStarted(spec.getDescription()); + spec.execute(rhinoContext); + while (!spec.isDone()) { + waitALittle(); + } + + reportSpecResultToNotifier(notifier, spec); + resetEnvjsWindowSpace(); + } finally { + fireMethodsWithSpecifiedAnnotationIfAny(testClassInstance, After.class); + } + } + + this.rhinoContext.exit(); + } + + private Object createTestClassInstance() { + try { + return testClass.newInstance(); + } catch (Exception ex) { + throw new RuntimeException("Unable to create a new instance of testClass " + testClass.getSimpleName() + + " using a no-arg constructor", ex); + } + } + + private void fireMethodsWithSpecifiedAnnotationIfAny(Object testClassInstance, Class annotation) { + for (Method method : testClass.getDeclaredMethods()) { + + try { + if (method.getAnnotation(annotation) != null) { + if (!Modifier.isPublic(method.getModifiers())) { + throw new IllegalStateException("Annotated method should be public!"); + } + + method.setAccessible(true); + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length == 0) { + method.invoke(testClassInstance, (Object[]) null); + } else if (parameterTypes.length == 1 && RhinoContext.class.isAssignableFrom(parameterTypes[0])) { + method.invoke(testClassInstance, new Object[] { this.rhinoContext }); + } else { + throw new IllegalStateException("Annotated method does not have zero or rhinoContext as parameterTypes"); + } + } + } catch (Exception ex) { + throw new RuntimeException( + "Exception while firing " + annotation.getSimpleName() + " method: " + method.getName(), ex); + } + } + } + + private void generateSpecRunnerIfNeeded() { + if (suiteAnnotation.generateSpecRunner()) { + String[] jasmineSpecs = getJasmineSpecs(suiteAnnotation); + new JasmineSpecRunnerGenerator(jasmineSpecs, suiteAnnotation, suiteAnnotation.jsRootDir() + "/runners", + testClass.getSimpleName() + + "Runner.html") + .generate(); + } + } + + private void reportSpecResultToNotifier(RunNotifier notifier, JasmineSpec spec) { + if (spec.isPassed(rhinoContext)) { + notifier.fireTestFinished(spec.getDescription()); + } else if (spec.isFailed(rhinoContext)) { + notifier.fireTestFailure(spec.getJunitFailure(rhinoContext)); + } else { + throw new IllegalStateException("Unexpected spec status received: " + spec); + } + } + + private void waitALittle() { + try { + Thread.sleep(SLEEP_TIME_MILISECONDS); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/be/cegeka/rhino/ChainedErrorReporter.java b/src/main/java/be/cegeka/rhino/ChainedErrorReporter.java new file mode 100755 index 0000000..229a246 --- /dev/null +++ b/src/main/java/be/cegeka/rhino/ChainedErrorReporter.java @@ -0,0 +1,58 @@ +package be.cegeka.rhino; + +import java.util.ArrayList; +import java.util.List; + +import org.mozilla.javascript.ErrorReporter; +import org.mozilla.javascript.EvaluatorException; +import org.mozilla.javascript.tools.ToolErrorReporter; + +class ChainedErrorReporter implements ErrorReporter { + + private List chainedReporters = new ArrayList(); + + ChainedErrorReporter(ErrorReporter chainedDefaultReporter) { + chainedReporters.add(chainedDefaultReporter); + chainedReporters.add(new ToolErrorReporter(true, System.err)); + } + + @Override + public void error(String message, String sourceName, int line, String lineSource, int lineOffset) { + EvaluatorException ex = null; + for (ErrorReporter reporter : chainedReporters) { + try { + reporter.error(message, sourceName, line, lineSource, lineOffset); + } catch (EvaluatorException thrownByChainEx) { + ex = thrownByChainEx; + } + } + + if (ex != null) { + throw new RuntimeException(ex); + } + } + + @Override + public EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource, int lineOffset) { + EvaluatorException ex = null; + for (ErrorReporter reporter : chainedReporters) { + EvaluatorException returnedByChainEx = reporter.runtimeError(message, sourceName, line, lineSource, lineOffset); + if (returnedByChainEx != null) { + ex = returnedByChainEx; + } + } + + if (ex != null) { + throw ex; + } + return null; + } + + @Override + public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) { + for (ErrorReporter reporter : chainedReporters) { + reporter.warning(message, sourceName, line, lineSource, lineOffset); + } + } + +} diff --git a/src/main/java/be/cegeka/rhino/RhinoContext.java b/src/main/java/be/cegeka/rhino/RhinoContext.java new file mode 100755 index 0000000..3e4d639 --- /dev/null +++ b/src/main/java/be/cegeka/rhino/RhinoContext.java @@ -0,0 +1,154 @@ +package be.cegeka.rhino; + +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.tools.debugger.Main; +import org.mozilla.javascript.tools.shell.Global; + +public class RhinoContext { + + private Context jsContext; + private Scriptable jsScope; + + public RhinoContext() { + this.jsContext = createJavascriptContext(); + this.jsScope = createJavascriptScopeForContext(this.jsContext); + } + + public RhinoContext(Scriptable sharedScope) { + this.jsContext = createJavascriptContext(); + Scriptable newScope = this.jsContext.newObject(sharedScope); + newScope.setPrototype(sharedScope); + newScope.setParentScope(null); + + this.jsScope = newScope; + } + + private RhinoContext createNewRhinoContextBasedOnPrevious() { + return new RhinoContext(this.jsScope); + } + + public void runAsync(final RhinoRunnable runnable) { + new Thread(new Runnable() { + + @Override + public void run() { + RhinoContext newRhinoContextBasedOnPrevious = createNewRhinoContextBasedOnPrevious(); + try { + runnable.run(newRhinoContextBasedOnPrevious); + } finally { + newRhinoContextBasedOnPrevious.exit(); + } + } + }).start(); + } + + public Object evalJS(String js) { + return this.jsContext.evaluateString(this.jsScope, js, "script", 1, null); + } + + @SuppressWarnings("unchecked") + public T createClassInJS(Class classToExport) { + exportClass(classToExport); + T newObj = (T) jsContext.newObject(jsScope, classToExport.getSimpleName()); + return newObj; + } + + public void setProperty(String objectToReceiveProperty, String property, Object value) { + Object obj = evalJS(objectToReceiveProperty); + if (obj == null || !(obj instanceof ScriptableObject)) { + throw new IllegalStateException("object to receive property is no ScriptableObject but a " + + (obj == null ? "" : obj.getClass().getSimpleName())); + } + + ScriptableObject objectToReceive = (ScriptableObject) obj; + objectToReceive.put(property, objectToReceive, value); + } + + private void exportClass(Class classToExport) { + try { + ScriptableObject.defineClass(this.jsScope, classToExport); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void load(String path, String... jsFiles) { + for (String jsFile : jsFiles) { + load(path + jsFile); + } + } + + public void load(String fileName) { + evalJS("load('" + fileName + "')"); + // Main.processFile(this.jsContext, this.jsScope, fileName); + } + + public Object executeFunction(ScriptableObject object, String fnName, Object[] arguments) { + Object fnPointer = object.get(fnName, object); + if (fnPointer == null || !(fnPointer instanceof Function)) { + fnPointer = object.getPrototype().get(fnName, object); + } + + return ((Function) fnPointer).call(jsContext, jsScope, object, arguments); + } + + public Object executeFunction(ScriptableObject object, String fnName) { + return executeFunction(object, fnName, new Object[] {}); + } + + public Context getJsContext() { + return jsContext; + } + + public Scriptable getJsScope() { + return jsScope; + } + + public void loadEnv(String jsDir) { + // TODO ensure rhino 1.7R3 instead of R2 -> geen shim nodig + paths + // gedoe in orde zetten hier + load(jsDir + "/lib/es5-shim-0.0.4.min.js"); + load(jsDir + "/lib/env.rhino.1.2.js"); + load(jsDir + "/lib/env.utils.js"); + load(jsDir + "/envJsOptions.js"); + } + + private Global createJavascriptScopeForContext(Context jsContext) { + Global scope = new Global(); + scope.init(jsContext); + return scope; + } + + private Context createJavascriptContext() { + Context jsContext = ContextFactory.getGlobal().enterContext(); + jsContext.setOptimizationLevel(-1); + jsContext.setLanguageVersion(Context.VERSION_1_5); // TODO 1.8 plx + jsContext.setErrorReporter(new ChainedErrorReporter(jsContext.getErrorReporter())); + return jsContext; + } + + public void exit() { + Context.exit(); + } + + public Main createDebugger() { + Main debugger = new Main("JS Rhino Debugger"); + + debugger.setExitAction(new Runnable() { + + public void run() { + System.exit(0); + } + }); + + debugger.attachTo(ContextFactory.getGlobal()); + debugger.pack(); + debugger.setSize(600, 460); + debugger.setVisible(true); + return debugger; + } +} diff --git a/src/main/java/be/cegeka/rhino/RhinoRunnable.java b/src/main/java/be/cegeka/rhino/RhinoRunnable.java new file mode 100755 index 0000000..28437fb --- /dev/null +++ b/src/main/java/be/cegeka/rhino/RhinoRunnable.java @@ -0,0 +1,6 @@ +package be.cegeka.rhino; + +public interface RhinoRunnable { + + public void run(RhinoContext context); +} diff --git a/src/test/java/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.java b/src/test/java/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.java new file mode 100755 index 0000000..f1d6926 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/JasmineFailingSpecsTest.java @@ -0,0 +1,67 @@ +package be.cegeka.junit.jasmine; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mozilla.javascript.EvaluatorException; + +import be.cegeka.junit.jasmine.classes.JasmineTestRunnerExceptionInJSCode; +import be.cegeka.junit.jasmine.classes.JasmineTestRunnerExceptionInSpec; +import be.cegeka.junit.jasmine.classes.JasmineTestRunnerFailingSpec; + +@RunWith(MockitoJUnitRunner.class) +public class JasmineFailingSpecsTest { + + @Mock + private RunNotifier notifierMock; + + @Test + public void shouldNotifyOfSingleFailure() { + new JasmineTestRunner(JasmineTestRunnerFailingSpec.class).run(notifierMock); + + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass(Failure.class); + ArgumentCaptor descriptionCaptor = ArgumentCaptor.forClass(Description.class); + verify(notifierMock).fireTestStarted(descriptionCaptor.capture()); + verify(notifierMock).fireTestFailure(failureCaptor.capture()); + verifyNoMoreInteractions(notifierMock); + + Failure failure = failureCaptor.getValue(); + Description startedDescription = descriptionCaptor.getValue(); + + assertThat(failure.getDescription()).isEqualTo(startedDescription); + assertThat(failure.getDescription().getDisplayName()).isEqualTo("will always fail"); + assertThat(failure.getMessage()).isEqualTo("Expected true to be false."); + } + + @Test + public void shouldNotifyOfSingleExceptionWithinSpecFunction() { + new JasmineTestRunner(JasmineTestRunnerExceptionInSpec.class).run(notifierMock); + + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass(Failure.class); + ArgumentCaptor descriptionCaptor = ArgumentCaptor.forClass(Description.class); + verify(notifierMock).fireTestStarted(descriptionCaptor.capture()); + verify(notifierMock).fireTestFailure(failureCaptor.capture()); + verifyNoMoreInteractions(notifierMock); + + Failure failure = failureCaptor.getValue(); + Description startedDescription = descriptionCaptor.getValue(); + + assertThat(failure.getDescription()).isEqualTo(startedDescription); + assertThat(failure.getDescription().getDisplayName()).isEqualTo("will always crash"); + assertThat(failure.getMessage()).isEqualTo("ReferenceError: \"OEIWANU\" is not defined. in src/test/javascript/specs/crashingSpec.js (line 3)"); + } + + @Test(expected = EvaluatorException.class) + public void shouldCrashWhileTryingToLoadFaultyJSSpecFile() { + new JasmineTestRunner(JasmineTestRunnerExceptionInJSCode.class); + } +} diff --git a/src/test/java/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.java b/src/test/java/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.java new file mode 100755 index 0000000..b437ccb --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/JasmineFinishedSpecsTest.java @@ -0,0 +1,40 @@ +package be.cegeka.junit.jasmine; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.junit.runner.notification.RunNotifier; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import be.cegeka.junit.jasmine.classes.JasmineTestRunnerSuccessSpec; + +@RunWith(MockitoJUnitRunner.class) +public class JasmineFinishedSpecsTest { + + @Mock + private RunNotifier notifierMock; + + @Test + public void shouldNotifyOfSingleSuccess() { + new JasmineTestRunner(JasmineTestRunnerSuccessSpec.class).run(notifierMock); + + ArgumentCaptor descriptionStartedCaptor = ArgumentCaptor.forClass(Description.class); + ArgumentCaptor descriptionFinishedCaptor = ArgumentCaptor.forClass(Description.class); + verify(notifierMock).fireTestStarted(descriptionStartedCaptor.capture()); + verify(notifierMock).fireTestFinished(descriptionFinishedCaptor.capture()); + verifyNoMoreInteractions(notifierMock); + + Description startedDescription = descriptionStartedCaptor.getValue(); + Description finishedDescription = descriptionFinishedCaptor.getValue(); + + assertThat(startedDescription).isSameAs(finishedDescription); + assertThat(startedDescription.getDisplayName()).isEqualTo("will always run"); + } + +} diff --git a/src/test/java/be/cegeka/junit/jasmine/JasmineSuiteGeneratesRunnerTest.java b/src/test/java/be/cegeka/junit/jasmine/JasmineSuiteGeneratesRunnerTest.java new file mode 100755 index 0000000..1a8cc03 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/JasmineSuiteGeneratesRunnerTest.java @@ -0,0 +1,67 @@ +package be.cegeka.junit.jasmine; + +import static org.fest.assertions.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runner.notification.RunNotifier; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import be.cegeka.junit.jasmine.classes.JasmineSuiteGeneratorClassWithRunner; +import be.cegeka.junit.jasmine.classes.JasmineSuiteGeneratorClassWithoutRunner; + +@RunWith(MockitoJUnitRunner.class) +public class JasmineSuiteGeneratesRunnerTest { + + private static final String RUNNERS_OUTPUT_DIR = "src/test/javascript/runners/"; + @Mock + private RunNotifier notifierMock; + + @Before + public void clearRunnersOutputDirectory() throws IOException { + FileUtils.cleanDirectory(new File(RUNNERS_OUTPUT_DIR)); + } + + @Test + public void byDefaultDoNotGenerateJasmineTestRunner() { + Class testClass = JasmineSuiteGeneratorClassWithoutRunner.class; + new JasmineTestRunner(testClass).run(notifierMock); + + File runnerResult = getTestRunnerResultFile(testClass); + assertThat(runnerResult.isFile()).isFalse(); + } + + @Test + public void generateJasmineTestRunnerAfterRunningTests() throws IOException { + Class testClass = JasmineSuiteGeneratorClassWithRunner.class; + new JasmineTestRunner(testClass).run(notifierMock); + + File runnerResult = getTestRunnerResultFile(testClass); + assertThat(runnerResult.isFile()).isTrue(); + + String runnerContent = FileUtils.readFileToString(runnerResult); + + assertThat(runnerContent).contains("jasmine.getEnv().addReporter(new jasmine.TrivialReporter());"); + assertJSFileIncluded(runnerContent, + "./../../../main/webapp/js/source1.js", + "./../../../main/webapp/js/source2.js", + "./../specs/spec1.js", + "./../specs/spec2.js"); + } + + private File getTestRunnerResultFile(Class testClass) { + return new File(RUNNERS_OUTPUT_DIR + testClass.getSimpleName() + "Runner.html"); + } + + private void assertJSFileIncluded(String rawContent, String... files) { + for (String file : files) { + assertThat(rawContent).contains(""); + } + } +} diff --git a/src/test/java/be/cegeka/junit/jasmine/JasmineTestRunnerBeforeAndAfterTest.java b/src/test/java/be/cegeka/junit/jasmine/JasmineTestRunnerBeforeAndAfterTest.java new file mode 100755 index 0000000..8a01dc4 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/JasmineTestRunnerBeforeAndAfterTest.java @@ -0,0 +1,22 @@ +package be.cegeka.junit.jasmine; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runner.notification.RunNotifier; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import be.cegeka.junit.jasmine.JasmineTestRunner; +import be.cegeka.junit.jasmine.classes.JasmineTestRunnerBeforeAndAfterClass; + +@RunWith(MockitoJUnitRunner.class) +public class JasmineTestRunnerBeforeAndAfterTest { + + @Mock + private RunNotifier notifierMock; + + @Test + public void useJasmineRunnerOnJasmineTestRunnerBeforeAndAfterClass() { + new JasmineTestRunner(JasmineTestRunnerBeforeAndAfterClass.class).run(notifierMock); + } +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.java new file mode 100755 index 0000000..7a62e19 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithRunner.java @@ -0,0 +1,12 @@ +package be.cegeka.junit.jasmine.classes; + +import be.cegeka.junit.jasmine.JasmineSuite; + +@JasmineSuite( + specs = { "spec1.js", "spec2.js" }, + sources = { "source1.js", "source2.js" }, + sourcesRootDir = "src/test/javascript/sources/", + generateSpecRunner = true) +public class JasmineSuiteGeneratorClassWithRunner { + +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithoutRunner.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithoutRunner.java new file mode 100755 index 0000000..ff6bd55 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineSuiteGeneratorClassWithoutRunner.java @@ -0,0 +1,8 @@ +package be.cegeka.junit.jasmine.classes; + +import be.cegeka.junit.jasmine.JasmineSuite; + +@JasmineSuite(specs = { "spec1.js", "spec2.js" }, sources = { "source1.js", "source2.js" }, sourcesRootDir = "src/test/javascript/sources/") +public class JasmineSuiteGeneratorClassWithoutRunner { + +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.java new file mode 100755 index 0000000..af3b9d0 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerBeforeAndAfterClass.java @@ -0,0 +1,50 @@ +package be.cegeka.junit.jasmine.classes; + +import static junit.framework.Assert.fail; +import static org.fest.assertions.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; + +import be.cegeka.junit.jasmine.JasmineSuite; +import be.cegeka.rhino.RhinoContext; + +@JasmineSuite(specs = { "emptySpec.js" }) +public class JasmineTestRunnerBeforeAndAfterClass { + + private static final int RUN_MIJ_FLAG = 0; + private static final int RUN_MIJ_OOK_FLAG = 1; + + List runs = new ArrayList(); + + @Before + public void runMij() { + assertThat(runs).isEmpty(); + runs.add(RUN_MIJ_FLAG); + } + + @Before + public void runMijOok(RhinoContext context) { + assertThat(runs).containsOnly(RUN_MIJ_FLAG); + runs.add(RUN_MIJ_OOK_FLAG); + } + + @After + public void runMijAfter() { + assertThat(runs).containsOnly(RUN_MIJ_FLAG, RUN_MIJ_OOK_FLAG); + runs.remove((Object) RUN_MIJ_FLAG); + } + + @After + public void runMijAfterOok(RhinoContext context) { + assertThat(runs).containsOnly(RUN_MIJ_OOK_FLAG); + runs.remove((Object) RUN_MIJ_OOK_FLAG); + } + + public void runMijNiet() { + fail("should not be run"); + } +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.java new file mode 100755 index 0000000..f34e457 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInJSCode.java @@ -0,0 +1,8 @@ +package be.cegeka.junit.jasmine.classes; + +import be.cegeka.junit.jasmine.JasmineSuite; + +@JasmineSuite(specs = { "crashingJSCode.js" }) +public class JasmineTestRunnerExceptionInJSCode { + +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInSpec.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInSpec.java new file mode 100755 index 0000000..2fd6386 --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerExceptionInSpec.java @@ -0,0 +1,8 @@ +package be.cegeka.junit.jasmine.classes; + +import be.cegeka.junit.jasmine.JasmineSuite; + +@JasmineSuite(specs = { "crashingSpec.js" }) +public class JasmineTestRunnerExceptionInSpec { + +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.java new file mode 100755 index 0000000..a7d556f --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerFailingSpec.java @@ -0,0 +1,8 @@ +package be.cegeka.junit.jasmine.classes; + +import be.cegeka.junit.jasmine.JasmineSuite; + +@JasmineSuite(specs = { "failingSpec.js" }) +public class JasmineTestRunnerFailingSpec { + +} diff --git a/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.java b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.java new file mode 100755 index 0000000..d3543df --- /dev/null +++ b/src/test/java/be/cegeka/junit/jasmine/classes/JasmineTestRunnerSuccessSpec.java @@ -0,0 +1,8 @@ +package be.cegeka.junit.jasmine.classes; + +import be.cegeka.junit.jasmine.JasmineSuite; + +@JasmineSuite(specs = { "emptySpec.js" }) +public class JasmineTestRunnerSuccessSpec { + +} diff --git a/src/test/java/be/cegeka/rhino/ClassInJS.java b/src/test/java/be/cegeka/rhino/ClassInJS.java new file mode 100755 index 0000000..210be1d --- /dev/null +++ b/src/test/java/be/cegeka/rhino/ClassInJS.java @@ -0,0 +1,28 @@ +package be.cegeka.rhino; + +import org.mozilla.javascript.ScriptableObject; + +public class ClassInJS extends ScriptableObject { + + private int prop = 0; + + public ClassInJS() { + } + + public void increaseProp() { + prop++; + } + + public String jsFunction_fn() { + return "fn"; + } + + public int jsGet_prop() { + return prop; + } + + @Override + public String getClassName() { + return "ClassInJS"; + } +} diff --git a/src/test/java/be/cegeka/rhino/RhinoContextClassExportingTest.java b/src/test/java/be/cegeka/rhino/RhinoContextClassExportingTest.java new file mode 100755 index 0000000..5b7c7f9 --- /dev/null +++ b/src/test/java/be/cegeka/rhino/RhinoContextClassExportingTest.java @@ -0,0 +1,23 @@ +package be.cegeka.rhino; + +import static org.fest.assertions.Assertions.assertThat; + +import org.junit.Test; + +public class RhinoContextClassExportingTest { + + @Test + public void exposingClassInJS() { + RhinoContext context = new RhinoContext(); + + ClassInJS newDefaultInstance = context.createClassInJS(ClassInJS.class); + assertThat(newDefaultInstance.jsGet_prop()).isEqualTo(0); + + ClassInJS objInJava = (ClassInJS) context.evalJS("var obj = new ClassInJS(); obj"); + + objInJava.increaseProp(); + assertThat(newDefaultInstance.jsGet_prop()).isEqualTo(0); + assertThat(context.evalJS("obj.prop")).isEqualTo(1); + assertThat(context.evalJS("obj.fn()")).isEqualTo("fn"); + } +} diff --git a/src/test/java/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.java b/src/test/java/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.java new file mode 100755 index 0000000..0584017 --- /dev/null +++ b/src/test/java/be/cegeka/rhino/RhinoContextEnvjsLoadingTest.java @@ -0,0 +1,28 @@ +package be.cegeka.rhino; + +import static org.fest.assertions.Assertions.assertThat; + +import org.junit.Test; +import org.mozilla.javascript.EcmaError; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.tools.shell.Global; + +public class RhinoContextEnvjsLoadingTest { + + @Test + public void loadEnvShouldSetWindowSpaceAndBeES5Complaint() { + RhinoContext context = new RhinoContext(); + + context.loadEnv("src/test/javascript"); + assertThat(context.evalJS("window")).isInstanceOf(Global.class); + + assertThat(context.evalJS("Object.create({ test: 'test' });")).isInstanceOf(NativeObject.class); + } + + @Test(expected = EcmaError.class) + public void failWithoutLoadingEnvAndManipulatingDOMStuff() { + RhinoContext context = new RhinoContext(); + context.evalJS("document.getElementById"); + } + +} diff --git a/src/test/java/be/cegeka/rhino/RhinoContextTest.java b/src/test/java/be/cegeka/rhino/RhinoContextTest.java new file mode 100755 index 0000000..bb6055f --- /dev/null +++ b/src/test/java/be/cegeka/rhino/RhinoContextTest.java @@ -0,0 +1,80 @@ +package be.cegeka.rhino; + +import static org.fest.assertions.Assertions.assertThat; + +import org.junit.Test; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.ScriptableObject; + +public class RhinoContextTest { + + @Test + public void executeFunctionOnPrototypeAndActualObject() { + RhinoContext context = new RhinoContext(); + String js = "" + + "var obj = function() {" + + " this.actual = function() { " + + " return 5; " + + " }" + + "};" + + "obj.prototype = {" + + " go : function() {" + + " return 3; " + + " }" + + "}"; + + context.evalJS(js); + ScriptableObject obj = (ScriptableObject) context.evalJS("new obj()"); + + assertThat(context.executeFunction(obj, "go")).isEqualTo(3.0); + assertThat(context.executeFunction(obj, "actual")).isEqualTo(5.0); + } + + @Test + public void runAsyncUsesTheSameSharedGlobalScope() throws InterruptedException { + RhinoContext baseContext = new RhinoContext(); + baseContext.evalJS("var base = 'base'"); + + baseContext.runAsync(new RhinoRunnable() { + + @Override + public void run(RhinoContext context) { + assertThat(context.evalJS("base")).isEqualTo("base"); + } + }); + + Thread.sleep(500); + } + + @Test(expected = IllegalStateException.class) + public void setPropertyOnUndefinedNotPossible() { + RhinoContext context = new RhinoContext(); + context.evalJS("var zever"); + context.setProperty("zever", "prop", 1); + } + + @Test(expected = IllegalStateException.class) + public void setPropertyOnNullNotPossible() { + RhinoContext context = new RhinoContext(); + context.setProperty(null, null, null); + } + + @Test + public void setPropertyOnSomeObj() { + RhinoContext context = new RhinoContext(); + + NativeObject anObj = (NativeObject) context.evalJS("var obj = { a: 'a'}; obj"); + context.setProperty("obj", "b", "b"); + + assertThat(anObj.get("b", anObj)).isEqualTo("b"); + } + + @Test + public void loadMultipleJSFiles() { + RhinoContext context = new RhinoContext(); + context.load("src/test/javascript/", "loadTest.js", "loadTestTwo.js"); + + assertThat(context.evalJS("loaded")).isEqualTo(true); + assertThat(context.evalJS("loadedTwo")).isEqualTo(true); + } +} diff --git a/src/test/javascript/envJsOptions.js b/src/test/javascript/envJsOptions.js new file mode 100755 index 0000000..165127f --- /dev/null +++ b/src/test/javascript/envJsOptions.js @@ -0,0 +1,12 @@ +/** + * Basic Envjs options set here (not part of a hack or util) + * See http://www.envjs.com/doc/apis + */ +Envjs({ + scriptTypes : { + '': true, //inline and anonymous + 'text/javascript': true, + 'text/envjs': false + }, + appCodeName: 'Mozilla' +}); diff --git a/src/test/javascript/lib/blank.html b/src/test/javascript/lib/blank.html new file mode 100755 index 0000000..e69de29 diff --git a/src/test/javascript/lib/env.rhino.1.2.js b/src/test/javascript/lib/env.rhino.1.2.js new file mode 100755 index 0000000..8f09b47 --- /dev/null +++ b/src/test/javascript/lib/env.rhino.1.2.js @@ -0,0 +1,13989 @@ +/* + * Envjs core-env.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +var Envjs = function(){ + var i, + name, + override = function(){ + for(i=0;i and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author john resig + */ +// 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; +} + +/** + * Writes message to system out + * @param {String} message + */ +Envjs.log = function(message){}; + +/** + * Constants providing enumerated levels for logging in modules + */ +Envjs.DEBUG = 1; +Envjs.INFO = 2; +Envjs.WARN = 3; +Envjs.ERROR = 3; +Envjs.NONE = 3; + +/** + * Writes error info out to console + * @param {Error} e + */ +Envjs.lineSource = function(e){}; + + +/** + * TODO: used in ./event/eventtarget.js + * @param {Object} event + */ +Envjs.defaultEventBehaviors = {}; + + +/** + * describes which script src values will trigger Envjs to load + * the script like a browser would + */ +Envjs.scriptTypes = { + "text/javascript" :false, + "text/envjs" :true +}; + +/** + * will be called when loading a script throws an error + * @param {Object} script + * @param {Object} e + */ +Envjs.onScriptLoadError = function(script, e){ + console.log('error loading script %s %s', script, e); +}; + + +/** + * load and execute script tag text content + * @param {Object} script + */ +Envjs.loadInlineScript = function(script){ + var tmpFile; + tmpFile = Envjs.writeToTempFile(script.text, 'js') ; + load(tmpFile); +}; + +/** + * Should evaluate script in some context + * @param {Object} context + * @param {Object} source + * @param {Object} name + */ +Envjs.eval = function(context, source, name){}; + + +/** + * Executes a script tag + * @param {Object} script + * @param {Object} parser + */ +Envjs.loadLocalScript = function(script){ + //console.log("loading script %s", script); + var types, + src, + i, + base, + filename, + xhr; + + if(script.type){ + types = script.type.split(";"); + for(i=0;i + * - Via an innerHTML parse of a + * - A modificiation of the 'src' attribute of an Image/HTMLImageElement + * + * NOTE: this is optional API. If this doesn't exist then the default + * 'loaded' event occurs. + * + * @param node {Object} the node + * @param node the src value + * @return 'true' to indicate the 'load' succeed, false otherwise + */ +Envjs.loadImage = function(node, src) { + return true; +}; + + +/** + * A 'link' was requested by the document. Typically this occurs when: + * - During inital parse of a + * - Via an innerHTML parse of a + * - A modificiation of the 'href' attribute on a node in the tree + * + * @param node {Object} is the link node in question + * @param href {String} is the href. + * + * Return 'true' to indicate that the 'load' was successful, or false + * otherwise. The appropriate event is then triggered. + * + * NOTE: this is optional API. If this doesn't exist then the default + * 'loaded' event occurs + */ +Envjs.loadLink = function(node, href) { + return true; +}; + +(function(){ + + +/* + * cookie handling + * Private internal helper class used to save/retreive cookies + */ + +/** + * Specifies the location of the cookie file + */ +Envjs.cookieFile = function(){ + return 'file://'+Envjs.homedir+'/.cookies'; +}; + +/** + * saves cookies to a local file + * @param {Object} htmldoc + */ +Envjs.saveCookies = function(){ + var cookiejson = JSON.stringify(Envjs.cookies.peristent,null,'\t'); + //console.log('persisting cookies %s', cookiejson); + Envjs.writeToFile(cookiejson, Envjs.cookieFile()); +}; + +/** + * loads cookies from a local file + * @param {Object} htmldoc + */ +Envjs.loadCookies = function(){ + var cookiejson, + js; + try{ + cookiejson = Envjs.readFromFile(Envjs.cookieFile()) + js = JSON.parse(cookiejson, null, '\t'); + }catch(e){ + //console.log('failed to load cookies %s', e); + js = {}; + } + return js; +}; + +Envjs.cookies = { + persistent:{ + //domain - key on domain name { + //path - key on path { + //name - key on name { + //value : cookie value + //other cookie properties + //} + //} + //} + //expire - provides a timestamp for expiring the cookie + //cookie - the cookie! + }, + temporary:{//transient is a reserved word :( + //like above + } +}; + +var __cookies__; + +//HTMLDocument cookie +Envjs.setCookie = function(url, cookie){ + var i, + index, + name, + value, + properties = {}, + attr, + attrs; + url = Envjs.urlsplit(url); + if(cookie) + attrs = cookie.split(";"); + else + return; + + //for now the strategy is to simply create a json object + //and post it to a file in the .cookies.js file. I hate parsing + //dates so I decided not to implement support for 'expires' + //(which is deprecated) and instead focus on the easier 'max-age' + //(which succeeds 'expires') + cookie = {};//keyword properties of the cookie + cookie['domain'] = url.hostname; + cookie['path'] = url.path||'/'; + for(i=0;i -1){ + name = __trim__(attrs[i].slice(0,index)); + value = __trim__(attrs[i].slice(index+1)); + if(name=='max-age'){ + //we'll have to when to check these + //and garbage collect expired cookies + cookie[name] = parseInt(value, 10); + } else if( name == 'domain' ){ + if(__domainValid__(url, value)){ + cookie['domain'] = value; + } + } else if( name == 'path' ){ + //not sure of any special logic for path + cookie['path'] = value; + } else { + //its not a cookie keyword so store it in our array of properties + //and we'll serialize individually in a moment + properties[name] = value; + } + }else{ + if( attrs[i] == 'secure' ){ + cookie[attrs[i]] = true; + } + } + } + if(!('max-age' in cookie)){ + //it's a transient cookie so it only lasts as long as + //the window.location remains the same (ie in-memory cookie) + __mergeCookie__(Envjs.cookies.temporary, cookie, properties); + }else{ + //the cookie is persistent + __mergeCookie__(Envjs.cookies.persistent, cookie, properties); + Envjs.saveCookies(); + } +}; + +function __domainValid__(url, value){ + var i, + domainParts = url.hostname.split('.').reverse(), + newDomainParts = value.split('.').reverse(); + if(newDomainParts.length > 1){ + for(i=0;i -1) { + for (name in cookies[domain][path]) { + // console.log('cookie domain path name %s', name); + cookieString += + ((i++ > 0)?'; ':'') + + name + "=" + + cookies[domain][path][name].value; + } + } + } + } + } + return cookieString; +}; + +function __mergeCookie__(target, cookie, properties){ + var name, now; + if(!target[cookie.domain]){ + target[cookie.domain] = {}; + } + if(!target[cookie.domain][cookie.path]){ + target[cookie.domain][cookie.path] = {}; + } + for(name in properties){ + now = new Date().getTime(); + target[cookie.domain][cookie.path][name] = { + "value":properties[name], + "secure":cookie.secure, + "max-age":cookie['max-age'], + "date-created":now, + "expiration":(cookie['max-age']===0) ? + 0 : + now + cookie['max-age'] + }; + //console.log('cookie is %o',target[cookie.domain][cookie.path][name]); + } +}; + +})();//end cookies +/* + http://www.JSON.org/json2.js + 2008-07-15 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. +*/ +try{ JSON; }catch(e){ +JSON = function () { + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + Date.prototype.toJSON = function (key) { + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + String.prototype.toJSON = function (key) { + return String(this); + }; + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + + escapeable.lastIndex = 0; + return escapeable.test(string) ? + '"' + string.replace(escapeable, function (a) { + var c = meta[a]; + if (typeof c === 'string') { + return c; + } + return '\\u' + ('0000' + + (+(a.charCodeAt(0))).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + + return String(value); + + case 'object': + + if (!value) { + return 'null'; + } + gap += indent; + partial = []; + + if (typeof value.length === 'number' && + !(value.propertyIsEnumerable('length'))) { + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + + return { + stringify: function (value, replacer, space) { + + var i; + gap = ''; + indent = ''; + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + + } else if (typeof space === 'string') { + indent = space; + } + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + + return str('', {'': value}); + }, + + + parse: function (text, reviver) { + var j; + function walk(holder, key) { + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + ('0000' + + (+(a.charCodeAt(0))).toString(16)).slice(-4); + }); + } + + + if (/^[\],:{}\s]*$/. +test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). +replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). +replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + j = eval('(' + text + ')'); + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + + throw new SyntaxError('JSON.parse'); + } + }; +}(); + +} + +/** + * synchronizes thread modifications + * @param {Function} fn + */ +Envjs.sync = function(fn){}; + +/** + * sleep thread for specified duration + * @param {Object} millseconds + */ +Envjs.sleep = function(millseconds){}; + +/** + * Interval to wait on event loop when nothing is happening + */ +Envjs.WAIT_INTERVAL = 20;//milliseconds + +/* + * Copyright (c) 2010 Nick Galbreath + * http://code.google.com/p/stringencoders/source/browse/#svn/trunk/javascript + * + * 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. + */ + +/* + * url processing in the spirit of python's urlparse module + * see `pydoc urlparse` or + * http://docs.python.org/library/urlparse.html + * + * urlsplit: break apart a URL into components + * urlunsplit: reconsistute a URL from componets + * urljoin: join an absolute and another URL + * urldefrag: remove the fragment from a URL + * + * Take a look at the tests in urlparse-test.html + * + * On URL Normalization: + * + * urlsplit only does minor normalization the components Only scheme + * and hostname are lowercased urljoin does a bit more, normalizing + * paths with "." and "..". + + * urlnormalize adds additional normalization + * + * * removes default port numbers + * http://abc.com:80/ -> http://abc.com/, etc + * * normalizes path + * http://abc.com -> http://abc.com/ + * and other "." and ".." cleanups + * * if file, remove query and fragment + * + * It does not do: + * * normalizes escaped hex values + * http://abc.com/%7efoo -> http://abc.com/%7Efoo + * * normalize '+' <--> '%20' + * + * Differences with Python + * + * The javascript urlsplit returns a normal object with the following + * properties: scheme, netloc, hostname, port, path, query, fragment. + * All properties are read-write. + * + * In python, the resulting object is not a dict, but a specialized, + * read-only, and has alternative tuple interface (e.g. obj[0] == + * obj.scheme). It's not clear why such a simple function requires + * a unique datastructure. + * + * urlunsplit in javascript takes an duck-typed object, + * { scheme: 'http', netloc: 'abc.com', ...} + * while in * python it takes a list-like object. + * ['http', 'abc.com'... ] + * + * For all functions, the javascript version use + * hostname+port if netloc is missing. In python + * hostname+port were always ignored. + * + * Similar functionality in different languages: + * + * http://php.net/manual/en/function.parse-url.php + * returns assocative array but cannot handle relative URL + * + * TODO: test allowfragments more + * TODO: test netloc missing, but hostname present + */ + +var urlparse = {}; + +// Unlike to be useful standalone +// +// NORMALIZE PATH with "../" and "./" +// http://en.wikipedia.org/wiki/URL_normalization +// http://tools.ietf.org/html/rfc3986#section-5.2.3 +// +urlparse.normalizepath = function(path) +{ + if (!path || path === '/') { + return '/'; + } + + var parts = path.split('/'); + + var newparts = []; + // make sure path always starts with '/' + if (parts[0]) { + newparts.push(''); + } + + for (var i = 0; i < parts.length; ++i) { + if (parts[i] === '..') { + if (newparts.length > 1) { + newparts.pop(); + } else { + newparts.push(parts[i]); + } + } else if (parts[i] != '.') { + newparts.push(parts[i]); + } + } + + path = newparts.join('/'); + if (!path) { + path = '/'; + } + return path; +}; + +// +// Does many of the normalizations that the stock +// python urlsplit/urlunsplit/urljoin neglects +// +// Doesn't do hex-escape normalization on path or query +// %7e -> %7E +// Nor, '+' <--> %20 translation +// +urlparse.urlnormalize = function(url) +{ + var parts = urlparse.urlsplit(url); + switch (parts.scheme) { + case 'file': + // files can't have query strings + // and we don't bother with fragments + parts.query = ''; + parts.fragment = ''; + break; + case 'http': + case 'https': + // remove default port + if ((parts.scheme === 'http' && parts.port == 80) || + (parts.scheme === 'https' && parts.port == 443)) { + parts.port = null; + // hostname is already lower case + parts.netloc = parts.hostname; + } + break; + default: + // if we don't have specific normalizations for this + // scheme, return the original url unmolested + return url; + } + + // for [file|http|https]. Not sure about other schemes + parts.path = urlparse.normalizepath(parts.path); + + return urlparse.urlunsplit(parts); +}; + +urlparse.urldefrag = function(url) +{ + var idx = url.indexOf('#'); + if (idx == -1) { + return [ url, '' ]; + } else { + return [ url.substr(0,idx), url.substr(idx+1) ]; + } +}; + +urlparse.urlsplit = function(url, default_scheme, allow_fragments) +{ + var leftover; + + if (typeof allow_fragments === 'undefined') { + allow_fragments = true; + } + + // scheme (optional), host, port + var fullurl = /^([A-Za-z]+)?(:?\/\/)([0-9.\-A-Za-z]*)(?::(\d+))?(.*)$/; + // path, query, fragment + var parse_leftovers = /([^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/; + + var o = {}; + + var parts = url.match(fullurl); + if (parts) { + o.scheme = parts[1] || default_scheme || ''; + o.hostname = parts[3].toLowerCase() || ''; + o.port = parseInt(parts[4],10) || ''; + // Probably should grab the netloc from regexp + // and then parse again for hostname/port + + o.netloc = parts[3]; + if (parts[4]) { + o.netloc += ':' + parts[4]; + } + + leftover = parts[5]; + } else { + o.scheme = default_scheme || ''; + o.netloc = ''; + o.hostname = ''; + leftover = url; + } + o.scheme = o.scheme.toLowerCase(); + + parts = leftover.match(parse_leftovers); + + o.path = parts[1] || ''; + o.query = parts[2] || ''; + + if (allow_fragments) { + o.fragment = parts[3] || ''; + } else { + o.fragment = ''; + } + + return o; +}; + +urlparse.urlunsplit = function(o) { + var s = ''; + if (o.scheme) { + s += o.scheme + '://'; + } + + if (o.netloc) { + if (s == '') { + s += '//'; + } + s += o.netloc; + } else if (o.hostname) { + // extension. Python only uses netloc + if (s == '') { + s += '//'; + } + s += o.hostname; + if (o.port) { + s += ':' + o.port; + } + } + + if (o.path) { + s += o.path; + } + + if (o.query) { + s += '?' + o.query; + } + if (o.fragment) { + s += '#' + o.fragment; + } + return s; +}; + +urlparse.urljoin = function(base, url, allow_fragments) +{ + if (typeof allow_fragments === 'undefined') { + allow_fragments = true; + } + + var url_parts = urlparse.urlsplit(url); + + // if url parts has a scheme (i.e. absolute) + // then nothing to do + if (url_parts.scheme) { + if (! allow_fragments) { + return url; + } else { + return urlparse.urldefrag(url)[0]; + } + } + var base_parts = urlparse.urlsplit(base); + + // copy base, only if not present + if (!base_parts.scheme) { + base_parts.scheme = url_parts.scheme; + } + + // copy netloc, only if not present + if (!base_parts.netloc || !base_parts.hostname) { + base_parts.netloc = url_parts.netloc; + base_parts.hostname = url_parts.hostname; + base_parts.port = url_parts.port; + } + + // paths + if (url_parts.path.length > 0) { + if (url_parts.path.charAt(0) == '/') { + base_parts.path = url_parts.path; + } else { + // relative path.. get rid of "current filename" and + // replace. Same as var parts = + // base_parts.path.split('/'); parts[parts.length-1] = + // url_parts.path; base_parts.path = parts.join('/'); + var idx = base_parts.path.lastIndexOf('/'); + if (idx == -1) { + base_parts.path = url_parts.path; + } else { + base_parts.path = base_parts.path.substr(0,idx) + '/' + + url_parts.path; + } + } + } + + // clean up path + base_parts.path = urlparse.normalizepath(base_parts.path); + + // copy query string + base_parts.query = url_parts.query; + + // copy fragments + if (allow_fragments) { + base_parts.fragment = url_parts.fragment; + } else { + base_parts.fragment = ''; + } + + return urlparse.urlunsplit(base_parts); +}; + +/** + * getcwd - named after posix call of same name (see 'man 2 getcwd') + * + */ +Envjs.getcwd = function() { + return '.'; +}; + +/** + * resolves location relative to doc location + * + * @param {Object} path Relative or absolute URL + * @param {Object} base (semi-optional) The base url used in resolving "path" above + */ +Envjs.uri = function(path, base) { + //console.log('constructing uri from path %s and base %s', path, base); + + // Semi-common trick is to make an iframe with src='javascript:false' + // (or some equivalent). By returning '', the load is skipped + if (path.indexOf('javascript') === 0) { + return ''; + } + + // if path is absolute, then just normalize and return + if (path.match('^[a-zA-Z]+://')) { + return urlparse.urlnormalize(path); + } + + // interesting special case, a few very large websites use + // '//foo/bar/' to mean 'http://foo/bar' + if (path.match('^//')) { + path = 'http:' + path; + } + + // if base not passed in, try to get it from document + // Ideally I would like the caller to pass in document.baseURI to + // make this more self-sufficient and testable + if (!base && document) { + base = document.baseURI; + } + + // about:blank doesn't count + if (base === 'about:blank'){ + base = ''; + } + + // if base is still empty, then we are in QA mode loading local + // files. Get current working directory + if (!base) { + base = 'file://' + Envjs.getcwd() + '/'; + } + // handles all cases if path is abosulte or relative to base + // 3rd arg is "false" --> remove fragments + var newurl = urlparse.urlnormalize(urlparse.urljoin(base, path, false)); + + return newurl; +}; + + + +/** + * Used in the XMLHttpRquest implementation to run a + * request in a seperate thread + * @param {Object} fn + */ +Envjs.runAsync = function(fn){}; + + +/** + * Used to write to a local file + * @param {Object} text + * @param {Object} url + */ +Envjs.writeToFile = function(text, url){}; + + +/** + * Used to write to a local file + * @param {Object} text + * @param {Object} suffix + */ +Envjs.writeToTempFile = function(text, suffix){}; + +/** + * Used to read the contents of a local file + * @param {Object} url + */ +Envjs.readFromFile = function(url){}; + +/** + * Used to delete a local file + * @param {Object} url + */ +Envjs.deleteFile = function(url){}; + +/** + * establishes connection and calls responsehandler + * @param {Object} xhr + * @param {Object} responseHandler + * @param {Object} data + */ +Envjs.connection = function(xhr, responseHandler, data){}; + + +__extend__(Envjs, urlparse); + +/** + * Makes an object window-like by proxying object accessors + * @param {Object} scope + * @param {Object} parent + */ +Envjs.proxy = function(scope, parent, aliasList){}; + +Envjs.javaEnabled = false; + +Envjs.homedir = ''; +Envjs.tmpdir = ''; +Envjs.os_name = ''; +Envjs.os_arch = ''; +Envjs.os_version = ''; +Envjs.lang = ''; +Envjs.platform = ''; + +/** + * + * @param {Object} frameElement + * @param {Object} url + */ +Envjs.loadFrame = function(frame, url){ + try { + if(frame.contentWindow){ + //mark for garbage collection + frame.contentWindow = null; + } + + //create a new scope for the window proxy + //platforms will need to override this function + //to make sure the scope is global-like + frame.contentWindow = (function(){return this;})(); + new Window(frame.contentWindow, window); + + //I dont think frames load asynchronously in firefox + //and I think the tests have verified this but for + //some reason I'm less than confident... Are there cases? + frame.contentDocument = frame.contentWindow.document; + frame.contentDocument.async = false; + if(url){ + //console.log('envjs.loadFrame async %s', frame.contentDocument.async); + frame.contentWindow.location = url; + } + } catch(e) { + console.log("failed to load frame content: from %s %s", url, e); + } +}; + + +// The following are in rhino/window.js +// TODO: Envjs.unloadFrame +// TODO: Envjs.proxy + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); +/* + * Envjs rhino-env.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +var __context__ = Packages.org.mozilla.javascript.Context.getCurrentContext(); + +Envjs.platform = "Rhino"; +Envjs.revision = "1.7.0.rc2"; + +/* + * Envjs rhino-env.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author john resig + */ +// 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; +} + +/** + * Writes message to system out. + * + * Some sites redefine 'print' as in 'window.print', so instead of + * printing to stdout, you are popping open a new window, which might + * call print, etc, etc,etc This can cause infinite loops and can + * exhausing all memory. + * + * By defining this upfront now, Envjs.log will always call the native 'print' + * function + * + * @param {Object} message + */ +Envjs.log = print; + +Envjs.lineSource = function(e){ + return e&&e.rhinoException?e.rhinoException.lineSource():"(line ?)"; +}; +/** + * load and execute script tag text content + * @param {Object} script + */ +Envjs.loadInlineScript = function(script){ + if(script.ownerDocument.ownerWindow){ + Envjs.eval( + script.ownerDocument.ownerWindow, + script.text, + 'eval('+script.text.substring(0,16)+'...):'+new Date().getTime() + ); + }else{ + Envjs.eval( + __this__, + script.text, + 'eval('+script.text.substring(0,16)+'...):'+new Date().getTime() + ); + } + //console.log('evaluated at scope %s \n%s', + // script.ownerDocument.ownerWindow.guid, script.text); +}; + + +Envjs.eval = function(context, source, name){ + __context__.evaluateString( + context, + source, + name, + 0, + null + ); +}; + +//Temporary patch for parser module +Packages.org.mozilla.javascript.Context. + getCurrentContext().setOptimizationLevel(-1); + +/** + * Rhino provides a very succinct 'sync' + * @param {Function} fn + */ +try{ + Envjs.sync = sync; + Envjs.spawn = spawn; +} catch(e){ + //sync unavailable on AppEngine + Envjs.sync = function(fn){ + //console.log('Threadless platform, sync is safe'); + return fn; + }; + + Envjs.spawn = function(fn){ + //console.log('Threadless platform, spawn shares main thread.'); + return fn(); + }; +} + +/** + * sleep thread for specified duration + * @param {Object} millseconds + */ +Envjs.sleep = function(millseconds){ + try{ + java.lang.Thread.currentThread().sleep(millseconds); + }catch(e){ + console.log('Threadless platform, cannot sleep.'); + } +}; + +/** + * provides callback hook for when the system exits + */ +Envjs.onExit = function(callback){ + var rhino = Packages.org.mozilla.javascript, + contextFactory = __context__.getFactory(), + listener = new rhino.ContextFactory.Listener({ + contextReleased: function(context){ + if(context === __context__) + console.log('context released', context); + contextFactory.removeListener(this); + if(callback) + callback(); + } + }); + contextFactory.addListener(listener); +}; + +/** + * Get 'Current Working Directory' + */ +Envjs.getcwd = function() { + return java.lang.System.getProperty('user.dir'); +} + +/** + * + * @param {Object} fn + * @param {Object} onInterupt + */ +Envjs.runAsync = function(fn, onInterupt){ + ////Envjs.debug("running async"); + var running = true, + run; + + try{ + run = Envjs.sync(function(){ + fn(); + Envjs.wait(); + }); + Envjs.spawn(run); + }catch(e){ + console.log("error while running async operation", e); + try{if(onInterrupt)onInterrupt(e)}catch(ee){}; + } +}; + +/** + * Used to write to a local file + * @param {Object} text + * @param {Object} url + */ +Envjs.writeToFile = function(text, url){ + //Envjs.debug("writing text to url : " + url); + var out = new java.io.FileWriter( + new java.io.File( + new java.net.URI(url.toString()))); + out.write( text, 0, text.length ); + out.flush(); + out.close(); +}; + +/** + * Used to write to a local file + * @param {Object} text + * @param {Object} suffix + */ +Envjs.writeToTempFile = function(text, suffix){ + //Envjs.debug("writing text to temp url : " + suffix); + // Create temp file. + var temp = java.io.File.createTempFile("envjs-tmp", suffix); + + // Delete temp file when program exits. + temp.deleteOnExit(); + + // Write to temp file + var out = new java.io.FileWriter(temp); + out.write(text, 0, text.length); + out.close(); + return temp.getAbsolutePath().toString()+''; +}; + + +/** + * Used to read the contents of a local file + * @param {Object} url + */ +Envjs.readFromFile = function( url ){ + var fileReader = new java.io.FileReader( + new java.io.File( + new java.net.URI( url ))); + + var stringwriter = new java.io.StringWriter(), + buffer = java.lang.reflect.Array.newInstance(java.lang.Character.TYPE, 1024), + length; + + while ((length = fileReader.read(buffer, 0, 1024)) != -1) { + stringwriter.write(buffer, 0, length); + } + + stringwriter.close(); + return stringwriter.toString()+""; +}; + + +/** + * Used to delete a local file + * @param {Object} url + */ +Envjs.deleteFile = function(url){ + var file = new java.io.File( new java.net.URI( url ) ); + file["delete"](); +}; + +/** + * establishes connection and calls responsehandler + * @param {Object} xhr + * @param {Object} responseHandler + * @param {Object} data + */ +Envjs.connection = function(xhr, responseHandler, data){ + var url = java.net.URL(xhr.url), + connection, + header, + outstream, + buffer, + length, + binary = false, + name, value, + contentEncoding, + instream, + responseXML, + i; + if ( /^file\:/.test(url) ) { + try{ + if ( "PUT" == xhr.method || "POST" == xhr.method ) { + data = data || "" ; + Envjs.writeToFile(data, url); + xhr.readyState = 4; + //could be improved, I just cant recall the correct http codes + xhr.status = 200; + xhr.statusText = ""; + } else if ( xhr.method == "DELETE" ) { + Envjs.deleteFile(url); + xhr.readyState = 4; + //could be improved, I just cant recall the correct http codes + xhr.status = 200; + xhr.statusText = ""; + } else { + connection = url.openConnection(); + connection.connect(); + //try to add some canned headers that make sense + + try{ + if(xhr.url.match(/html$/)){ + xhr.responseHeaders["Content-Type"] = 'text/html'; + }else if(xhr.url.match(/.xml$/)){ + xhr.responseHeaders["Content-Type"] = 'text/xml'; + }else if(xhr.url.match(/.js$/)){ + xhr.responseHeaders["Content-Type"] = 'text/javascript'; + }else if(xhr.url.match(/.json$/)){ + xhr.responseHeaders["Content-Type"] = 'application/json'; + }else{ + xhr.responseHeaders["Content-Type"] = 'text/plain'; + } + //xhr.responseHeaders['Last-Modified'] = connection.getLastModified(); + //xhr.responseHeaders['Content-Length'] = headerValue+''; + //xhr.responseHeaders['Date'] = new Date()+'';*/ + }catch(e){ + console.log('failed to load response headers',e); + } + } + }catch(e){ + console.log('failed to open file %s %s', url, e); + connection = null; + xhr.readyState = 4; + xhr.statusText = "Local File Protocol Error"; + xhr.responseText = "

"+ e+ "

"; + } + } else { + connection = url.openConnection(); + connection.setRequestMethod( xhr.method ); + + // Add headers to Java connection + for (header in xhr.headers){ + connection.addRequestProperty(header+'', xhr.headers[header]+''); + } + + //write data to output stream if required + if(data){ + if(data instanceof Document){ + if ( xhr.method == "PUT" || xhr.method == "POST" ) { + connection.setDoOutput(true); + outstream = connection.getOutputStream(), + xml = (new XMLSerializer()).serializeToString(data); + buffer = new java.lang.String(xml).getBytes('UTF-8'); + outstream.write(buffer, 0, buffer.length); + outstream.close(); + } + }else if(data.length&&data.length>0){ + if ( xhr.method == "PUT" || xhr.method == "POST" ) { + connection.setDoOutput(true); + outstream = connection.getOutputStream(); + buffer = new java.lang.String(data).getBytes('UTF-8'); + outstream.write(buffer, 0, buffer.length); + outstream.close(); + } + } + connection.connect(); + }else{ + connection.connect(); + } + } + + if(connection){ + try{ + length = connection.getHeaderFields().size(); + // Stick the response headers into responseHeaders + for (i = 0; i < length; i++) { + name = connection.getHeaderFieldKey(i); + value = connection.getHeaderField(i); + if (name) + xhr.responseHeaders[name+''] = value+''; + } + }catch(e){ + console.log('failed to load response headers \n%s',e); + } + + xhr.readyState = 4; + xhr.status = parseInt(connection.responseCode,10) || undefined; + xhr.statusText = connection.responseMessage || ""; + + contentEncoding = connection.getContentEncoding() || "utf-8"; + instream = null; + responseXML = null; + + try{ + //console.log('contentEncoding %s', contentEncoding); + if( contentEncoding.equalsIgnoreCase("gzip") || + contentEncoding.equalsIgnoreCase("decompress")){ + //zipped content + binary = true; + outstream = new java.io.ByteArrayOutputStream(); + buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1024); + instream = new java.util.zip.GZIPInputStream(connection.getInputStream()) + }else{ + //this is a text file + outstream = new java.io.StringWriter(); + buffer = java.lang.reflect.Array.newInstance(java.lang.Character.TYPE, 1024); + instream = new java.io.InputStreamReader(connection.getInputStream()); + } + }catch(e){ + if (connection.getResponseCode() == 404){ + console.log('failed to open connection stream \n %s %s', + e.toString(), e); + }else{ + console.log('failed to open connection stream \n %s %s', + e.toString(), e); + } + instream = connection.getErrorStream(); + } + + while ((length = instream.read(buffer, 0, 1024)) != -1) { + outstream.write(buffer, 0, length); + } + + outstream.close(); + instream.close(); + + if(binary){ + xhr.responseText = new String(outstream.toByteArray(), 'UTF-8') + ''; + }else{ + xhr.responseText = outstream.toString() + ''; + } + + } + if(responseHandler){ + //Envjs.debug('calling ajax response handler'); + responseHandler(); + } +}; + +//Since we're running in rhino I guess we can safely assume +//java is 'enabled'. I'm sure this requires more thought +//than I've given it here +Envjs.javaEnabled = true; + +Envjs.homedir = java.lang.System.getProperty("user.home"); +Envjs.tmpdir = java.lang.System.getProperty("java.io.tmpdir"); +Envjs.os_name = java.lang.System.getProperty("os.name"); +Envjs.os_arch = java.lang.System.getProperty("os.arch"); +Envjs.os_version = java.lang.System.getProperty("os.version"); +Envjs.lang = java.lang.System.getProperty("user.lang"); + + +/** + * + * @param {Object} frameElement + * @param {Object} url + */ +Envjs.loadFrame = function(frame, url){ + try { + if(frame.contentWindow){ + //mark for garbage collection + frame.contentWindow = null; + } + + //create a new scope for the window proxy + frame.contentWindow = Envjs.proxy(); + new Window(frame.contentWindow, window); + + //I dont think frames load asynchronously in firefox + //and I think the tests have verified this but for + //some reason I'm less than confident... Are there cases? + frame.contentDocument = frame.contentWindow.document; + frame.contentDocument.async = false; + if(url){ + //console.log('envjs.loadFrame async %s', frame.contentDocument.async); + frame.contentWindow.location = url; + } + } catch(e) { + console.log("failed to load frame content: from %s %s", url, e); + } +}; + +/** + * unloadFrame + * @param {Object} frame + */ +Envjs.unloadFrame = function(frame){ + var all, length, i; + try{ + //TODO: probably self-referencing structures within a document tree + //preventing it from being entirely garbage collected once orphaned. + //Should have code to walk tree and break all links between contained + //objects. + frame.contentDocument = null; + if(frame.contentWindow){ + frame.contentWindow.close(); + } + gc(); + }catch(e){ + console.log(e); + } +}; + +/** + * Makes an object window-like by proxying object accessors + * @param {Object} scope + * @param {Object} parent + */ +Envjs.proxy = function(scope, parent) { + try{ + if(scope+'' == '[object global]'){ + return scope + }else{ + return __context__.initStandardObjects(); + } + }catch(e){ + console.log('failed to init standard objects %s %s \n%s', scope, parent, e); + } + +}; + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); + +/** + * @author envjs team + */ +var Console, + console; + +/* + * Envjs console.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author envjs team + * borrowed 99%-ish with love from firebug-lite + * + * http://wiki.commonjs.org/wiki/Console + */ +Console = function(module){ + var $level, + $logger, + $null = function(){}; + + + if(Envjs[module] && Envjs[module].loglevel){ + $level = Envjs.module.loglevel; + $logger = { + log: function(level){ + logFormatted(arguments, (module)+" "); + }, + debug: $level>1 ? $null: function() { + logFormatted(arguments, (module)+" debug"); + }, + info: $level>2 ? $null:function(){ + logFormatted(arguments, (module)+" info"); + }, + warn: $level>3 ? $null:function(){ + logFormatted(arguments, (module)+" warning"); + }, + error: $level>4 ? $null:function(){ + logFormatted(arguments, (module)+" error"); + } + }; + } else { + $logger = { + log: function(level){ + logFormatted(arguments, ""); + }, + debug: $null, + info: $null, + warn: $null, + error: $null + }; + } + + return $logger; +}; + +console = new Console("console",1); + +function logFormatted(objects, className) +{ + var html = []; + + var format = objects[0]; + var objIndex = 0; + + if (typeof(format) != "string") + { + format = ""; + objIndex = -1; + } + + var parts = parseFormat(format); + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + part.appender(object, html); + } + else { + appendText(part, html); + } + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + if (typeof(object) == "string") { + appendText(object, html); + } else { + appendObject(object, html); + } + } + + Envjs.log(html.join(' ')); +} + +function parseFormat(format) +{ + var parts = []; + + var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/; + var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat}; + + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + var type = m[8] ? m[8] : m[5]; + var appender = type in appenderMap ? appenderMap[type] : appendObject; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({appender: appender, precision: precision}); + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + + return parts; +} + +function escapeHTML(value) +{ + return value; +} + +function objectToString(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +} + +// ******************************************************************************************** + +function appendText(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendNull(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendString(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendInteger(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendFloat(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendFunction(object, html) +{ + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m ? m[1] : "function"; + html.push(escapeHTML(name)); +} + +function appendObject(object, html) +{ + try + { + if (object == undefined) { + appendNull("undefined", html); + } else if (object == null) { + appendNull("null", html); + } else if (typeof object == "string") { + appendString(object, html); + } else if (typeof object == "number") { + appendInteger(object, html); + } else if (typeof object == "function") { + appendFunction(object, html); + } else if (object.nodeType == 1) { + appendSelector(object, html); + } else if (typeof object == "object") { + appendObjectFormatted(object, html); + } else { + appendText(object, html); + } + } + catch (exc) + { + } +} + +function appendObjectFormatted(object, html) +{ + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push( m ? m[1] : text); +} + +function appendSelector(object, html) +{ + + html.push(escapeHTML(object.nodeName.toLowerCase())); + if (object.id) { + html.push(escapeHTML(object.id)); + } + if (object.className) { + html.push(escapeHTML(object.className)); + } +} + +function appendNode(node, html) +{ + if (node.nodeType == 1) + { + html.push( node.nodeName.toLowerCase()); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified) { + continue; + } + + html.push( attr.nodeName.toLowerCase(),escapeHTML(attr.nodeValue)); + } + + if (node.firstChild) + { + for (var child = node.firstChild; child; child = child.nextSibling) { + appendNode(child, html); + } + + html.push( node.nodeName.toLowerCase()); + } + } + else if (node.nodeType === 3) + { + html.push(escapeHTML(node.nodeValue)); + } +}; + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); +/* + * Envjs dom.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + * + * Parts of the implementation were originally written by:\ + * and Jon van Noort (jon@webarcana.com.au) \ + * and David Joham (djoham@yahoo.com)",\ + * and Scott Severtson + * + * This file simply provides the global definitions we need to \ + * be able to correctly implement to core browser DOM interfaces." + */ + +var Attr, + CDATASection, + CharacterData, + Comment, + Document, + DocumentFragment, + DocumentType, + DOMException, + DOMImplementation, + Element, + Entity, + EntityReference, + NamedNodeMap, + Namespace, + Node, + NodeList, + Notation, + ProcessingInstruction, + Text, + Range, + XMLSerializer, + DOMParser; + + + +/* + * Envjs dom.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author john resig + */ +// 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; +} + +/** + * @author john resig + */ +//from jQuery +function __setArray__( target, array ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + target.length = 0; + Array.prototype.push.apply( target, array ); +} + +/** + * @class NodeList - + * provides the abstraction of an ordered collection of nodes + * + * @param ownerDocument : Document - the ownerDocument + * @param parentNode : Node - the node that the NodeList is attached to (or null) + */ +NodeList = function(ownerDocument, parentNode) { + this.length = 0; + this.parentNode = parentNode; + this.ownerDocument = ownerDocument; + this._readonly = false; + __setArray__(this, []); +}; + +__extend__(NodeList.prototype, { + item : function(index) { + var ret = null; + if ((index >= 0) && (index < this.length)) { + // bounds check + ret = this[index]; + } + // if the index is out of bounds, default value null is returned + return ret; + }, + get xml() { + var ret = "", + i; + + // create string containing the concatenation of the string values of each child + for (i=0; i < this.length; i++) { + if(this[i]){ + if(this[i].nodeType == Node.TEXT_NODE && i>0 && + this[i-1].nodeType == Node.TEXT_NODE){ + //add a single space between adjacent text nodes + ret += " "+this[i].xml; + }else{ + ret += this[i].xml; + } + } + } + return ret; + }, + toArray: function () { + var children = [], + i; + for ( i=0; i < this.length; i++) { + children.push (this[i]); + } + return children; + }, + toString: function(){ + return "[object NodeList]"; + } +}); + + +/** + * @method __findItemIndex__ + * find the item index of the node + * @author Jon van Noort (jon@webarcana.com.au) + * @param node : Node + * @return : int + */ +var __findItemIndex__ = function (nodelist, node) { + var ret = -1, i; + for (i=0; i= 0) && (refChildIndex <= nodelist.length)) { + // bounds check + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // node is a DocumentFragment + // append the children of DocumentFragment + Array.prototype.splice.apply(nodelist, + [refChildIndex, 0].concat(newChild.childNodes.toArray())); + } + else { + // append the newChild + Array.prototype.splice.apply(nodelist,[refChildIndex, 0, newChild]); + } + } +}; + +/** + * @method __replaceChild__ + * replace the specified Node in the NodeList at the specified index + * Used by Node.replaceChild(). Note: Node.replaceChild() is responsible + * for Node Pointer surgery __replaceChild__ simply modifies the internal + * data structure (Array). + * + * @param newChild : Node - the Node to be inserted + * @param refChildIndex : int - the array index to hold the Node + */ +var __replaceChild__ = function(nodelist, newChild, refChildIndex) { + var ret = null; + + // bounds check + if ((refChildIndex >= 0) && (refChildIndex < nodelist.length)) { + // preserve old child for return + ret = nodelist[refChildIndex]; + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // node is a DocumentFragment + // get array containing children prior to refChild + Array.prototype.splice.apply(nodelist, + [refChildIndex, 1].concat(newChild.childNodes.toArray())); + } + else { + // simply replace node in array (links between Nodes are + // made at higher level) + nodelist[refChildIndex] = newChild; + } + } + // return replaced node + return ret; +}; + +/** + * @method __removeChild__ + * remove the specified Node in the NodeList at the specified index + * Used by Node.removeChild(). Note: Node.removeChild() is responsible + * for Node Pointer surgery __removeChild__ simply modifies the internal + * data structure (Array). + * @param refChildIndex : int - the array index holding the Node to be removed + */ +var __removeChild__ = function(nodelist, refChildIndex) { + var ret = null; + + if (refChildIndex > -1) { + // found it! + // return removed node + ret = nodelist[refChildIndex]; + + // rebuild array without removed child + Array.prototype.splice.apply(nodelist,[refChildIndex, 1]); + } + // return removed node + return ret; +}; + +/** + * @method __appendChild__ + * append the specified Node to the NodeList. Used by Node.appendChild(). + * Note: Node.appendChild() is responsible for Node Pointer surgery + * __appendChild__ simply modifies the internal data structure (Array). + * @param newChild : Node - the Node to be inserted + */ +var __appendChild__ = function(nodelist, newChild) { + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // node is a DocumentFragment + // append the children of DocumentFragment + Array.prototype.push.apply(nodelist, newChild.childNodes.toArray() ); + } else { + // simply add node to array (links between Nodes are made at higher level) + Array.prototype.push.apply(nodelist, [newChild]); + } + +}; + +/** + * @method __cloneNodes__ - + * Returns a NodeList containing clones of the Nodes in this NodeList + * @param deep : boolean - + * If true, recursively clone the subtree under each of the nodes; + * if false, clone only the nodes themselves (and their attributes, + * if it is an Element). + * @param parentNode : Node - the new parent of the cloned NodeList + * @return : NodeList - NodeList containing clones of the Nodes in this NodeList + */ +var __cloneNodes__ = function(nodelist, deep, parentNode) { + var cloneNodeList = new NodeList(nodelist.ownerDocument, parentNode); + + // create list containing clones of each child + for (var i=0; i < nodelist.length; i++) { + __appendChild__(cloneNodeList, nodelist[i].cloneNode(deep)); + } + + return cloneNodeList; +}; + + +var __ownerDocument__ = function(node){ + return (node.nodeType == Node.DOCUMENT_NODE)?node:node.ownerDocument; +}; + +/** + * @class Node - + * The Node interface is the primary datatype for the entire + * Document Object Model. It represents a single node in the + * document tree. + * @param ownerDocument : Document - The Document object associated with this node. + */ + +Node = function(ownerDocument) { + this.baseURI = 'about:blank'; + this.namespaceURI = null; + this.nodeName = ""; + this.nodeValue = null; + + // A NodeList that contains all children of this node. If there are no + // children, this is a NodeList containing no nodes. The content of the + // returned NodeList is "live" in the sense that, for instance, changes to + // the children of the node object that it was created from are immediately + // reflected in the nodes returned by the NodeList accessors; it is not a + // static snapshot of the content of the node. This is true for every + // NodeList, including the ones returned by the getElementsByTagName method. + this.childNodes = new NodeList(ownerDocument, this); + + // The first child of this node. If there is no such node, this is null + this.firstChild = null; + // The last child of this node. If there is no such node, this is null. + this.lastChild = null; + // The node immediately preceding this node. If there is no such node, + // this is null. + this.previousSibling = null; + // The node immediately following this node. If there is no such node, + // this is null. + this.nextSibling = null; + + this.attributes = null; + // The namespaces in scope for this node + this._namespaces = new NamespaceNodeMap(ownerDocument, this); + this._readonly = false; + + //IMPORTANT: These must come last so rhino will not iterate parent + // properties before child properties. (qunit.equiv issue) + + // The parent of this node. All nodes, except Document, DocumentFragment, + // and Attr may have a parent. However, if a node has just been created + // and not yet added to the tree, or if it has been removed from the tree, + // this is null + this.parentNode = null; + // The Document object associated with this node + this.ownerDocument = ownerDocument; + +}; + +// nodeType constants +Node.ELEMENT_NODE = 1; +Node.ATTRIBUTE_NODE = 2; +Node.TEXT_NODE = 3; +Node.CDATA_SECTION_NODE = 4; +Node.ENTITY_REFERENCE_NODE = 5; +Node.ENTITY_NODE = 6; +Node.PROCESSING_INSTRUCTION_NODE = 7; +Node.COMMENT_NODE = 8; +Node.DOCUMENT_NODE = 9; +Node.DOCUMENT_TYPE_NODE = 10; +Node.DOCUMENT_FRAGMENT_NODE = 11; +Node.NOTATION_NODE = 12; +Node.NAMESPACE_NODE = 13; + +Node.DOCUMENT_POSITION_EQUAL = 0x00; +Node.DOCUMENT_POSITION_DISCONNECTED = 0x01; +Node.DOCUMENT_POSITION_PRECEDING = 0x02; +Node.DOCUMENT_POSITION_FOLLOWING = 0x04; +Node.DOCUMENT_POSITION_CONTAINS = 0x08; +Node.DOCUMENT_POSITION_CONTAINED_BY = 0x10; +Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; + + +__extend__(Node.prototype, { + get localName(){ + return this.prefix? + this.nodeName.substring(this.prefix.length+1, this.nodeName.length): + this.nodeName; + }, + get prefix(){ + return this.nodeName.split(':').length>1? + this.nodeName.split(':')[0]: + null; + }, + set prefix(value){ + if(value === null){ + this.nodeName = this.localName; + }else{ + this.nodeName = value+':'+this.localName; + } + }, + hasAttributes : function() { + if (this.attributes.length == 0) { + return false; + }else{ + return true; + } + }, + get textContent(){ + return __recursivelyGatherText__(this); + }, + set textContent(newText){ + while(this.firstChild != null){ + this.removeChild( this.firstChild ); + } + var text = this.ownerDocument.createTextNode(newText); + this.appendChild(text); + }, + insertBefore : function(newChild, refChild) { + var prevNode; + + if(newChild==null){ + return newChild; + } + if(refChild==null){ + this.appendChild(newChild); + return this.newChild; + } + + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Node is readonly + if (this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if newChild was not created by this Document + if (__ownerDocument__(this) != __ownerDocument__(newChild)) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if the node is an ancestor + if (__isAncestor__(this, newChild)) { + throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); + } + } + + // if refChild is specified, insert before it + if (refChild) { + // find index of refChild + var itemIndex = __findItemIndex__(this.childNodes, refChild); + // throw Exception if there is no child node with this id + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // if the newChild is already in the tree, + var newChildParent = newChild.parentNode; + if (newChildParent) { + // remove it + newChildParent.removeChild(newChild); + } + + // insert newChild into childNodes + __insertBefore__(this.childNodes, newChild, itemIndex); + + // do node pointer surgery + prevNode = refChild.previousSibling; + + // handle DocumentFragment + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + if (newChild.childNodes.length > 0) { + // set the parentNode of DocumentFragment's children + for (var ind = 0; ind < newChild.childNodes.length; ind++) { + newChild.childNodes[ind].parentNode = this; + } + + // link refChild to last child of DocumentFragment + refChild.previousSibling = newChild.childNodes[newChild.childNodes.length-1]; + } + }else { + // set the parentNode of the newChild + newChild.parentNode = this; + // link refChild to newChild + refChild.previousSibling = newChild; + } + + }else { + // otherwise, append to end + prevNode = this.lastChild; + this.appendChild(newChild); + } + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // do node pointer surgery for DocumentFragment + if (newChild.childNodes.length > 0) { + if (prevNode) { + prevNode.nextSibling = newChild.childNodes[0]; + }else { + // this is the first child in the list + this.firstChild = newChild.childNodes[0]; + } + newChild.childNodes[0].previousSibling = prevNode; + newChild.childNodes[newChild.childNodes.length-1].nextSibling = refChild; + } + }else { + // do node pointer surgery for newChild + if (prevNode) { + prevNode.nextSibling = newChild; + }else { + // this is the first child in the list + this.firstChild = newChild; + } + newChild.previousSibling = prevNode; + newChild.nextSibling = refChild; + } + + return newChild; + }, + replaceChild : function(newChild, oldChild) { + var ret = null; + + if(newChild==null || oldChild==null){ + return oldChild; + } + + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Node is readonly + if (this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if newChild was not created by this Document + if (__ownerDocument__(this) != __ownerDocument__(newChild)) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if the node is an ancestor + if (__isAncestor__(this, newChild)) { + throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); + } + } + + // get index of oldChild + var index = __findItemIndex__(this.childNodes, oldChild); + + // throw Exception if there is no child node with this id + if (__ownerDocument__(this).implementation.errorChecking && (index < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // if the newChild is already in the tree, + var newChildParent = newChild.parentNode; + if (newChildParent) { + // remove it + newChildParent.removeChild(newChild); + } + + // add newChild to childNodes + ret = __replaceChild__(this.childNodes,newChild, index); + + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // do node pointer surgery for Document Fragment + if (newChild.childNodes.length > 0) { + for (var ind = 0; ind < newChild.childNodes.length; ind++) { + newChild.childNodes[ind].parentNode = this; + } + + if (oldChild.previousSibling) { + oldChild.previousSibling.nextSibling = newChild.childNodes[0]; + } else { + this.firstChild = newChild.childNodes[0]; + } + + if (oldChild.nextSibling) { + oldChild.nextSibling.previousSibling = newChild; + } else { + this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; + } + + newChild.childNodes[0].previousSibling = oldChild.previousSibling; + newChild.childNodes[newChild.childNodes.length-1].nextSibling = oldChild.nextSibling; + } + } else { + // do node pointer surgery for newChild + newChild.parentNode = this; + + if (oldChild.previousSibling) { + oldChild.previousSibling.nextSibling = newChild; + }else{ + this.firstChild = newChild; + } + if (oldChild.nextSibling) { + oldChild.nextSibling.previousSibling = newChild; + }else{ + this.lastChild = newChild; + } + newChild.previousSibling = oldChild.previousSibling; + newChild.nextSibling = oldChild.nextSibling; + } + + return ret; + }, + removeChild : function(oldChild) { + if(!oldChild){ + return null; + } + // throw Exception if NamedNodeMap is readonly + if (__ownerDocument__(this).implementation.errorChecking && + (this._readonly || oldChild._readonly)) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // get index of oldChild + var itemIndex = __findItemIndex__(this.childNodes, oldChild); + + // throw Exception if there is no child node with this id + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // remove oldChild from childNodes + __removeChild__(this.childNodes, itemIndex); + + // do node pointer surgery + oldChild.parentNode = null; + + if (oldChild.previousSibling) { + oldChild.previousSibling.nextSibling = oldChild.nextSibling; + }else { + this.firstChild = oldChild.nextSibling; + } + if (oldChild.nextSibling) { + oldChild.nextSibling.previousSibling = oldChild.previousSibling; + }else { + this.lastChild = oldChild.previousSibling; + } + + oldChild.previousSibling = null; + oldChild.nextSibling = null; + + return oldChild; + }, + appendChild : function(newChild) { + if(!newChild){ + return null; + } + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Node is readonly + if (this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if arg was not created by this Document + if (__ownerDocument__(this) != __ownerDocument__(this)) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if the node is an ancestor + if (__isAncestor__(this, newChild)) { + throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); + } + } + + // if the newChild is already in the tree, + var newChildParent = newChild.parentNode; + if (newChildParent) { + // remove it + //console.debug('removing node %s', newChild); + newChildParent.removeChild(newChild); + } + + // add newChild to childNodes + __appendChild__(this.childNodes, newChild); + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // do node pointer surgery for DocumentFragment + if (newChild.childNodes.length > 0) { + for (var ind = 0; ind < newChild.childNodes.length; ind++) { + newChild.childNodes[ind].parentNode = this; + } + + if (this.lastChild) { + this.lastChild.nextSibling = newChild.childNodes[0]; + newChild.childNodes[0].previousSibling = this.lastChild; + this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; + } else { + this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; + this.firstChild = newChild.childNodes[0]; + } + } + } else { + // do node pointer surgery for newChild + newChild.parentNode = this; + if (this.lastChild) { + this.lastChild.nextSibling = newChild; + newChild.previousSibling = this.lastChild; + this.lastChild = newChild; + } else { + this.lastChild = newChild; + this.firstChild = newChild; + } + } + return newChild; + }, + hasChildNodes : function() { + return (this.childNodes.length > 0); + }, + cloneNode: function(deep) { + // use importNode to clone this Node + //do not throw any exceptions + try { + return __ownerDocument__(this).importNode(this, deep); + } catch (e) { + //there shouldn't be any exceptions, but if there are, return null + // may want to warn: $debug("could not clone node: "+e.code); + return null; + } + }, + normalize : function() { + var i; + var inode; + var nodesToRemove = new NodeList(); + + if (this.nodeType == Node.ELEMENT_NODE || this.nodeType == Node.DOCUMENT_NODE) { + var adjacentTextNode = null; + + // loop through all childNodes + for(i = 0; i < this.childNodes.length; i++) { + inode = this.childNodes.item(i); + + if (inode.nodeType == Node.TEXT_NODE) { + // this node is a text node + if (inode.length < 1) { + // this text node is empty + // add this node to the list of nodes to be remove + __appendChild__(nodesToRemove, inode); + }else { + if (adjacentTextNode) { + // previous node was also text + adjacentTextNode.appendData(inode.data); + // merge the data in adjacent text nodes + // add this node to the list of nodes to be removed + __appendChild__(nodesToRemove, inode); + } else { + // remember this node for next cycle + adjacentTextNode = inode; + } + } + } else { + // (soon to be) previous node is not a text node + adjacentTextNode = null; + // normalize non Text childNodes + inode.normalize(); + } + } + + // remove redundant Text Nodes + for(i = 0; i < nodesToRemove.length; i++) { + inode = nodesToRemove.item(i); + inode.parentNode.removeChild(inode); + } + } + }, + isSupported : function(feature, version) { + // use Implementation.hasFeature to determine if this feature is supported + return __ownerDocument__(this).implementation.hasFeature(feature, version); + }, + getElementsByTagName : function(tagname) { + // delegate to _getElementsByTagNameRecursive + // recurse childNodes + var nodelist = new NodeList(__ownerDocument__(this)); + for (var i = 0; i < this.childNodes.length; i++) { + __getElementsByTagNameRecursive__(this.childNodes.item(i), + tagname, + nodelist); + } + return nodelist; + }, + getElementsByTagNameNS : function(namespaceURI, localName) { + // delegate to _getElementsByTagNameNSRecursive + return __getElementsByTagNameNSRecursive__(this, namespaceURI, localName, + new NodeList(__ownerDocument__(this))); + }, + importNode : function(importedNode, deep) { + var i; + var importNode; + + //there is no need to perform namespace checks since everything has already gone through them + //in order to have gotten into the DOM in the first place. The following line + //turns namespace checking off in ._isValidNamespace + __ownerDocument__(this).importing = true; + + if (importedNode.nodeType == Node.ELEMENT_NODE) { + if (!__ownerDocument__(this).implementation.namespaceAware) { + // create a local Element (with the name of the importedNode) + importNode = __ownerDocument__(this).createElement(importedNode.tagName); + + // create attributes matching those of the importedNode + for(i = 0; i < importedNode.attributes.length; i++) { + importNode.setAttribute(importedNode.attributes.item(i).name, importedNode.attributes.item(i).value); + } + } else { + // create a local Element (with the name & namespaceURI of the importedNode) + importNode = __ownerDocument__(this).createElementNS(importedNode.namespaceURI, importedNode.nodeName); + + // create attributes matching those of the importedNode + for(i = 0; i < importedNode.attributes.length; i++) { + importNode.setAttributeNS(importedNode.attributes.item(i).namespaceURI, + importedNode.attributes.item(i).name, importedNode.attributes.item(i).value); + } + + // create namespace definitions matching those of the importedNode + for(i = 0; i < importedNode._namespaces.length; i++) { + importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName); + importNode._namespaces[i].value = importedNode._namespaces.item(i).value; + } + } + } else if (importedNode.nodeType == Node.ATTRIBUTE_NODE) { + if (!__ownerDocument__(this).implementation.namespaceAware) { + // create a local Attribute (with the name of the importedAttribute) + importNode = __ownerDocument__(this).createAttribute(importedNode.name); + } else { + // create a local Attribute (with the name & namespaceURI of the importedAttribute) + importNode = __ownerDocument__(this).createAttributeNS(importedNode.namespaceURI, importedNode.nodeName); + + // create namespace definitions matching those of the importedAttribute + for(i = 0; i < importedNode._namespaces.length; i++) { + importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName); + importNode._namespaces[i].value = importedNode._namespaces.item(i).value; + } + } + + // set the value of the local Attribute to match that of the importedAttribute + importNode.value = importedNode.value; + + } else if (importedNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // create a local DocumentFragment + importNode = __ownerDocument__(this).createDocumentFragment(); + } else if (importedNode.nodeType == Node.NAMESPACE_NODE) { + // create a local NamespaceNode (with the same name & value as the importedNode) + importNode = __ownerDocument__(this).createNamespace(importedNode.nodeName); + importNode.value = importedNode.value; + } else if (importedNode.nodeType == Node.TEXT_NODE) { + // create a local TextNode (with the same data as the importedNode) + importNode = __ownerDocument__(this).createTextNode(importedNode.data); + } else if (importedNode.nodeType == Node.CDATA_SECTION_NODE) { + // create a local CDATANode (with the same data as the importedNode) + importNode = __ownerDocument__(this).createCDATASection(importedNode.data); + } else if (importedNode.nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + // create a local ProcessingInstruction (with the same target & data as the importedNode) + importNode = __ownerDocument__(this).createProcessingInstruction(importedNode.target, importedNode.data); + } else if (importedNode.nodeType == Node.COMMENT_NODE) { + // create a local Comment (with the same data as the importedNode) + importNode = __ownerDocument__(this).createComment(importedNode.data); + } else { // throw Exception if nodeType is not supported + throw(new DOMException(DOMException.NOT_SUPPORTED_ERR)); + } + + if (deep) { + // recurse childNodes + for(i = 0; i < importedNode.childNodes.length; i++) { + importNode.appendChild(__ownerDocument__(this).importNode(importedNode.childNodes.item(i), true)); + } + } + + //reset importing + __ownerDocument__(this).importing = false; + return importNode; + + }, + contains : function(node){ + while(node && node != this ){ + node = node.parentNode; + } + return !!node; + }, + compareDocumentPosition : function(b){ + //console.log("comparing document position %s %s", this, b); + var i, + length, + a = this, + parent, + aparents, + bparents; + //handle a couple simpler case first + if(a === b) { + return Node.DOCUMENT_POSITION_EQUAL; + } + if(a.ownerDocument !== b.ownerDocument) { + return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC| + Node.DOCUMENT_POSITION_FOLLOWING| + Node.DOCUMENT_POSITION_DISCONNECTED; + } + if(a.parentNode === b.parentNode){ + length = a.parentNode.childNodes.length; + for(i=0;i aparents.length){ + return Node.DOCUMENT_POSITION_FOLLOWING; + }else if(bparents.length < aparents.length){ + return Node.DOCUMENT_POSITION_PRECEDING; + }else{ + //common ancestor diverge point + if (i === 0) { + return Node.DOCUMENT_POSITION_FOLLOWING; + } else { + parent = aparents[i-1]; + } + return parent.compareDocumentPosition(bparents.pop()); + } + } + } + + return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC| + Node.DOCUMENT_POSITION_DISCONNECTED; + + }, + toString : function() { + return '[object Node]'; + } + +}); + + + +/** + * @method __getElementsByTagNameRecursive__ - implements getElementsByTagName() + * @param elem : Element - The element which are checking and then recursing into + * @param tagname : string - The name of the tag to match on. The special value "*" matches all tags + * @param nodeList : NodeList - The accumulating list of matching nodes + * + * @return : NodeList + */ +var __getElementsByTagNameRecursive__ = function (elem, tagname, nodeList) { + + if (elem.nodeType == Node.ELEMENT_NODE || elem.nodeType == Node.DOCUMENT_NODE) { + + if(elem.nodeType !== Node.DOCUMENT_NODE && + ((elem.nodeName.toUpperCase() == tagname.toUpperCase()) || + (tagname == "*")) ){ + // add matching node to nodeList + __appendChild__(nodeList, elem); + } + + // recurse childNodes + for(var i = 0; i < elem.childNodes.length; i++) { + nodeList = __getElementsByTagNameRecursive__(elem.childNodes.item(i), tagname, nodeList); + } + } + + return nodeList; +}; + +/** + * @method __getElementsByTagNameNSRecursive__ + * implements getElementsByTagName() + * + * @param elem : Element - The element which are checking and then recursing into + * @param namespaceURI : string - the namespace URI of the required node + * @param localName : string - the local name of the required node + * @param nodeList : NodeList - The accumulating list of matching nodes + * + * @return : NodeList + */ +var __getElementsByTagNameNSRecursive__ = function(elem, namespaceURI, localName, nodeList) { + if (elem.nodeType == Node.ELEMENT_NODE || elem.nodeType == Node.DOCUMENT_NODE) { + + if (((elem.namespaceURI == namespaceURI) || (namespaceURI == "*")) && + ((elem.localName == localName) || (localName == "*"))) { + // add matching node to nodeList + __appendChild__(nodeList, elem); + } + + // recurse childNodes + for(var i = 0; i < elem.childNodes.length; i++) { + nodeList = __getElementsByTagNameNSRecursive__( + elem.childNodes.item(i), namespaceURI, localName, nodeList); + } + } + + return nodeList; +}; + +/** + * @method __isAncestor__ - returns true if node is ancestor of target + * @param target : Node - The node we are using as context + * @param node : Node - The candidate ancestor node + * @return : boolean + */ +var __isAncestor__ = function(target, node) { + // if this node matches, return true, + // otherwise recurse up (if there is a parentNode) + return ((target == node) || ((target.parentNode) && (__isAncestor__(target.parentNode, node)))); +}; + + + +var __recursivelyGatherText__ = function(aNode) { + var accumulateText = "", + idx, + node; + for (idx=0;idx < aNode.childNodes.length;idx++){ + node = aNode.childNodes.item(idx); + if(node.nodeType == Node.TEXT_NODE) + accumulateText += node.data; + else + accumulateText += __recursivelyGatherText__(node); + } + return accumulateText; +}; + +/** + * function __escapeXML__ + * @param str : string - The string to be escaped + * @return : string - The escaped string + */ +var escAmpRegEx = /&(?!(amp;|lt;|gt;|quot|apos;))/g; +var escLtRegEx = //g; +var quotRegEx = /"/g; +var aposRegEx = /'/g; + +function __escapeXML__(str) { + str = str.replace(escAmpRegEx, "&"). + replace(escLtRegEx, "<"). + replace(escGtRegEx, ">"). + replace(quotRegEx, """). + replace(aposRegEx, "'"); + + return str; +}; + +/* +function __escapeHTML5__(str) { + str = str.replace(escAmpRegEx, "&"). + replace(escLtRegEx, "<"). + replace(escGtRegEx, ">"); + + return str; +}; +function __escapeHTML5Atribute__(str) { + str = str.replace(escAmpRegEx, "&"). + replace(escLtRegEx, "<"). + replace(escGtRegEx, ">"). + replace(quotRegEx, """). + replace(aposRegEx, "'"); + + return str; +}; +*/ + +/** + * function __unescapeXML__ + * @param str : string - The string to be unescaped + * @return : string - The unescaped string + */ +var unescAmpRegEx = /&/g; +var unescLtRegEx = /</g; +var unescGtRegEx = />/g; +var unquotRegEx = /"/g; +var unaposRegEx = /'/g; +function __unescapeXML__(str) { + str = str.replace(unescAmpRegEx, "&"). + replace(unescLtRegEx, "<"). + replace(unescGtRegEx, ">"). + replace(unquotRegEx, "\""). + replace(unaposRegEx, "'"); + + return str; +}; + +/** + * @class NamedNodeMap - + * used to represent collections of nodes that can be accessed by name + * typically a set of Element attributes + * + * @extends NodeList - + * note W3C spec says that this is not the case, but we need an item() + * method identical to NodeList's, so why not? + * @param ownerDocument : Document - the ownerDocument + * @param parentNode : Node - the node that the NamedNodeMap is attached to (or null) + */ +NamedNodeMap = function(ownerDocument, parentNode) { + NodeList.apply(this, arguments); + __setArray__(this, []); +}; +NamedNodeMap.prototype = new NodeList(); +__extend__(NamedNodeMap.prototype, { + add: function(name){ + this[this.length] = name; + }, + getNamedItem : function(name) { + var ret = null; + //console.log('NamedNodeMap getNamedItem %s', name); + // test that Named Node exists + var itemIndex = __findNamedItemIndex__(this, name); + + if (itemIndex > -1) { + // found it! + ret = this[itemIndex]; + } + // if node is not found, default value null is returned + return ret; + }, + setNamedItem : function(arg) { + //console.log('setNamedItem %s', arg); + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if arg was not created by this Document + if (this.ownerDocument != arg.ownerDocument) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if DOMNamedNodeMap is readonly + if (this._readonly || (this.parentNode && this.parentNode._readonly)) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if arg is already an attribute of another Element object + if (arg.ownerElement && (arg.ownerElement != this.parentNode)) { + throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR)); + } + } + + //console.log('setNamedItem __findNamedItemIndex__ '); + // get item index + var itemIndex = __findNamedItemIndex__(this, arg.name); + var ret = null; + + //console.log('setNamedItem __findNamedItemIndex__ %s', itemIndex); + if (itemIndex > -1) { // found it! + ret = this[itemIndex]; // use existing Attribute + + // throw Exception if DOMAttr is readonly + if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } else { + this[itemIndex] = arg; // over-write existing NamedNode + this[arg.name.toLowerCase()] = arg; + } + } else { + // add new NamedNode + //console.log('setNamedItem add new named node map (by index)'); + Array.prototype.push.apply(this, [arg]); + //console.log('setNamedItem add new named node map (by name) %s %s', arg, arg.name); + this[arg.name] = arg; + //console.log('finsished setNamedItem add new named node map (by name) %s', arg.name); + + } + + //console.log('setNamedItem parentNode'); + arg.ownerElement = this.parentNode; // update ownerElement + // return old node or new node + //console.log('setNamedItem exit'); + return ret; + }, + removeNamedItem : function(name) { + var ret = null; + // test for exceptions + // throw Exception if NamedNodeMap is readonly + if (__ownerDocument__(this).implementation.errorChecking && + (this._readonly || (this.parentNode && this.parentNode._readonly))) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // get item index + var itemIndex = __findNamedItemIndex__(this, name); + + // throw Exception if there is no node named name in this map + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // get Node + var oldNode = this[itemIndex]; + //this[oldNode.name] = undefined; + + // throw Exception if Node is readonly + if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // return removed node + return __removeChild__(this, itemIndex); + }, + getNamedItemNS : function(namespaceURI, localName) { + var ret = null; + + // test that Named Node exists + var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName); + + if (itemIndex > -1) { + // found it! return NamedNode + ret = this[itemIndex]; + } + // if node is not found, default value null is returned + return ret; + }, + setNamedItemNS : function(arg) { + //console.log('setNamedItemNS %s', arg); + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if NamedNodeMap is readonly + if (this._readonly || (this.parentNode && this.parentNode._readonly)) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if arg was not created by this Document + if (__ownerDocument__(this) != __ownerDocument__(arg)) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if arg is already an attribute of another Element object + if (arg.ownerElement && (arg.ownerElement != this.parentNode)) { + throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR)); + } + } + + // get item index + var itemIndex = __findNamedItemNSIndex__(this, arg.namespaceURI, arg.localName); + var ret = null; + + if (itemIndex > -1) { + // found it! + // use existing Attribute + ret = this[itemIndex]; + // throw Exception if Attr is readonly + if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } else { + // over-write existing NamedNode + this[itemIndex] = arg; + } + }else { + // add new NamedNode + Array.prototype.push.apply(this, [arg]); + } + arg.ownerElement = this.parentNode; + + // return old node or null + return ret; + //console.log('finished setNamedItemNS %s', arg); + }, + removeNamedItemNS : function(namespaceURI, localName) { + var ret = null; + + // test for exceptions + // throw Exception if NamedNodeMap is readonly + if (__ownerDocument__(this).implementation.errorChecking && (this._readonly || (this.parentNode && this.parentNode._readonly))) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // get item index + var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName); + + // throw Exception if there is no matching node in this map + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // get Node + var oldNode = this[itemIndex]; + + // throw Exception if Node is readonly + if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + return __removeChild__(this, itemIndex); // return removed node + }, + get xml() { + var ret = ""; + + // create string containing concatenation of all (but last) Attribute string values (separated by spaces) + for (var i=0; i < this.length -1; i++) { + ret += this[i].xml +" "; + } + + // add last Attribute to string (without trailing space) + if (this.length > 0) { + ret += this[this.length -1].xml; + } + + return ret; + }, + toString : function(){ + return "[object NamedNodeMap]"; + } + +}); + +/** + * @method __findNamedItemIndex__ + * find the item index of the node with the specified name + * + * @param name : string - the name of the required node + * @param isnsmap : if its a NamespaceNodeMap + * @return : int + */ +var __findNamedItemIndex__ = function(namednodemap, name, isnsmap) { + var ret = -1; + // loop through all nodes + for (var i=0; i -1) { + // found it! + ret = true; + } + // if node is not found, default value false is returned + return ret; +} + +/** + * @method __hasAttributeNS__ + * Returns true if specified node exists + * + * @param namespaceURI : string - the namespace URI of the required node + * @param localName : string - the local name of the required node + * @return : boolean + */ +var __hasAttributeNS__ = function(namednodemap, namespaceURI, localName) { + var ret = false; + // test that Named Node exists + var itemIndex = __findNamedItemNSIndex__(namednodemap, namespaceURI, localName); + if (itemIndex > -1) { + // found it! + ret = true; + } + // if node is not found, default value false is returned + return ret; +} + +/** + * @method __cloneNamedNodes__ + * Returns a NamedNodeMap containing clones of the Nodes in this NamedNodeMap + * + * @param parentNode : Node - the new parent of the cloned NodeList + * @param isnsmap : bool - is this a NamespaceNodeMap + * @return NamedNodeMap containing clones of the Nodes in this NamedNodeMap + */ +var __cloneNamedNodes__ = function(namednodemap, parentNode, isnsmap) { + var cloneNamedNodeMap = isnsmap? + new NamespaceNodeMap(namednodemap.ownerDocument, parentNode): + new NamedNodeMap(namednodemap.ownerDocument, parentNode); + + // create list containing clones of all children + for (var i=0; i < namednodemap.length; i++) { + __appendChild__(cloneNamedNodeMap, namednodemap[i].cloneNode(false)); + } + + return cloneNamedNodeMap; +}; + + +/** + * @class NamespaceNodeMap - + * used to represent collections of namespace nodes that can be + * accessed by name typically a set of Element attributes + * + * @extends NamedNodeMap + * + * @param ownerDocument : Document - the ownerDocument + * @param parentNode : Node - the node that the NamespaceNodeMap is attached to (or null) + */ +var NamespaceNodeMap = function(ownerDocument, parentNode) { + this.NamedNodeMap = NamedNodeMap; + this.NamedNodeMap(ownerDocument, parentNode); + __setArray__(this, []); +}; +NamespaceNodeMap.prototype = new NamedNodeMap(); +__extend__(NamespaceNodeMap.prototype, { + get xml() { + var ret = "", + ns, + ind; + // identify namespaces declared local to this Element (ie, not inherited) + for (ind = 0; ind < this.length; ind++) { + // if namespace declaration does not exist in the containing node's, parentNode's namespaces + ns = null; + try { + var ns = this.parentNode.parentNode._namespaces. + getNamedItem(this[ind].localName); + }catch (e) { + //breaking to prevent default namespace being inserted into return value + break; + } + if (!(ns && (""+ ns.nodeValue == ""+ this[ind].nodeValue))) { + // display the namespace declaration + ret += this[ind].xml +" "; + } + } + return ret; + } +}); + +/** + * @class Namespace - + * The Namespace interface represents an namespace in an Element object + * + * @param ownerDocument : The Document object associated with this node. + */ +Namespace = function(ownerDocument) { + Node.apply(this, arguments); + // the name of this attribute + this.name = ""; + + // If this attribute was explicitly given a value in the original document, + // this is true; otherwise, it is false. + // Note that the implementation is in charge of this attribute, not the user. + // If the user changes the value of the attribute (even if it ends up having + // the same value as the default value) then the specified flag is + // automatically flipped to true + this.specified = false; +}; +Namespace.prototype = new Node(); +__extend__(Namespace.prototype, { + get value(){ + // the value of the attribute is returned as a string + return this.nodeValue; + }, + set value(value){ + this.nodeValue = value+''; + }, + get nodeType(){ + return Node.NAMESPACE_NODE; + }, + get xml(){ + var ret = ""; + + // serialize Namespace Declaration + if (this.nodeName != "") { + ret += this.nodeName +"=\""+ __escapeXML__(this.nodeValue) +"\""; + } + else { // handle default namespace + ret += "xmlns=\""+ __escapeXML__(this.nodeValue) +"\""; + } + + return ret; + }, + toString: function(){ + return '[object Namespace]'; + } +}); + + +/** + * @class CharacterData - parent abstract class for Text and Comment + * @extends Node + * @param ownerDocument : The Document object associated with this node. + */ +CharacterData = function(ownerDocument) { + Node.apply(this, arguments); +}; +CharacterData.prototype = new Node(); +__extend__(CharacterData.prototype,{ + get data(){ + return this.nodeValue; + }, + set data(data){ + this.nodeValue = data; + }, + get textContent(){ + return this.nodeValue; + }, + set textContent(newText){ + this.nodeValue = newText; + }, + get length(){return this.nodeValue.length;}, + appendData: function(arg){ + // throw Exception if CharacterData is readonly + if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + // append data + this.data = "" + this.data + arg; + }, + deleteData: function(offset, count){ + // throw Exception if CharacterData is readonly + if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + if (this.data) { + // throw Exception if offset is negative or greater than the data length, + if (__ownerDocument__(this).implementation.errorChecking && + ((offset < 0) || (offset > this.data.length) || (count < 0))) { + throw(new DOMException(DOMException.INDEX_SIZE_ERR)); + } + + // delete data + if(!count || (offset + count) > this.data.length) { + this.data = this.data.substring(0, offset); + }else { + this.data = this.data.substring(0, offset). + concat(this.data.substring(offset + count)); + } + } + }, + insertData: function(offset, arg){ + // throw Exception if CharacterData is readonly + if(__ownerDocument__(this).implementation.errorChecking && this._readonly){ + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + if(this.data){ + // throw Exception if offset is negative or greater than the data length, + if (__ownerDocument__(this).implementation.errorChecking && + ((offset < 0) || (offset > this.data.length))) { + throw(new DOMException(DOMException.INDEX_SIZE_ERR)); + } + + // insert data + this.data = this.data.substring(0, offset).concat(arg, this.data.substring(offset)); + }else { + // throw Exception if offset is negative or greater than the data length, + if (__ownerDocument__(this).implementation.errorChecking && (offset !== 0)) { + throw(new DOMException(DOMException.INDEX_SIZE_ERR)); + } + + // set data + this.data = arg; + } + }, + replaceData: function(offset, count, arg){ + // throw Exception if CharacterData is readonly + if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + if (this.data) { + // throw Exception if offset is negative or greater than the data length, + if (__ownerDocument__(this).implementation.errorChecking && + ((offset < 0) || (offset > this.data.length) || (count < 0))) { + throw(new DOMException(DOMException.INDEX_SIZE_ERR)); + } + + // replace data + this.data = this.data.substring(0, offset). + concat(arg, this.data.substring(offset + count)); + }else { + // set data + this.data = arg; + } + }, + substringData: function(offset, count){ + var ret = null; + if (this.data) { + // throw Exception if offset is negative or greater than the data length, + // or the count is negative + if (__ownerDocument__(this).implementation.errorChecking && + ((offset < 0) || (offset > this.data.length) || (count < 0))) { + throw(new DOMException(DOMException.INDEX_SIZE_ERR)); + } + // if count is not specified + if (!count) { + ret = this.data.substring(offset); // default to 'end of string' + }else{ + ret = this.data.substring(offset, offset + count); + } + } + return ret; + }, + toString : function(){ + return "[object CharacterData]"; + } +}); + +/** + * @class Text + * The Text interface represents the textual content (termed + * character data in XML) of an Element or Attr. + * If there is no markup inside an element's content, the text is + * contained in a single object implementing the Text interface that + * is the only child of the element. If there is markup, it is + * parsed into a list of elements and Text nodes that form the + * list of children of the element. + * @extends CharacterData + * @param ownerDocument The Document object associated with this node. + */ +Text = function(ownerDocument) { + CharacterData.apply(this, arguments); + this.nodeName = "#text"; +}; +Text.prototype = new CharacterData(); +__extend__(Text.prototype,{ + get localName(){ + return null; + }, + // Breaks this Text node into two Text nodes at the specified offset, + // keeping both in the tree as siblings. This node then only contains + // all the content up to the offset point. And a new Text node, which + // is inserted as the next sibling of this node, contains all the + // content at and after the offset point. + splitText : function(offset) { + var data, + inode; + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Node is readonly + if (this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + // throw Exception if offset is negative or greater than the data length, + if ((offset < 0) || (offset > this.data.length)) { + throw(new DOMException(DOMException.INDEX_SIZE_ERR)); + } + } + if (this.parentNode) { + // get remaining string (after offset) + data = this.substringData(offset); + // create new TextNode with remaining string + inode = __ownerDocument__(this).createTextNode(data); + // attach new TextNode + if (this.nextSibling) { + this.parentNode.insertBefore(inode, this.nextSibling); + } else { + this.parentNode.appendChild(inode); + } + // remove remaining string from original TextNode + this.deleteData(offset); + } + return inode; + }, + get nodeType(){ + return Node.TEXT_NODE; + }, + get xml(){ + return __escapeXML__(""+ this.nodeValue); + }, + toString: function(){ + return "[object Text]"; + } +}); + +/** + * @class CDATASection + * CDATA sections are used to escape blocks of text containing + * characters that would otherwise be regarded as markup. + * The only delimiter that is recognized in a CDATA section is + * the "\]\]\>" string that ends the CDATA section + * @extends Text + * @param ownerDocument : The Document object associated with this node. + */ +CDATASection = function(ownerDocument) { + Text.apply(this, arguments); + this.nodeName = '#cdata-section'; +}; +CDATASection.prototype = new Text(); +__extend__(CDATASection.prototype,{ + get nodeType(){ + return Node.CDATA_SECTION_NODE; + }, + get xml(){ + return ""; + }, + toString : function(){ + return "[object CDATASection]"; + } +}); +/** + * @class Comment + * This represents the content of a comment, i.e., all the + * characters between the starting '' + * @extends CharacterData + * @param ownerDocument : The Document object associated with this node. + */ +Comment = function(ownerDocument) { + CharacterData.apply(this, arguments); + this.nodeName = "#comment"; +}; +Comment.prototype = new CharacterData(); +__extend__(Comment.prototype, { + get localName(){ + return null; + }, + get nodeType(){ + return Node.COMMENT_NODE; + }, + get xml(){ + return ""; + }, + toString : function(){ + return "[object Comment]"; + } +}); + + +/** + * @author envjs team + * @param {Document} onwnerDocument + */ +DocumentType = function(ownerDocument) { + Node.apply(this, arguments); + this.systemId = null; + this.publicId = null; +}; +DocumentType.prototype = new Node(); +__extend__({ + get name(){ + return this.nodeName; + }, + get entities(){ + return null; + }, + get internalSubsets(){ + return null; + }, + get notations(){ + return null; + }, + toString : function(){ + return "[object DocumentType]"; + } +}); + +/** + * @class Attr + * The Attr interface represents an attribute in an Element object + * @extends Node + * @param ownerDocument : The Document object associated with this node. + */ +Attr = function(ownerDocument) { + Node.apply(this, arguments); + // set when Attr is added to NamedNodeMap + this.ownerElement = null; + //TODO: our implementation of Attr is incorrect because we don't + // treat the value of the attribute as a child text node. +}; +Attr.prototype = new Node(); +__extend__(Attr.prototype, { + // the name of this attribute + get name(){ + return this.nodeName; + }, + // the value of the attribute is returned as a string + get value(){ + return this.nodeValue||''; + }, + set value(value){ + // throw Exception if Attribute is readonly + if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + // delegate to node + this.nodeValue = value; + }, + get textContent(){ + return this.nodeValue; + }, + set textContent(newText){ + this.nodeValue = newText; + }, + get specified(){ + return (this !== null && this !== undefined); + }, + get nodeType(){ + return Node.ATTRIBUTE_NODE; + }, + get xml() { + if (this.nodeValue) { + return __escapeXML__(this.nodeValue+""); + } else { + return ''; + } + }, + toString : function() { + return '[object Attr]'; + } +}); + + +/** + * @class Element - + * By far the vast majority of objects (apart from text) + * that authors encounter when traversing a document are + * Element nodes. + * @extends Node + * @param ownerDocument : The Document object associated with this node. + */ +Element = function(ownerDocument) { + Node.apply(this, arguments); + this.attributes = new NamedNodeMap(this.ownerDocument, this); +}; +Element.prototype = new Node(); +__extend__(Element.prototype, { + // The name of the element. + get tagName(){ + return this.nodeName; + }, + + getAttribute: function(name) { + var ret = null; + // if attribute exists, use it + var attr = this.attributes.getNamedItem(name); + if (attr) { + ret = attr.value; + } + // if Attribute exists, return its value, otherwise, return null + return ret; + }, + setAttribute : function (name, value) { + // if attribute exists, use it + var attr = this.attributes.getNamedItem(name); + //console.log('attr %s', attr); + //I had to add this check because as the script initializes + //the id may be set in the constructor, and the html element + //overrides the id property with a getter/setter. + if(__ownerDocument__(this)){ + if (attr===null||attr===undefined) { + // otherwise create it + attr = __ownerDocument__(this).createAttribute(name); + //console.log('attr %s', attr); + } + + + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Attribute is readonly + if (attr._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if the value string contains an illegal character + if (!__isValidString__(value+'')) { + throw(new DOMException(DOMException.INVALID_CHARACTER_ERR)); + } + } + + // assign values to properties (and aliases) + attr.value = value + ''; + + // add/replace Attribute in NamedNodeMap + this.attributes.setNamedItem(attr); + //console.log('element setNamedItem %s', attr); + }else{ + console.warn('Element has no owner document '+this.tagName+ + '\n\t cant set attribute ' + name + ' = '+value ); + } + }, + removeAttribute : function removeAttribute(name) { + // delegate to NamedNodeMap.removeNamedItem + return this.attributes.removeNamedItem(name); + }, + getAttributeNode : function getAttributeNode(name) { + // delegate to NamedNodeMap.getNamedItem + return this.attributes.getNamedItem(name); + }, + setAttributeNode: function(newAttr) { + // if this Attribute is an ID + if (__isIdDeclaration__(newAttr.name)) { + this.id = newAttr.value; // cache ID for getElementById() + } + // delegate to NamedNodeMap.setNamedItem + return this.attributes.setNamedItem(newAttr); + }, + removeAttributeNode: function(oldAttr) { + // throw Exception if Attribute is readonly + if (__ownerDocument__(this).implementation.errorChecking && oldAttr._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // get item index + var itemIndex = this.attributes._findItemIndex(oldAttr._id); + + // throw Exception if node does not exist in this map + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + return this.attributes._removeChild(itemIndex); + }, + getAttributeNS : function(namespaceURI, localName) { + var ret = ""; + // delegate to NAmedNodeMap.getNamedItemNS + var attr = this.attributes.getNamedItemNS(namespaceURI, localName); + if (attr) { + ret = attr.value; + } + return ret; // if Attribute exists, return its value, otherwise return "" + }, + setAttributeNS : function(namespaceURI, qualifiedName, value) { + // call NamedNodeMap.getNamedItem + //console.log('setAttributeNS %s %s %s', namespaceURI, qualifiedName, value); + var attr = this.attributes.getNamedItem(namespaceURI, qualifiedName); + + if (!attr) { // if Attribute exists, use it + // otherwise create it + attr = __ownerDocument__(this).createAttributeNS(namespaceURI, qualifiedName); + } + + value = '' + value; + + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Attribute is readonly + if (attr._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if the Namespace is invalid + if (!__isValidNamespace__(this.ownerDocument, namespaceURI, qualifiedName, true)) { + throw(new DOMException(DOMException.NAMESPACE_ERR)); + } + + // throw Exception if the value string contains an illegal character + if (!__isValidString__(value)) { + throw(new DOMException(DOMException.INVALID_CHARACTER_ERR)); + } + } + + // if this Attribute is an ID + //if (__isIdDeclaration__(name)) { + // this.id = value; + //} + + // assign values to properties (and aliases) + attr.value = value; + attr.nodeValue = value; + + // delegate to NamedNodeMap.setNamedItem + this.attributes.setNamedItemNS(attr); + }, + removeAttributeNS : function(namespaceURI, localName) { + // delegate to NamedNodeMap.removeNamedItemNS + return this.attributes.removeNamedItemNS(namespaceURI, localName); + }, + getAttributeNodeNS : function(namespaceURI, localName) { + // delegate to NamedNodeMap.getNamedItemNS + return this.attributes.getNamedItemNS(namespaceURI, localName); + }, + setAttributeNodeNS : function(newAttr) { + // if this Attribute is an ID + if ((newAttr.prefix == "") && __isIdDeclaration__(newAttr.name)) { + this.id = newAttr.value+''; // cache ID for getElementById() + } + + // delegate to NamedNodeMap.setNamedItemNS + return this.attributes.setNamedItemNS(newAttr); + }, + hasAttribute : function(name) { + // delegate to NamedNodeMap._hasAttribute + return __hasAttribute__(this.attributes,name); + }, + hasAttributeNS : function(namespaceURI, localName) { + // delegate to NamedNodeMap._hasAttributeNS + return __hasAttributeNS__(this.attributes, namespaceURI, localName); + }, + get nodeType(){ + return Node.ELEMENT_NODE; + }, + get xml() { + var ret = "", + ns = "", + attrs, + attrstring, + i; + + // serialize namespace declarations + if (this.namespaceURI ){ + if((this === this.ownerDocument.documentElement) || + (!this.parentNode)|| + (this.parentNode && (this.parentNode.namespaceURI !== this.namespaceURI))) { + ns = ' xmlns' + (this.prefix?(':'+this.prefix):'') + + '="' + this.namespaceURI + '"'; + } + } + + // serialize Attribute declarations + attrs = this.attributes; + attrstring = ""; + for(i=0;i< attrs.length;i++){ + if(attrs[i].name.match('xmlns:')) { + attrstring += " "+attrs[i].name+'="'+attrs[i].xml+'"'; + } + } + for(i=0;i< attrs.length;i++){ + if(!attrs[i].name.match('xmlns:')) { + attrstring += " "+attrs[i].name+'="'+attrs[i].xml+'"'; + } + } + + if(this.hasChildNodes()){ + // serialize this Element + ret += "<" + this.tagName + ns + attrstring +">"; + ret += this.childNodes.xml; + ret += ""; + }else{ + ret += "<" + this.tagName + ns + attrstring +"/>"; + } + + return ret; + }, + toString : function(){ + return '[object Element]'; + } +}); +/** + * @class DOMException - raised when an operation is impossible to perform + * @author Jon van Noort (jon@webarcana.com.au) + * @param code : int - the exception code (one of the DOMException constants) + */ +DOMException = function(code) { + this.code = code; +}; + +// DOMException constants +// Introduced in DOM Level 1: +DOMException.INDEX_SIZE_ERR = 1; +DOMException.DOMSTRING_SIZE_ERR = 2; +DOMException.HIERARCHY_REQUEST_ERR = 3; +DOMException.WRONG_DOCUMENT_ERR = 4; +DOMException.INVALID_CHARACTER_ERR = 5; +DOMException.NO_DATA_ALLOWED_ERR = 6; +DOMException.NO_MODIFICATION_ALLOWED_ERR = 7; +DOMException.NOT_FOUND_ERR = 8; +DOMException.NOT_SUPPORTED_ERR = 9; +DOMException.INUSE_ATTRIBUTE_ERR = 10; + +// Introduced in DOM Level 2: +DOMException.INVALID_STATE_ERR = 11; +DOMException.SYNTAX_ERR = 12; +DOMException.INVALID_MODIFICATION_ERR = 13; +DOMException.NAMESPACE_ERR = 14; +DOMException.INVALID_ACCESS_ERR = 15; + +/** + * @class DocumentFragment - + * DocumentFragment is a "lightweight" or "minimal" Document object. + * @extends Node + * @param ownerDocument : The Document object associated with this node. + */ +DocumentFragment = function(ownerDocument) { + Node.apply(this, arguments); + this.nodeName = "#document-fragment"; +}; +DocumentFragment.prototype = new Node(); +__extend__(DocumentFragment.prototype,{ + get nodeType(){ + return Node.DOCUMENT_FRAGMENT_NODE; + }, + get xml(){ + var xml = "", + count = this.childNodes.length; + + // create string concatenating the serialized ChildNodes + for (var i = 0; i < count; i++) { + xml += this.childNodes.item(i).xml; + } + + return xml; + }, + toString : function(){ + return "[object DocumentFragment]"; + }, + get localName(){ + return null; + } +}); + + +/** + * @class ProcessingInstruction - + * The ProcessingInstruction interface represents a + * "processing instruction", used in XML as a way to + * keep processor-specific information in the text of + * the document + * @extends Node + * @author Jon van Noort (jon@webarcana.com.au) + * @param ownerDocument : The Document object associated with this node. + */ +ProcessingInstruction = function(ownerDocument) { + Node.apply(this, arguments); +}; +ProcessingInstruction.prototype = new Node(); +__extend__(ProcessingInstruction.prototype, { + get data(){ + return this.nodeValue; + }, + set data(data){ + // throw Exception if Node is readonly + if (__ownerDocument__(this).errorChecking && this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + this.nodeValue = data; + }, + get textContent(){ + return this.data; + }, + get localName(){ + return null; + }, + get target(){ + // The target of this processing instruction. + // XML defines this as being the first token following the markup that begins the processing instruction. + // The content of this processing instruction. + return this.nodeName; + }, + set target(value){ + // The target of this processing instruction. + // XML defines this as being the first token following the markup that begins the processing instruction. + // The content of this processing instruction. + this.nodeName = value; + }, + get nodeType(){ + return Node.PROCESSING_INSTRUCTION_NODE; + }, + get xml(){ + return ""; + }, + toString : function(){ + return "[object ProcessingInstruction]"; + } +}); + + +/** + * @author envjs team + */ + +Entity = function() { + throw new Error("Entity Not Implemented" ); +}; + +Entity.constants = { + // content taken from W3C "HTML 4.01 Specification" + // "W3C Recommendation 24 December 1999" + + nbsp: "\u00A0", + iexcl: "\u00A1", + cent: "\u00A2", + pound: "\u00A3", + curren: "\u00A4", + yen: "\u00A5", + brvbar: "\u00A6", + sect: "\u00A7", + uml: "\u00A8", + copy: "\u00A9", + ordf: "\u00AA", + laquo: "\u00AB", + not: "\u00AC", + shy: "\u00AD", + reg: "\u00AE", + macr: "\u00AF", + deg: "\u00B0", + plusmn: "\u00B1", + sup2: "\u00B2", + sup3: "\u00B3", + acute: "\u00B4", + micro: "\u00B5", + para: "\u00B6", + middot: "\u00B7", + cedil: "\u00B8", + sup1: "\u00B9", + ordm: "\u00BA", + raquo: "\u00BB", + frac14: "\u00BC", + frac12: "\u00BD", + frac34: "\u00BE", + iquest: "\u00BF", + Agrave: "\u00C0", + Aacute: "\u00C1", + Acirc: "\u00C2", + Atilde: "\u00C3", + Auml: "\u00C4", + Aring: "\u00C5", + AElig: "\u00C6", + Ccedil: "\u00C7", + Egrave: "\u00C8", + Eacute: "\u00C9", + Ecirc: "\u00CA", + Euml: "\u00CB", + Igrave: "\u00CC", + Iacute: "\u00CD", + Icirc: "\u00CE", + Iuml: "\u00CF", + ETH: "\u00D0", + Ntilde: "\u00D1", + Ograve: "\u00D2", + Oacute: "\u00D3", + Ocirc: "\u00D4", + Otilde: "\u00D5", + Ouml: "\u00D6", + times: "\u00D7", + Oslash: "\u00D8", + Ugrave: "\u00D9", + Uacute: "\u00DA", + Ucirc: "\u00DB", + Uuml: "\u00DC", + Yacute: "\u00DD", + THORN: "\u00DE", + szlig: "\u00DF", + agrave: "\u00E0", + aacute: "\u00E1", + acirc: "\u00E2", + atilde: "\u00E3", + auml: "\u00E4", + aring: "\u00E5", + aelig: "\u00E6", + ccedil: "\u00E7", + egrave: "\u00E8", + eacute: "\u00E9", + ecirc: "\u00EA", + euml: "\u00EB", + igrave: "\u00EC", + iacute: "\u00ED", + icirc: "\u00EE", + iuml: "\u00EF", + eth: "\u00F0", + ntilde: "\u00F1", + ograve: "\u00F2", + oacute: "\u00F3", + ocirc: "\u00F4", + otilde: "\u00F5", + ouml: "\u00F6", + divide: "\u00F7", + oslash: "\u00F8", + ugrave: "\u00F9", + uacute: "\u00FA", + ucirc: "\u00FB", + uuml: "\u00FC", + yacute: "\u00FD", + thorn: "\u00FE", + yuml: "\u00FF", + fnof: "\u0192", + Alpha: "\u0391", + Beta: "\u0392", + Gamma: "\u0393", + Delta: "\u0394", + Epsilon: "\u0395", + Zeta: "\u0396", + Eta: "\u0397", + Theta: "\u0398", + Iota: "\u0399", + Kappa: "\u039A", + Lambda: "\u039B", + Mu: "\u039C", + Nu: "\u039D", + Xi: "\u039E", + Omicron: "\u039F", + Pi: "\u03A0", + Rho: "\u03A1", + Sigma: "\u03A3", + Tau: "\u03A4", + Upsilon: "\u03A5", + Phi: "\u03A6", + Chi: "\u03A7", + Psi: "\u03A8", + Omega: "\u03A9", + alpha: "\u03B1", + beta: "\u03B2", + gamma: "\u03B3", + delta: "\u03B4", + epsilon: "\u03B5", + zeta: "\u03B6", + eta: "\u03B7", + theta: "\u03B8", + iota: "\u03B9", + kappa: "\u03BA", + lambda: "\u03BB", + mu: "\u03BC", + nu: "\u03BD", + xi: "\u03BE", + omicron: "\u03BF", + pi: "\u03C0", + rho: "\u03C1", + sigmaf: "\u03C2", + sigma: "\u03C3", + tau: "\u03C4", + upsilon: "\u03C5", + phi: "\u03C6", + chi: "\u03C7", + psi: "\u03C8", + omega: "\u03C9", + thetasym: "\u03D1", + upsih: "\u03D2", + piv: "\u03D6", + bull: "\u2022", + hellip: "\u2026", + prime: "\u2032", + Prime: "\u2033", + oline: "\u203E", + frasl: "\u2044", + weierp: "\u2118", + image: "\u2111", + real: "\u211C", + trade: "\u2122", + alefsym: "\u2135", + larr: "\u2190", + uarr: "\u2191", + rarr: "\u2192", + darr: "\u2193", + harr: "\u2194", + crarr: "\u21B5", + lArr: "\u21D0", + uArr: "\u21D1", + rArr: "\u21D2", + dArr: "\u21D3", + hArr: "\u21D4", + forall: "\u2200", + part: "\u2202", + exist: "\u2203", + empty: "\u2205", + nabla: "\u2207", + isin: "\u2208", + notin: "\u2209", + ni: "\u220B", + prod: "\u220F", + sum: "\u2211", + minus: "\u2212", + lowast: "\u2217", + radic: "\u221A", + prop: "\u221D", + infin: "\u221E", + ang: "\u2220", + and: "\u2227", + or: "\u2228", + cap: "\u2229", + cup: "\u222A", + intXX: "\u222B", + there4: "\u2234", + sim: "\u223C", + cong: "\u2245", + asymp: "\u2248", + ne: "\u2260", + equiv: "\u2261", + le: "\u2264", + ge: "\u2265", + sub: "\u2282", + sup: "\u2283", + nsub: "\u2284", + sube: "\u2286", + supe: "\u2287", + oplus: "\u2295", + otimes: "\u2297", + perp: "\u22A5", + sdot: "\u22C5", + lceil: "\u2308", + rceil: "\u2309", + lfloor: "\u230A", + rfloor: "\u230B", + lang: "\u2329", + rang: "\u232A", + loz: "\u25CA", + spades: "\u2660", + clubs: "\u2663", + hearts: "\u2665", + diams: "\u2666", + quot: "\u0022", + amp: "\u0026", + lt: "\u003C", + gt: "\u003E", + OElig: "\u0152", + oelig: "\u0153", + Scaron: "\u0160", + scaron: "\u0161", + Yuml: "\u0178", + circ: "\u02C6", + tilde: "\u02DC", + ensp: "\u2002", + emsp: "\u2003", + thinsp: "\u2009", + zwnj: "\u200C", + zwj: "\u200D", + lrm: "\u200E", + rlm: "\u200F", + ndash: "\u2013", + mdash: "\u2014", + lsquo: "\u2018", + rsquo: "\u2019", + sbquo: "\u201A", + ldquo: "\u201C", + rdquo: "\u201D", + bdquo: "\u201E", + dagger: "\u2020", + Dagger: "\u2021", + permil: "\u2030", + lsaquo: "\u2039", + rsaquo: "\u203A", + euro: "\u20AC", + + // non-standard entities + apos: "'" +}; + +/** + * @author envjs team + */ + +EntityReference = function() { + throw new Error("EntityReference Not Implemented" ); +}; + +/** + * @class DOMImplementation - + * provides a number of methods for performing operations + * that are independent of any particular instance of the + * document object model. + * + * @author Jon van Noort (jon@webarcana.com.au) + */ +DOMImplementation = function() { + this.preserveWhiteSpace = false; // by default, ignore whitespace + this.namespaceAware = true; // by default, handle namespaces + this.errorChecking = true; // by default, test for exceptions +}; + +__extend__(DOMImplementation.prototype,{ + // @param feature : string - The package name of the feature to test. + // the legal only values are "XML" and "CORE" (case-insensitive). + // @param version : string - This is the version number of the package + // name to test. In Level 1, this is the string "1.0".* + // @return : boolean + hasFeature : function(feature, version) { + var ret = false; + if (feature.toLowerCase() == "xml") { + ret = (!version || (version == "1.0") || (version == "2.0")); + } + else if (feature.toLowerCase() == "core") { + ret = (!version || (version == "2.0")); + } + else if (feature == "http://www.w3.org/TR/SVG11/feature#BasicStructure") { + ret = (version == "1.1"); + } + return ret; + }, + createDocumentType : function(qname, publicId, systemId){ + var doctype = new DocumentType(); + doctype.nodeName = qname?qname.toUpperCase():null; + doctype.publicId = publicId?publicId:null; + doctype.systemId = systemId?systemId:null; + return doctype; + }, + createDocument : function(nsuri, qname, doctype){ + + var doc = null, documentElement; + + doc = new Document(this, null); + if(doctype){ + doc.doctype = doctype; + } + + if(nsuri && qname){ + documentElement = doc.createElementNS(nsuri, qname); + }else if(qname){ + documentElement = doc.createElement(qname); + } + if(documentElement){ + doc.appendChild(documentElement); + } + return doc; + }, + createHTMLDocument : function(title){ + var doc = new HTMLDocument($implementation, null, ""); + var html = doc.createElement("html"); doc.appendChild(html); + var head = doc.createElement("head"); html.appendChild(head); + var body = doc.createElement("body"); html.appendChild(body); + var t = doc.createElement("title"); head.appendChild(t); + if( title) { + t.appendChild(doc.createTextNode(title)); + } + return doc; + }, + translateErrCode : function(code) { + //convert DOMException Code to human readable error message; + var msg = ""; + + switch (code) { + case DOMException.INDEX_SIZE_ERR : // 1 + msg = "INDEX_SIZE_ERR: Index out of bounds"; + break; + + case DOMException.DOMSTRING_SIZE_ERR : // 2 + msg = "DOMSTRING_SIZE_ERR: The resulting string is too long to fit in a DOMString"; + break; + + case DOMException.HIERARCHY_REQUEST_ERR : // 3 + msg = "HIERARCHY_REQUEST_ERR: The Node can not be inserted at this location"; + break; + + case DOMException.WRONG_DOCUMENT_ERR : // 4 + msg = "WRONG_DOCUMENT_ERR: The source and the destination Documents are not the same"; + break; + + case DOMException.INVALID_CHARACTER_ERR : // 5 + msg = "INVALID_CHARACTER_ERR: The string contains an invalid character"; + break; + + case DOMException.NO_DATA_ALLOWED_ERR : // 6 + msg = "NO_DATA_ALLOWED_ERR: This Node / NodeList does not support data"; + break; + + case DOMException.NO_MODIFICATION_ALLOWED_ERR : // 7 + msg = "NO_MODIFICATION_ALLOWED_ERR: This object cannot be modified"; + break; + + case DOMException.NOT_FOUND_ERR : // 8 + msg = "NOT_FOUND_ERR: The item cannot be found"; + break; + + case DOMException.NOT_SUPPORTED_ERR : // 9 + msg = "NOT_SUPPORTED_ERR: This implementation does not support function"; + break; + + case DOMException.INUSE_ATTRIBUTE_ERR : // 10 + msg = "INUSE_ATTRIBUTE_ERR: The Attribute has already been assigned to another Element"; + break; + + // Introduced in DOM Level 2: + case DOMException.INVALID_STATE_ERR : // 11 + msg = "INVALID_STATE_ERR: The object is no longer usable"; + break; + + case DOMException.SYNTAX_ERR : // 12 + msg = "SYNTAX_ERR: Syntax error"; + break; + + case DOMException.INVALID_MODIFICATION_ERR : // 13 + msg = "INVALID_MODIFICATION_ERR: Cannot change the type of the object"; + break; + + case DOMException.NAMESPACE_ERR : // 14 + msg = "NAMESPACE_ERR: The namespace declaration is incorrect"; + break; + + case DOMException.INVALID_ACCESS_ERR : // 15 + msg = "INVALID_ACCESS_ERR: The object does not support this function"; + break; + + default : + msg = "UNKNOWN: Unknown Exception Code ("+ code +")"; + } + + return msg; + }, + toString : function(){ + return "[object DOMImplementation]"; + } +}); + + + +/** + * @method DOMImplementation._isNamespaceDeclaration - Return true, if attributeName is a namespace declaration + * @author Jon van Noort (jon@webarcana.com.au) + * @param attributeName : string - the attribute name + * @return : boolean + */ +function __isNamespaceDeclaration__(attributeName) { + // test if attributeName is 'xmlns' + return (attributeName.indexOf('xmlns') > -1); +} + +/** + * @method DOMImplementation._isIdDeclaration - Return true, if attributeName is an id declaration + * @author Jon van Noort (jon@webarcana.com.au) + * @param attributeName : string - the attribute name + * @return : boolean + */ +function __isIdDeclaration__(attributeName) { + // test if attributeName is 'id' (case insensitive) + return attributeName?(attributeName.toLowerCase() == 'id'):false; +} + +/** + * @method DOMImplementation._isValidName - Return true, + * if name contains no invalid characters + * @author Jon van Noort (jon@webarcana.com.au) + * @param name : string - the candidate name + * @return : boolean + */ +function __isValidName__(name) { + // test if name contains only valid characters + return name.match(re_validName); +} +var re_validName = /^[a-zA-Z_:][a-zA-Z0-9\.\-_:]*$/; + +/** + * @method DOMImplementation._isValidString - Return true, if string does not contain any illegal chars + * All of the characters 0 through 31 and character 127 are nonprinting control characters. + * With the exception of characters 09, 10, and 13, (Ox09, Ox0A, and Ox0D) + * Note: different from _isValidName in that ValidStrings may contain spaces + * @author Jon van Noort (jon@webarcana.com.au) + * @param name : string - the candidate string + * @return : boolean + */ +function __isValidString__(name) { + // test that string does not contains invalid characters + return (name.search(re_invalidStringChars) < 0); +} +var re_invalidStringChars = /\x01|\x02|\x03|\x04|\x05|\x06|\x07|\x08|\x0B|\x0C|\x0E|\x0F|\x10|\x11|\x12|\x13|\x14|\x15|\x16|\x17|\x18|\x19|\x1A|\x1B|\x1C|\x1D|\x1E|\x1F|\x7F/; + +/** + * @method DOMImplementation._parseNSName - parse the namespace name. + * if there is no colon, the + * @author Jon van Noort (jon@webarcana.com.au) + * @param qualifiedName : string - The qualified name + * @return : NSName - [ + .prefix : string - The prefix part of the qname + .namespaceName : string - The namespaceURI part of the qname + ] + */ +function __parseNSName__(qualifiedName) { + var resultNSName = {}; + // unless the qname has a namespaceName, the prefix is the entire String + resultNSName.prefix = qualifiedName; + resultNSName.namespaceName = ""; + // split on ':' + var delimPos = qualifiedName.indexOf(':'); + if (delimPos > -1) { + // get prefix + resultNSName.prefix = qualifiedName.substring(0, delimPos); + // get namespaceName + resultNSName.namespaceName = qualifiedName.substring(delimPos +1, qualifiedName.length); + } + return resultNSName; +} + +/** + * @method DOMImplementation._parseQName - parse the qualified name + * @author Jon van Noort (jon@webarcana.com.au) + * @param qualifiedName : string - The qualified name + * @return : QName + */ +function __parseQName__(qualifiedName) { + var resultQName = {}; + // unless the qname has a prefix, the local name is the entire String + resultQName.localName = qualifiedName; + resultQName.prefix = ""; + // split on ':' + var delimPos = qualifiedName.indexOf(':'); + if (delimPos > -1) { + // get prefix + resultQName.prefix = qualifiedName.substring(0, delimPos); + // get localName + resultQName.localName = qualifiedName.substring(delimPos +1, qualifiedName.length); + } + return resultQName; +} +/** + * @author envjs team + */ +Notation = function() { + throw new Error("Notation Not Implemented" ); +};/** + * @author thatcher + */ +Range = function(){ + +}; + +__extend__(Range.prototype, { + get startContainer(){ + + }, + get endContainer(){ + + }, + get startOffset(){ + + }, + get endOffset(){ + + }, + get collapsed(){ + + }, + get commonAncestorContainer(){ + + }, + setStart: function(refNode, offset){//throws RangeException + + }, + setEnd: function(refNode, offset){//throws RangeException + + }, + setStartBefore: function(refNode){//throws RangeException + + }, + setStartAfter: function(refNode){//throws RangeException + + }, + setEndBefore: function(refNode){//throws RangeException + + }, + setEndAfter: function(refNode){//throws RangeException + + }, + collapse: function(toStart){//throws RangeException + + }, + selectNode: function(refNode){//throws RangeException + + }, + selectNodeContents: function(refNode){//throws RangeException + + }, + compareBoundaryPoints: function(how, sourceRange){ + + }, + deleteContents: function(){ + + }, + extractContents: function(){ + + }, + cloneContents: function(){ + + }, + insertNode: function(newNode){ + + }, + surroundContents: function(newParent){ + + }, + cloneRange: function(){ + + }, + toString: function(){ + return '[object Range]'; + }, + detach: function(){ + + } +}); + + + // CompareHow +Range.START_TO_START = 0; +Range.START_TO_END = 1; +Range.END_TO_END = 2; +Range.END_TO_START = 3; + +/* + * Forward declarations + */ +var __isValidNamespace__; + +/** + * @class Document - The Document interface represents the entire HTML + * or XML document. Conceptually, it is the root of the document tree, + * and provides the primary access to the document's data. + * + * @extends Node + * @param implementation : DOMImplementation - the creator Implementation + */ +Document = function(implementation, docParentWindow) { + Node.apply(this, arguments); + + //TODO: Temporary!!! Cnage back to true!!! + this.async = true; + // The Document Type Declaration (see DocumentType) associated with this document + this.doctype = null; + // The DOMImplementation object that handles this document. + this.implementation = implementation; + + this.nodeName = "#document"; + // initially false, set to true by parser + this.parsing = false; + this.baseURI = 'about:blank'; + + this.ownerDocument = null; + + this.importing = false; +}; + +Document.prototype = new Node(); +__extend__(Document.prototype,{ + get localName(){ + return null; + }, + get textContent(){ + return null; + }, + get all(){ + return this.getElementsByTagName("*"); + }, + get documentElement(){ + var i, length = this.childNodes?this.childNodes.length:0; + for(i=0;i -1 ){ + valid = false; + } + + if ((valid) && (!isAttribute)) { + // if the namespaceURI is not null + if (!namespaceURI) { + valid = false; + } + } + + // if the qualifiedName has a prefix + if ((valid) && (qName.prefix === "")) { + valid = false; + } + } + + // if the qualifiedName has a prefix that is "xml" and the namespaceURI is + // different from "http://www.w3.org/XML/1998/namespace" [Namespaces]. + if ((valid) && (qName.prefix === "xml") && (namespaceURI !== "http://www.w3.org/XML/1998/namespace")) { + valid = false; + } + + return valid; +}; +/** + * + * This file only handles XML parser. + * It is extended by parser/domparser.js (and parser/htmlparser.js) + * + * This depends on e4x, which some engines may not have. + * + * @author thatcher + */ +DOMParser = function(principle, documentURI, baseURI) { + // TODO: why/what should these 3 args do? +}; +__extend__(DOMParser.prototype,{ + parseFromString: function(xmlstring, mimetype){ + var doc = new Document(new DOMImplementation()), + e4; + + // The following are e4x directives. + // Full spec is here: + // http://www.ecma-international.org/publications/standards/Ecma-357.htm + // + // that is pretty gross, so checkout this summary + // http://rephrase.net/days/07/06/e4x + // + // also see the Mozilla Developer Center: + // https://developer.mozilla.org/en/E4X + // + XML.ignoreComments = false; + XML.ignoreProcessingInstructions = false; + XML.ignoreWhitespace = false; + + // for some reason e4x can't handle initial xml declarations + // https://bugzilla.mozilla.org/show_bug.cgi?id=336551 + // The official workaround is the big regexp below + // but simpler one seems to be ok + // xmlstring = xmlstring.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, ""); + // + xmlstring = xmlstring.replace(/<\?xml.*\?>/); + + e4 = new XMLList(xmlstring); + + __toDomNode__(e4, doc, doc); + + //console.log('xml \n %s', doc.documentElement.xml); + return doc; + } +}); + +var __toDomNode__ = function(e4, parent, doc){ + var xnode, + domnode, + children, + target, + value, + length, + element, + kind, + item; + //console.log('converting e4x node list \n %s', e4) + + // not using the for each(item in e4) since some engines can't + // handle the syntax (i.e. says syntax error) + // + // for each(xnode in e4) { + for (item in e4) { + // NO do not do this if (e4.hasOwnProperty(item)) { + // breaks spidermonkey + xnode = e4[item]; + + kind = xnode.nodeKind(); + //console.log('treating node kind %s', kind); + switch(kind){ + case 'element': + // add node + //console.log('creating element %s %s', xnode.localName(), xnode.namespace()); + if(xnode.namespace() && (xnode.namespace()+'') !== ''){ + //console.log('createElementNS %s %s',xnode.namespace()+'', xnode.localName() ); + domnode = doc.createElementNS(xnode.namespace()+'', xnode.localName()); + }else{ + domnode = doc.createElement(xnode.name()+''); + } + parent.appendChild(domnode); + + // add attributes + __toDomNode__(xnode.attributes(), domnode, doc); + + // add children + children = xnode.children(); + length = children.length(); + //console.log('recursing? %s', length ? 'yes' : 'no'); + if (length > 0) { + __toDomNode__(children, domnode, doc); + } + break; + case 'attribute': + // console.log('setting attribute %s %s %s', + // xnode.localName(), xnode.namespace(), xnode.valueOf()); + + // + // cross-platform alert. The original code used + // xnode.text() to get the attribute value + // This worked in Rhino, but did not in Spidermonkey + // valueOf seemed to work in both + // + if(xnode.namespace() && xnode.namespace().prefix){ + //console.log("%s", xnode.namespace().prefix); + parent.setAttributeNS(xnode.namespace()+'', + xnode.namespace().prefix+':'+xnode.localName(), + xnode.valueOf()); + }else if((xnode.name()+'').match('http://www.w3.org/2000/xmlns/::')){ + if(xnode.localName()!=='xmlns'){ + parent.setAttributeNS('http://www.w3.org/2000/xmlns/', + 'xmlns:'+xnode.localName(), + xnode.valueOf()); + } + }else{ + parent.setAttribute(xnode.localName()+'', xnode.valueOf()); + } + break; + case 'text': + //console.log('creating text node : %s', xnode); + domnode = doc.createTextNode(xnode+''); + parent.appendChild(domnode); + break; + case 'comment': + //console.log('creating comment node : %s', xnode); + value = xnode+''; + domnode = doc.createComment(value.substring(4,value.length-3)); + parent.appendChild(domnode); + break; + case 'processing-instruction': + //console.log('creating processing-instruction node : %s', xnode); + value = xnode+''; + target = value.split(' ')[0].substring(2); + value = value.split(' ').splice(1).join(' ').replace('?>',''); + //console.log('creating processing-instruction data : %s', value); + domnode = doc.createProcessingInstruction(target, value); + parent.appendChild(domnode); + break; + default: + console.log('e4x DOM ERROR'); + throw new Error("Assertion failed in xml parser"); + } + } +}; +/** + * @author envjs team + * @class XMLSerializer + */ + +XMLSerializer = function() {}; + +__extend__(XMLSerializer.prototype, { + serializeToString: function(node){ + return node.xml; + }, + toString : function(){ + return "[object XMLSerializer]"; + } +}); + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); +/* + * Envjs event.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + * + * This file simply provides the global definitions we need to + * be able to correctly implement to core browser DOM Event interfaces. + */ +var Event, + MouseEvent, + UIEvent, + KeyboardEvent, + MutationEvent, + DocumentEvent, + EventTarget, + EventException, + //nonstandard but very useful for implementing mutation events + //among other things like general profiling + Aspect; +/* + * Envjs event.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author john resig + */ +// 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; +} + +/** + * @author john resig + */ +//from jQuery +function __setArray__( target, array ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + target.length = 0; + Array.prototype.push.apply( target, array ); +} +/** + * Borrowed with love from: + * + * jQuery AOP - jQuery plugin to add features of aspect-oriented programming (AOP) to jQuery. + * http://jquery-aop.googlecode.com/ + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Version: 1.1 + */ +(function() { + + var _after = 1; + var _before = 2; + var _around = 3; + var _intro = 4; + var _regexEnabled = true; + + /** + * Private weaving function. + */ + var weaveOne = function(source, method, advice) { + + var old = source[method]; + + var aspect; + if (advice.type == _after) + aspect = function() { + var returnValue = old.apply(this, arguments); + return advice.value.apply(this, [returnValue, method]); + }; + else if (advice.type == _before) + aspect = function() { + advice.value.apply(this, [arguments, method]); + return old.apply(this, arguments); + }; + else if (advice.type == _intro) + aspect = function() { + return advice.value.apply(this, arguments); + }; + else if (advice.type == _around) { + aspect = function() { + var invocation = { object: this, args: arguments }; + return advice.value.apply(invocation.object, [{ arguments: invocation.args, method: method, proceed : + function() { + return old.apply(invocation.object, invocation.args); + } + }] ); + }; + } + + aspect.unweave = function() { + source[method] = old; + pointcut = source = aspect = old = null; + }; + + source[method] = aspect; + + return aspect; + + }; + + + /** + * Private weaver and pointcut parser. + */ + var weave = function(pointcut, advice) + { + + var source = (typeof(pointcut.target.prototype) != 'undefined') ? pointcut.target.prototype : pointcut.target; + var advices = []; + + // If it's not an introduction and no method was found, try with regex... + if (advice.type != _intro && typeof(source[pointcut.method]) == 'undefined') + { + + for (var method in source) + { + if (source[method] != null && source[method] instanceof Function && method.match(pointcut.method)) + { + advices[advices.length] = weaveOne(source, method, advice); + } + } + + if (advices.length == 0) + throw 'No method: ' + pointcut.method; + + } + else + { + // Return as an array of one element + advices[0] = weaveOne(source, pointcut.method, advice); + } + + return _regexEnabled ? advices : advices[0]; + + }; + + Aspect = + { + /** + * Creates an advice after the defined point-cut. The advice will be executed after the point-cut method + * has completed execution successfully, and will receive one parameter with the result of the execution. + * This function returns an array of weaved aspects (Function). + * + * @example jQuery.aop.after( {target: window, method: 'MyGlobalMethod'}, function(result) { alert('Returned: ' + result); } ); + * @result Array + * + * @example jQuery.aop.after( {target: String, method: 'indexOf'}, function(index) { alert('Result found at: ' + index + ' on:' + this); } ); + * @result Array + * + * @name after + * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. + * @option Object target Target object to be weaved. + * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. + * @param Function advice Function containing the code that will get called after the execution of the point-cut. It receives one parameter + * with the result of the point-cut's execution. + * + * @type Array + * @cat Plugins/General + */ + after : function(pointcut, advice) + { + return weave( pointcut, { type: _after, value: advice } ); + }, + + /** + * Creates an advice before the defined point-cut. The advice will be executed before the point-cut method + * but cannot modify the behavior of the method, or prevent its execution. + * This function returns an array of weaved aspects (Function). + * + * @example jQuery.aop.before( {target: window, method: 'MyGlobalMethod'}, function() { alert('About to execute MyGlobalMethod'); } ); + * @result Array + * + * @example jQuery.aop.before( {target: String, method: 'indexOf'}, function(index) { alert('About to execute String.indexOf on: ' + this); } ); + * @result Array + * + * @name before + * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. + * @option Object target Target object to be weaved. + * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. + * @param Function advice Function containing the code that will get called before the execution of the point-cut. + * + * @type Array + * @cat Plugins/General + */ + before : function(pointcut, advice) + { + return weave( pointcut, { type: _before, value: advice } ); + }, + + + /** + * Creates an advice 'around' the defined point-cut. This type of advice can control the point-cut method execution by calling + * the functions '.proceed()' on the 'invocation' object, and also, can modify the arguments collection before sending them to the function call. + * This function returns an array of weaved aspects (Function). + * + * @example jQuery.aop.around( {target: window, method: 'MyGlobalMethod'}, function(invocation) { + * alert('# of Arguments: ' + invocation.arguments.length); + * return invocation.proceed(); + * } ); + * @result Array + * + * @example jQuery.aop.around( {target: String, method: 'indexOf'}, function(invocation) { + * alert('Searching: ' + invocation.arguments[0] + ' on: ' + this); + * return invocation.proceed(); + * } ); + * @result Array + * + * @example jQuery.aop.around( {target: window, method: /Get(\d+)/}, function(invocation) { + * alert('Executing ' + invocation.method); + * return invocation.proceed(); + * } ); + * @desc Matches all global methods starting with 'Get' and followed by a number. + * @result Array + * + * + * @name around + * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. + * @option Object target Target object to be weaved. + * @option String method Name of the function to be weaved. Regex are supported, but not on built-in objects. + * @param Function advice Function containing the code that will get called around the execution of the point-cut. This advice will be called with one + * argument containing one function '.proceed()', the collection of arguments '.arguments', and the matched method name '.method'. + * + * @type Array + * @cat Plugins/General + */ + around : function(pointcut, advice) + { + return weave( pointcut, { type: _around, value: advice } ); + }, + + /** + * Creates an introduction on the defined point-cut. This type of advice replaces any existing methods with the same + * name. To restore them, just unweave it. + * This function returns an array with only one weaved aspect (Function). + * + * @example jQuery.aop.introduction( {target: window, method: 'MyGlobalMethod'}, function(result) { alert('Returned: ' + result); } ); + * @result Array + * + * @example jQuery.aop.introduction( {target: String, method: 'log'}, function() { alert('Console: ' + this); } ); + * @result Array + * + * @name introduction + * @param Map pointcut Definition of the point-cut to apply the advice. A point-cut is the definition of the object/s and method/s to be weaved. + * @option Object target Target object to be weaved. + * @option String method Name of the function to be weaved. + * @param Function advice Function containing the code that will be executed on the point-cut. + * + * @type Array + * @cat Plugins/General + */ + introduction : function(pointcut, advice) + { + return weave( pointcut, { type: _intro, value: advice } ); + }, + + /** + * Configures global options. + * + * @name setup + * @param Map settings Configuration options. + * @option Boolean regexMatch Enables/disables regex matching of method names. + * + * @example jQuery.aop.setup( { regexMatch: false } ); + * @desc Disable regex matching. + * + * @type Void + * @cat Plugins/General + */ + setup: function(settings) + { + _regexEnabled = settings.regexMatch; + } + }; + +})(); + + + + +/** + * @name EventTarget + * @w3c:domlevel 2 + * @uri -//TODO: paste dom event level 2 w3c spc uri here + */ +EventTarget = function(){}; +EventTarget.prototype.addEventListener = function(type, fn, phase){ + __addEventListener__(this, type, fn, phase); +}; +EventTarget.prototype.removeEventListener = function(type, fn){ + __removeEventListener__(this, type, fn); +}; +EventTarget.prototype.dispatchEvent = function(event, bubbles){ + __dispatchEvent__(this, event, bubbles); +}; + +__extend__(Node.prototype, EventTarget.prototype); + + +var $events = [{}]; + +function __addEventListener__(target, type, fn, phase){ + phase = !!phase?"CAPTURING":"BUBBLING"; + if ( !target.uuid ) { + //console.log('event uuid %s %s', target, target.uuid); + target.uuid = $events.length+''; + } + if ( !$events[target.uuid] ) { + //console.log('creating listener for target: %s %s', target, target.uuid); + $events[target.uuid] = {}; + } + if ( !$events[target.uuid][type] ){ + //console.log('creating listener for type: %s %s %s', target, target.uuid, type); + $events[target.uuid][type] = { + CAPTURING:[], + BUBBLING:[] + }; + } + if ( $events[target.uuid][type][phase].indexOf( fn ) < 0 ){ + //console.log('adding event listener %s %s %s %s %s %s', target, target.uuid, type, phase, + // $events[target.uuid][type][phase].length, $events[target.uuid][type][phase].indexOf( fn )); + //console.log('creating listener for function: %s %s %s', target, target.uuid, phase); + $events[target.uuid][type][phase].push( fn ); + //console.log('adding event listener %s %s %s %s %s %s', target, target.uuid, type, phase, + // $events[target.uuid][type][phase].length, $events[target.uuid][type][phase].indexOf( fn )); + } + //console.log('registered event listeners %s', $events.length); +} + +function __removeEventListener__(target, type, fn, phase){ + + phase = !!phase?"CAPTURING":"BUBBLING"; + if ( !target.uuid ) { + return; + } + if ( !$events[target.uuid] ) { + return; + } + if(type == '*'){ + //used to clean all event listeners for a given node + //console.log('cleaning all event listeners for node %s %s',target, target.uuid); + delete $events[target.uuid]; + return; + }else if ( !$events[target.uuid][type] ){ + return; + } + $events[target.uuid][type][phase] = + $events[target.uuid][type][phase].filter(function(f){ + //console.log('removing event listener %s %s %s %s', target, type, phase, fn); + return f != fn; + }); +} + +var __eventuuid__ = 0; +function __dispatchEvent__(target, event, bubbles){ + + if (!event.uuid) { + event.uuid = __eventuuid__++; + } + //the window scope defines the $event object, for IE(^^^) compatibility; + //$event = event; + //console.log('dispatching event %s', event.uuid); + if (bubbles === undefined || bubbles === null) { + bubbles = true; + } + + if (!event.target) { + event.target = target; + } + + //console.log('dispatching? %s %s %s', target, event.type, bubbles); + if ( event.type && (target.nodeType || target === window )) { + + //console.log('dispatching event %s %s %s', target, event.type, bubbles); + __captureEvent__(target, event); + + event.eventPhase = Event.AT_TARGET; + if ( target.uuid && $events[target.uuid] && $events[target.uuid][event.type] ) { + event.currentTarget = target; + //console.log('dispatching %s %s %s %s', target, event.type, + // $events[target.uuid][event.type]['CAPTURING'].length); + $events[target.uuid][event.type].CAPTURING.forEach(function(fn){ + //console.log('AT_TARGET (CAPTURING) event %s', fn); + var returnValue = fn( event ); + //console.log('AT_TARGET (CAPTURING) return value %s', returnValue); + if(returnValue === false){ + event.stopPropagation(); + } + }); + //console.log('dispatching %s %s %s %s', target, event.type, + // $events[target.uuid][event.type]['BUBBLING'].length); + $events[target.uuid][event.type].BUBBLING.forEach(function(fn){ + //console.log('AT_TARGET (BUBBLING) event %s', fn); + var returnValue = fn( event ); + //console.log('AT_TARGET (BUBBLING) return value %s', returnValue); + if(returnValue === false){ + event.stopPropagation(); + } + }); + } + if (target["on" + event.type]) { + target["on" + event.type](event); + } + if (bubbles && !event.cancelled){ + __bubbleEvent__(target, event); + } + if(!event._preventDefault){ + //At this point I'm guessing that just HTMLEvents are concerned + //with default behavior being executed in a browser but I could be + //wrong as usual. The goal is much more to filter at this point + //what events have no need to be handled + //console.log('triggering default behavior for %s', event.type); + if(event.type in Envjs.defaultEventBehaviors){ + Envjs.defaultEventBehaviors[event.type](event); + } + } + //console.log('deleting event %s', event.uuid); + event.target = null; + event = null; + }else{ + throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR); + } +} + +function __captureEvent__(target, event){ + var ancestorStack = [], + parent = target.parentNode; + + event.eventPhase = Event.CAPTURING_PHASE; + while(parent){ + if(parent.uuid && $events[parent.uuid] && $events[parent.uuid][event.type]){ + ancestorStack.push(parent); + } + parent = parent.parentNode; + } + while(ancestorStack.length && !event.cancelled){ + event.currentTarget = ancestorStack.pop(); + if($events[event.currentTarget.uuid] && $events[event.currentTarget.uuid][event.type]){ + $events[event.currentTarget.uuid][event.type].CAPTURING.forEach(function(fn){ + var returnValue = fn( event ); + if(returnValue === false){ + event.stopPropagation(); + } + }); + } + } +} + +function __bubbleEvent__(target, event){ + var parent = target.parentNode; + event.eventPhase = Event.BUBBLING_PHASE; + while(parent){ + if(parent.uuid && $events[parent.uuid] && $events[parent.uuid][event.type] ){ + event.currentTarget = parent; + $events[event.currentTarget.uuid][event.type].BUBBLING.forEach(function(fn){ + var returnValue = fn( event ); + if(returnValue === false){ + event.stopPropagation(); + } + }); + } + parent = parent.parentNode; + } +} + +/** + * @class Event + */ +Event = function(options){ + // event state is kept read-only by forcing + // a new object for each event. This may not + // be appropriate in the long run and we'll + // have to decide if we simply dont adhere to + // the read-only restriction of the specification + this._bubbles = true; + this._cancelable = true; + this._cancelled = false; + this._currentTarget = null; + this._target = null; + this._eventPhase = Event.AT_TARGET; + this._timeStamp = new Date().getTime(); + this._preventDefault = false; + this._stopPropogation = false; +}; + +__extend__(Event.prototype,{ + get bubbles(){return this._bubbles;}, + get cancelable(){return this._cancelable;}, + get currentTarget(){return this._currentTarget;}, + set currentTarget(currentTarget){ this._currentTarget = currentTarget; }, + get eventPhase(){return this._eventPhase;}, + set eventPhase(eventPhase){this._eventPhase = eventPhase;}, + get target(){return this._target;}, + set target(target){ this._target = target;}, + get timeStamp(){return this._timeStamp;}, + get type(){return this._type;}, + initEvent: function(type, bubbles, cancelable){ + this._type=type?type:''; + this._bubbles=!!bubbles; + this._cancelable=!!cancelable; + }, + preventDefault: function(){ + this._preventDefault = true; + }, + stopPropagation: function(){ + if(this._cancelable){ + this._cancelled = true; + this._bubbles = false; + } + }, + get cancelled(){ + return this._cancelled; + }, + toString: function(){ + return '[object Event]'; + } +}); + +__extend__(Event,{ + CAPTURING_PHASE : 1, + AT_TARGET : 2, + BUBBLING_PHASE : 3 +}); + + + +/** + * @name UIEvent + * @param {Object} options + */ +UIEvent = function(options) { + this._view = null; + this._detail = 0; +}; + +UIEvent.prototype = new Event(); +__extend__(UIEvent.prototype,{ + get view(){ + return this._view; + }, + get detail(){ + return this._detail; + }, + initUIEvent: function(type, bubbles, cancelable, windowObject, detail){ + this.initEvent(type, bubbles, cancelable); + this._detail = 0; + this._view = windowObject; + } +}); + +var $onblur, + $onfocus, + $onresize; + + +/** + * @name MouseEvent + * @w3c:domlevel 2 + * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html + */ +MouseEvent = function(options) { + this._screenX= 0; + this._screenY= 0; + this._clientX= 0; + this._clientY= 0; + this._ctrlKey= false; + this._metaKey= false; + this._altKey= false; + this._button= null; + this._relatedTarget= null; +}; +MouseEvent.prototype = new UIEvent(); +__extend__(MouseEvent.prototype,{ + get screenX(){ + return this._screenX; + }, + get screenY(){ + return this._screenY; + }, + get clientX(){ + return this._clientX; + }, + get clientY(){ + return this._clientY; + }, + get ctrlKey(){ + return this._ctrlKey; + }, + get altKey(){ + return this._altKey; + }, + get shiftKey(){ + return this._shiftKey; + }, + get metaKey(){ + return this._metaKey; + }, + get button(){ + return this._button; + }, + get relatedTarget(){ + return this._relatedTarget; + }, + initMouseEvent: function(type, bubbles, cancelable, windowObject, detail, + screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, + metaKey, button, relatedTarget){ + this.initUIEvent(type, bubbles, cancelable, windowObject, detail); + this._screenX = screenX; + this._screenY = screenY; + this._clientX = clientX; + this._clientY = clientY; + this._ctrlKey = ctrlKey; + this._altKey = altKey; + this._shiftKey = shiftKey; + this._metaKey = metaKey; + this._button = button; + this._relatedTarget = relatedTarget; + } +}); + +/** + * Interface KeyboardEvent (introduced in DOM Level 3) + */ +KeyboardEvent = function(options) { + this._keyIdentifier = 0; + this._keyLocation = 0; + this._ctrlKey = false; + this._metaKey = false; + this._altKey = false; + this._metaKey = false; +}; +KeyboardEvent.prototype = new UIEvent(); + +__extend__(KeyboardEvent.prototype,{ + + get ctrlKey(){ + return this._ctrlKey; + }, + get altKey(){ + return this._altKey; + }, + get shiftKey(){ + return this._shiftKey; + }, + get metaKey(){ + return this._metaKey; + }, + get button(){ + return this._button; + }, + get relatedTarget(){ + return this._relatedTarget; + }, + getModifiersState: function(keyIdentifier){ + + }, + initMouseEvent: function(type, bubbles, cancelable, windowObject, + keyIdentifier, keyLocation, modifiersList, repeat){ + this.initUIEvent(type, bubbles, cancelable, windowObject, 0); + this._keyIdentifier = keyIdentifier; + this._keyLocation = keyLocation; + this._modifiersList = modifiersList; + this._repeat = repeat; + } +}); + +KeyboardEvent.DOM_KEY_LOCATION_STANDARD = 0; +KeyboardEvent.DOM_KEY_LOCATION_LEFT = 1; +KeyboardEvent.DOM_KEY_LOCATION_RIGHT = 2; +KeyboardEvent.DOM_KEY_LOCATION_NUMPAD = 3; +KeyboardEvent.DOM_KEY_LOCATION_MOBILE = 4; +KeyboardEvent.DOM_KEY_LOCATION_JOYSTICK = 5; + + + +//We dont fire mutation events until someone has registered for them +var __supportedMutations__ = /DOMSubtreeModified|DOMNodeInserted|DOMNodeRemoved|DOMAttrModified|DOMCharacterDataModified/; + +var __fireMutationEvents__ = Aspect.before({ + target: EventTarget, + method: 'addEventListener' +}, function(target, type){ + if(type && type.match(__supportedMutations__)){ + //unweaving removes the __addEventListener__ aspect + __fireMutationEvents__.unweave(); + // These two methods are enough to cover all dom 2 manipulations + Aspect.around({ + target: Node, + method:"removeChild" + }, function(invocation){ + var event, + node = invocation.arguments[0]; + event = node.ownerDocument.createEvent('MutationEvents'); + event.initEvent('DOMNodeRemoved', true, false, node.parentNode, null, null, null, null); + node.dispatchEvent(event, false); + return invocation.proceed(); + + }); + Aspect.around({ + target: Node, + method:"appendChild" + }, function(invocation) { + var event, + node = invocation.proceed(); + event = node.ownerDocument.createEvent('MutationEvents'); + event.initEvent('DOMNodeInserted', true, false, node.parentNode, null, null, null, null); + node.dispatchEvent(event, false); + return node; + }); + } +}); + +/** + * @name MutationEvent + * @param {Object} options + */ +MutationEvent = function(options) { + this._cancelable = false; + this._timeStamp = 0; +}; + +MutationEvent.prototype = new Event(); +__extend__(MutationEvent.prototype,{ + get relatedNode(){ + return this._relatedNode; + }, + get prevValue(){ + return this._prevValue; + }, + get newValue(){ + return this._newValue; + }, + get attrName(){ + return this._attrName; + }, + get attrChange(){ + return this._attrChange; + }, + initMutationEvent: function( type, bubbles, cancelable, + relatedNode, prevValue, newValue, attrName, attrChange ){ + this._relatedNode = relatedNode; + this._prevValue = prevValue; + this._newValue = newValue; + this._attrName = attrName; + this._attrChange = attrChange; + switch(type){ + case "DOMSubtreeModified": + this.initEvent(type, true, false); + break; + case "DOMNodeInserted": + this.initEvent(type, true, false); + break; + case "DOMNodeRemoved": + this.initEvent(type, true, false); + break; + case "DOMNodeRemovedFromDocument": + this.initEvent(type, false, false); + break; + case "DOMNodeInsertedIntoDocument": + this.initEvent(type, false, false); + break; + case "DOMAttrModified": + this.initEvent(type, true, false); + break; + case "DOMCharacterDataModified": + this.initEvent(type, true, false); + break; + default: + this.initEvent(type, bubbles, cancelable); + } + } +}); + +// constants +MutationEvent.ADDITION = 0; +MutationEvent.MODIFICATION = 1; +MutationEvent.REMOVAL = 2; + + +/** + * @name EventException + */ +EventException = function(code) { + this.code = code; +}; +EventException.UNSPECIFIED_EVENT_TYPE_ERR = 0; +/** + * + * DOM Level 2: http://www.w3.org/TR/DOM-Level-2-Events/events.html + * DOM Level 3: http://www.w3.org/TR/DOM-Level-3-Events/ + * + * interface DocumentEvent { + * Event createEvent (in DOMString eventType) + * raises (DOMException); + * }; + * + * Firefox (3.6) exposes DocumentEvent + * Safari (4) does NOT. + */ + +/** + * TODO: Not sure we need a full prototype. We not just an regular object? + */ +DocumentEvent = function(){}; +DocumentEvent.prototype.__EventMap__ = { + // Safari4: singular and plural forms accepted + // Firefox3.6: singular and plural forms accepted + 'Event' : Event, + 'Events' : Event, + 'UIEvent' : UIEvent, + 'UIEvents' : UIEvent, + 'MouseEvent' : MouseEvent, + 'MouseEvents' : MouseEvent, + 'MutationEvent' : MutationEvent, + 'MutationEvents' : MutationEvent, + + // Safari4: accepts HTMLEvents, but not HTMLEvent + // Firefox3.6: accepts HTMLEvents, but not HTMLEvent + 'HTMLEvent' : Event, + 'HTMLEvents' : Event, + + // Safari4: both not accepted + // Firefox3.6, only KeyEvents is accepted + 'KeyEvent' : KeyboardEvent, + 'KeyEvents' : KeyboardEvent, + + // Safari4: both accepted + // Firefox3.6: none accepted + 'KeyboardEvent' : KeyboardEvent, + 'KeyboardEvents' : KeyboardEvent +}; + +DocumentEvent.prototype.createEvent = function(eventType) { + var Clazz = this.__EventMap__[eventType]; + if (Clazz) { + return new Clazz(); + } + throw(new DOMException(DOMException.NOT_SUPPORTED_ERR)); +}; + +__extend__(Document.prototype, DocumentEvent.prototype); + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); + +/* + * Envjs timer.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + * + * Parts of the implementation were originally written by:\ + * Steven Parkes + * + * requires Envjs.wait, Envjs.sleep, Envjs.WAIT_INTERVAL + */ +var setTimeout, + clearTimeout, + setInterval, + clearInterval; + +/* + * Envjs timer.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + +/* +* timer.js +* implementation provided by Steven Parkes +*/ + +//private +var $timers = [], + EVENT_LOOP_RUNNING = false; + +$timers.lock = function(fn){ + Envjs.sync(fn)(); +}; + +//private internal class +var Timer = function(fn, interval){ + this.fn = fn; + this.interval = interval; + this.at = Date.now() + interval; + // allows for calling wait() from callbacks + this.running = false; +}; + +Timer.prototype.start = function(){}; +Timer.prototype.stop = function(){}; + +//static +Timer.normalize = function(time) { + time = time*1; + if ( isNaN(time) || time < 0 ) { + time = 0; + } + + if ( EVENT_LOOP_RUNNING && time < Timer.MIN_TIME ) { + time = Timer.MIN_TIME; + } + return time; +}; +// html5 says this should be at least 4, but the parser is using +// a setTimeout for the SAX stuff which messes up the world +Timer.MIN_TIME = /* 4 */ 0; + +/** + * @function setTimeout + * @param {Object} fn + * @param {Object} time + */ +setTimeout = function(fn, time){ + var num; + time = Timer.normalize(time); + $timers.lock(function(){ + num = $timers.length+1; + var tfn; + if (typeof fn == 'string') { + tfn = function() { + try { + // eval in global scope + eval(fn, null); + } catch (e) { + console.log('timer error %s %s', fn, e); + } finally { + clearInterval(num); + } + }; + } else { + tfn = function() { + try { + fn(); + } catch (e) { + console.log('timer error %s %s', fn, e); + } finally { + clearInterval(num); + } + }; + } + //console.log("Creating timer number %s", num); + $timers[num] = new Timer(tfn, time); + $timers[num].start(); + }); + return num; +}; + +/** + * @function setInterval + * @param {Object} fn + * @param {Object} time + */ +setInterval = function(fn, time){ + //console.log('setting interval %s %s', time, fn.toString().substring(0,64)); + time = Timer.normalize(time); + if ( time < 10 ) { + time = 10; + } + if (typeof fn == 'string') { + var fnstr = fn; + fn = function() { + eval(fnstr); + }; + } + var num; + $timers.lock(function(){ + num = $timers.length+1; + //Envjs.debug("Creating timer number "+num); + $timers[num] = new Timer(fn, time); + $timers[num].start(); + }); + return num; +}; + +/** + * clearInterval + * @param {Object} num + */ +clearInterval = clearTimeout = function(num){ + //console.log("clearing interval "+num); + $timers.lock(function(){ + if ( $timers[num] ) { + $timers[num].stop(); + delete $timers[num]; + } + }); +}; + +// wait === null/undefined: execute any timers as they fire, +// waiting until there are none left +// wait(n) (n > 0): execute any timers as they fire until there +// are none left waiting at least n ms but no more, even if there +// are future events/current threads +// wait(0): execute any immediately runnable timers and return +// wait(-n): keep sleeping until the next event is more than n ms +// in the future +// +// TODO: make a priority queue ... + +Envjs.wait = function(wait) { + //console.log('wait %s', wait); + var delta_wait, + start = Date.now(), + was_running = EVENT_LOOP_RUNNING; + + if (wait < 0) { + delta_wait = -wait; + wait = 0; + } + EVENT_LOOP_RUNNING = true; + if (wait !== 0 && wait !== null && wait !== undefined){ + wait += Date.now(); + } + + var earliest, + timer, + sleep, + index, + goal, + now, + nextfn; + + for (;;) { + //console.log('timer loop'); + earliest = sleep = goal = now = nextfn = null; + $timers.lock(function(){ + for(index in $timers){ + if( isNaN(index*0) ) { + continue; + } + timer = $timers[index]; + // determine timer with smallest run-at time that is + // not already running + if( !timer.running && ( !earliest || timer.at < earliest.at) ) { + earliest = timer; + } + } + }); + //next sleep time + sleep = earliest && earliest.at - Date.now(); + if ( earliest && sleep <= 0 ) { + nextfn = earliest.fn; + try { + //console.log('running stack %s', nextfn.toString().substring(0,64)); + earliest.running = true; + nextfn(); + } catch (e) { + console.log('timer error %s %s', nextfn, e); + } finally { + earliest.running = false; + } + goal = earliest.at + earliest.interval; + now = Date.now(); + if ( goal < now ) { + earliest.at = now; + } else { + earliest.at = goal; + } + continue; + } + + // bunch of subtle cases here ... + if ( !earliest ) { + // no events in the queue (but maybe XHR will bring in events, so ... + if ( !wait || wait < Date.now() ) { + // Loop ends if there are no events and a wait hasn't been + // requested or has expired + break; + } + // no events, but a wait requested: fall through to sleep + } else { + // there are events in the queue, but they aren't firable now + /*if ( delta_wait && sleep <= delta_wait ) { + //TODO: why waste a check on a tight + // loop if it just falls through? + // if they will happen within the next delta, fall through to sleep + } else */if ( wait === 0 || ( wait > 0 && wait < Date.now () ) ) { + // loop ends even if there are events but the user + // specifcally asked not to wait too long + break; + } + // there are events and the user wants to wait: fall through to sleep + } + + // Related to ajax threads ... hopefully can go away .. + var interval = Envjs.WAIT_INTERVAL || 100; + if ( !sleep || sleep > interval ) { + sleep = interval; + } + //console.log('sleeping %s', sleep); + Envjs.sleep(sleep); + + } + EVENT_LOOP_RUNNING = was_running; +}; + + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); +/* + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + * + * This file simply provides the global definitions we need to + * be able to correctly implement to core browser DOM HTML interfaces. + */ +var HTMLDocument, + HTMLElement, + HTMLCollection, + HTMLAnchorElement, + HTMLAreaElement, + HTMLBaseElement, + HTMLQuoteElement, + HTMLBodyElement, + HTMLBRElement, + HTMLButtonElement, + HTMLCanvasElement, + HTMLTableColElement, + HTMLModElement, + HTMLDivElement, + HTMLDListElement, + HTMLFieldSetElement, + HTMLFormElement, + HTMLFrameElement, + HTMLFrameSetElement, + HTMLHeadElement, + HTMLHeadingElement, + HTMLHRElement, + HTMLHtmlElement, + HTMLIFrameElement, + HTMLImageElement, + HTMLInputElement, + HTMLLabelElement, + HTMLLegendElement, + HTMLLIElement, + HTMLLinkElement, + HTMLMapElement, + HTMLMetaElement, + HTMLObjectElement, + HTMLOListElement, + HTMLOptGroupElement, + HTMLOptionElement, + HTMLParagraphElement, + HTMLParamElement, + HTMLPreElement, + HTMLScriptElement, + HTMLSelectElement, + HTMLSpanElement, + HTMLStyleElement, + HTMLTableElement, + HTMLTableSectionElement, + HTMLTableCellElement, + HTMLTableDataCellElement, + HTMLTableHeaderCellElement, + HTMLTableRowElement, + HTMLTextAreaElement, + HTMLTitleElement, + HTMLUListElement, + HTMLUnknownElement, + Image, + Option, + __loadImage__, + __loadLink__; + +/* + * Envjs html.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author ariel flesler + * http://flesler.blogspot.com/2008/11/fast-trim-function-for-javascript.html + * @param {Object} str + */ +function __trim__( str ){ + return (str || "").replace( /^\s+|\s+$/g, "" ); +} + + +/** + * @author john resig + */ +// 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; +} + +/** + * @author john resig + */ +//from jQuery +function __setArray__( target, array ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + target.length = 0; + Array.prototype.push.apply( target, array ); +} + +/** + * @class HTMLDocument + * The Document interface represents the entire HTML or XML document. + * Conceptually, it is the root of the document tree, and provides + * the primary access to the document's data. + * + * @extends Document + */ +HTMLDocument = function(implementation, ownerWindow, referrer) { + Document.apply(this, arguments); + this.referrer = referrer || ''; + this.baseURI = "about:blank"; + this.ownerWindow = ownerWindow; +}; + +HTMLDocument.prototype = new Document(); + +__extend__(HTMLDocument.prototype, { + createElement: function(tagName){ + var node; + tagName = tagName.toUpperCase(); + // create Element specifying 'this' as ownerDocument + // This is an html document so we need to use explicit interfaces per the + //TODO: would be much faster as a big switch + switch(tagName){ + case "A": + node = new HTMLAnchorElement(this);break; + case "AREA": + node = new HTMLAreaElement(this);break; + case "BASE": + node = new HTMLBaseElement(this);break; + case "BLOCKQUOTE": + node = new HTMLQuoteElement(this);break; + case "CANVAS": + node = new HTMLCanvasElement(this);break; + case "Q": + node = new HTMLQuoteElement(this);break; + case "BODY": + node = new HTMLBodyElement(this);break; + case "BR": + node = new HTMLBRElement(this);break; + case "BUTTON": + node = new HTMLButtonElement(this);break; + case "CAPTION": + node = new HTMLElement(this);break; + case "COL": + node = new HTMLTableColElement(this);break; + case "COLGROUP": + node = new HTMLTableColElement(this);break; + case "DEL": + node = new HTMLModElement(this);break; + case "INS": + node = new HTMLModElement(this);break; + case "DIV": + node = new HTMLDivElement(this);break; + case "DL": + node = new HTMLDListElement(this);break; + case "DT": + node = new HTMLElement(this); break; + case "FIELDSET": + node = new HTMLFieldSetElement(this);break; + case "FORM": + node = new HTMLFormElement(this);break; + case "FRAME": + node = new HTMLFrameElement(this);break; + case "H1": + node = new HTMLHeadingElement(this);break; + case "H2": + node = new HTMLHeadingElement(this);break; + case "H3": + node = new HTMLHeadingElement(this);break; + case "H4": + node = new HTMLHeadingElement(this);break; + case "H5": + node = new HTMLHeadingElement(this);break; + case "H6": + node = new HTMLHeadingElement(this);break; + case "HEAD": + node = new HTMLHeadElement(this);break; + case "HR": + node = new HTMLHRElement(this);break; + case "HTML": + node = new HTMLHtmlElement(this);break; + case "IFRAME": + node = new HTMLIFrameElement(this);break; + case "IMG": + node = new HTMLImageElement(this);break; + case "INPUT": + node = new HTMLInputElement(this);break; + case "LABEL": + node = new HTMLLabelElement(this);break; + case "LEGEND": + node = new HTMLLegendElement(this);break; + case "LI": + node = new HTMLLIElement(this);break; + case "LINK": + node = new HTMLLinkElement(this);break; + case "MAP": + node = new HTMLMapElement(this);break; + case "META": + node = new HTMLMetaElement(this);break; + case "NOSCRIPT": + node = new HTMLElement(this);break; + case "OBJECT": + node = new HTMLObjectElement(this);break; + case "OPTGROUP": + node = new HTMLOptGroupElement(this);break; + case "OL": + node = new HTMLOListElement(this); break; + case "OPTION": + node = new HTMLOptionElement(this);break; + case "P": + node = new HTMLParagraphElement(this);break; + case "PARAM": + node = new HTMLParamElement(this);break; + case "PRE": + node = new HTMLPreElement(this);break; + case "SCRIPT": + node = new HTMLScriptElement(this);break; + case "SELECT": + node = new HTMLSelectElement(this);break; + case "SMALL": + node = new HTMLElement(this);break; + case "SPAN": + node = new HTMLSpanElement(this);break; + case "STRONG": + node = new HTMLElement(this);break; + case "STYLE": + node = new HTMLStyleElement(this);break; + case "TABLE": + node = new HTMLTableElement(this);break; + case "TBODY": + node = new HTMLTableSectionElement(this);break; + case "TFOOT": + node = new HTMLTableSectionElement(this);break; + case "THEAD": + node = new HTMLTableSectionElement(this);break; + case "TD": + node = new HTMLTableDataCellElement(this);break; + case "TH": + node = new HTMLTableHeaderCellElement(this);break; + case "TEXTAREA": + node = new HTMLTextAreaElement(this);break; + case "TITLE": + node = new HTMLTitleElement(this);break; + case "TR": + node = new HTMLTableRowElement(this);break; + case "UL": + node = new HTMLUListElement(this);break; + default: + node = new HTMLUnknownElement(this); + } + // assign values to properties (and aliases) + node.nodeName = tagName; + return node; + }, + createElementNS : function (uri, local) { + //print('createElementNS :'+uri+" "+local); + if(!uri){ + return this.createElement(local); + }else if ("http://www.w3.org/1999/xhtml" == uri) { + return this.createElement(local); + } else if ("http://www.w3.org/1998/Math/MathML" == uri) { + return this.createElement(local); + } else { + return Document.prototype.createElementNS.apply(this,[uri, local]); + } + }, + get anchors(){ + return new HTMLCollection(this.getElementsByTagName('a')); + }, + get applets(){ + return new HTMLCollection(this.getElementsByTagName('applet')); + }, + get documentElement(){ + var html = Document.prototype.__lookupGetter__('documentElement').apply(this,[]); + if( html === null){ + html = this.createElement('html'); + this.appendChild(html); + html.appendChild(this.createElement('head')); + html.appendChild(this.createElement('body')); + } + return html; + }, + //document.head is non-standard + get head(){ + //console.log('get head'); + if (!this.documentElement) { + this.appendChild(this.createElement('html')); + } + var element = this.documentElement, + length = element.childNodes.length, + i; + //check for the presence of the head element in this html doc + for(i=0;i1?matches[1]:""; + }, + set domain(value){ + var i, + domainParts = this.domain.split('.').reverse(), + newDomainParts = value.split('.').reverse(); + if(newDomainParts.length > 1){ + for(i=0;i 0){ + event = doc.createEvent('HTMLEvents'); + event.initEvent( okay ? "load" : "error", false, false ); + node.dispatchEvent( event, false ); + } + }catch(e){ + console.log('error loading html element %s %e', node, e.toString()); + } + } + break; + case 'frame': + case 'iframe': + node.contentWindow = { }; + node.contentDocument = new HTMLDocument(new DOMImplementation(), node.contentWindow); + node.contentWindow.document = node.contentDocument; + try{ + Window; + }catch(e){ + node.contentDocument.addEventListener('DOMContentLoaded', function(){ + event = node.contentDocument.createEvent('HTMLEvents'); + event.initEvent("load", false, false); + node.dispatchEvent( event, false ); + }); + } + try{ + if (node.src && node.src.length > 0){ + //console.log("getting content document for (i)frame from %s", node.src); + Envjs.loadFrame(node, Envjs.uri(node.src)); + event = node.contentDocument.createEvent('HTMLEvents'); + event.initEvent("load", false, false); + node.dispatchEvent( event, false ); + }else{ + //I dont like this being here: + //TODO: better mix-in strategy so the try/catch isnt required + try{ + if(Window){ + Envjs.loadFrame(node); + //console.log('src/html/document.js: triggering frame load'); + event = node.contentDocument.createEvent('HTMLEvents'); + event.initEvent("load", false, false); + node.dispatchEvent( event, false ); + } + }catch(e){} + } + }catch(e){ + console.log('error loading html element %s %e', node, e.toString()); + } + break; + + case 'link': + if (node.href && node.href.length > 0) { + __loadLink__(node, node.href); + } + break; + /* + case 'img': + if (node.src && node.src.length > 0){ + // don't actually load anything, so we're "done" immediately: + event = doc.createEvent('HTMLEvents'); + event.initEvent("load", false, false); + node.dispatchEvent( event, false ); + } + break; + */ + case 'option': + node._updateoptions(); + break; + default: + if(node.getAttribute('onload')){ + console.log('calling attribute onload %s | %s', node.onload, node.tagName); + node.onload(); + } + break; + }//switch on name + default: + break; + }//switch on ns + break; + default: + // console.log('element appended: %s %s', node+'', node.namespaceURI); + }//switch on doc.parsing + return node; + +}); + +Aspect.around({ + target: Node, + method:"removeChild" +}, function(invocation) { + var event, + okay, + node = invocation.proceed(), + doc = node.ownerDocument; + if((node.nodeType !== Node.ELEMENT_NODE)){ + //for now we are only handling element insertions. probably we will need + //to handle text node changes to script tags and changes to src + //attributes + if(node.nodeType !== Node.DOCUMENT_NODE && node.uuid){ + //console.log('removing event listeners, %s', node, node.uuid); + node.removeEventListener('*', null, null); + } + return node; + } + //console.log('appended html element %s %s %s', node.namespaceURI, node.nodeName, node); + + switch(doc.parsing){ + case true: + //handled by parser if included + break; + case false: + switch(node.namespaceURI){ + case null: + //fall through + case "": + //fall through + case "http://www.w3.org/1999/xhtml": + //this is interesting dillema since our event engine is + //storing the registered events in an array accessed + //by the uuid property of the node. unforunately this + //means listeners hang out way after(forever ;)) the node + //has been removed and gone out of scope. + //console.log('removing event listeners, %s', node, node.uuid); + node.removeEventListener('*', null, null); + switch(node.tagName.toLowerCase()){ + case 'frame': + case 'iframe': + try{ + //console.log('removing iframe document'); + try{ + Envjs.unloadFrame(node); + }catch(e){ + console.log('error freeing resources from frame %s', e); + } + node.contentWindow = null; + node.contentDocument = null; + }catch(e){ + console.log('error unloading html element %s %e', node, e.toString()); + } + break; + default: + break; + }//switch on name + default: + break; + }//switch on ns + break; + default: + console.log('element appended: %s %s', node+'', node.namespaceURI); + }//switch on doc.parsing + return node; + +}); + + + +/** + * Named Element Support + * + * + */ + +/* + * + * @returns 'name' if the node has a appropriate name + * null if node does not have a name + */ + +var __isNamedElement__ = function(node) { + if (node.nodeType !== Node.ELEMENT_NODE) { + return null; + } + var tagName = node.tagName.toLowerCase(); + var nodename = null; + + switch (tagName) { + case 'embed': + case 'form': + case 'iframe': + nodename = node.getAttribute('name'); + break; + case 'applet': + nodename = node.id; + break; + case 'object': + // TODO: object needs to be 'fallback free' + nodename = node.id; + break; + case 'img': + nodename = node.id; + if (!nodename || ! node.getAttribute('name')) { + nodename = null; + } + break; + } + return (nodename) ? nodename : null; +}; + + +var __addNamedMap__ = function(target, node) { + var nodename = __isNamedElement__(node); + if (nodename) { + target.__defineGetter__(nodename, function() { + return node; + }); + } +}; + +var __removeNamedMap__ = function(target, node) { + if (!node) { + return; + } + var nodename = __isNamedElement__(node); + if (nodename) { + delete target[nodename]; + } +}; + +/** + * @name HTMLEvents + * @w3c:domlevel 2 + * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html + */ + +var __eval__ = function(script, node){ + if (!script == ""){ + // don't assemble environment if no script... + try{ + eval(script); + }catch(e){ + console.log('error evaluating %s', e); + } + } +}; + +var HTMLEvents= function(){}; +HTMLEvents.prototype = { + onload: function(event){ + __eval__(this.getAttribute('onload')||'', this); + }, + onunload: function(event){ + __eval__(this.getAttribute('onunload')||'', this); + }, + onabort: function(event){ + __eval__(this.getAttribute('onabort')||'', this); + }, + onerror: function(event){ + __eval__(this.getAttribute('onerror')||'', this); + }, + onselect: function(event){ + __eval__(this.getAttribute('onselect')||'', this); + }, + onchange: function(event){ + __eval__(this.getAttribute('onchange')||'', this); + }, + onsubmit: function(event){ + if (__eval__(this.getAttribute('onsubmit')||'', this)) { + this.submit(); + } + }, + onreset: function(event){ + __eval__(this.getAttribute('onreset')||'', this); + }, + onfocus: function(event){ + __eval__(this.getAttribute('onfocus')||'', this); + }, + onblur: function(event){ + __eval__(this.getAttribute('onblur')||'', this); + }, + onresize: function(event){ + __eval__(this.getAttribute('onresize')||'', this); + }, + onscroll: function(event){ + __eval__(this.getAttribute('onscroll')||'', this); + } +}; + +//HTMLDocument, HTMLFramesetElement, HTMLObjectElement +var __load__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("load", false, false); + element.dispatchEvent(event); + return event; +}; + +//HTMLFramesetElement, HTMLBodyElement +var __unload__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("unload", false, false); + element.dispatchEvent(event); + return event; +}; + +//HTMLObjectElement +var __abort__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("abort", true, false); + element.dispatchEvent(event); + return event; +}; + +//HTMLFramesetElement, HTMLObjectElement, HTMLBodyElement +var __error__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("error", true, false); + element.dispatchEvent(event); + return event; +}; + +//HTMLInputElement, HTMLTextAreaElement +var __select__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("select", true, false); + element.dispatchEvent(event); + return event; +}; + +//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement +var __change__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("change", true, false); + element.dispatchEvent(event); + return event; +}; + +//HtmlFormElement +var __submit__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("submit", true, true); + element.dispatchEvent(event); + return event; +}; + +//HtmlFormElement +var __reset__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("reset", false, false); + element.dispatchEvent(event); + return event; +}; + +//LABEL, INPUT, SELECT, TEXTAREA, and BUTTON +var __focus__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("focus", false, false); + element.dispatchEvent(event); + return event; +}; + +//LABEL, INPUT, SELECT, TEXTAREA, and BUTTON +var __blur__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("blur", false, false); + element.dispatchEvent(event); + return event; +}; + +//Window +var __resize__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("resize", true, false); + element.dispatchEvent(event); + return event; +}; + +//Window +var __scroll__ = function(element){ + var event = new Event('HTMLEvents'); + event.initEvent("scroll", true, false); + element.dispatchEvent(event); + return event; +}; + +/** + * @name KeyboardEvents + * @w3c:domlevel 2 + * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html + */ +var KeyboardEvents= function(){}; +KeyboardEvents.prototype = { + onkeydown: function(event){ + __eval__(this.getAttribute('onkeydown')||'', this); + }, + onkeypress: function(event){ + __eval__(this.getAttribute('onkeypress')||'', this); + }, + onkeyup: function(event){ + __eval__(this.getAttribute('onkeyup')||'', this); + } +}; + + +var __registerKeyboardEventAttrs__ = function(elm){ + if(elm.hasAttribute('onkeydown')){ + elm.addEventListener('keydown', elm.onkeydown, false); + } + if(elm.hasAttribute('onkeypress')){ + elm.addEventListener('keypress', elm.onkeypress, false); + } + if(elm.hasAttribute('onkeyup')){ + elm.addEventListener('keyup', elm.onkeyup, false); + } + return elm; +}; + +//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement +var __keydown__ = function(element){ + var event = new Event('KeyboardEvents'); + event.initEvent("keydown", false, false); + element.dispatchEvent(event); +}; + +//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement +var __keypress__ = function(element){ + var event = new Event('KeyboardEvents'); + event.initEvent("keypress", false, false); + element.dispatchEvent(event); +}; + +//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement +var __keyup__ = function(element){ + var event = new Event('KeyboardEvents'); + event.initEvent("keyup", false, false); + element.dispatchEvent(event); +}; + +/** + * @name MaouseEvents + * @w3c:domlevel 2 + * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html + */ +var MouseEvents= function(){}; +MouseEvents.prototype = { + onclick: function(event){ + __eval__(this.getAttribute('onclick')||'', this); + }, + ondblclick: function(event){ + __eval__(this.getAttribute('ondblclick')||'', this); + }, + onmousedown: function(event){ + __eval__(this.getAttribute('onmousedown')||'', this); + }, + onmousemove: function(event){ + __eval__(this.getAttribute('onmousemove')||'', this); + }, + onmouseout: function(event){ + __eval__(this.getAttribute('onmouseout')||'', this); + }, + onmouseover: function(event){ + __eval__(this.getAttribute('onmouseover')||'', this); + }, + onmouseup: function(event){ + __eval__(this.getAttribute('onmouseup')||'', this); + } +}; + +var __registerMouseEventAttrs__ = function(elm){ + if(elm.hasAttribute('onclick')){ + elm.addEventListener('click', elm.onclick, false); + } + if(elm.hasAttribute('ondblclick')){ + elm.addEventListener('dblclick', elm.ondblclick, false); + } + if(elm.hasAttribute('onmousedown')){ + elm.addEventListener('mousedown', elm.onmousedown, false); + } + if(elm.hasAttribute('onmousemove')){ + elm.addEventListener('mousemove', elm.onmousemove, false); + } + if(elm.hasAttribute('onmouseout')){ + elm.addEventListener('mouseout', elm.onmouseout, false); + } + if(elm.hasAttribute('onmouseover')){ + elm.addEventListener('mouseover', elm.onmouseover, false); + } + if(elm.hasAttribute('onmouseup')){ + elm.addEventListener('mouseup', elm.onmouseup, false); + } + return elm; +}; + + +var __click__ = function(element){ + var event = new Event('MouseEvents'); + event.initEvent("click", true, true, null, 0, + 0, 0, 0, 0, false, false, false, + false, null, null); + element.dispatchEvent(event); +}; +var __mousedown__ = function(element){ + var event = new Event('MouseEvents'); + event.initEvent("mousedown", true, true, null, 0, + 0, 0, 0, 0, false, false, false, + false, null, null); + element.dispatchEvent(event); +}; +var __mouseup__ = function(element){ + var event = new Event('MouseEvents'); + event.initEvent("mouseup", true, true, null, 0, + 0, 0, 0, 0, false, false, false, + false, null, null); + element.dispatchEvent(event); +}; +var __mouseover__ = function(element){ + var event = new Event('MouseEvents'); + event.initEvent("mouseover", true, true, null, 0, + 0, 0, 0, 0, false, false, false, + false, null, null); + element.dispatchEvent(event); +}; +var __mousemove__ = function(element){ + var event = new Event('MouseEvents'); + event.initEvent("mousemove", true, true, null, 0, + 0, 0, 0, 0, false, false, false, + false, null, null); + element.dispatchEvent(event); +}; +var __mouseout__ = function(element){ + var event = new Event('MouseEvents'); + event.initEvent("mouseout", true, true, null, 0, + 0, 0, 0, 0, false, false, false, + false, null, null); + element.dispatchEvent(event); +}; + +/** + * HTMLElement - DOM Level 2 + */ + + +/* Hack for http://www.prototypejs.org/ + * + * Prototype 1.6 (the library) creates a new global Element, which causes + * envjs to use the wrong Element. + * + * http://envjs.lighthouseapp.com/projects/21590/tickets/108-prototypejs-wont-load-due-it-clobbering-element + * + * Options: + * (1) Rename the dom/element to something else + * rejected: been done before. people want Element. + * (2) merge dom+html and not export Element to global namespace + * (meaning we would use a local var Element in a closure, so prototype + * can do what ever it wants) + * rejected: want dom and html separate + * (3) use global namespace (put everything under Envjs = {}) + * rejected: massive change + * (4) use commonjs modules (similar to (3) in spirit) + * rejected: massive change + * + * or + * + * (5) take a reference to Element during initial loading ("compile + * time"), and use the reference instead of "Element". That's + * what the next line does. We use __DOMElement__ if we need to + * reference the parent class. Only this file explcity uses + * Element so this should work, and is the most minimal change I + * could think of with no external API changes. + * + */ +var __DOMElement__ = Element; + +HTMLElement = function(ownerDocument) { + __DOMElement__.apply(this, arguments); +}; + +HTMLElement.prototype = new Element(); +__extend__(HTMLElement.prototype, HTMLEvents.prototype); +__extend__(HTMLElement.prototype, { + get className() { + return this.getAttribute("class")||''; + }, + set className(value) { + return this.setAttribute("class",__trim__(value)); + }, + get dir() { + return this.getAttribute("dir")||"ltr"; + }, + set dir(val) { + return this.setAttribute("dir",val); + }, + get id(){ + return this.getAttribute('id'); + }, + set id(id){ + this.setAttribute('id', id); + }, + get innerHTML(){ + var ret = "", + i; + + // create string containing the concatenation of the string + // values of each child + for (i=0; i < this.childNodes.length; i++) { + if(this.childNodes[i]){ + if(this.childNodes[i].nodeType === Node.ELEMENT_NODE){ + ret += this.childNodes[i].xhtml; + } else if (this.childNodes[i].nodeType === Node.TEXT_NODE && i>0 && + this.childNodes[i-1].nodeType === Node.TEXT_NODE){ + //add a single space between adjacent text nodes + ret += " "+this.childNodes[i].xml; + }else{ + ret += this.childNodes[i].xml; + } + } + } + return ret; + }, + get lang() { + return this.getAttribute("lang"); + }, + set lang(val) { + return this.setAttribute("lang",val); + }, + get offsetHeight(){ + return Number((this.style.height || '').replace("px","")); + }, + get offsetWidth(){ + return Number((this.style.width || '').replace("px","")); + }, + offsetLeft: 0, + offsetRight: 0, + get offsetParent(){ + /* TODO */ + return; + }, + set offsetParent(element){ + /* TODO */ + return; + }, + scrollHeight: 0, + scrollWidth: 0, + scrollLeft: 0, + scrollRight: 0, + get style(){ + return this.getAttribute('style')||''; + }, + get title() { + return this.getAttribute("title"); + }, + set title(value) { + return this.setAttribute("title", value); + }, + get tabIndex(){ + var tabindex = this.getAttribute('tabindex'); + if(tabindex!==null){ + return Number(tabindex); + } else { + return 0; + } + }, + set tabIndex(value){ + if (value === undefined || value === null) { + value = 0; + } + this.setAttribute('tabindex',Number(value)); + }, + get outerHTML(){ + //Not in the specs but I'll leave it here for now. + return this.xhtml; + }, + scrollIntoView: function(){ + /*TODO*/ + return; + }, + toString: function(){ + return '[object HTMLElement]'; + }, + get xhtml() { + // HTMLDocument.xhtml is non-standard + // This is exactly like Document.xml except the tagName has to be + // lower cased. I dont like to duplicate this but its really not + // a simple work around between xml and html serialization via + // XMLSerializer (which uppercases html tags) and innerHTML (which + // lowercases tags) + + var ret = "", + ns = "", + name = (this.tagName+"").toLowerCase(), + attrs, + attrstring = "", + i; + + // serialize namespace declarations + if (this.namespaceURI){ + if((this === this.ownerDocument.documentElement) || + (!this.parentNode) || + (this.parentNode && + (this.parentNode.namespaceURI !== this.namespaceURI))) { + ns = ' xmlns' + (this.prefix ? (':' + this.prefix) : '') + + '="' + this.namespaceURI + '"'; + } + } + + // serialize Attribute declarations + attrs = this.attributes; + for(i=0;i< attrs.length;i++){ + attrstring += " "+attrs[i].name+'="'+attrs[i].xml+'"'; + } + + if(this.hasChildNodes()){ + // serialize this Element + ret += "<" + name + ns + attrstring +">"; + for(i=0;i< this.childNodes.length;i++){ + ret += this.childNodes[i].xhtml ? + this.childNodes[i].xhtml : + this.childNodes[i].xml; + } + ret += ""; + }else{ + switch(name){ + case 'script': + ret += "<" + name + ns + attrstring +">"; + break; + default: + ret += "<" + name + ns + attrstring +"/>"; + } + } + + return ret; + }, + + /** + * setAttribute use a dispatch table that other tags can set to + * "listen" to various values being set. The dispatch table + * and registration functions are at the end of the file. + * + */ + + setAttribute: function(name, value) { + var result = __DOMElement__.prototype.setAttribute.apply(this, arguments); + __addNamedMap__(this.ownerDocument, this); + var tagname = this.tagName; + var callback = HTMLElement.getAttributeCallback('set', tagname, name); + if (callback) { + callback(this, value); + } + }, + setAttributeNS: function(namespaceURI, name, value) { + var result = __DOMElement__.prototype.setAttributeNS.apply(this, arguments); + __addNamedMap__(this.ownerDocument, this); + var tagname = this.tagName; + var callback = HTMLElement.getAttributeCallback('set', tagname, name); + if (callback) { + callback(this, value); + } + + return result; + }, + setAttributeNode: function(newnode) { + var result = __DOMElement__.prototype.setAttributeNode.apply(this, arguments); + __addNamedMap__(this.ownerDocument, this); + var tagname = this.tagName; + var callback = HTMLElement.getAttributeCallback('set', tagname, newnode.name); + if (callback) { + callback(this, node.value); + } + return result; + }, + setAttributeNodeNS: function(newnode) { + var result = __DOMElement__.prototype.setAttributeNodeNS.apply(this, arguments); + __addNamedMap__(this.ownerDocument, this); + var tagname = this.tagName; + var callback = HTMLElement.getAttributeCallback('set', tagname, newnode.name); + if (callback) { + callback(this, node.value); + } + return result; + }, + removeAttribute: function(name) { + __removeNamedMap__(this.ownerDocument, this); + return __DOMElement__.prototype.removeAttribute.apply(this, arguments); + }, + removeAttributeNS: function(namespace, localname) { + __removeNamedMap__(this.ownerDocument, this); + return __DOMElement__.prototype.removeAttributeNS.apply(this, arguments); + }, + removeAttributeNode: function(name) { + __removeNamedMap__(this.ownerDocument, this); + return __DOMElement__.prototype.removeAttribute.apply(this, arguments); + }, + removeChild: function(oldChild) { + __removeNamedMap__(this.ownerDocument, oldChild); + return __DOMElement__.prototype.removeChild.apply(this, arguments); + }, + importNode: function(othernode, deep) { + var newnode = __DOMElement__.prototype.importNode.apply(this, arguments); + __addNamedMap__(this.ownerDocument, newnode); + return newnode; + }, + + // not actually sure if this is needed or not + replaceNode: function(newchild, oldchild) { + var newnode = __DOMElement__.prototype.replaceNode.apply(this, arguments); + __removeNamedMap__(this.ownerDocument, oldchild); + __addNamedMap__(this.ownerDocument, newnode); + return newnode; + } +}); + + +HTMLElement.attributeCallbacks = {}; +HTMLElement.registerSetAttribute = function(tag, attrib, callbackfn) { + HTMLElement.attributeCallbacks[tag + ':set:' + attrib] = callbackfn; +}; +HTMLElement.registerRemoveAttribute = function(tag, attrib, callbackfn) { + HTMLElement.attributeCallbacks[tag + ':remove:' + attrib] = callbackfn; +}; + +/** + * This is really only useful internally + * + */ +HTMLElement.getAttributeCallback = function(type, tag, attrib) { + return HTMLElement.attributeCallbacks[tag + ':' + type + ':' + attrib] || null; +}; +/* + * HTMLCollection + * + * HTML5 -- 2.7.2.1 HTMLCollection + * http://dev.w3.org/html5/spec/Overview.html#htmlcollection + * http://dev.w3.org/html5/spec/Overview.html#collections + */ +HTMLCollection = function(nodelist, type) { + + __setArray__(this, []); + var n; + for (var i=0; i= 0) && (idx < this.length)) ? this[idx] : null; + }, + + namedItem: function (name) { + return this[name] || null; + }, + + toString: function() { + return '[object HTMLCollection]'; + } +}; +/* + * a set of convenience classes to centralize implementation of + * properties and methods across multiple in-form elements + * + * the hierarchy of related HTML elements and their members is as follows: + * + * Condensed Version + * + * HTMLInputCommon + * * legent (no value attr) + * * fieldset (no value attr) + * * label (no value attr) + * * option (custom value) + * HTMLTypeValueInputs (extends InputCommon) + * * select (custom value) + * * button (just sets value) + * HTMLInputAreaCommon (extends TypeValueIput) + * * input (custom) + * * textarea (just sets value) + * + * ----------------------- + * HTMLInputCommon: common to all elements + * .form + * + * + * [common plus:] + * .align + * + *
+ * [identical to "legend" plus:] + * .margin + * + * + * **** + * + *