nwmatcher/0000755000175000017500000000000012316015515011201 5ustar wmbwmbnwmatcher/.npmignore0000644000175000017500000000011312316015515013173 0ustar wmbwmbbin/ build/ dist/ lib/ test/ .gitattributes .gitignore .npmignore Makefile nwmatcher/bin/0000755000175000017500000000000012407423423011753 5ustar wmbwmbnwmatcher/build/0000755000175000017500000000000012316015515012300 5ustar wmbwmbnwmatcher/build/HEADER0000644000175000017500000000017712316015515013160 0ustar wmbwmb/*! * NWMatcher 1.3.3 - Fast CSS3 Selector Engine * Copyright (C) 2007-2014 Diego Perini * See http://nwbox.com/license */ nwmatcher/build/conf/0000755000175000017500000000000012316015515013225 5ustar wmbwmbnwmatcher/build/conf/jsl.default.conf0000755000175000017500000001354712316015515016324 0ustar wmbwmb# # Configuration File for JavaScript Lint 0.3.0 # Developed by Matthias Miller (http://www.JavaScriptLint.com) # # This configuration file can be used to lint a collection of scripts, or to enable # or disable warnings for scripts that are linted via the command line. # ### Warnings # Enable or disable warnings based on requirements. # Use "+WarningName" to display or "-WarningName" to suppress. # +no_return_value # function {0} does not always return a value +duplicate_formal # duplicate formal argument {0} +equal_as_assign # test for equality (==) mistyped as assignment (=)?{0} +var_hides_arg # variable {0} hides argument +redeclared_var # redeclaration of {0} {1} +anon_no_return_value # anonymous function does not always return a value +missing_semicolon # missing semicolon +meaningless_block # meaningless block; curly braces have no impact +comma_separated_stmts # multiple statements separated by commas (use semicolons?) +unreachable_code # unreachable code +missing_break # missing break statement +missing_break_for_last_case # missing break statement for last case in switch +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) +inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement +useless_void # use of the void type may be unnecessary (void is always undefined) +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs +use_of_label # use of label -block_without_braces # block statement without curly braces +leading_decimal_point # leading decimal point may indicate a number or an object member +trailing_decimal_point # trailing decimal point may indicate a number or an object member +octal_number # leading zeros make an octal number +nested_comment # nested comment +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement +empty_statement # empty statement or extra semicolon -missing_option_explicit # the "option explicit" control comment is missing +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag +dup_option_explicit # duplicate "option explicit" control comment +useless_assign # useless assignment +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent) +missing_default_case # missing default case in switch statement +duplicate_case_in_switch # duplicate case in switch statements +default_not_at_end # the default case is not at the end of the switch statement +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax +useless_comparison # useless comparison; comparing identical expressions +with_statement # with statement hides undeclared variables; use temporary variable instead +trailing_comma_in_array # extra comma is not recommended in array initializers +assign_to_function_call # assignment to a function call +parseint_missing_radix # parseInt missing radix parameter ### Output format # Customize the format of the error message. # __FILE__ indicates current file path # __FILENAME__ indicates current file name # __LINE__ indicates current line # __ERROR__ indicates error message # # Visual Studio syntax (default): +output-format __FILE__(__LINE__): __ERROR__ # Alternative syntax: #+output-format __FILE__:__LINE__: __ERROR__ ### Context # Show the in-line position of the error. # Use "+context" to display or "-context" to suppress. # +context ### Semicolons # By default, assignments of an anonymous function to a variable or # property (such as a function prototype) must be followed by a semicolon. # +lambda_assign_requires_semicolon ### Control Comments # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason, # although legacy control comments are enabled by default for backward compatibility. # +legacy_control_comments ### JScript Function Extensions # JScript allows member functions to be defined like this: # function MyObj() { /*constructor*/ } # function MyObj.prototype.go() { /*member function*/ } # # It also allows events to be attached like this: # function window::onload() { /*init page*/ } # # This is a Microsoft-only JavaScript extension. Enable this setting to allow them. # -jscript_function_extensions ### Defining identifiers # By default, "option explicit" is enabled on a per-file basis. # To enable this for all files, use "+always_use_option_explicit" -always_use_option_explicit # Define certain identifiers of which the lint is not aware. # (Use this in conjunction with the "undeclared identifier" warning.) # # Common uses for webpages might be: #+define window #+define document ### Files # Specify which files to lint # Use "+recurse" to enable recursion (disabled by default). # To add a set of files, use "+process FileName", "+process Folder\Path\*.js", # or "+process Folder\Path\*.htm". # #+process jsl-test.js nwmatcher/build/conf/jsl.conf0000755000175000017500000001354712316015515014701 0ustar wmbwmb# # Configuration File for JavaScript Lint 0.3.0 # Developed by Matthias Miller (http://www.JavaScriptLint.com) # # This configuration file can be used to lint a collection of scripts, or to enable # or disable warnings for scripts that are linted via the command line. # ### Warnings # Enable or disable warnings based on requirements. # Use "+WarningName" to display or "-WarningName" to suppress. # -no_return_value # function {0} does not always return a value +duplicate_formal # duplicate formal argument {0} -equal_as_assign # test for equality (==) mistyped as assignment (=)?{0} +var_hides_arg # variable {0} hides argument +redeclared_var # redeclaration of {0} {1} -anon_no_return_value # anonymous function does not always return a value -missing_semicolon # missing semicolon +meaningless_block # meaningless block; curly braces have no impact +comma_separated_stmts # multiple statements separated by commas (use semicolons?) +unreachable_code # unreachable code +missing_break # missing break statement +missing_break_for_last_case # missing break statement for last case in switch -comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) -inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement +useless_void # use of the void type may be unnecessary (void is always undefined) +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs +use_of_label # use of label -block_without_braces # block statement without curly braces +leading_decimal_point # leading decimal point may indicate a number or an object member +trailing_decimal_point # trailing decimal point may indicate a number or an object member +octal_number # leading zeros make an octal number +nested_comment # nested comment +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma -ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement +empty_statement # empty statement or extra semicolon -missing_option_explicit # the "option explicit" control comment is missing +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag +dup_option_explicit # duplicate "option explicit" control comment +useless_assign # useless assignment -ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent) +missing_default_case # missing default case in switch statement +duplicate_case_in_switch # duplicate case in switch statements +default_not_at_end # the default case is not at the end of the switch statement +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax +useless_comparison # useless comparison; comparing identical expressions +with_statement # with statement hides undeclared variables; use temporary variable instead +trailing_comma_in_array # extra comma is not recommended in array initializers +assign_to_function_call # assignment to a function call +parseint_missing_radix # parseInt missing radix parameter ### Output format # Customize the format of the error message. # __FILE__ indicates current file path # __FILENAME__ indicates current file name # __LINE__ indicates current line # __ERROR__ indicates error message # # Visual Studio syntax (default): +output-format __FILE__(__LINE__): __ERROR__ # Alternative syntax: #+output-format __FILE__:__LINE__: __ERROR__ ### Context # Show the in-line position of the error. # Use "+context" to display or "-context" to suppress. # +context ### Semicolons # By default, assignments of an anonymous function to a variable or # property (such as a function prototype) must be followed by a semicolon. # +lambda_assign_requires_semicolon ### Control Comments # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason, # although legacy control comments are enabled by default for backward compatibility. # +legacy_control_comments ### JScript Function Extensions # JScript allows member functions to be defined like this: # function MyObj() { /*constructor*/ } # function MyObj.prototype.go() { /*member function*/ } # # It also allows events to be attached like this: # function window::onload() { /*init page*/ } # # This is a Microsoft-only JavaScript extension. Enable this setting to allow them. # -jscript_function_extensions ### Defining identifiers # By default, "option explicit" is enabled on a per-file basis. # To enable this for all files, use "+always_use_option_explicit" -always_use_option_explicit # Define certain identifiers of which the lint is not aware. # (Use this in conjunction with the "undeclared identifier" warning.) # # Common uses for webpages might be: #+define window #+define document ### Files # Specify which files to lint # Use "+recurse" to enable recursion (disabled by default). # To add a set of files, use "+process FileName", "+process Folder\Path\*.js", # or "+process Folder\Path\*.htm". # #+process jsl-test.js nwmatcher/build/scripts/0000755000175000017500000000000012316015515013767 5ustar wmbwmbnwmatcher/build/scripts/nwpacker.js0000755000175000017500000000154412316015515016146 0ustar wmbwmb/* * SpiderMonkey wrapper to compress Javascript source files, * uses Dean Edwards (http://dean.edwards.name/packer/) * * Author: Diego Perini * * Usage: fusecomp.js < input > output (uses stdin/stdout) * * Depends on correctly installed SpiderMonkey executable (js) * * Released under the Creative Commons license: * http://creativecommons.org/licenses/by/3.0/ */ // import Dean Edwards project files load("build/packer/base2.js"); load("build/packer/packer.js"); // read file from stdin function _readFile(from) { var outstr = '', line = ''; while ((line = readline()) != null) { outstr += line + '\x0a'; } return outstr; } // read from input pack and send to output (function minify() { // create new packer instance var packer = new Packer(); // shrink! print(packer.pack(_readFile(), 0, 1, 1)); })(); nwmatcher/build/scripts/nwtestjs.sh0000755000175000017500000000135312316015515016211 0ustar wmbwmb#!/bin/bash echo -ne "NW: VM loading test, building test units..." # retrieve build infos VERSION=`cat ${SOURCES}build/VERSION` REVISION=1 # set used variables BASEDIR=`pwd` PKGNAME="nwmatcher" RELEASE=`date +%Y%m%d%H%M%S` # set source SOURCES=${1} if [ "${SOURCES}x" == 'x' ]; then pushd . &> /dev/null cd ..; SOURCES=`pwd` popd &> /dev/null fi # check platform PLATFORM=`uname -s` if [ $PLATFORM == 'Darwin' ]; then JS=bin/js_macos elif [ $PLATFORM == 'Linux' ]; then JS=bin/js_linux elif [ $PLATFORM == 'Windows' ]; then JS=bin/js.exe fi pusdh . &> /dev/null $JS test/jsvm/load_test.js < test/jsvm/load_test.html if [ $? == '0' ]; then echo 'PASSED' elif [ $? != '0' ]; then echo 'FAILED' fi popd &> /dev/null exit 0 nwmatcher/build/scripts/nwjslint.sh0000755000175000017500000000151012316015515016173 0ustar wmbwmb#!/bin/bash echo -ne "NW: running javascript lint on sources" # set sources SOURCES=${1} if [ "${SOURCES}x" == 'x' ]; then pushd . &> /dev/null cd ..; SOURCES=`pwd` popd &> /dev/null fi # check platform PLATFORM=`uname -s` # set platform specifick executables if [ $PLATFORM == 'Darwin' ]; then JSL=bin/jsl_macos elif [ $PLATFORM == 'Linux' ]; then JSL=bin/jsl_linux elif [ $PLATFORM == 'Windows' ]; then JSL=bin/jsl.exe fi # save current working path pusdh . &> /dev/null # enter root path cd $SOURCES > $SOURCES/dist/lint.log for item in `find $SOURCES/src -type d` do { sources=`ls $item/*.js 2>/dev/null` for file in $sources do { $JSL -conf build/conf/jsl.conf -nologo -nofilelisting -nosummary -process $file >> $SOURCES/dist/lint.log echo -ne "." } done } done echo "" popd &> /dev/null exit 0 nwmatcher/build/scripts/nwpackjs.sh0000755000175000017500000000303012316015515016142 0ustar wmbwmb#!/bin/bash echo -ne "NW: building distribution from sources" # retrieve build infos VERSION=`cat ${SOURCES}build/VERSION` REVISION=1 # set used variables BASEDIR=`pwd` PKGNAME="nwmatcher" RELEASE=`date +%Y%m%d%H%M%S` # set sources SOURCES=${1} if [ "${SOURCES}x" == 'x' ]; then pushd . &> /dev/null cd ..; SOURCES=`pwd` popd &> /dev/null fi # check working platform PLATFORM=`uname -s` # set platform specifick executables if [ $PLATFORM == 'Darwin' ]; then JSMIN=bin/jsmin_macos JSVM=bin/js_macos elif [ $PLATFORM == 'Linux' ]; then JSMIN=bin/jsmin_linux JSVM=bin/js_linux elif [ $PLATFORM == 'Windows' ]; then JSMIN=bin/jsmin.exe JSVM=bin/js.exe fi pushd . &> /dev/null cd $SOURCES # ensure empty > dist/$PKGNAME-src.js > dist/$PKGNAME-min.js cat build/HEADER >> dist/$PKGNAME-pac.js # add selector engine to source file cat src/nwmatcher.js >> dist/$PKGNAME-src.js # add selector engine to minified file cat src/nwmatcher.js | $JSMIN | tr -d "\n" >> dist/$PKGNAME-min.js # minification of variables and privates echo "" echo -ne "NW: starting minification, takes time please wait, " $JSVM build/scripts/nwpacker.js < dist/nwmatcher-src.js >> dist/nwmatcher-pac.js echo -ne "complete..." echo "" # build a compressed version of the minified file gzip -c -n9 dist/$PKGNAME-pac.js > dist/$PKGNAME-zip.js # build a versioned file name of the minified file #cp dist/$PKGNAME-pac.js dist/$PKGNAME-$RELEASE.js # now copy packed file to the real nwmatcher.js cp dist/nwmatcher-pac.js dist/nwmatcher.js popd &> /dev/null exit 0 nwmatcher/build/packer/0000755000175000017500000000000012316015515013545 5ustar wmbwmbnwmatcher/build/packer/packer.js0000644000175000017500000004077612316015515015366 0ustar wmbwmb/* Packer version 3.1 - copyright 2004-2008, Dean Edwards http://www.opensource.org/licenses/mit-license.php */ // timestamp: Mon, 30 Mar 2009 18:26:18 new function() { /////////////// BEGIN: CLOSURE /////////////// new base2.Package(this, { imports: "Function2,Enumerable" }); eval(this.imports); var IGNORE = RegGrp.IGNORE; var KEYS = "~"; var REMOVE = ""; var SPACE = " "; // ========================================================================= // packer/Parser.js // ========================================================================= var Parser = RegGrp.extend({ put: function(expression, replacement) { if (typeOf(expression) == "string") { expression = Parser.dictionary.exec(expression); } this.base(expression, replacement); } }, { dictionary: new RegGrp({ OPERATOR: /return|typeof|[\[(\^=,{}:;&|!*?]/.source, CONDITIONAL: /\/\*@\w*|\w*@\*\/|\/\/@\w*|@\w+/.source, COMMENT1: /\/\/[^\n]*/.source, COMMENT2: /\/\*[^*]*\*+([^\/][^*]*\*+)*\//.source, REGEXP: /\/(\\[\/\\]|[^*\/])(\\.|[^\/\n\\])*\/[gim]*/.source, STRING1: /'(\\.|[^'\\])*'/.source, STRING2: /"(\\.|[^"\\])*"/.source }) }); // ========================================================================= // packer/Words.js // ========================================================================= var Words = Collection.extend({ add: function(word) { if (!this.has(word)) this.base(word); word = this.get(word); if (!word.index) { word.index = this.size(); } word.count++; return word; }, sort: function(sorter) { return this.base(sorter || function(word1, word2) { // sort by frequency return (word2.count - word1.count) || (word1.index - word2.index); }); } }, { Item: { constructor: function(word) { this.toString = K(word); }, index: 0, count: 0, encoded: "" } }); // ========================================================================= // packer/Encoder.js // ========================================================================= var Encoder = Base.extend({ constructor: function(pattern, encoder, ignore) { this.parser = new Parser(ignore); if (pattern) this.parser.put(pattern, ""); this.encoder = encoder; }, parser: null, encoder: Undefined, search: function(script) { var words = new Words; this.parser.putAt(-1, function(word) { words.add(word); }); this.parser.exec(script); return words; }, encode: function(script) { var words = this.search(script); words.sort(); var index = 0; forEach (words, function(word) { word.encoded = this.encoder(index++); }, this); this.parser.putAt(-1, function(word) { return words.get(word).encoded; }); return this.parser.exec(script); } }); // ========================================================================= // packer/Privates.js // ========================================================================= var Privates = Encoder.extend({ constructor: function() { return this.base(Privates.PATTERN, function(index) { return "_" + Packer.encode62(index); }, Privates.IGNORE); } }, { IGNORE: { CONDITIONAL: IGNORE, "(OPERATOR)(REGEXP)": IGNORE }, PATTERN: /\b_[\da-zA-Z$][\w$]*\b/g }); // ========================================================================= // packer/Base62.js // ========================================================================= var Base62 = Encoder.extend({ encode: function(script) { var words = this.search(script); words.sort(); var encoded = new Collection; // a dictionary of base62 -> base10 var size = words.size(); for (var i = 0; i < size; i++) { encoded.put(Packer.encode62(i), i); } function replacement(word) { return words["#" + word].replacement; }; var empty = K(""); var index = 0; forEach (words, function(word) { if (encoded.has(word)) { word.index = encoded.get(word); word.toString = empty; } else { while (words.has(Packer.encode62(index))) index++; word.index = index++; if (word.count == 1) { word.toString = empty; } } word.replacement = Packer.encode62(word.index); if (word.replacement.length == word.toString().length) { word.toString = empty; } }); // sort by encoding words.sort(function(word1, word2) { return word1.index - word2.index; }); // trim unencoded words words = words.slice(0, this.getKeyWords(words).split("|").length); script = script.replace(this.getPattern(words), replacement); /* build the packed script */ var p = this.escape(script); var a = "[]"; var c = this.getCount(words); var k = this.getKeyWords(words); var e = this.getEncoder(words); var d = this.getDecoder(words); // the whole thing return format(Base62.UNPACK, p,a,c,k,e,d); }, search: function(script) { var words = new Words; forEach (script.match(Base62.WORDS), words.add, words); return words; }, escape: function(script) { // Single quotes wrap the final string so escape them. // Also, escape new lines (required by conditional comments). return script.replace(/([\\'])/g, "\\$1").replace(/[\r\n]+/g, "\\n"); }, getCount: function(words) { return words.size() || 1; }, getDecoder: function(words) { // returns a pattern used for fast decoding of the packed script var trim = new RegGrp({ "(\\d)(\\|\\d)+\\|(\\d)": "$1-$3", "([a-z])(\\|[a-z])+\\|([a-z])": "$1-$3", "([A-Z])(\\|[A-Z])+\\|([A-Z])": "$1-$3", "\\|": "" }); var pattern = trim.exec(words.map(function(word) { if (word.toString()) return word.replacement; return ""; }).slice(0, 62).join("|")); if (!pattern) return "^$"; pattern = "[" + pattern + "]"; var size = words.size(); if (size > 62) { pattern = "(" + pattern + "|"; var c = Packer.encode62(size).charAt(0); if (c > "9") { pattern += "[\\\\d"; if (c >= "a") { pattern += "a"; if (c >= "z") { pattern += "-z"; if (c >= "A") { pattern += "A"; if (c > "A") pattern += "-" + c; } } else if (c == "b") { pattern += "-" + c; } } pattern += "]"; } else if (c == 9) { pattern += "\\\\d"; } else if (c == 2) { pattern += "[12]"; } else if (c == 1) { pattern += "1"; } else { pattern += "[1-" + c + "]"; } pattern += "\\\\w)"; } return pattern; }, getEncoder: function(words) { var size = words.size(); return Base62["ENCODE" + (size > 10 ? size > 36 ? 62 : 36 : 10)]; }, getKeyWords: function(words) { return words.map(String).join("|").replace(/\|+$/, ""); }, getPattern: function(words) { words = words.map(String).join("|").replace(/\|{2,}/g, "|").replace(/^\|+|\|+$/g, "") || "\\x0"; return new RegExp("\\b(" + words + ")\\b", "g"); } }, { WORDS: /\b[\da-zA-Z]\b|\w{2,}/g, ENCODE10: "String", ENCODE36: "function(c){return c.toString(36)}", ENCODE62: "function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))}", UNPACK: "eval(function(p,a,c,k,e,r){e=%5;if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];" + "k=[function(e){return r[e]||e}];e=function(){return'%6'};c=1};while(c--)if(k[c])p=p." + "replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('%1',%2,%3,'%4'.split('|'),0,{}))" }); // ========================================================================= // packer/Packer.js // ========================================================================= global.Packer = Base.extend({ constructor: function() { this.minifier = new Minifier; this.shrinker = new Shrinker; this.privates = new Privates; this.base62 = new Base62; }, minifier: null, shrinker: null, privates: null, base62: null, pack: function(script, base62, shrink, privates) { script = this.minifier.minify(script); if (shrink) script = this.shrinker.shrink(script); if (privates) script = this.privates.encode(script); if (base62) script = this.base62.encode(script); return script; } }, { version: "3.1", init: function() { eval("var e=this.encode62=" + Base62.ENCODE62); }, data: new Parser({ "STRING1": IGNORE, 'STRING2': IGNORE, "CONDITIONAL": IGNORE, // conditional comments "(OPERATOR)\\s*(REGEXP)": "$1$2" }), encode52: function(c) { // Base52 encoding (a-Z) function encode(c) { return (c < 52 ? '' : encode(parseInt(c / 52))) + ((c = c % 52) > 25 ? String.fromCharCode(c + 39) : String.fromCharCode(c + 97)); }; var encoded = encode(c); if (/^(do|if|in)$/.test(encoded)) encoded = encoded.slice(1) + 0; return encoded; } }); // ========================================================================= // packer/Minifier.js // ========================================================================= var Minifier = Base.extend({ minify: function(script) { // packing with no additional options script += "\n"; script = script.replace(Minifier.CONTINUE, ""); script = Minifier.comments.exec(script); script = Minifier.clean.exec(script); script = Minifier.whitespace.exec(script); script = Minifier.concat.exec(script); return script; } }, { CONTINUE: /\\\r?\n/g, init: function() { this.concat = new Parser(this.concat).merge(Packer.data); extend(this.concat, "exec", function(script) { var parsed = this.base(script); while (parsed != script) { script = parsed; parsed = this.base(script); } return parsed; }); forEach.csv("comments,clean,whitespace", function(name) { this[name] = Packer.data.union(new Parser(this[name])); }, this); this.conditionalComments = this.comments.copy(); this.conditionalComments.putAt(-1, " $3"); this.whitespace.removeAt(2); // conditional comments this.comments.removeAt(2); }, clean: { "\\(\\s*([^;)]*)\\s*;\\s*([^;)]*)\\s*;\\s*([^;)]*)\\)": "($1;$2;$3)", // for (;;) loops "throw[^};]+[};]": IGNORE, // a safari 1.3 bug ";+\\s*([};])": "$1" }, comments: { ";;;[^\\n]*\\n": REMOVE, "(COMMENT1)\\n\\s*(REGEXP)?": "\n$3", "(COMMENT2)\\s*(REGEXP)?": function(match, comment, $2, regexp) { if (/^\/\*@/.test(comment) && /@\*\/$/.test(comment)) { comment = Minifier.conditionalComments.exec(comment); } else { comment = ""; } return comment + " " + (regexp || ""); } }, concat: { "(STRING1)\\+(STRING1)": function(match, a, $2, b) { return a.slice(0, -1) + b.slice(1); }, "(STRING2)\\+(STRING2)": function(match, a, $2, b) { return a.slice(0, -1) + b.slice(1); } }, whitespace: { "\\/\\/@[^\\n]*\\n": IGNORE, "@\\s+\\b": "@ ", // protect conditional comments "\\b\\s+@": " @", "(\\d)\\s+(\\.\\s*[a-z\\$_\\[(])": "$1 $2", // http://dean.edwards.name/weblog/2007/04/packer3/#comment84066 "([+-])\\s+([+-])": "$1 $2", // c = a++ +b; "(\\w)\\s+([\\u0080-\\uffff])": "$1 $2", // http://code.google.com/p/base2/issues/detail?id=78 "\\b\\s+\\$\\s+\\b": " $ ", // var $ in "\\$\\s+\\b": "$ ", // object$ in "\\b\\s+\\$": " $", // return $object // "\\b\\s+#": " #", // CSS "\\b\\s+\\b": SPACE, "\\s+": REMOVE } }); // ========================================================================= // packer/Shrinker.js // ========================================================================= var Shrinker = Base.extend({ decodeData: function(script) { // put strings and regular expressions back var data = this._data; // encoded strings and regular expressions delete this._data; return script.replace(Shrinker.ENCODED_DATA, function(match, index) { return data[index]; }); }, encodeData: function(script) { // encode strings and regular expressions var data = this._data = []; // encoded strings and regular expressions return Packer.data.exec(script, function(match, operator, regexp) { var replacement = "\x01" + data.length + "\x01"; if (regexp) { replacement = operator + replacement; match = regexp; } data.push(match); return replacement; }); }, shrink: function(script) { script = this.encodeData(script); // Windows Scripting Host cannot do regexp.test() on global regexps. function global(regexp) { // This function creates a global version of the passed regexp. return new RegExp(regexp.source, "g"); }; // identify blocks, particularly identify function blocks (which define scope) var BLOCK = /((catch|do|if|while|with|function)\b[^~{};]*(\(\s*[^{};]*\s*\))\s*)?(\{[^{}]*\})/; var BLOCK_g = global(BLOCK); var BRACKETS = /\{[^{}]*\}|\[[^\[\]]*\]|\([^\(\)]*\)|~[^~]+~/; var BRACKETS_g = global(BRACKETS); var ENCODED_BLOCK = /~#?(\d+)~/; var IDENTIFIER = /[a-zA-Z_$][\w\$]*/g; var SCOPED = /~#(\d+)~/; var VAR_g = /\bvar\b/g; var VARS = /\bvar\s+[\w$]+[^;#]*|\bfunction\s+[\w$]+/g; var VAR_TIDY = /\b(var|function)\b|\sin\s+[^;]+/g; var VAR_EQUAL = /\s*=[^,;]*/g; var blocks = []; // store program blocks (anything between braces {}) var total = 0; // encoder for program blocks function encodeBlocks($, prefix, blockType, args, block) { if (!prefix) prefix = ""; if (blockType == "function") { // decode the function block (THIS IS THE IMPORTANT BIT) // We are retrieving all sub-blocks and will re-parse them in light // of newly shrunk variables block = args + decodeBlocks(block, SCOPED); prefix = prefix.replace(BRACKETS, ""); // create the list of variable and argument names args = args.slice(1, -1); if (args != "_no_shrink_") { var vars = match(block, VARS).join(";").replace(VAR_g, ";var"); while (BRACKETS.test(vars)) { vars = vars.replace(BRACKETS_g, ""); } vars = vars.replace(VAR_TIDY, "").replace(VAR_EQUAL, ""); } block = decodeBlocks(block, ENCODED_BLOCK); // process each identifier if (args != "_no_shrink_") { var count = 0, shortId; var ids = match([args, vars], IDENTIFIER); var processed = {}; for (var i = 0; i < ids.length; i++) { id = ids[i]; if (!processed["#" + id]) { processed["#" + id] = true; id = rescape(id); // encode variable names while (new RegExp(Shrinker.PREFIX + count + "\\b").test(block)) count++; var reg = new RegExp("([^\\w$.])" + id + "([^\\w$:])"); while (reg.test(block)) { block = block.replace(global(reg), "$1" + Shrinker.PREFIX + count + "$2"); } var reg = new RegExp("([^{,\\w$.])" + id + ":", "g"); block = block.replace(reg, "$1" + Shrinker.PREFIX + count + ":"); count++; } } total = Math.max(total, count); } var replacement = prefix + "~" + blocks.length + "~"; blocks.push(block); } else { var replacement = "~#" + blocks.length + "~"; blocks.push(prefix + block); } return replacement; }; // decoder for program blocks function decodeBlocks(script, encoded) { while (encoded.test(script)) { script = script.replace(global(encoded), function(match, index) { return blocks[index]; }); } return script; }; // encode blocks, as we encode we replace variable and argument names while (BLOCK.test(script)) { script = script.replace(BLOCK_g, encodeBlocks); } // put the blocks back script = decodeBlocks(script, ENCODED_BLOCK); var shortId, count = 0; var shrunk = new Encoder(Shrinker.SHRUNK, function() { // find the next free short name do shortId = Packer.encode52(count++); while (new RegExp("[^\\w$.]" + shortId + "[^\\w$:]").test(script)); return shortId; }); script = shrunk.encode(script); return this.decodeData(script); } }, { ENCODED_DATA: /\x01(\d+)\x01/g, PREFIX: "\x02", SHRUNK: /\x02\d+\b/g }); }; //////////////////// END: CLOSURE ///////////////////////////////////// nwmatcher/build/packer/base2.js0000644000175000017500000014235412316015515015110 0ustar wmbwmb/* base2 - copyright 2007-2008, Dean Edwards http://code.google.com/p/base2/ http://www.opensource.org/licenses/mit-license.php Contributors: Doeke Zanstra */ // timestamp: Sat, 06 Sep 2008 16:52:32 var base2 = { name: "base2", version: "1.0", exports: "Base,Package,Abstract,Module,Enumerable,Map,Collection,RegGrp," + "Undefined,Null,This,True,False,assignID,detect,global", namespace: "" }; new function(_no_shrink_) { /////////////// BEGIN: CLOSURE /////////////// // ========================================================================= // base2/header.js // ========================================================================= var Undefined = K(), Null = K(null), True = K(true), False = K(false), This = function(){return this}; var global = This(); var base2 = global.base2; // private var _FORMAT = /%([1-9])/g; var _LTRIM = /^\s\s*/; var _RTRIM = /\s\s*$/; var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g; // safe regular expressions var _BASE = /try/.test(detect) ? /\bbase\b/ : /.*/; // some platforms don't allow decompilation var _HIDDEN = ["constructor", "toString", "valueOf"]; // only override these when prototyping var _MSIE_NATIVE_FUNCTION = detect("(jscript)") ? new RegExp("^" + rescape(isNaN).replace(/isNaN/, "\\w+") + "$") : {test: False}; var _counter = 1; var _slice = Array.prototype.slice; _Function_forEach(); // make sure this is initialised function assignID(object) { // Assign a unique ID to an object. if (!object.base2ID) object.base2ID = "b2_" + _counter++; return object.base2ID; }; // ========================================================================= // base2/Base.js // ========================================================================= // http://dean.edwards.name/weblog/2006/03/base/ var _subclass = function(_instance, _static) { // Build the prototype. base2.__prototyping = this.prototype; var _prototype = new this; if (_instance) extend(_prototype, _instance); delete base2.__prototyping; // Create the wrapper for the constructor function. var _constructor = _prototype.constructor; function _class() { // Don't call the constructor function when prototyping. if (!base2.__prototyping) { if (this.constructor == arguments.callee || this.__constructing) { // Instantiation. this.__constructing = true; _constructor.apply(this, arguments); delete this.__constructing; } else { // Casting. return extend(arguments[0], _prototype); } } return this; }; _prototype.constructor = _class; // Build the static interface. for (var i in Base) _class[i] = this[i]; _class.ancestor = this; _class.base = Undefined; //_class.init = Undefined; if (_static) extend(_class, _static); _class.prototype = _prototype; if (_class.init) _class.init(); // introspection (removed when packed) ;;; _class["#implements"] = []; ;;; _class["#implemented_by"] = []; return _class; }; var Base = _subclass.call(Object, { constructor: function() { if (arguments.length > 0) { this.extend(arguments[0]); } }, base: function() { // Call this method from any other method to invoke the current method's ancestor (super). }, extend: delegate(extend) }, Base = { ancestorOf: function(klass) { return _ancestorOf(this, klass); }, extend: _subclass, forEach: function(object, block, context) { _Function_forEach(this, object, block, context); }, implement: function(source) { if (typeof source == "function") { ;;; if (_ancestorOf(Base, source)) { // introspection (removed when packed) ;;; this["#implements"].push(source); ;;; source["#implemented_by"].push(this); ;;; } source = source.prototype; } // Add the interface using the extend() function. extend(this.prototype, source); return this; } }); // ========================================================================= // base2/Package.js // ========================================================================= var Package = Base.extend({ constructor: function(_private, _public) { this.extend(_public); if (this.init) this.init(); if (this.name && this.name != "base2") { if (!this.parent) this.parent = base2; this.parent.addName(this.name, this); this.namespace = format("var %1=%2;", this.name, String2.slice(this, 1, -1)); } if (_private) { // This next line gets round a bug in old Mozilla browsers var JSNamespace = base2.JavaScript ? base2.JavaScript.namespace : ""; // This string should be evaluated immediately after creating a Package object. _private.imports = Array2.reduce(csv(this.imports), function(namespace, name) { var ns = lookup(name) || lookup("JavaScript." + name); ;;; assert(ns, format("Object not found: '%1'.", name), ReferenceError); return namespace += ns.namespace; }, "var base2=(function(){return this.base2})();" + base2.namespace + JSNamespace) + lang.namespace; // This string should be evaluated after you have created all of the objects // that are being exported. _private.exports = Array2.reduce(csv(this.exports), function(namespace, name) { var fullName = this.name + "." + name; this.namespace += "var " + name + "=" + fullName + ";"; return namespace += "if(!" + fullName + ")" + fullName + "=" + name + ";"; }, "", this) + "this._label_" + this.name + "();"; var pkg = this; var packageName = String2.slice(this, 1, -1); _private["_label_" + this.name] = function() { Package.forEach (pkg, function(object, name) { if (object && object.ancestorOf == Base.ancestorOf) { object.toString = K(format("[%1.%2]", packageName, name)); if (object.prototype.toString == Base.prototype.toString) { object.prototype.toString = K(format("[object %1.%2]", packageName, name)); } } }); }; } function lookup(names) { names = names.split("."); var value = base2, i = 0; while (value && names[i] != null) { value = value[names[i++]]; } return value; }; }, exports: "", imports: "", name: "", namespace: "", parent: null, addName: function(name, value) { if (!this[name]) { this[name] = value; this.exports += "," + name; this.namespace += format("var %1=%2.%1;", name, this.name); } }, addPackage: function(name) { this.addName(name, new Package(null, {name: name, parent: this})); }, toString: function() { return format("[%1]", this.parent ? String2.slice(this.parent, 1, -1) + "." + this.name : this.name); } }); // ========================================================================= // base2/Abstract.js // ========================================================================= var Abstract = Base.extend({ constructor: function() { throw new TypeError("Abstract class cannot be instantiated."); } }); // ========================================================================= // base2/Module.js // ========================================================================= var _moduleCount = 0; var Module = Abstract.extend(null, { namespace: "", extend: function(_interface, _static) { // Extend a module to create a new module. var module = this.base(); var index = _moduleCount++; module.namespace = ""; module.partial = this.partial; module.toString = K("[base2.Module[" + index + "]]"); Module[index] = module; // Inherit class methods. module.implement(this); // Implement module (instance AND static) methods. if (_interface) module.implement(_interface); // Implement static properties and methods. if (_static) { extend(module, _static); if (module.init) module.init(); } return module; }, forEach: function(block, context) { _Function_forEach (Module, this.prototype, function(method, name) { if (typeOf(method) == "function") { block.call(context, this[name], name, this); } }, this); }, implement: function(_interface) { var module = this; var id = module.toString().slice(1, -1); if (typeof _interface == "function") { if (!_ancestorOf(_interface, module)) { this.base(_interface); } if (_ancestorOf(Module, _interface)) { // Implement static methods. for (var name in _interface) { if (module[name] === undefined) { var property = _interface[name]; if (typeof property == "function" && property.call && _interface.prototype[name]) { property = _staticModuleMethod(_interface, name); } module[name] = property; } } module.namespace += _interface.namespace.replace(/base2\.Module\[\d+\]/g, id); } } else { // Add static interface. extend(module, _interface); // Add instance interface. _extendModule(module, _interface); } return module; }, partial: function() { var module = Module.extend(); var id = module.toString().slice(1, -1); // partial methods are already bound so remove the binding to speed things up module.namespace = this.namespace.replace(/(\w+)=b[^\)]+\)/g, "$1=" + id + ".$1"); this.forEach(function(method, name) { module[name] = partial(bind(method, module)); }); return module; } }); function _extendModule(module, _interface) { var proto = module.prototype; var id = module.toString().slice(1, -1); for (var name in _interface) { var property = _interface[name], namespace = ""; if (name.charAt(0) == "@") { // object detection if (detect(name.slice(1))) _extendModule(module, property); } else if (!proto[name]) { if (name == name.toUpperCase()) { namespace = "var " + name + "=" + id + "." + name + ";"; } else if (typeof property == "function" && property.call) { namespace = "var " + name + "=base2.lang.bind('" + name + "'," + id + ");"; proto[name] = _moduleMethod(module, name); ;;; proto[name]._module = module; // introspection } if (module.namespace.indexOf(namespace) == -1) { module.namespace += namespace; } } } }; function _staticModuleMethod(module, name) { return function() { return module[name].apply(module, arguments); }; }; function _moduleMethod(module, name) { return function() { var args = _slice.call(arguments); args.unshift(this); return module[name].apply(module, args); }; }; // ========================================================================= // base2/Enumerable.js // ========================================================================= var Enumerable = Module.extend({ every: function(object, test, context) { var result = true; try { forEach (object, function(value, key) { result = test.call(context, value, key, object); if (!result) throw StopIteration; }); } catch (error) { if (error != StopIteration) throw error; } return !!result; // cast to boolean }, filter: function(object, test, context) { var i = 0; return this.reduce(object, function(result, value, key) { if (test.call(context, value, key, object)) { result[i++] = value; } return result; }, []); }, invoke: function(object, method) { // Apply a method to each item in the enumerated object. var args = _slice.call(arguments, 2); return this.map(object, (typeof method == "function") ? function(item) { return item == null ? undefined : method.apply(item, args); } : function(item) { return item == null ? undefined : item[method].apply(item, args); }); }, map: function(object, block, context) { var result = [], i = 0; forEach (object, function(value, key) { result[i++] = block.call(context, value, key, object); }); return result; }, pluck: function(object, key) { return this.map(object, function(item) { return item == null ? undefined : item[key]; }); }, reduce: function(object, block, result, context) { var initialised = arguments.length > 2; forEach (object, function(value, key) { if (initialised) { result = block.call(context, result, value, key, object); } else { result = value; initialised = true; } }); return result; }, some: function(object, test, context) { return !this.every(object, not(test), context); } }); // ========================================================================= // base2/Map.js // ========================================================================= // http://wiki.ecmascript.org/doku.php?id=proposals:dictionary var _HASH = "#"; var Map = Base.extend({ constructor: function(values) { if (values) this.merge(values); }, clear: function() { for (var key in this) if (key.indexOf(_HASH) == 0) { delete this[key]; } }, copy: function() { base2.__prototyping = true; // not really prototyping but it stops [[construct]] being called var copy = new this.constructor; delete base2.__prototyping; for (var i in this) if (this[i] !== copy[i]) { copy[i] = this[i]; } return copy; }, forEach: function(block, context) { for (var key in this) if (key.indexOf(_HASH) == 0) { block.call(context, this[key], key.slice(1), this); } }, get: function(key) { return this[_HASH + key]; }, getKeys: function() { return this.map(II); }, getValues: function() { return this.map(I); }, // Ancient browsers throw an error if we use "in" as an operator. has: function(key) { /*@cc_on @*/ /*@if (@_jscript_version < 5.5) return $Legacy.has(this, _HASH + key); @else @*/ return _HASH + key in this; /*@end @*/ }, merge: function(values) { var put = flip(this.put); forEach (arguments, function(values) { forEach (values, put, this); }, this); return this; }, put: function(key, value) { // create the new entry (or overwrite the old entry). this[_HASH + key] = value; }, remove: function(key) { delete this[_HASH + key]; }, size: function() { // this is expensive because we are not storing the keys var size = 0; for (var key in this) if (key.indexOf(_HASH) == 0) size++; return size; }, union: function(values) { return this.merge.apply(this.copy(), arguments); } }); Map.implement(Enumerable); Map.prototype.filter = function(test, context) { return this.reduce(function(result, value, key) { if (!test.call(context, value, key, this)) { result.remove(key); } return result; }, this.copy(), this); }; // ========================================================================= // base2/Collection.js // ========================================================================= // A Map that is more array-like (accessible by index). // Collection classes have a special (optional) property: Item // The Item property points to a constructor function. // Members of the collection must be an instance of Item. // The static create() method is responsible for all construction of collection items. // Instance methods that add new items (add, put, insertAt, putAt) pass *all* of their arguments // to the static create() method. If you want to modify the way collection items are // created then you only need to override this method for custom collections. var _KEYS = "~"; var Collection = Map.extend({ constructor: function(values) { this[_KEYS] = new Array2; this.base(values); }, add: function(key, item) { // Duplicates not allowed using add(). // But you can still overwrite entries using put(). assert(!this.has(key), "Duplicate key '" + key + "'."); this.put.apply(this, arguments); }, clear: function() { this.base(); this[_KEYS].length = 0; }, copy: function() { var copy = this.base(); copy[_KEYS] = this[_KEYS].copy(); return copy; }, forEach: function(block, context) { var keys = this[_KEYS]; var length = keys.length; for (var i = 0; i < length; i++) { block.call(context, this[_HASH + keys[i]], keys[i], this); } }, getAt: function(index) { var key = this[_KEYS].item(index); return (key === undefined) ? undefined : this[_HASH + key]; }, getKeys: function() { return this[_KEYS].copy(); }, indexOf: function(key) { return this[_KEYS].indexOf(String(key)); }, insertAt: function(index, key, item) { assert(this[_KEYS].item(index) !== undefined, "Index out of bounds."); assert(!this.has(key), "Duplicate key '" + key + "'."); this[_KEYS].insertAt(index, String(key)); this[_HASH + key] = null; // placeholder this.put.apply(this, _slice.call(arguments, 1)); }, item: function(keyOrIndex) { return this[typeof keyOrIndex == "number" ? "getAt" : "get"](keyOrIndex); }, put: function(key, item) { if (!this.has(key)) { this[_KEYS].push(String(key)); } var klass = this.constructor; if (klass.Item && !instanceOf(item, klass.Item)) { item = klass.create.apply(klass, arguments); } this[_HASH + key] = item; }, putAt: function(index, item) { arguments[0] = this[_KEYS].item(index); assert(arguments[0] !== undefined, "Index out of bounds."); this.put.apply(this, arguments); }, remove: function(key) { // The remove() method of the Array object can be slow so check if the key exists first. if (this.has(key)) { this[_KEYS].remove(String(key)); delete this[_HASH + key]; } }, removeAt: function(index) { var key = this[_KEYS].item(index); if (key !== undefined) { this[_KEYS].removeAt(index); delete this[_HASH + key]; } }, reverse: function() { this[_KEYS].reverse(); return this; }, size: function() { return this[_KEYS].length; }, slice: function(start, end) { var sliced = this.copy(); if (arguments.length > 0) { var keys = this[_KEYS], removed = keys; sliced[_KEYS] = Array2(_slice.apply(keys, arguments)); if (sliced[_KEYS].length) { removed = removed.slice(0, start); if (arguments.length > 1) { removed = removed.concat(keys.slice(end)); } } for (var i = 0; i < removed.length; i++) { delete sliced[_HASH + removed[i]]; } } return sliced; }, sort: function(compare) { // optimised (refers to _HASH) if (compare) { this[_KEYS].sort(bind(function(key1, key2) { return compare(this[_HASH + key1], this[_HASH + key2], key1, key2); }, this)); } else this[_KEYS].sort(); return this; }, toString: function() { return "(" + (this[_KEYS] || "") + ")"; } }, { Item: null, // If specified, all members of the collection must be instances of Item. create: function(key, item) { return this.Item ? new this.Item(key, item) : item; }, extend: function(_instance, _static) { var klass = this.base(_instance); klass.create = this.create; if (_static) extend(klass, _static); if (!klass.Item) { klass.Item = this.Item; } else if (typeof klass.Item != "function") { klass.Item = (this.Item || Base).extend(klass.Item); } if (klass.init) klass.init(); return klass; } }); // ========================================================================= // base2/RegGrp.js // ========================================================================= // A collection of regular expressions and their associated replacement values. // A Base class for creating parsers. var _RG_BACK_REF = /\\(\d+)/g, _RG_ESCAPE_CHARS = /\\./g, _RG_ESCAPE_BRACKETS = /\(\?[:=!]|\[[^\]]+\]/g, _RG_BRACKETS = /\(/g, _RG_LOOKUP = /\$(\d+)/, _RG_LOOKUP_SIMPLE = /^\$\d+$/; var RegGrp = Collection.extend({ constructor: function(values, ignoreCase) { this.base(values); this.ignoreCase = !!ignoreCase; }, ignoreCase: false, exec: function(string, override) { // optimised (refers to _HASH/_KEYS) string += ""; // type-safe var items = this, keys = this[_KEYS]; if (!keys.length) return string; if (override == RegGrp.IGNORE) override = 0; return string.replace(new RegExp(this, this.ignoreCase ? "gi" : "g"), function(match) { var item, offset = 1, i = 0; // Loop through the RegGrp items. while ((item = items[_HASH + keys[i++]])) { var next = offset + item.length + 1; if (arguments[offset]) { // do we have a result? var replacement = override == null ? item.replacement : override; switch (typeof replacement) { case "function": return replacement.apply(items, _slice.call(arguments, offset, next)); case "number": return arguments[offset + replacement]; default: return replacement; } } offset = next; } return match; }); }, insertAt: function(index, expression, replacement) { if (instanceOf(expression, RegExp)) { arguments[1] = expression.source; } return base(this, arguments); }, test: function(string) { // The slow way to do it. Hopefully, this isn't called too often. :-) return this.exec(string) != string; }, toString: function() { var offset = 1; return "(" + this.map(function(item) { // Fix back references. var expression = (item + "").replace(_RG_BACK_REF, function(match, index) { return "\\" + (offset + Number(index)); }); offset += item.length + 1; return expression; }).join(")|(") + ")"; } }, { IGNORE: "$0", init: function() { forEach ("add,get,has,put,remove".split(","), function(name) { _override(this, name, function(expression) { if (instanceOf(expression, RegExp)) { arguments[0] = expression.source; } return base(this, arguments); }); }, this.prototype); }, Item: { constructor: function(expression, replacement) { if (replacement == null) replacement = RegGrp.IGNORE; else if (replacement.replacement != null) replacement = replacement.replacement; else if (typeof replacement != "function") replacement = String(replacement); // does the pattern use sub-expressions? if (typeof replacement == "string" && _RG_LOOKUP.test(replacement)) { // a simple lookup? (e.g. "$2") if (_RG_LOOKUP_SIMPLE.test(replacement)) { // store the index (used for fast retrieval of matched strings) replacement = parseInt(replacement.slice(1)); } else { // a complicated lookup (e.g. "Hello $2 $1") // build a function to do the lookup // Improved version by Alexei Gorkov: var Q = '"'; replacement = replacement .replace(/\\/g, "\\\\") .replace(/"/g, "\\x22") .replace(/\n/g, "\\n") .replace(/\r/g, "\\r") .replace(/\$(\d+)/g, Q + "+(arguments[$1]||" + Q+Q + ")+" + Q) .replace(/(['"])\1\+(.*)\+\1\1$/, "$1"); replacement = new Function("return " + Q + replacement + Q); } } this.length = RegGrp.count(expression); this.replacement = replacement; this.toString = K(expression + ""); }, length: 0, replacement: "" }, count: function(expression) { // Count the number of sub-expressions in a RegExp/RegGrp.Item. expression = (expression + "").replace(_RG_ESCAPE_CHARS, "").replace(_RG_ESCAPE_BRACKETS, ""); return match(expression, _RG_BRACKETS).length; } }); // ========================================================================= // lang/package.js // ========================================================================= var lang = { name: "lang", version: base2.version, exports: "assert,assertArity,assertType,base,bind,copy,extend,forEach,format,instanceOf,match,pcopy,rescape,trim,typeOf", namespace: "" // fixed later }; // ========================================================================= // lang/assert.js // ========================================================================= function assert(condition, message, ErrorClass) { if (!condition) { throw new (ErrorClass || Error)(message || "Assertion failed."); } }; function assertArity(args, arity, message) { if (arity == null) arity = args.callee.length; if (args.length < arity) { throw new SyntaxError(message || "Not enough arguments."); } }; function assertType(object, type, message) { if (type && (typeof type == "function" ? !instanceOf(object, type) : typeOf(object) != type)) { throw new TypeError(message || "Invalid type."); } }; // ========================================================================= // lang/copy.js // ========================================================================= function copy(object) { // a quick copy var copy = {}; for (var i in object) { copy[i] = object[i]; } return copy; }; function pcopy(object) { // Doug Crockford / Richard Cornford _dummy.prototype = object; return new _dummy; }; function _dummy(){}; // ========================================================================= // lang/extend.js // ========================================================================= function base(object, args) { return object.base.apply(object, args); }; function extend(object, source) { // or extend(object, key, value) if (object && source) { if (arguments.length > 2) { // Extending with a key/value pair. var key = source; source = {}; source[key] = arguments[2]; } var proto = global[(typeof source == "function" ? "Function" : "Object")].prototype; // Add constructor, toString etc if (base2.__prototyping) { var i = _HIDDEN.length, key; while ((key = _HIDDEN[--i])) { var value = source[key]; if (value != proto[key]) { if (_BASE.test(value)) { _override(object, key, value) } else { object[key] = value; } } } } // Copy each of the source object's properties to the target object. for (key in source) { if (proto[key] === undefined) { var value = source[key]; // Object detection. if (key.charAt(0) == "@") { if (detect(key.slice(1))) extend(object, value); } else { // Check for method overriding. var ancestor = object[key]; if (ancestor && typeof value == "function") { if (value != ancestor) { if (_BASE.test(value)) { _override(object, key, value); } else { value.ancestor = ancestor; object[key] = value; } } } else { object[key] = value; } } } } } return object; }; function _ancestorOf(ancestor, fn) { // Check if a function is in another function's inheritance chain. while (fn) { if (!fn.ancestor) return false; fn = fn.ancestor; if (fn == ancestor) return true; } return false; }; function _override(object, name, method) { // Override an existing method. var ancestor = object[name]; var superObject = base2.__prototyping; // late binding for prototypes if (superObject && ancestor != superObject[name]) superObject = null; function _base() { var previous = this.base; this.base = superObject ? superObject[name] : ancestor; var returnValue = method.apply(this, arguments); this.base = previous; return returnValue; }; _base.method = method; _base.ancestor = ancestor; object[name] = _base; // introspection (removed when packed) ;;; _base.toString = K(method + ""); }; // ========================================================================= // lang/forEach.js // ========================================================================= // http://dean.edwards.name/weblog/2006/07/enum/ if (typeof StopIteration == "undefined") { StopIteration = new Error("StopIteration"); } function forEach(object, block, context, fn) { if (object == null) return; if (!fn) { if (typeof object == "function" && object.call) { // Functions are a special case. fn = Function; } else if (typeof object.forEach == "function" && object.forEach != arguments.callee) { // The object implements a custom forEach method. object.forEach(block, context); return; } else if (typeof object.length == "number") { // The object is array-like. _Array_forEach(object, block, context); return; } } _Function_forEach(fn || Object, object, block, context); }; forEach.csv = function(string, block, context) { forEach (csv(string), block, context); }; forEach.detect = function(object, block, context) { forEach (object, function(value, key) { if (key.charAt(0) == "@") { // object detection if (detect(key.slice(1))) forEach (value, arguments.callee); } else block.call(context, value, key, object); }); }; // These are the two core enumeration methods. All other forEach methods // eventually call one of these two. function _Array_forEach(array, block, context) { if (array == null) array = global; var length = array.length || 0, i; // preserve length if (typeof array == "string") { for (i = 0; i < length; i++) { block.call(context, array.charAt(i), i, array); } } else { // Cater for sparse arrays. for (i = 0; i < length; i++) { /*@cc_on @*/ /*@if (@_jscript_version < 5.2) if ($Legacy.has(array, i)) @else @*/ if (i in array) /*@end @*/ block.call(context, array[i], i, array); } } }; function _Function_forEach(fn, object, block, context) { // http://code.google.com/p/base2/issues/detail?id=10 // Run the test for Safari's buggy enumeration. var Temp = function(){this.i=1}; Temp.prototype = {i:1}; var count = 0; for (var i in new Temp) count++; // Overwrite the main function the first time it is called. _Function_forEach = (count > 1) ? function(fn, object, block, context) { // Safari fix (pre version 3) var processed = {}; for (var key in object) { if (!processed[key] && fn.prototype[key] === undefined) { processed[key] = true; block.call(context, object[key], key, object); } } } : function(fn, object, block, context) { // Enumerate an object and compare its keys with fn's prototype. for (var key in object) { if (fn.prototype[key] === undefined) { block.call(context, object[key], key, object); } } }; _Function_forEach(fn, object, block, context); }; // ========================================================================= // lang/instanceOf.js // ========================================================================= function instanceOf(object, klass) { // Handle exceptions where the target object originates from another frame. // This is handy for JSON parsing (amongst other things). if (typeof klass != "function") { throw new TypeError("Invalid 'instanceOf' operand."); } if (object == null) return false; /*@cc_on // COM objects don't have a constructor if (typeof object.constructor != "function") { return typeOf(object) == typeof klass.prototype.valueOf(); } @*/ if (object.constructor == klass) return true; if (klass.ancestorOf) return klass.ancestorOf(object.constructor); /*@if (@_jscript_version < 5.1) // do nothing @else @*/ if (object instanceof klass) return true; /*@end @*/ // If the class is a base2 class then it would have passed the test above. if (Base.ancestorOf == klass.ancestorOf) return false; // base2 objects can only be instances of Object. if (Base.ancestorOf == object.constructor.ancestorOf) return klass == Object; switch (klass) { case Array: // This is the only troublesome one. return !!(typeof object == "object" && object.join && object.splice); case Function: return typeOf(object) == "function"; case RegExp: return typeof object.constructor.$1 == "string"; case Date: return !!object.getTimezoneOffset; case String: case Number: case Boolean: return typeOf(object) == typeof klass.prototype.valueOf(); case Object: return true; } return false; }; // ========================================================================= // lang/typeOf.js // ========================================================================= // http://wiki.ecmascript.org/doku.php?id=proposals:typeof function typeOf(object) { var type = typeof object; switch (type) { case "object": return object == null ? "null" : typeof object.constructor == "undefined" // COM object ? _MSIE_NATIVE_FUNCTION.test(object) ? "function" : type : typeof object.constructor.prototype.valueOf(); // underlying type case "function": return typeof object.call == "function" ? type : "object"; default: return type; } }; // ========================================================================= // JavaScript/package.js // ========================================================================= var JavaScript = { name: "JavaScript", version: base2.version, exports: "Array2,Date2,Function2,String2", namespace: "", // fixed later bind: function(host) { var top = global; global = host; forEach.csv(this.exports, function(name2) { var name = name2.slice(0, -1); extend(host[name], this[name2]); this[name2](host[name].prototype); // cast }, this); global = top; return host; } }; function _createObject2(Native, constructor, generics, extensions) { // Clone native objects and extend them. // Create a Module that will contain all the new methods. var INative = Module.extend(); var id = INative.toString().slice(1, -1); // http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics forEach.csv(generics, function(name) { INative[name] = unbind(Native.prototype[name]); INative.namespace += format("var %1=%2.%1;", name, id); }); forEach (_slice.call(arguments, 3), INative.implement, INative); // create a faux constructor that augments the native object var Native2 = function() { return INative(this.constructor == INative ? constructor.apply(null, arguments) : arguments[0]); }; Native2.prototype = INative.prototype; // Remove methods that are already implemented. for (var name in INative) { if (name != "prototype" && Native[name]) { INative[name] = Native[name]; delete INative.prototype[name]; } Native2[name] = INative[name]; } Native2.ancestor = Object; delete Native2.extend; // remove "lang.bind.." Native2.namespace = Native2.namespace.replace(/(var (\w+)=)[^,;]+,([^\)]+)\)/g, "$1$3.$2"); return Native2; }; // ========================================================================= // JavaScript/~/Date.js // ========================================================================= // Fix Date.get/setYear() (IE5-7) if ((new Date).getYear() > 1900) { Date.prototype.getYear = function() { return this.getFullYear() - 1900; }; Date.prototype.setYear = function(year) { return this.setFullYear(year + 1900); }; } // https://bugs.webkit.org/show_bug.cgi?id=9532 var _testDate = new Date(Date.UTC(2006, 1, 20)); _testDate.setUTCDate(15); if (_testDate.getUTCHours() != 0) { forEach.csv("FullYear,Month,Date,Hours,Minutes,Seconds,Milliseconds", function(type) { extend(Date.prototype, "setUTC" + type, function() { var value = base(this, arguments); if (value >= 57722401000) { value -= 3600000; this.setTime(value); } return value; }); }); } // ========================================================================= // JavaScript/~/Function.js // ========================================================================= // Some browsers don't define this. Function.prototype.prototype = {}; // ========================================================================= // JavaScript/~/String.js // ========================================================================= // A KHTML bug. if ("".replace(/^/, K("$$")) == "$") { extend(String.prototype, "replace", function(expression, replacement) { if (typeof replacement == "function") { var fn = replacement; replacement = function() { return String(fn.apply(null, arguments)).split("$").join("$$"); }; } return this.base(expression, replacement); }); } // ========================================================================= // JavaScript/Array2.js // ========================================================================= var Array2 = _createObject2( Array, Array, "concat,join,pop,push,reverse,shift,slice,sort,splice,unshift", // generics Enumerable, { combine: function(keys, values) { // Combine two arrays to make a hash. if (!values) values = keys; return Array2.reduce(keys, function(hash, key, index) { hash[key] = values[index]; return hash; }, {}); }, contains: function(array, item) { return Array2.indexOf(array, item) != -1; }, copy: function(array) { var copy = _slice.call(array); if (!copy.swap) Array2(copy); // cast to Array2 return copy; }, flatten: function(array) { var i = 0; return Array2.reduce(array, function(result, item) { if (Array2.like(item)) { Array2.reduce(item, arguments.callee, result); } else { result[i++] = item; } return result; }, []); }, forEach: _Array_forEach, indexOf: function(array, item, fromIndex) { var length = array.length; if (fromIndex == null) { fromIndex = 0; } else if (fromIndex < 0) { fromIndex = Math.max(0, length + fromIndex); } for (var i = fromIndex; i < length; i++) { if (array[i] === item) return i; } return -1; }, insertAt: function(array, index, item) { Array2.splice(array, index, 0, item); return item; }, item: function(array, index) { if (index < 0) index += array.length; // starting from the end return array[index]; }, lastIndexOf: function(array, item, fromIndex) { var length = array.length; if (fromIndex == null) { fromIndex = length - 1; } else if (fromIndex < 0) { fromIndex = Math.max(0, length + fromIndex); } for (var i = fromIndex; i >= 0; i--) { if (array[i] === item) return i; } return -1; }, map: function(array, block, context) { var result = []; Array2.forEach (array, function(item, index) { result[index] = block.call(context, item, index, array); }); return result; }, remove: function(array, item) { var index = Array2.indexOf(array, item); if (index != -1) Array2.removeAt(array, index); }, removeAt: function(array, index) { Array2.splice(array, index, 1); }, swap: function(array, index1, index2) { if (index1 < 0) index1 += array.length; // starting from the end if (index2 < 0) index2 += array.length; var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; return array; } } ); Array2.reduce = Enumerable.reduce; // Mozilla does not implement the thisObj argument Array2.like = function(object) { // is the object like an array? return typeOf(object) == "object" && typeof object.length == "number"; }; // introspection (removed when packed) ;;; Enumerable["#implemented_by"].pop(); ;;; Enumerable["#implemented_by"].push(Array2); // ========================================================================= // JavaScript/Date2.js // ========================================================================= // http://developer.mozilla.org/es4/proposals/date_and_time.html // big, ugly, regular expression var _DATE_PATTERN = /^((-\d+|\d{4,})(-(\d{2})(-(\d{2}))?)?)?T((\d{2})(:(\d{2})(:(\d{2})(\.(\d{1,3})(\d)?\d*)?)?)?)?(([+-])(\d{2})(:(\d{2}))?|Z)?$/; var _DATE_PARTS = { // indexes to the sub-expressions of the RegExp above FullYear: 2, Month: 4, Date: 6, Hours: 8, Minutes: 10, Seconds: 12, Milliseconds: 14 }; var _TIMEZONE_PARTS = { // idem, but without the getter/setter usage on Date object Hectomicroseconds: 15, // :-P UTC: 16, Sign: 17, Hours: 18, Minutes: 20 }; var _TRIM_ZEROES = /(((00)?:0+)?:0+)?\.0+$/; var _TRIM_TIMEZONE = /(T[0-9:.]+)$/; var Date2 = _createObject2( Date, function(yy, mm, dd, h, m, s, ms) { switch (arguments.length) { case 0: return new Date; case 1: return typeof yy == "number" ? new Date(yy) : Date2.parse(yy); default: return new Date(yy, mm, arguments.length == 2 ? 1 : dd, h || 0, m || 0, s || 0, ms || 0); } }, "", { toISOString: function(date) { var string = "####-##-##T##:##:##.###"; for (var part in _DATE_PARTS) { string = string.replace(/#+/, function(digits) { var value = date["getUTC" + part](); if (part == "Month") value++; // js month starts at zero return ("000" + value).slice(-digits.length); // pad }); } // remove trailing zeroes, and remove UTC timezone, when time's absent return string.replace(_TRIM_ZEROES, "").replace(_TRIM_TIMEZONE, "$1Z"); } } ); delete Date2.forEach; Date2.now = function() { return (new Date).valueOf(); // milliseconds since the epoch }; Date2.parse = function(string, defaultDate) { if (arguments.length > 1) { assertType(defaultDate, "number", "default date should be of type 'number'.") } // parse ISO date var parts = match(string, _DATE_PATTERN); if (parts.length) { if (parts[_DATE_PARTS.Month]) parts[_DATE_PARTS.Month]--; // js months start at zero // round milliseconds on 3 digits if (parts[_TIMEZONE_PARTS.Hectomicroseconds] >= 5) parts[_DATE_PARTS.Milliseconds]++; var date = new Date(defaultDate || 0); var prefix = parts[_TIMEZONE_PARTS.UTC] || parts[_TIMEZONE_PARTS.Hours] ? "UTC" : ""; for (var part in _DATE_PARTS) { var value = parts[_DATE_PARTS[part]]; if (!value) continue; // empty value // set a date part date["set" + prefix + part](value); // make sure that this setting does not overflow if (date["get" + prefix + part]() != parts[_DATE_PARTS[part]]) { return NaN; } } // timezone can be set, without time being available // without a timezone, local timezone is respected if (parts[_TIMEZONE_PARTS.Hours]) { var hours = Number(parts[_TIMEZONE_PARTS.Sign] + parts[_TIMEZONE_PARTS.Hours]); var minutes = Number(parts[_TIMEZONE_PARTS.Sign] + (parts[_TIMEZONE_PARTS.Minutes] || 0)); date.setUTCMinutes(date.getUTCMinutes() + (hours * 60) + minutes); } return date.valueOf(); } else { return Date.parse(string); } }; // ========================================================================= // JavaScript/String2.js // ========================================================================= var String2 = _createObject2( String, function(string) { return new String(arguments.length == 0 ? "" : string); }, "charAt,charCodeAt,concat,indexOf,lastIndexOf,match,replace,search,slice,split,substr,substring,toLowerCase,toUpperCase", { csv: csv, format: format, rescape: rescape, trim: trim } ); delete String2.forEach; // http://blog.stevenlevithan.com/archives/faster-trim-javascript function trim(string) { return String(string).replace(_LTRIM, "").replace(_RTRIM, ""); }; function csv(string) { return string ? (string + "").split(/\s*,\s*/) : []; }; function format(string) { // Replace %n with arguments[n]. // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls"); // ==> "she sells sea shells" // Only %1 - %9 supported. var args = arguments; var pattern = new RegExp("%([1-" + (arguments.length - 1) + "])", "g"); return (string + "").replace(pattern, function(match, index) { return args[index]; }); }; function match(string, expression) { // Same as String.match() except that this function will return an empty // array if there is no match. return (string + "").match(expression) || []; }; function rescape(string) { // Make a string safe for creating a RegExp. return (string + "").replace(_RESCAPE, "\\$1"); }; // ========================================================================= // JavaScript/Function2.js // ========================================================================= var Function2 = _createObject2( Function, Function, "", { I: I, II: II, K: K, bind: bind, compose: compose, delegate: delegate, flip: flip, not: not, partial: partial, unbind: unbind } ); function I(i) { // return first argument return i; }; function II(i, ii) { // return second argument return ii; }; function K(k) { return function() { return k; }; }; function bind(fn, context) { var lateBound = typeof fn != "function"; if (arguments.length > 2) { var args = _slice.call(arguments, 2); return function() { return (lateBound ? context[fn] : fn).apply(context, args.concat.apply(args, arguments)); }; } else { // faster if there are no additional arguments return function() { return (lateBound ? context[fn] : fn).apply(context, arguments); }; } }; function compose() { var fns = _slice.call(arguments); return function() { var i = fns.length, result = fns[--i].apply(this, arguments); while (i--) result = fns[i].call(this, result); return result; }; }; function delegate(fn, context) { return function() { var args = _slice.call(arguments); args.unshift(this); return fn.apply(context, args); }; }; function flip(fn) { return function() { return fn.apply(this, Array2.swap(arguments, 0, 1)); }; }; function not(fn) { return function() { return !fn.apply(this, arguments); }; }; function partial(fn) { var args = _slice.call(arguments, 1); // based on Oliver Steele's version return function() { var specialised = args.concat(), i = 0, j = 0; while (i < args.length && j < arguments.length) { if (specialised[i] === undefined) specialised[i] = arguments[j++]; i++; } while (j < arguments.length) { specialised[i++] = arguments[j++]; } if (Array2.contains(specialised, undefined)) { specialised.unshift(fn); return partial.apply(null, specialised); } return fn.apply(this, specialised); }; }; function unbind(fn) { return function(context) { return fn.apply(context, _slice.call(arguments, 1)); }; }; // ========================================================================= // base2/detect.js // ========================================================================= function detect() { // Two types of detection: // 1. Object detection // e.g. detect("(java)"); // e.g. detect("!(document.addEventListener)"); // 2. Platform detection (browser sniffing) // e.g. detect("MSIE"); // e.g. detect("MSIE|opera"); var jscript = NaN/*@cc_on||@_jscript_version@*/; // http://dean.edwards.name/weblog/2007/03/sniff/#comment85164 var javaEnabled = global.java ? true : false; if (global.navigator) { // browser var MSIE = /MSIE[\d.]+/g; var element = document.createElement("span"); // Close up the space between name and version number. // e.g. MSIE 6 -> MSIE6 var userAgent = navigator.userAgent.replace(/([a-z])[\s\/](\d)/gi, "$1$2"); // Fix opera's (and others) user agent string. if (!jscript) userAgent = userAgent.replace(MSIE, ""); if (MSIE.test(userAgent)) userAgent = userAgent.match(MSIE)[0] + " " + userAgent.replace(MSIE, ""); base2.userAgent = navigator.platform + " " + userAgent.replace(/like \w+/gi, ""); javaEnabled &= navigator.javaEnabled(); //} else if (java) { // rhino // var System = java.lang.System; // base2.userAgent = "Rhino " + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version"); //} else if (jscript) { // Windows Scripting Host // base2.userAgent = "WSH"; } var _cache = {}; detect = function(expression) { if (_cache[expression] == null) { var returnValue = false, test = expression; var not = test.charAt(0) == "!"; if (not) test = test.slice(1); if (test.charAt(0) == "(") { try { returnValue = new Function("element,jscript,java,global", "return !!" + test)(element, jscript, javaEnabled, global); } catch (ex) { // the test failed } } else { // Browser sniffing. returnValue = new RegExp("(" + test + ")", "i").test(base2.userAgent); } _cache[expression] = !!(not ^ returnValue); } return _cache[expression]; }; return detect(arguments[0]); }; // ========================================================================= // base2/init.js // ========================================================================= base2 = global.base2 = new Package(this, base2); var exports = this.exports; lang = new Package(this, lang); exports += this.exports; JavaScript = new Package(this, JavaScript); eval(exports + this.exports); lang.base = base; lang.extend = extend; }; //////////////////// END: CLOSURE ///////////////////////////////////// nwmatcher/build/VERSION0000644000175000017500000000000612316015515013344 0ustar wmbwmb1.3.3 nwmatcher/.gitignore0000644000175000017500000000001112316015515013161 0ustar wmbwmb.DS_Storenwmatcher/README.md0000644000175000017500000000607112316015515012464 0ustar wmbwmb# [NWMatcher](http://dperini.github.io/nwmatcher/) A fast CSS selector engine and matcher. ## Installation To include NWMatcher in a standard web page: ```html ``` To use it with Node.js: ``` $ npm install nwmatcher.js ``` NWMatcher currently supports browsers (as a global, `NW.Dom`) and headless environments (as a CommonJS module). ## Supported Selectors Here is a list of all the CSS2/CSS3 [Supported selectors](https://github.com/dperini/nwmatcher/wiki/CSS-supported-selectors). ## Features and Compliance You can read more about NWMatcher [features and compliance](https://github.com/dperini/nwmatcher/wiki/Features-and-compliance) on the wiki. ## API ### DOM Selection #### `first( selector, context )` Returns a reference to the first element matching `selector`, starting at `context`. #### `match( element, selector, context )` Returns `true` if `element` matches `selector`, starting at `context`; returns `false` otherwise. #### `select( selector, context, callback )` Returns an array of all the elements matching `selector`, starting at `context`. If `callback` is provided, it is invoked for each matching element. ### DOM Helpers #### `byId( id, from )` Returns a reference to the first element with ID `id`, optionally filtered to descendants of the element `from`. #### `byTag( tag, from )` Returns an array of elements having the specified tag name `tag`, optionally filtered to descendants of the element `from`. #### `byClass( class, from )` Returns an array of elements having the specified class name `class`, optionally filtered to descendants of the element `from`. #### `byName( name, from )` Returns an array of elements having the specified value `name` for their name attribute, optionally filtered to descendants of the element `from`. #### `getAttribute( element, attribute )` Return the value read from the attribute of `element` with name `attribute`, as a string. #### `hasAttribute( element, attribute )` Returns true `element` has an attribute with name `attribute` set; returns `false` otherwise. ### Engine Configuration #### `configure( options )` The following options exist and can be set to `true` or `false`: * `CACHING`: enable caching of results * `SHORTCUTS`: allow accepting mangled selectors * `SIMPLENOT`: disallow nested complex `:not()` selectors * `UNIQUE_ID`: disallow multiple elements with same ID * `USE_QSAPI`: enable native `querySelectorAll` if available * `USE_HTML5`: enable special HTML5 rules, related to the relationship between `:checked` and `:selected` * `VERBOSITY`: choose between throwing errors or just console warnings Example: ```js NW.Dom.configure( { USE_QSAPI: false, VERBOSITY: false } ); ``` #### `registerOperator( symbol, resolver )` Registers a new symbol and its matching resolver in the operators table. Example: ```js NW.Dom.registerOperator( '!=', 'n!="%m"' ); ``` #### `registerSelector( name, rexp, func )` Registers a new selector, with the matching regular expression and the appropriate resolver function, in the selectors table. nwmatcher/test/0000755000175000017500000000000012316015515012160 5ustar wmbwmbnwmatcher/test/ender/0000755000175000017500000000000012316015515013255 5ustar wmbwmbnwmatcher/test/ender/.gitignore0000644000175000017500000000003212316015515015240 0ustar wmbwmbnode_modules ender.min.js nwmatcher/test/ender/integration.html0000644000175000017500000000536512316015515016477 0ustar wmbwmb Simple NWMatcher Ender Integration Tests nwmatcher/test/ender/sink-test/0000755000175000017500000000000012316015515015176 5ustar wmbwmbnwmatcher/test/ender/sink-test/sink.js0000644000175000017500000001304112316015515016477 0ustar wmbwmb/*! * Sink - Browser & Headless JavaScript Unit Tester * copyright Dustin Diaz & Jacob Thornton * https://github.com/ded/sink-test * License MIT */ !function(context) { var total = 0 , logKey = '' , fail = false , modules = [] , tests = [] , item , setPasses = true , allPass = true , beforeMethods = [] , afterMethods = [] , currentSetName , isHeadless = (typeof module !== 'undefined' && module.exports) isHeadless ? (require('colors')) : String.prototype.__defineGetter__ && !function () { each(['red', 'green', 'magenta', 'rainbow', 'yellow'], function (color) { String.prototype.__defineGetter__(color, function () { return this.replace(/( )/, '$1') // stupid workaround to not log an object }) String.prototype.__defineSetter__(color, function (v) {}) }) }() !isHeadless && window && !('console' in window) && !function () { context.console = {log: function () {}} }() function reset() { total = 0 fail = false init() } function failure(li, check) { setPasses = false allPass = false if (!isHeadless) { check.innerHTML = '✗' li.className = 'fail' } reset() } function each(items, fn) { for (var i = 0; i < items.length; i++) fn(items[i]) } function pass(li, check) { if (!isHeadless) { check.innerHTML = '✓' li.className = 'pass' } reset() } function before(fn) { fn ? beforeMethods.push(fn) : each(beforeMethods, function (f) { f() }) } function after(fn) { fn ? afterMethods.push(fn) : each(afterMethods, function (f) { f() }) } function bind(li) { li.onclick = function() { var ul = this.getElementsByTagName('ul')[0] ul.className = (ul.className) ? '' : 'show' } } function _test(name, expect, fn) { before() total = expect var li, check, start = +new Date if (!isHeadless) { li = document.createElement('li') li.innerHTML = name + ' ... o' item = li.getElementsByTagName('ul')[0] bind(li) check = li.getElementsByTagName('span')[0] document.getElementById('tests').appendChild(li) } else { console.log(logKey + (name + '...').yellow) } fn() setTimeout(function() { if (sink.timeout && (+new Date - start > sink.timeout)) { failure(li, check) after() } else { if (fail) { failure(li, check) after() } else if (!total) { after() pass(li, check) } else { setTimeout(arguments.callee, 10) } } }, 10) } function test(name, expect, fn) { tests.push({ name: name, expect: expect, fn: fn }) } function init() { if (tests.length) { var o = tests.shift() _test(o.name, o.expect, o.fn) } else { setPasses = true start() } } function assert(actual, expected, msg) { var b = actual === expected , message = b ? '' : 'actual: ' + actual.toString() + 'expected: ' + expected.toString() + '' if (isHeadless) { message = b ? '' : '\n\tactual: ' + actual.toString() + '\n\texpected: ' + expected.toString() if (b) console.log(logKey + msg + (message + ' ✓').green) else console.log(logKey + msg + (message + ' ✗').red) } else { var li = document.createElement('li') li.className = b ? 'pass' : 'fail' li.innerHTML = msg + ' ' + message + ' ' + '' + (b ? '✓' : '✗') + '' item.appendChild(li) } if (b) total-- else fail = true } function ok(b, message) { if (isHeadless) { if (b) console.log(logKey + (message + ' ✓').green) else console.log(logKey + (message + ' ✗').red) } else { var li = document.createElement('li') li.className = b ? 'pass' : 'fail' li.innerHTML = message + ' ' + (b ? '✓' : '✗') item.appendChild(li) } if (b) total-- else fail = true } function sink(name, fn) { modules.push({ name: name, fn: fn }) } function nextGroup(name, fn) { beforeMethods = [] afterMethods = [] var mod = ('MODULE: ' + name) if (isHeadless) { console.log(logKey + mod.magenta) } else { var li = document.createElement('li') li.innerHTML = mod document.getElementById('tests').appendChild(li) li.className = 'mod' } fn(test, ok, before, after, assert) currentSetName = name init() } function start() { var current = modules.shift() current ? nextGroup(current.name, current.fn) : !function () { var message = [ 'Congratulations! All tests have passed!' , 'There were some errors! The suite has failed.' ] , color = allPass ? 'rainbow' : 'red' , status = allPass ? 'sink-pass' : 'sink-failure' message = message[allPass ? 0 : 1].toUpperCase() isHeadless ? console.log(logKey + message[color]) : (document.getElementById('tests').className = status) }() } function setLogKey (key) { var log = console.log logKey = key || '$__sinkTest::' console.log = function (msg) { if (~(''+msg).indexOf(logKey)) { log(msg.replace(logKey, '')) } } } if (isHeadless) { exports.sink = sink exports.start = start exports.sink.timeout = 10000 exports.setLogKey = setLogKey } else { context.sink = sink context.start = start context.sink.timeout = 10000 } }(this) nwmatcher/test/ender/sink-test/sink.css0000644000175000017500000000326212316015515016657 0ustar wmbwmbbody { width: 650px; margin: 20px auto; font: 300 16px 'helvetica neue', helvetica, arial; text-shadow: 0 2px 2px #ccc; } h1 { font-size: 30px; font-weight: 300; } ol,li { list-style: none; } ol { -moz-box-shadow: 0 0 5px #ccc; -moz-border-radius: 5px; -webkit-box-shadow: 0 0 5px #ccc; -webkit-border-radius: 5px; box-shadow: 0 0 5px #ccc; border-radius: 5px; padding: 10px; } ol.sink-pass { background-color: lightgreen; } ol.sink-failure { background-color: lightpink; } li { margin: 3px 5px; padding: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; overflow: hidden; cursor: pointer; } ol > li { opacity: 0; background-color: lightblue; color: #000; } li span { color: #aaa; text-align: right; display: inline-block; float: right; } li.fail span { color: red; } li.pass span { color: green; } li.fail { background-color: #eed5d2; } li.pass { background-color: #bdfcc9; } li.pass, li.fail, li.mod { -webkit-transition: opacity .5s linear; opacity: 1; } li ul { height: 0; overflow: hidden; margin: 0; padding: 0; list-style: none; position: relative; /*early IE overflow bug*/ } li ul.show { position: static; /*early IE overflow bug*/ } li.pass ul.show { background-color: #8fffa3; } li.fail ul.show { background-color: #efada4; } li ul.show { height: auto; padding: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; margin: 5px; } li ul li { padding: 3px 6px; margin: 2px 0; list-style: none; font-size: 15px; } li b { display: block; margin-left: 40px; } li em.marker { display: block; position: absolute; right: 5px; top: 0; } nwmatcher/test/ender/tests.js0000644000175000017500000005631312316015515014765 0ustar wmbwmbvar Q = $ sink('Contexts', function (test, ok) { test('should be able to pass optional context', 2, function () { ok(Q('.a').length === 3, 'no context found 3 elements (.a)'); ok(Q('.a', Q('#boosh')).length === 2, 'context found 2 elements (#boosh .a)'); }); test('should be able to pass string as context', 5, function() { ok(Q('.a', '#boosh').length == 2, 'context found 2 elements(.a, #boosh)'); ok(Q('.a', '.a').length == 0, 'context found 0 elements(.a, .a)'); ok(Q('.a', '.b').length == 1, 'context found 1 elements(.a, .b)'); ok(Q('.a', '#boosh .b').length == 1, 'context found 1 elements(.a, #boosh .b)'); ok(Q('.b', '#boosh .b').length == 0, 'context found 0 elements(.b, #boosh .b)'); }); test('should be able to pass qwery result as context', 5, function() { ok(Q('.a', Q('#boosh')).length == 2, 'context found 2 elements(.a, #boosh)'); ok(Q('.a', Q('.a')).length == 0, 'context found 0 elements(.a, .a)'); ok(Q('.a', Q('.b')).length == 1, 'context found 1 elements(.a, .b)'); ok(Q('.a', Q('#boosh .b')).length == 1, 'context found 1 elements(.a, #boosh .b)'); ok(Q('.b', Q('#boosh .b')).length == 0, 'context found 0 elements(.b, #boosh .b)'); }); test('should not return duplicates from combinators', 2, function () { ok(Q('#boosh,#boosh').length == 1, 'two booshes dont make a thing go right'); ok(Q('#boosh,.apples,#boosh').length == 1, 'two booshes and an apple dont make a thing go right'); }); test('byId sub-queries within context', 5, function() { ok(Q('#booshTest', Q('#boosh')).length == 1, 'found "#id #id"') ok(Q('.a.b #booshTest', Q('#boosh')).length == 1, 'found ".class.class #id"') ok(Q('.a>#booshTest', Q('#boosh')).length == 1, 'found ".class>#id"') ok(!Q('#boosh', Q('#booshTest')).length, 'shouldn\'t find #boosh (ancestor) within #booshTest (descendent)') ok(!Q('#boosh', Q('#lonelyBoosh')).length, 'shouldn\'t find #boosh within #lonelyBoosh (unrelated)') }) }); sink('CSS 1', function (test, ok) { test('get element by id', 2, function () { var result = Q('#boosh'); ok(!!result[0], 'found element with id=boosh'); ok(!!Q('h1')[0], 'found 1 h1'); }); test('byId sub-queries', 4, function() { ok(Q('#boosh #booshTest').length == 1, 'found "#id #id"') ok(Q('.a.b #booshTest').length == 1, 'found ".class.class #id"') ok(Q('#boosh>.a>#booshTest').length == 1, 'found "#id>.class>#id"') ok(Q('.a>#booshTest').length == 1, 'found ".class>#id"') }) test('get elements by class', 6, function () { ok(Q('#boosh .a').length == 2, 'found two elements'); ok(!!Q('#boosh div.a')[0], 'found one element'); ok(Q('#boosh div').length == 2, 'found two {div} elements'); ok(!!Q('#boosh span')[0], 'found one {span} element'); ok(!!Q('#boosh div div')[0], 'found a single div'); ok(Q('a.odd').length == 1, 'found single a'); }); test('combos', 1, function () { ok(Q('#boosh div,#boosh span').length == 3, 'found 2 divs and 1 span'); }); test('class with dashes', 1, function() { ok(Q('.class-with-dashes').length == 1, 'found something'); }); test('should ignore comment nodes', 1, function() { ok(Q('#boosh *').length === 4, 'found only 4 elements under #boosh') }); test('deep messy relationships', 6, function() { // these are mostly characterised by a combination of tight relationships and loose relationships // on the right side of the query it's easy to find matches but they tighten up quickly as you // go to the left // they are useful for making sure the dom crawler doesn't stop short or over-extend as it works // up the tree the crawl needs to be comprehensive ok(Q('div#fixtures > div a').length == 5, 'found four results for "div#fixtures > div a"') ok(Q('.direct-descend > .direct-descend .lvl2').length == 1, 'found one result for ".direct-descend > .direct-descend .lvl2"') ok(Q('.direct-descend > .direct-descend div').length == 1, 'found one result for ".direct-descend > .direct-descend div"') ok(Q('.direct-descend > .direct-descend div').length == 1, 'found one result for ".direct-descend > .direct-descend div"') ok(Q('div#fixtures div ~ a div').length == 0, 'found no results for odd query') ok(Q('.direct-descend > .direct-descend > .direct-descend ~ .lvl2').length == 0, 'found no results for another odd query') }); }); sink('CSS 2', function (test, ok) { test('get elements by attribute', 4, function () { var wanted = Q('#boosh div[test]')[0]; var expected = document.getElementById('booshTest'); ok(wanted == expected, 'found attribute'); ok(Q('#boosh div[test=fg]')[0] == expected, 'found attribute with value'); ok(Q('em[rel~="copyright"]').length == 1, 'found em[rel~="copyright"]'); ok(Q('em[nopass~="copyright"]').length == 0, 'found em[nopass~="copyright"]'); }); test('should not throw error by attribute selector', 1, function () { ok(Q('[foo^="bar"]').length === 1, 'found 1 element'); }); test('crazy town', 1, function () { var el = document.getElementById('attr-test3'); ok(Q('div#attr-test3.found.you[title="whatup duders"]')[0] == el, 'found the right element'); }); }); sink('CSS 2 identification', function (test, ok) { // cases that we should be able to pass through to native non-CSS3 qSA where present (IE8) // we get to ignore grouping here since selectors are split up for this case anyway // we also get to work with normalized selectors // this regex must be kept in sync with the one in src/qwery.js for the test to make sense var css2 = /^(([\w\-]*[#\.]?[\w\-]+|\*)?(\[[\w\-]+([\~\|]?=['"][ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+["'])?\])?(\:(link|visited|active|hover))?([\s>+~\.,]|(?:$)))+$/ , css2Selectors = [ '*', , 'DIV', , 'e1 e2', , 'parent>child' , 'parent+child' , 'parent~child' // CSS3 but IE8 supports ~ , '#id' , 'el#id' , 'el #id' , 'el>#id' , '#id>#id2' , '.class' , 'div.class' , '#id.class' , 'element.with.multiple.classes>bam' //, 'el:first-child' -> IE8 buggy, don't do native , 'a:link' , 'a#id:link' , '.class:visited' , '#boo:active' , 'div.class:hover' //, '*:focus' -> IE8 doesn't support, don't do native , 'hoo[foo]' , '#hah[boo="moo"]' , '.claz[attrib~=\'nooooooo!\']' , 'ele[prop|="huh?"]' , '.direct-descend>.direct-descend>.direct-descend' , '.direct-descend>.direct-descend>.direct-descend~.lvl2' ] , nonCSS2Selectors = [ 'p:empty' , 'hoo:enabled' , 'haa:disabled' , '#bing:checked' , '*:first-of-type' , '*:last-of-type' , '.class:last-child' , 'yes:not' , 'p:nth-child(2n+1)' , 'p:nth-last-child(1n+2)' , 'p:nth-last-of-type(3n+3)' , 'p:nth-of-type(4n+2)' , '*:only-child' , '*:only-of-type' , 'p#id:root' , '#gak::selection' , 'body:target' // CSS2 buggy , 'el:first-child' , '*:focus' ] test('CSS2 selectors', css2Selectors.length, function() { for (var i = 0; i < css2Selectors.length; i++) { ok(css2.test(css2Selectors[i]), 'matched ' + css2Selectors[i]) } }) test('CSS2 selectors grouped', 1, function() { ok(css2.test(css2Selectors.join(',')), 'matched grouped CSS2 selectors') }) test('non-CSS2 selectors', nonCSS2Selectors.length, function() { for (var i = 0; i < nonCSS2Selectors.length; i++) { ok(!css2.test(nonCSS2Selectors[i]), 'did not matche ' + nonCSS2Selectors[i]) } }) }); sink('attribute selectors', function (test, ok, b, a, assert) { /* CSS 2 SPEC */ test('[attr]', 1, function () { var expected = document.getElementById('attr-test-1'); ok(Q('#attributes div[unique-test]')[0] == expected, 'found attribute with [attr]'); }); test('[attr=val]', 3, function () { var expected = document.getElementById('attr-test-2'); ok(Q('#attributes div[test="two-foo"]')[0] == expected, 'found attribute with ='); ok(Q("#attributes div[test='two-foo']")[0] == expected, 'found attribute with ='); ok(Q('#attributes div[test=two-foo]')[0] == expected, 'found attribute with ='); }); test('[attr~=val]', 1, function () { var expected = document.getElementById('attr-test-3'); ok(Q('#attributes div[test~=three]')[0] == expected, 'found attribute with ~='); }); test('[attr|=val]', 2, function () { var expected = document.getElementById('attr-test-2'); ok(Q('#attributes div[test|="two-foo"]')[0] == expected, 'found attribute with |='); ok(Q('#attributes div[test|=two]')[0] == expected, 'found attribute with |='); }); test('[href=#x] special case', 1, function () { var expected = document.getElementById('attr-test-4'); ok(Q('#attributes a[href="#aname"]')[0] == expected, 'found attribute with href=#x'); }); /* CSS 3 SPEC */ test('[attr^=val]', 1, function () { var expected = document.getElementById('attr-test-2'); ok(Q('#attributes div[test^=two]')[0] == expected, 'found attribute with ^='); }); test('[attr$=val]', 1, function () { var expected = document.getElementById('attr-test-2'); ok(Q('#attributes div[test$=foo]')[0] == expected, 'found attribute with $='); }); test('[attr*=val]', 1, function () { var expected = document.getElementById('attr-test-3'); ok(Q('#attributes div[test*=hree]')[0] == expected, 'found attribute with *='); }); test('direct descendants', 2, function () { ok(Q('#direct-descend > .direct-descend').length == 2, 'found two direct descendents'); ok(Q('#direct-descend > .direct-descend > .lvl2').length == 3, 'found three second-level direct descendents'); }); test('sibling elements', 17, function () { assert(Q('#sibling-selector ~ .sibling-selector').length, 2, 'found two siblings') assert(Q('#sibling-selector ~ div.sibling-selector').length, 2, 'found two siblings') assert(Q('#sibling-selector + div.sibling-selector').length, 1, 'found one sibling') assert(Q('#sibling-selector + .sibling-selector').length, 1, 'found one sibling') assert(Q('.parent .oldest ~ .sibling').length, 4, 'found four younger siblings') assert(Q('.parent .middle ~ .sibling').length, 2, 'found two younger siblings') assert(Q('.parent .middle ~ h4').length, 1, 'found next sibling by tag') assert(Q('.parent .middle ~ h4.younger').length, 1, 'found next sibling by tag and class') assert(Q('.parent .middle ~ h3').length, 0, 'an element can\'t be its own sibling') assert(Q('.parent .middle ~ h2').length, 0, 'didn\'t find an older sibling') assert(Q('.parent .youngest ~ .sibling').length, 0, 'found no younger siblings') assert(Q('.parent .oldest + .sibling').length, 1, 'found next sibling') assert(Q('.parent .middle + .sibling').length, 1, 'found next sibling') assert(Q('.parent .middle + h4').length, 1, 'found next sibling by tag') assert(Q('.parent .middle + h3').length, 0, 'an element can\'t be its own sibling') assert(Q('.parent .middle + h2').length, 0, 'didn\'t find an older sibling') assert(Q('.parent .youngest + .sibling').length, 0, 'found no younger siblings') }); }); sink('element-context queries', function(test, ok) { // should be able to query on an element that hasn't been inserted into the dom var frag = document.createElement('div') frag.innerHTML = '

' test('detached fragments', 1, function() { ok(Q('.a span', frag).length == 1, 'should find child elements of fragment') }) test('byId sub-queries within detached fragment', 5, function () { ok(Q('#emem', frag).length == 1, 'found "#id" in fragment') ok(Q('.d.i #emem', frag).length == 1, 'found ".class.class #id" in fragment') ok(Q('.d #oooo #emem', frag).length == 1, 'found ".class #id #id" in fragment') ok(!Q('#oooo', Q('#emem', frag)).length, 'shouldn\'t find #oooo (ancestor) within #emem (descendent)') ok(!Q('#sep', Q('#emem', frag)).length, 'shouldn\'t find #sep within #emem (unrelated)') }) test('exclude self in match', 1, function() { ok(Q('.order-matters', Q('#order-matters')).length == 4, 'should not include self in element-context queries') }); // because form's have .length test('forms can be used as contexts', 1, function() { ok(Q('*', Q('form')[0]).length === 3, 'found 3 elements under <form>') }) }) sink('tokenizer', function (test, ok) { test('should not get weird tokens', 5, function () { ok(Q('div .tokens[title="one"]')[0] == document.getElementById('token-one'), 'found div .tokens[title="one"]'); ok(Q('div .tokens[title="one two"]')[0] == document.getElementById('token-two'), 'found div .tokens[title="one two"]'); ok(Q('div .tokens[title="one two three #%"]')[0] == document.getElementById('token-three'), 'found div .tokens[title="one two three #%"]'); ok(Q("div .tokens[title='one two three #%'] a")[0] == document.getElementById('token-four'), 'found div .tokens[title=\'one two three #%\'] a'); ok(Q('div .tokens[title="one two three #%"] a[href$=foo] div')[0] == document.getElementById('token-five'), 'found div .tokens[title="one two three #%"] a[href=foo] div'); }); }); sink('interesting syntaxes', function (test, ok) { test('should parse bad selectors', 1, function () { ok(Q('#spaced-tokens p em a').length, 'found element with funny tokens') }); }); sink('order matters', function (test, ok) { function tag(el) { return el.tagName.toLowerCase(); } //
//

// // // //
test('the order of elements return matters', 4, function () { var els = Q('#order-matters .order-matters'); ok(tag(els[0]) == 'p', 'first element matched is a {p} tag'); ok(tag(els[1]) == 'a', 'first element matched is a {a} tag'); ok(tag(els[2]) == 'em', 'first element matched is a {em} tag'); ok(tag(els[3]) == 'b', 'first element matched is a {b} tag'); }); }); sink('pseudo-selectors', function (test, ok) { test(':not', 1, function() { ok(Q('.odd:not(div)').length == 1, 'found one .odd :not an <a>') }) test(':first-child', 2, function () { ok(Q('#pseudos div:first-child')[0] == document.getElementById('pseudos').getElementsByTagName('*')[0], 'found first child') ok(Q('#pseudos div:first-child').length == 1, 'found only 1') }); test(':last-child', 2, function () { var all = document.getElementById('pseudos').getElementsByTagName('div'); ok(Q('#pseudos div:last-child')[0] == all[all.length - 1], 'found last child') ok(Q('#pseudos div:last-child').length == 1, 'found only 1') }); test('ol > li[attr="boosh"]:last-child', 2, function () { var expected = document.getElementById('attr-child-boosh'); ok(Q('ol > li[attr="boosh"]:last-child').length == 1, 'only 1 element found'); ok(Q('ol > li[attr="boosh"]:last-child')[0] == expected, 'found correct element'); }); test(':nth-child(odd|even|x)', 4, function () { var second = document.getElementById('pseudos').getElementsByTagName('div')[1]; ok(Q('#pseudos :nth-child(odd)').length == 4, 'found 4 odd elements'); ok(Q('#pseudos div:nth-child(odd)').length == 3, 'found 3 odd elements with div tag'); ok(Q('#pseudos div:nth-child(even)').length == 3, 'found 3 even elements with div tag'); ok(Q('#pseudos div:nth-child(2)')[0] == second, 'found 2nd nth-child of pseudos'); }); test(':nth-child(expr)', 6, function () { var fifth = document.getElementById('pseudos').getElementsByTagName('a')[0]; var sixth = document.getElementById('pseudos').getElementsByTagName('div')[4]; ok(Q('#pseudos :nth-child(3n+1)').length == 3, 'found 3 elements'); ok(Q('#pseudos :nth-child(3n-2)').length == 3, 'found 3 elements'); // was +3n-2 but older safari no likey + ok(Q('#pseudos :nth-child(-n+6)').length == 6, 'found 6 elements'); ok(Q('#pseudos :nth-child(-n+5)').length == 5, 'found 5 elements'); ok(Q('#pseudos :nth-child(3n+2)')[1] == fifth, 'second :nth-child(3n+2) is the fifth child'); ok(Q('#pseudos :nth-child(3n)')[1] == sixth, 'second :nth-child(3n) is the sixth child'); }); test(':nth-last-child(odd|even|x)', 4, function () { var second = document.getElementById('pseudos').getElementsByTagName('div')[1]; ok(Q('#pseudos :nth-last-child(odd)').length == 4, 'found 4 odd elements'); ok(Q('#pseudos div:nth-last-child(odd)').length == 3, 'found 3 odd elements with div tag'); ok(Q('#pseudos div:nth-last-child(even)').length == 3, 'found 3 even elements with div tag'); ok(Q('#pseudos div:nth-last-child(6)')[0] == second, '6th nth-last-child should be 2nd of 7 elements'); }); test(':nth-last-child(expr)', 5, function () { var third = document.getElementById('pseudos').getElementsByTagName('div')[2]; ok(Q('#pseudos :nth-last-child(3n+1)').length == 3, 'found 3 elements'); ok(Q('#pseudos :nth-last-child(3n-2)').length == 3, 'found 3 elements'); ok(Q('#pseudos :nth-last-child(-n+6)').length == 6, 'found 6 elements'); ok(Q('#pseudos :nth-last-child(-n+5)').length == 5, 'found 5 elements'); ok(Q('#pseudos :nth-last-child(3n+2)')[0] == third, 'first :nth-last-child(3n+2) is the third child'); }); test(':nth-of-type(expr)', 6, function () { var a = document.getElementById('pseudos').getElementsByTagName('a')[0]; ok(Q('#pseudos div:nth-of-type(3n+1)').length == 2, 'found 2 div elements'); ok(Q('#pseudos a:nth-of-type(3n+1)').length == 1, 'found 1 a element'); ok(Q('#pseudos a:nth-of-type(3n+1)')[0] == a, 'found the right a element'); ok(Q('#pseudos a:nth-of-type(3n)').length == 0, 'no matches for every third a'); ok(Q('#pseudos a:nth-of-type(odd)').length == 1, 'found the odd a'); ok(Q('#pseudos a:nth-of-type(1)').length == 1, 'found the first a'); }); test(':nth-last-of-type(expr)', 3, function () { var second = document.getElementById('pseudos').getElementsByTagName('div')[1]; ok(Q('#pseudos div:nth-last-of-type(3n+1)').length == 2, 'found 2 div elements'); ok(Q('#pseudos a:nth-last-of-type(3n+1)').length == 1, 'found 1 a element'); ok(Q('#pseudos div:nth-last-of-type(5)')[0] == second, '5th nth-last-of-type should be 2nd of 7 elements'); }); test(':first-of-type', 2, function () { ok(Q('#pseudos a:first-of-type')[0] == document.getElementById('pseudos').getElementsByTagName('a')[0], 'found first a element') ok(Q('#pseudos a:first-of-type').length == 1, 'found only 1') }); test(':last-of-type', 2, function () { var all = document.getElementById('pseudos').getElementsByTagName('div'); ok(Q('#pseudos div:last-of-type')[0] == all[all.length - 1], 'found last div element') ok(Q('#pseudos div:last-of-type').length == 1, 'found only 1') }); test(':only-of-type', 2, function () { ok(Q('#pseudos a:only-of-type')[0] == document.getElementById('pseudos').getElementsByTagName('a')[0], 'found the only a element') ok(Q('#pseudos a:first-of-type').length == 1, 'found only 1') }); test(':target', 2, function () { location.hash = ''; ok(Q('#pseudos:target').length == 0, '#pseudos is not the target'); location.hash = '#pseudos'; ok(Q('#pseudos:target').length == 1, 'now #pseudos is the target'); location.hash = ''; }); }); sink('is()', function (test, ok) { var el = document.getElementById('attr-child-boosh'); test('simple selectors', 9, function () { ok(Q(el).is('li'), 'tag'); ok(Q(el).is('*'), 'wildcard'); ok(Q(el).is('#attr-child-boosh'), '#id'); ok(Q(el).is('[attr]'), '[attr]'); ok(Q(el).is('[attr=boosh]'), '[attr=val]'); ok(!Q(el).is('div'), 'wrong tag'); ok(!Q(el).is('#foo'), 'wrong #id'); ok(!Q(el).is('[foo]'), 'wrong [attr]'); ok(!Q(el).is('[attr=foo]'), 'wrong [attr=val]'); }); test('selector sequences', 2, function () { ok(Q(el).is('li#attr-child-boosh[attr=boosh]'), 'tag#id[attr=val]'); ok(!Q(el).is('div#attr-child-boosh[attr=boosh]'), 'wrong tag#id[attr=val]'); }); test('selector sequences combinators', 7, function () { ok(Q(el).is('ol li'), 'tag tag'); ok(Q(el).is('ol>li'), 'tag>tag'); ok(Q(el).is('ol>li+li'), 'tab>tag+tag'); ok(Q(el).is('ol#list li#attr-child-boosh[attr=boosh]'), 'tag#id tag#id[attr=val]'); ok(!Q(el).is('ol#list>li#attr-child-boosh[attr=boosh]'), 'wrong tag#id>tag#id[attr=val]'); ok(Q(el).is('ol ol li#attr-child-boosh[attr=boosh]'), 'tag tag tag#id[attr=val]'); ok(Q('#token-four').is('div#fixtures>div a'), 'tag#id>tag tag where ambiguous middle tag requires backtracking'); }); test('context', 2, function () { ok(Q(el).is('li#attr-child-boosh[attr=boosh]', Q('#list')[0]), 'context'); ok(!Q(el).is('ol#list li#attr-child-boosh[attr=boosh]', Q('#boosh')[0]), 'wrong context'); }); }); sink('selecting elements in other documents', function (test, ok) { var doc = document.getElementById('frame').contentWindow.document doc.body.innerHTML = '
' + '
' + '

' + '' + '' + '
' + '

' + '
' + '
' test('get element by id', 1, function () { var result = Q('#hsoob', doc); ok(!!result[0], 'found element with id=hsoob'); }); test('get elements by class', 6, function () { ok(Q('#hsoob .a', doc).length == 2, 'found two elements'); ok(!!Q('#hsoob div.a', doc)[0], 'found one element'); ok(Q('#hsoob div', doc).length == 2, 'found two {div} elements'); ok(!!Q('#hsoob span', doc)[0], 'found one {span} element'); ok(!!Q('#hsoob div div', doc)[0], 'found a single div'); ok(Q('p.odd', doc).length == 1, 'found single br'); }); test('complex selectors', 4, function () { ok(Q('.d ~ .sib', doc).length === 2, 'found one ~ sibling') ok(Q('.a .d + .sib', doc).length === 1, 'found 2 + siblings') ok(Q('#hsoob > div > .h', doc).length === 1, 'found span using child selectors') ok(Q('.a .d ~ .sib[test="f g"]', doc).length === 1, 'found 1 ~ sibling with test attribute') }); test('byId sub-queries', 3, function () { ok(Q('#hsoob #spanny', doc).length == 1, 'found "#id #id" in frame') ok(Q('.a #spanny', doc).length == 1, 'found ".class #id" in frame') ok(Q('.a #booshTest #spanny', doc).length == 1, 'found ".class #id #id" in frame') }) test('byId sub-queries within sub-context', 6, function () { ok(Q('#spanny', Q('#hsoob', doc)[0]).length == 1, 'found "#id -> #id" in frame') ok(Q('.a #spanny', Q('#hsoob', doc)[0]).length == 1, 'found ".class #id" in frame') ok(Q('.a #booshTest #spanny', Q('#hsoob', doc)[0]).length == 1, 'found ".class #id #id" in frame') ok(Q('.a > #booshTest', Q('#hsoob', doc)[0]).length == 1, 'found "> .class #id" in frame') ok(!Q('#booshTest', Q('#spanny', doc)[0]).length, 'shouldn\'t find #booshTest (ancestor) within #spanny (descendent)') ok(!Q('#booshTest', Q('#lonelyHsoob', doc)[0]).length, 'shouldn\'t find #booshTest within #lonelyHsoob (unrelated)') }) }); start(); nwmatcher/test/ender/index.html0000644000175000017500000001042012316015515015247 0ustar wmbwmb NWMatcher Ender Integration Tests

NWMatcher Ender Integration Tests

These tests mostly mirror the Qwery tests but are bound to an Ender context

  1. hello
  2. world
    1. world
    2. hello
  3. humans

    nwmatcher/test/ender/ender.js0000644000175000017500000020605012316015515014713 0ustar wmbwmb/*! * ============================================================= * Ender: open module JavaScript framework (https://ender.no.de) * Build: ender build ../../ * ============================================================= */ /*! * Ender: open module JavaScript framework (client-lib) * copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat) * http://ender.no.de * License MIT */ !function (context) { // a global object for node.js module compatiblity // ============================================ context['global'] = context // Implements simple module system // losely based on CommonJS Modules spec v1.1.1 // ============================================ var modules = {} , old = context.$ function require (identifier) { // modules can be required from ender's build system, or found on the window var module = modules[identifier] || window[identifier] if (!module) throw new Error("Requested module '" + identifier + "' has not been defined.") return module } function provide (name, what) { return (modules[name] = what) } context['provide'] = provide context['require'] = require function aug(o, o2) { for (var k in o2) k != 'noConflict' && k != '_VERSION' && (o[k] = o2[k]) return o } function boosh(s, r, els) { // string || node || nodelist || window if (typeof s == 'string' || s.nodeName || (s.length && 'item' in s) || s == window) { els = ender._select(s, r) els.selector = s } else els = isFinite(s.length) ? s : [s] return aug(els, boosh) } function ender(s, r) { return boosh(s, r) } aug(ender, { _VERSION: '0.3.6' , fn: boosh // for easy compat to jQuery plugins , ender: function (o, chain) { aug(chain ? boosh : ender, o) } , _select: function (s, r) { return (r || document).querySelectorAll(s) } }) aug(boosh, { forEach: function (fn, scope, i) { // opt out of native forEach so we can intentionally call our own scope // defaulting to the current item and be able to return self for (i = 0, l = this.length; i < l; ++i) i in this && fn.call(scope || this[i], this[i], i, this) // return self for chaining return this }, $: ender // handy reference to self }) ender.noConflict = function () { context.$ = old return this } if (typeof module !== 'undefined' && module.exports) module.exports = ender // use subscript notation as extern for Closure compilation context['ender'] = context['$'] = context['ender'] || ender }(this); !function () { var module = { exports: {} }, exports = module.exports; /* * Copyright (C) 2007-2014 Diego Perini * All rights reserved. * * nwmatcher.js - A fast CSS selector engine and matcher * * Author: Diego Perini * Version: 1.3.3 * Created: 20070722 * Release: 20140330 * * License: * http://javascript.nwbox.com/NWMatcher/MIT-LICENSE * Download: * http://javascript.nwbox.com/NWMatcher/nwmatcher.js */ (function(global, factory) { if (typeof module == 'object' && typeof exports == 'object') { // in a Node.js environment, the nwmatcher functions will operate on // the passed "browserGlobal" and will be returned in an object module.exports = function (browserGlobal) { // passed global does not contain // references to native objects browserGlobal.console = console; browserGlobal.parseInt = parseInt; browserGlobal.Function = Function; browserGlobal.Boolean = Boolean; browserGlobal.Number = Number; browserGlobal.RegExp = RegExp; browserGlobal.String = String; browserGlobal.Object = Object; browserGlobal.Array = Array; browserGlobal.Error = Error; browserGlobal.Date = Date; browserGlobal.Math = Math; var exports = browserGlobal.Object(); factory(browserGlobal, exports); return exports; }; module.factory = factory; } else { // in a browser environment, the nwmatcher functions will operate on // the "global" loading them and be attached to "global.NW.Dom" factory(global, (global.NW || (global.NW = global.Object())) && (global.NW.Dom || (global.NW.Dom = global.Object()))); global.NW.Dom.factory = factory; } })(this, function(global, exports) { var version = 'nwmatcher-1.3.3', Dom = exports, // processing context & root element doc = global.document, root = doc.documentElement, // save utility methods references slice = global.Array.prototype.slice, string = global.Object.prototype.toString, // persist previous parsed data isSingleMatch, isSingleSelect, lastSlice, lastContext, lastPosition, lastMatcher, lastSelector, lastPartsMatch, lastPartsSelect, // accepted prefix identifiers // (id, class & pseudo-class) prefixes = '[#.:]?', // accepted attribute operators operators = '([~*^$|!]?={1})', // accepted whitespace characters whitespace = '[\\x20\\t\\n\\r\\f]*', // 4 combinators F E, F>E, F+E, F~E combinators = '[\\x20]|[>+~][^>+~]', // an+b format params for pseudo-classes pseudoparms = '(?:[-+]?\\d*n)?[-+]?\\d*', // CSS quoted string values quotedvalue = '"[^"]*"' + "|'[^']*'", // skip round brackets groups skipround = '\\([^()]+\\)|\\(.*\\)', // skip curly brackets groups skipcurly = '\\{[^{}]+\\}|\\{.*\\}', // skip square brackets groups skipsquare = '\\[[^[\\]]*\\]|\\[.*\\]', // skip [ ], ( ), { } brackets groups skipgroup = '\\[.*\\]|\\(.*\\)|\\{.*\\}', // http://www.w3.org/TR/css3-syntax/#characters // unicode/ISO 10646 characters 161 and higher // NOTE: Safari 2.0.x crashes with escaped (\\) // Unicode ranges in regular expressions so we // use a negated character range class instead encoding = '(?:[-\\w]|[^\\x00-\\xa0]|\\\\.)', // CSS identifier syntax identifier = '(?:-?[_a-zA-Z]{1}[-\\w]*|[^\\x00-\\xa0]+|\\\\.+)+', // build attribute string attrcheck = '(' + quotedvalue + '|' + identifier + ')', attributes = whitespace + '(' + encoding + '*:?' + encoding + '+)' + whitespace + '(?:' + operators + whitespace + attrcheck + ')?' + whitespace, attrmatcher = attributes.replace(attrcheck, '([\\x22\\x27]*)((?:\\\\?.)*?)\\3'), // build pseudoclass string pseudoclass = '((?:' + // an+b parameters or quoted string pseudoparms + '|' + quotedvalue + '|' + // id, class, pseudo-class selector prefixes + '|' + encoding + '+|' + // nested HTML attribute selector '\\[' + attributes + '\\]|' + // nested pseudo-class selector '\\(.+\\)|' + whitespace + '|' + // nested pseudos/separators ',)+)', // placeholder for extensions extensions = '.+', // CSS3: syntax scanner and // one pass validation only // using regular expression standardValidator = // discard start '(?=[\\x20\\t\\n\\r\\f]*[^>+~(){}<>])' + // open match group '(' + //universal selector '\\*' + // id/class/tag/pseudo-class identifier '|(?:' + prefixes + identifier + ')' + // combinator selector '|' + combinators + // HTML attribute selector '|\\[' + attributes + '\\]' + // pseudo-classes parameters '|\\(' + pseudoclass + '\\)' + // dom properties selector (extension) '|\\{' + extensions + '\\}' + // selector group separator (comma) '|(?:,|' + whitespace + ')' + // close match group ')+', // validator for complex selectors in ':not()' pseudo-classes extendedValidator = standardValidator.replace(pseudoclass, '.*'), // validator for standard selectors as default reValidator = new global.RegExp(standardValidator, 'g'), // whitespace is any combination of these 5 character [\x20\t\n\r\f] // http://www.w3.org/TR/css3-selectors/#selector-syntax reTrimSpaces = new global.RegExp('^' + whitespace + '|' + whitespace + '$', 'g'), // only allow simple selectors nested in ':not()' pseudo-classes reSimpleNot = new global.RegExp('^(' + '(?!:not)' + '(' + prefixes + '|' + identifier + '|\\([^()]*\\))+' + '|\\[' + attributes + '\\]' + ')$'), // split comma groups, exclude commas from // quotes '' "" and from brackets () [] {} reSplitGroup = new global.RegExp('(' + '[^,\\\\()[\\]]+' + '|' + skipsquare + '|' + skipround + '|' + skipcurly + '|\\\\.' + ')+', 'g'), // split last, right most, selector group token reSplitToken = new global.RegExp('(' + '\\[' + attributes + '\\]|' + '\\(' + pseudoclass + '\\)|' + '\\\\.|[^\\x20\\t\\r\\n\\f>+~])+', 'g'), // for in excess whitespace removal reWhiteSpace = /[\x20\t\n\r\f]+/g, reOptimizeSelector = new global.RegExp(identifier + '|^$'), /*----------------------------- FEATURE TESTING ----------------------------*/ // detect native methods isNative = (function() { var s = (doc.appendChild + '').replace(/appendChild/g, ''); return function(object, method) { var m = object && object[method] || false; return m && typeof m != 'string' && s == (m + '').replace(new global.RegExp(method, 'g'), ''); }; })(), // NATIVE_XXXXX true if method exist and is callable // detect if DOM methods are native in browsers NATIVE_FOCUS = isNative(doc, 'hasFocus'), NATIVE_QSAPI = isNative(doc, 'querySelector'), NATIVE_GEBID = isNative(doc, 'getElementById'), NATIVE_GEBTN = isNative(root, 'getElementsByTagName'), NATIVE_GEBCN = isNative(root, 'getElementsByClassName'), // detect native getAttribute/hasAttribute methods, // frameworks extend these to elements, but it seems // this does not work for XML namespaced attributes, // used to check both getAttribute/hasAttribute in IE NATIVE_GET_ATTRIBUTE = isNative(root, 'getAttribute'), NATIVE_HAS_ATTRIBUTE = isNative(root, 'hasAttribute'), // check if slice() can convert nodelist to array // see http://yura.thinkweb2.com/cft/ NATIVE_SLICE_PROTO = (function() { var isBuggy = false; try { isBuggy = !!slice.call(doc.childNodes, 0)[0]; } catch(e) { } return isBuggy; })(), // supports the new traversal API NATIVE_TRAVERSAL_API = 'nextElementSibling' in root && 'previousElementSibling' in root, // BUGGY_XXXXX true if method is feature tested and has known bugs // detect buggy gEBID BUGGY_GEBID = NATIVE_GEBID ? (function() { var isBuggy = true, x = 'x' + global.String(+new global.Date), a = doc.createElementNS ? 'a' : ''; (a = doc.createElement(a)).name = x; root.insertBefore(a, root.firstChild); isBuggy = !!doc.getElementById(x); root.removeChild(a); return isBuggy; })() : true, // detect IE gEBTN comment nodes bug BUGGY_GEBTN = NATIVE_GEBTN ? (function() { var div = doc.createElement('div'); div.appendChild(doc.createComment('')); return !!div.getElementsByTagName('*')[0]; })() : true, // detect Opera gEBCN second class and/or UTF8 bugs as well as Safari 3.2 // caching class name results and not detecting when changed, // tests are based on the jQuery selector test suite BUGGY_GEBCN = NATIVE_GEBCN ? (function() { var isBuggy, div = doc.createElement('div'), test = '\u53f0\u5317'; // Opera tests div.appendChild(doc.createElement('span')). setAttribute('class', test + 'abc ' + test); div.appendChild(doc.createElement('span')). setAttribute('class', 'x'); isBuggy = !div.getElementsByClassName(test)[0]; // Safari test div.lastChild.className = test; return isBuggy || div.getElementsByClassName(test).length != 2; })() : true, // detect IE bug with dynamic attributes BUGGY_GET_ATTRIBUTE = NATIVE_GET_ATTRIBUTE ? (function() { var input = doc.createElement('input'); input.setAttribute('value', 5); return input.defaultValue != 5; })() : true, // detect IE bug with non-standard boolean attributes BUGGY_HAS_ATTRIBUTE = NATIVE_HAS_ATTRIBUTE ? (function() { var option = doc.createElement('option'); option.setAttribute('selected', 'selected'); return !option.hasAttribute('selected'); })() : true, // detect Safari bug with selected option elements BUGGY_SELECTED = (function() { var select = doc.createElement('select'); select.appendChild(doc.createElement('option')); return !select.firstChild.selected; })(), // initialized with the loading context // and reset for each different context BUGGY_QUIRKS_GEBCN, BUGGY_QUIRKS_QSAPI, QUIRKS_MODE, XML_DOCUMENT, // detect Opera browser OPERA = /opera/i.test(string.call(global.opera)), // skip simple selector optimizations for Opera >= 11 OPERA_QSAPI = OPERA && global.parseFloat(global.opera.version()) >= 11, // check Selector API implementations RE_BUGGY_QSAPI = NATIVE_QSAPI ? (function() { var pattern = new global.Array(), div = doc.createElement('div'), element, expect = function(selector, context, element, n) { var result = false; context.appendChild(element); try { result = context.querySelectorAll(selector).length == n; } catch(e) { } while (context.firstChild) { context.removeChild(context.firstChild); } return result; }; // ^= $= *= operators bugs with empty values (Opera 10 / IE8) element = doc.createElement('p'); element.setAttribute('class', ''); expect('[class^=""]', div, element, 1) && pattern.push('[*^$]=[\\x20\\t\\n\\r\\f]*(?:""|' + "'')"); // :checked bug with option elements (Firefox 3.6.x) // it wrongly includes 'selected' options elements // HTML5 rules says selected options also match element = doc.createElement('option'); element.setAttribute('selected', 'selected'); expect(':checked', div, element, 0) && pattern.push(':checked'); // :enabled :disabled bugs with hidden fields (Firefox 3.5) // http://www.w3.org/TR/html5/links.html#selector-enabled // http://www.w3.org/TR/css3-selectors/#enableddisabled // not supported by IE8 Query Selector element = doc.createElement('input'); element.setAttribute('type', 'hidden'); expect(':enabled', div, element, 0) && pattern.push(':enabled', ':disabled'); // :link bugs with hyperlinks matching (Firefox/Safari) element = doc.createElement('link'); element.setAttribute('href', 'x'); expect(':link', div, element, 1) || pattern.push(':link'); // avoid attribute selectors for IE QSA if (BUGGY_HAS_ATTRIBUTE) { // IE fails in reading: // - original values for input/textarea // - original boolean values for controls pattern.push('\\[[\\x20\\t\\n\\r\\f]*(?:checked|disabled|ismap|multiple|readonly|selected|value)'); } return pattern.length ? new global.RegExp(pattern.join('|')) : { 'test': function() { return false; } }; })() : true, // matches class selectors RE_CLASS = new global.RegExp('(?:\\[[\\x20\\t\\n\\r\\f]*class\\b|\\.' + identifier + ')'), // matches simple id, tag & class selectors RE_SIMPLE_SELECTOR = new global.RegExp( BUGGY_GEBTN && BUGGY_GEBCN || OPERA ? '^#?-?[_a-zA-Z]{1}' + encoding + '*$' : BUGGY_GEBTN ? '^[.#]?-?[_a-zA-Z]{1}' + encoding + '*$' : BUGGY_GEBCN ? '^(?:\\*|#-?[_a-zA-Z]{1}' + encoding + '*)$' : '^(?:\\*|[.#]?-?[_a-zA-Z]{1}' + encoding + '*)$'), /*----------------------------- LOOKUP OBJECTS -----------------------------*/ LINK_NODES = new global.Object({ 'a': 1, 'A': 1, 'area': 1, 'AREA': 1, 'link': 1, 'LINK': 1 }), // boolean attributes should return attribute name instead of true/false ATTR_BOOLEAN = new global.Object({ 'checked': 1, 'disabled': 1, 'ismap': 1, 'multiple': 1, 'readonly': 1, 'selected': 1 }), // dynamic attributes that needs to be checked against original HTML value ATTR_DEFAULT = new global.Object({ 'value': 'defaultValue', 'checked': 'defaultChecked', 'selected': 'defaultSelected' }), // attributes referencing URI data values need special treatment in IE ATTR_URIDATA = new global.Object({ 'action': 2, 'cite': 2, 'codebase': 2, 'data': 2, 'href': 2, 'longdesc': 2, 'lowsrc': 2, 'src': 2, 'usemap': 2 }), // HTML 5 draft specifications // http://www.whatwg.org/specs/web-apps/current-work/#selectors HTML_TABLE = new global.Object({ // class attribute must be treated case-insensitive in HTML quirks mode // initialized by default to Standard Mode (case-sensitive), // set dynamically by the attribute resolver 'class': 0, 'accept': 1, 'accept-charset': 1, 'align': 1, 'alink': 1, 'axis': 1, 'bgcolor': 1, 'charset': 1, 'checked': 1, 'clear': 1, 'codetype': 1, 'color': 1, 'compact': 1, 'declare': 1, 'defer': 1, 'dir': 1, 'direction': 1, 'disabled': 1, 'enctype': 1, 'face': 1, 'frame': 1, 'hreflang': 1, 'http-equiv': 1, 'lang': 1, 'language': 1, 'link': 1, 'media': 1, 'method': 1, 'multiple': 1, 'nohref': 1, 'noresize': 1, 'noshade': 1, 'nowrap': 1, 'readonly': 1, 'rel': 1, 'rev': 1, 'rules': 1, 'scope': 1, 'scrolling': 1, 'selected': 1, 'shape': 1, 'target': 1, 'text': 1, 'type': 1, 'valign': 1, 'valuetype': 1, 'vlink': 1 }), // the following attributes must be treated case-insensitive in XHTML mode // Niels Leenheer http://rakaz.nl/item/css_selector_bugs_case_sensitivity XHTML_TABLE = new global.Object({ 'accept': 1, 'accept-charset': 1, 'alink': 1, 'axis': 1, 'bgcolor': 1, 'charset': 1, 'codetype': 1, 'color': 1, 'enctype': 1, 'face': 1, 'hreflang': 1, 'http-equiv': 1, 'lang': 1, 'language': 1, 'link': 1, 'media': 1, 'rel': 1, 'rev': 1, 'target': 1, 'text': 1, 'type': 1, 'vlink': 1 }), /*-------------------------- REGULAR EXPRESSIONS ---------------------------*/ // placeholder to add functionalities Selectors = new global.Object({ // as a simple example this will check // for chars not in standard ascii table // // 'mySpecialSelector': { // 'Expression': /\u0080-\uffff/, // 'Callback': mySelectorCallback // } // // 'mySelectorCallback' will be invoked // only after passing all other standard // checks and only if none of them worked }), // attribute operators Operators = new global.Object({ '=': "n=='%m'", '^=': "n.indexOf('%m')==0", '*=': "n.indexOf('%m')>-1", '|=': "(n+'-').indexOf('%m-')==0", '~=': "(' '+n+' ').indexOf(' %m ')>-1", '$=': "n.substr(n.length-'%m'.length)=='%m'" }), // optimization expressions Optimize = new global.Object({ ID: new global.RegExp('^\\*?#(' + encoding + '+)|' + skipgroup), TAG: new global.RegExp('^(' + encoding + '+)|' + skipgroup), CLASS: new global.RegExp('^\\*?\\.(' + encoding + '+$)|' + skipgroup) }), // precompiled Regular Expressions Patterns = new global.Object({ // structural pseudo-classes and child selectors spseudos: /^\:(root|empty|(?:first|last|only)(?:-child|-of-type)|nth(?:-last)?(?:-child|-of-type)\(\s*(even|odd|(?:[-+]{0,1}\d*n\s*)?[-+]{0,1}\s*\d*)\s*\))?(.*)/i, // uistates + dynamic + negation pseudo-classes dpseudos: /^\:(link|visited|target|active|focus|hover|checked|disabled|enabled|selected|lang\(([-\w]{2,})\)|not\(([^()]*|.*)\))?(.*)/i, // element attribute matcher attribute: new global.RegExp('^\\[' + attrmatcher + '\\](.*)'), // E > F children: /^[\x20\t\n\r\f]*\>[\x20\t\n\r\f]*(.*)/, // E + F adjacent: /^[\x20\t\n\r\f]*\+[\x20\t\n\r\f]*(.*)/, // E ~ F relative: /^[\x20\t\n\r\f]*\~[\x20\t\n\r\f]*(.*)/, // E F ancestor: /^[\x20\t\n\r\f]+(.*)/, // all universal: /^\*(.*)/, // id id: new global.RegExp('^#(' + encoding + '+)(.*)'), // tag tagName: new global.RegExp('^(' + encoding + '+)(.*)'), // class className: new global.RegExp('^\\.(' + encoding + '+)(.*)') }), /*------------------------------ UTIL METHODS ------------------------------*/ // concat elements to data concatList = function(data, elements) { var i = -1, element; if (!data.length && global.Array.slice) return global.Array.slice(elements); while ((element = elements[++i])) data[data.length] = element; return data; }, // concat elements to data and callback concatCall = function(data, elements, callback) { var i = -1, element; while ((element = elements[++i])) { if (false === callback(data[data.length] = element)) { break; } } return data; }, // change context specific variables switchContext = function(from, force) { var div, oldDoc = doc; // save passed context lastContext = from; // set new context document doc = from.ownerDocument || from; if (force || oldDoc !== doc) { // set document root root = doc.documentElement; // set host environment flags XML_DOCUMENT = doc.createElement('DiV').nodeName == 'DiV'; // In quirks mode css class names are case insensitive. // In standards mode they are case sensitive. See docs: // https://developer.mozilla.org/en/Mozilla_Quirks_Mode_Behavior // http://www.whatwg.org/specs/web-apps/current-work/#selectors QUIRKS_MODE = !XML_DOCUMENT && typeof doc.compatMode == 'string' ? doc.compatMode.indexOf('CSS') < 0 : (function() { var style = doc.createElement('div').style; return style && (style.width = 1) && style.width == '1px'; })(); div = doc.createElement('div'); div.appendChild(doc.createElement('p')).setAttribute('class', 'xXx'); div.appendChild(doc.createElement('p')).setAttribute('class', 'xxx'); // GEBCN buggy in quirks mode, match count is: // Firefox 3.0+ [xxx = 1, xXx = 1] // Opera 10.63+ [xxx = 0, xXx = 2] BUGGY_QUIRKS_GEBCN = !XML_DOCUMENT && NATIVE_GEBCN && QUIRKS_MODE && (div.getElementsByClassName('xxx').length != 2 || div.getElementsByClassName('xXx').length != 2); // QSAPI buggy in quirks mode, match count is: // At least Chrome 4+, Firefox 3.5+, Opera 10.x+, Safari 4+ [xxx = 1, xXx = 2] // Safari 3.2 QSA doesn't work with mixedcase in quirksmode [xxx = 1, xXx = 0] // https://bugs.webkit.org/show_bug.cgi?id=19047 // must test the attribute selector '[class~=xxx]' // before '.xXx' or the bug may not present itself BUGGY_QUIRKS_QSAPI = !XML_DOCUMENT && NATIVE_QSAPI && QUIRKS_MODE && (div.querySelectorAll('[class~=xxx]').length != 2 || div.querySelectorAll('.xXx').length != 2); Config.CACHING && Dom.setCache(true, doc); } }, /*------------------------------ DOM METHODS -------------------------------*/ // element by id (raw) // @return reference or null byIdRaw = function(id, elements) { var i = -1, element = null; while ((element = elements[++i])) { if (element.getAttribute('id') == id) { break; } } return element; }, // element by id // @return reference or null _byId = !BUGGY_GEBID ? function(id, from) { id = id.replace(/\\([^\\]{1})/g, '$1'); return from.getElementById && from.getElementById(id) || byIdRaw(id, from.getElementsByTagName('*')); } : function(id, from) { var element = null; id = id.replace(/\\([^\\]{1})/g, '$1'); if (XML_DOCUMENT || from.nodeType != 9) { return byIdRaw(id, from.getElementsByTagName('*')); } if ((element = from.getElementById(id)) && element.name == id && from.getElementsByName) { return byIdRaw(id, from.getElementsByName(id)); } return element; }, // publicly exposed byId // @return reference or null byId = function(id, from) { from || (from = doc); if (lastContext !== from) { switchContext(from); } return _byId(id, from); }, // elements by tag (raw) // @return array byTagRaw = function(tag, from) { var any = tag == '*', element = from, elements = new global.Array(), next = element.firstChild; any || (tag = tag.toUpperCase()); while ((element = next)) { if (element.tagName > '@' && (any || element.tagName.toUpperCase() == tag)) { elements[elements.length] = element; } if ((next = element.firstChild || element.nextSibling)) continue; while (!next && (element = element.parentNode) && element !== from) { next = element.nextSibling; } } return elements; }, // elements by tag // @return array _byTag = !BUGGY_GEBTN && NATIVE_SLICE_PROTO ? function(tag, from) { return XML_DOCUMENT || from.nodeType == 11 ? byTagRaw(tag, from) : slice.call(from.getElementsByTagName(tag), 0); } : function(tag, from) { var i = -1, j = i, data = new global.Array(), element, elements = from.getElementsByTagName(tag); if (tag == '*') { while ((element = elements[++i])) { if (element.nodeName > '@') data[++j] = element; } } else { while ((element = elements[++i])) { data[i] = element; } } return data; }, // publicly exposed byTag // @return array byTag = function(tag, from) { from || (from = doc); if (lastContext !== from) { switchContext(from); } return _byTag(tag, from); }, // publicly exposed byName // @return array byName = function(name, from) { return select('[name="' + name.replace(/\\([^\\]{1})/g, '$1') + '"]', from); }, // elements by class (raw) // @return array byClassRaw = function(name, from) { var i = -1, j = i, data = new global.Array(), element, elements = _byTag('*', from), n; name = ' ' + (QUIRKS_MODE ? name.toLowerCase() : name).replace(/\\([^\\]{1})/g, '$1') + ' '; while ((element = elements[++i])) { n = XML_DOCUMENT ? element.getAttribute('class') : element.className; if (n && n.length && (' ' + (QUIRKS_MODE ? n.toLowerCase() : n). replace(reWhiteSpace, ' ') + ' ').indexOf(name) > -1) { data[++j] = element; } } return data; }, // elements by class // @return array _byClass = function(name, from) { return (BUGGY_GEBCN || BUGGY_QUIRKS_GEBCN || XML_DOCUMENT || !from.getElementsByClassName) ? byClassRaw(name, from) : slice.call(from.getElementsByClassName(name.replace(/\\([^\\]{1})/g, '$1')), 0); }, // publicly exposed byClass // @return array byClass = function(name, from) { from || (from = doc); if (lastContext !== from) { switchContext(from); } return _byClass(name, from); }, // check element is descendant of container // @return boolean contains = 'compareDocumentPosition' in root ? function(container, element) { return (container.compareDocumentPosition(element) & 16) == 16; } : 'contains' in root ? function(container, element) { return container !== element && container.contains(element); } : function(container, element) { while ((element = element.parentNode)) { if (element === container) return true; } return false; }, // attribute value // @return string getAttribute = !BUGGY_GET_ATTRIBUTE ? function(node, attribute) { return node.getAttribute(attribute) || ''; } : function(node, attribute) { attribute = attribute.toLowerCase(); if (typeof node[attribute] == 'object') { return node.attributes[attribute] && node.attributes[attribute].value || ''; } return ( // 'type' can only be read by using native getAttribute attribute == 'type' ? node.getAttribute(attribute) || '' : // specific URI data attributes (parameter 2 to fix IE bug) ATTR_URIDATA[attribute] ? node.getAttribute(attribute, 2) || '' : // boolean attributes should return name instead of true/false ATTR_BOOLEAN[attribute] ? node.getAttribute(attribute) ? attribute : 'false' : ((node = node.getAttributeNode(attribute)) && node.value) || ''); }, // attribute presence // @return boolean hasAttribute = !BUGGY_HAS_ATTRIBUTE ? function(node, attribute) { return XML_DOCUMENT ? !!node.getAttribute(attribute) : node.hasAttribute(attribute); } : function(node, attribute) { attribute = attribute.toLowerCase(); if (ATTR_DEFAULT[attribute]) { return !!node[ATTR_DEFAULT[attribute]]; } // read the attribute node node = node.getAttributeNode(attribute); return !!(node && node.specified); }, // check node emptyness // @return boolean isEmpty = function(node) { node = node.firstChild; while (node) { if (node.nodeType == 3 || node.nodeName > '@') return false; node = node.nextSibling; } return true; }, // check if element matches the :link pseudo // @return boolean isLink = function(element) { return hasAttribute(element,'href') && LINK_NODES[element.nodeName]; }, // child position by nodeType // @return number nthElement = function(element, last) { var count = 1, succ = last ? 'nextSibling' : 'previousSibling'; while ((element = element[succ])) { if (element.nodeName > '@') ++count; } return count; }, // child position by nodeName // @return number nthOfType = function(element, last) { var count = 1, succ = last ? 'nextSibling' : 'previousSibling', type = element.nodeName; while ((element = element[succ])) { if (element.nodeName == type) ++count; } return count; }, /*------------------------------- DEBUGGING --------------------------------*/ // get/set (string/object) working modes configure = function(option) { if (typeof option == 'string') { return Config[option]; } if (typeof option != 'object') { return false; } for (var i in option) { Config[i] = !!option[i]; if (i == 'SIMPLENOT') { matchContexts = new global.Object(); matchResolvers = new global.Object(); selectContexts = new global.Object(); selectResolvers = new global.Object(); Config['USE_QSAPI'] = false; } else if (i == 'USE_QSAPI') { Config[i] = !!option[i] && NATIVE_QSAPI; } } reValidator = new global.RegExp(Config.SIMPLENOT ? standardValidator : extendedValidator, 'g'); return true; }, // control user notifications emit = function(message) { if (Config.VERBOSITY) { throw new global.Error(message); } if (global.console && global.console.log) { global.console.log(message); } }, Config = new global.Object({ // used to enable/disable caching of result sets CACHING: false, // by default do not add missing left/right context // to selector string shortcuts like "+div" or "ul>" // callable Dom.shortcuts method has to be available SHORTCUTS: false, // by default disable complex selectors nested in // ':not()' pseudo-classes, as for specifications SIMPLENOT: true, // strict QSA match all non-unique IDs (false) // speed & libs compat match unique ID (true) UNIQUE_ID: true, // HTML5 handling for the ":checked" pseudo-class USE_HTML5: true, // controls enabling the Query Selector API branch USE_QSAPI: NATIVE_QSAPI, // controls the engine error/warning notifications VERBOSITY: true }), /*---------------------------- COMPILER METHODS ----------------------------*/ // code string reused to build compiled functions ACCEPT_NODE = 'r[r.length]=c[k];if(f&&false===f(c[k]))break main;else continue main;', // compile a comma separated group of selector // @mode boolean true for select, false for match // return a compiled function compile = function(selector, source, mode) { var parts = typeof selector == 'string' ? selector.match(reSplitGroup) : selector; // ensures that source is a string typeof source == 'string' || (source = ''); if (parts.length == 1) { source += compileSelector(parts[0], mode ? ACCEPT_NODE : 'f&&f(k);return true;', mode); } else { // for each selector in the group var i = -1, seen = new global.Object(), token; while ((token = parts[++i])) { token = token.replace(reTrimSpaces, ''); // avoid repeating the same token // in comma separated group (p, p) if (!seen[token] && (seen[token] = true)) { source += compileSelector(token, mode ? ACCEPT_NODE : 'f&&f(k);return true;', mode); } } } if (mode) { // for select method return new global.Function('c,s,r,d,h,g,f,v', 'var N,n,x=0,k=-1,e;main:while((e=c[++k])){' + source + '}return r;'); } else { // for match method return new global.Function('e,s,r,d,h,g,f,v', 'var N,n,x=0,k=e;' + source + 'return false;'); } }, // allows to cache already visited nodes FILTER = 'var z=v[@]||(v[@]=[]),l=z.length-1;' + 'while(l>=0&&z[l]!==e)--l;' + 'if(l!==-1){break;}' + 'z[z.length]=e;', // compile a CSS3 string selector into ad-hoc javascript matching function // @return string (to be compiled) compileSelector = function(selector, source, mode) { var a, b, n, k = 0, expr, match, result, status, test, type; while (selector) { k++; // *** Universal selector // * match all (empty block, do not remove) if ((match = selector.match(Patterns.universal))) { // do nothing, handled in the compiler where // BUGGY_GEBTN return comment nodes (ex: IE) expr = ''; } // *** ID selector // #Foo Id case sensitive else if ((match = selector.match(Patterns.id))) { // document can contain conflicting elements (id/name) // prototype selector unit need this method to recover bad HTML forms source = 'if(' + (XML_DOCUMENT ? 's.getAttribute(e,"id")' : '(e.submit?s.getAttribute(e,"id"):e.id)') + '=="' + match[1] + '"' + '){' + source + '}'; } // *** Type selector // Foo Tag (case insensitive) else if ((match = selector.match(Patterns.tagName))) { // both tagName and nodeName properties may be upper/lower case // depending on their creation NAMESPACE in createElementNS() source = 'if(e.nodeName' + (XML_DOCUMENT ? '=="' + match[1] + '"' : '.toUpperCase()' + '=="' + match[1].toUpperCase() + '"') + '){' + source + '}'; } // *** Class selector // .Foo Class (case sensitive) else if ((match = selector.match(Patterns.className))) { // W3C CSS3 specs: element whose "class" attribute has been assigned a // list of whitespace-separated values, see section 6.4 Class selectors // and notes at the bottom; explicitly non-normative in this specification. source = 'if((n=' + (XML_DOCUMENT ? 's.getAttribute(e,"class")' : 'e.className') + ')&&n.length&&(" "+' + (QUIRKS_MODE ? 'n.toLowerCase()' : 'n') + '.replace(' + reWhiteSpace + '," ")+" ").indexOf(" ' + (QUIRKS_MODE ? match[1].toLowerCase() : match[1]) + ' ")>-1' + '){' + source + '}'; } // *** Attribute selector // [attr] [attr=value] [attr="value"] [attr='value'] and !=, *=, ~=, |=, ^=, $= // case sensitivity is treated differently depending on the document type (see map) else if ((match = selector.match(Patterns.attribute))) { // xml namespaced attribute ? expr = match[1].split(':'); expr = expr.length == 2 ? expr[1] : expr[0] + ''; if (match[2] && !Operators[match[2]]) { emit('Unsupported operator in attribute selectors "' + selector + '"'); return ''; } test = false; type = 'false'; // replace Operators parameter if needed if (match[2] && match[4] && (type = Operators[match[2]])) { // case treatment depends on document HTML_TABLE['class'] = QUIRKS_MODE ? 1 : 0; // replace escaped values and HTML entities match[4] = match[4].replace(/(\x22|\x27)/g, '\\$1'); match[4] = match[4].replace(/\\([0-9a-f]{2,2})/g, '\\x$1'); test = (XML_DOCUMENT ? XHTML_TABLE : HTML_TABLE)[expr.toLowerCase()]; type = type.replace(/\%m/g, test ? match[4].toLowerCase() : match[4]); } else if (match[2] == '!=' || match[2] == '=') { match[4] = match[4].replace(/(\x22|\x27)/g, '\\$1'); type = 'n' + match[2] + '="' + match[4] + '"'; } // build expression for has/getAttribute expr = 'n=s.' + (match[2] ? 'get' : 'has') + 'Attribute(e,"' + match[1] + '")' + (test ? '.toLowerCase();' : ';'); source = expr + 'if(' + (match[2] ? type : 'n') + '){' + source + '}'; } // *** Adjacent sibling combinator // E + F (F adiacent sibling of E) else if ((match = selector.match(Patterns.adjacent))) { source = (mode ? '' : FILTER.replace(/@/g, k)) + source; source = NATIVE_TRAVERSAL_API ? 'var N' + k + '=e;while(e&&(e=e.previousElementSibling)){' + source + 'break;}e=N' + k + ';' : 'var N' + k + '=e;while(e&&(e=e.previousSibling)){if(e.nodeName>"@"){' + source + 'break;}}e=N' + k + ';'; } // *** General sibling combinator // E ~ F (F relative sibling of E) else if ((match = selector.match(Patterns.relative))) { source = (mode ? '' : FILTER.replace(/@/g, k)) + source; source = NATIVE_TRAVERSAL_API ? ('var N' + k + '=e;e=e.parentNode.firstElementChild;' + 'while(e&&e!==N' + k + '){' + source + 'e=e.nextElementSibling;}e=N' + k + ';') : ('var N' + k + '=e;e=e.parentNode.firstChild;' + 'while(e&&e!==N' + k + '){if(e.nodeName>"@"){' + source + '}e=e.nextSibling;}e=N' + k + ';'); } // *** Child combinator // E > F (F children of E) else if ((match = selector.match(Patterns.children))) { source = (mode ? '' : FILTER.replace(/@/g, k)) + source; source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + 'break;}e=N' + k + ';'; } // *** Descendant combinator // E F (E ancestor of F) else if ((match = selector.match(Patterns.ancestor))) { source = (mode ? '' : FILTER.replace(/@/g, k)) + source; source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + '}e=N' + k + ';'; } // *** Structural pseudo-classes // :root, :empty, // :first-child, :last-child, :only-child, // :first-of-type, :last-of-type, :only-of-type, // :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-of-type() else if ((match = selector.match(Patterns.spseudos)) && match[1]) { switch (match[1]) { case 'root': // element root of the document if (match[3]) { source = 'if(e===h||s.contains(h,e)){' + source + '}'; } else { source = 'if(e===h){' + source + '}'; } break; case 'empty': // element that has no children source = 'if(s.isEmpty(e)){' + source + '}'; break; default: if (match[1] && match[2]) { if (match[2] == 'n') { source = 'if(e!==h){' + source + '}'; break; } else if (match[2] == 'even') { a = 2; b = 0; } else if (match[2] == 'odd') { a = 2; b = 1; } else { // assumes correct "an+b" format, "b" before "a" to keep "n" values b = ((n = match[2].match(/(-?\d+)$/)) ? global.parseInt(n[1], 10) : 0); a = ((n = match[2].match(/(-?\d*)n/i)) ? global.parseInt(n[1], 10) : 0); if (n && n[1] == '-') a = -1; } // build test expression out of structural pseudo (an+b) parameters // see here: http://www.w3.org/TR/css3-selectors/#nth-child-pseudo test = a > 1 ? (/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' : 'n>=' + b + '&&(n-(' + b + '))%' + a + '==0' : a < -1 ? (/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' : 'n<=' + b + '&&(n-(' + b + '))%' + a + '==0' : a=== 0 ? 'n==' + b : (/last/i.test(match[1])) ? a == -1 ? 'n>=' + b : 'n<=' + b : a == -1 ? 'n<=' + b : 'n>=' + b; // 4 cases: 1 (nth) x 4 (child, of-type, last-child, last-of-type) source = 'if(e!==h){' + 'n=s[' + (/-of-type/i.test(match[1]) ? '"nthOfType"' : '"nthElement"') + ']' + '(e,' + (/last/i.test(match[1]) ? 'true' : 'false') + ');' + 'if(' + test + '){' + source + '}' + '}'; } else { // 6 cases: 3 (first, last, only) x 1 (child) x 2 (-of-type) a = /first/i.test(match[1]) ? 'previous' : 'next'; n = /only/i.test(match[1]) ? 'previous' : 'next'; b = /first|last/i.test(match[1]); type = /-of-type/i.test(match[1]) ? '&&n.nodeName!=e.nodeName' : '&&n.nodeName<"@"'; source = 'if(e!==h){' + ( 'n=e;while((n=n.' + a + 'Sibling)' + type + ');if(!n){' + (b ? source : 'n=e;while((n=n.' + n + 'Sibling)' + type + ');if(!n){' + source + '}') + '}' ) + '}'; } break; } } // *** negation, user action and target pseudo-classes // *** UI element states and dynamic pseudo-classes // CSS3 :not, :checked, :enabled, :disabled, :target // CSS3 :active, :hover, :focus // CSS3 :link, :visited else if ((match = selector.match(Patterns.dpseudos)) && match[1]) { switch (match[1].match(/^\w+/)[0]) { // CSS3 negation pseudo-class case 'not': // compile nested selectors, DO NOT pass the callback parameter // SIMPLENOT allow disabling complex selectors nested // in ':not()' pseudo-classes, breaks some test units expr = match[3].replace(reTrimSpaces, ''); if (Config.SIMPLENOT && !reSimpleNot.test(expr)) { // see above, log error but continue execution emit('Negation pseudo-class only accepts simple selectors "' + selector + '"'); return ''; } else { if ('compatMode' in doc) { source = 'if(!' + compile(expr, '', false) + '(e,s,r,d,h,g)){' + source + '}'; } else { source = 'if(!s.match(e, "' + expr.replace(/\x22/g, '\\"') + '",g)){' + source +'}'; } } break; // CSS3 UI element states case 'checked': // for radio buttons checkboxes (HTML4) and options (HTML5) source = 'if((typeof e.form!=="undefined"&&(/^(?:radio|checkbox)$/i).test(e.type)&&e.checked)' + (Config.USE_HTML5 ? '||(/^option$/i.test(e.nodeName)&&(e.selected||e.checked))' : '') + '){' + source + '}'; break; case 'disabled': // does not consider hidden input fields source = 'if(((typeof e.form!=="undefined"' + (Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') + ')||s.isLink(e))&&e.disabled===true){' + source + '}'; break; case 'enabled': // does not consider hidden input fields source = 'if(((typeof e.form!=="undefined"' + (Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') + ')||s.isLink(e))&&e.disabled===false){' + source + '}'; break; // CSS3 lang pseudo-class case 'lang': test = ''; if (match[2]) test = match[2].substr(0, 2) + '-'; source = 'do{(n=e.lang||"").toLowerCase();' + 'if((n==""&&h.lang=="' + match[2].toLowerCase() + '")||' + '(n&&(n=="' + match[2].toLowerCase() + '"||n.substr(0,3)=="' + test.toLowerCase() + '")))' + '{' + source + 'break;}}while((e=e.parentNode)&&e!==g);'; break; // CSS3 target pseudo-class case 'target': n = doc.location ? doc.location.hash : ''; if (n) { source = 'if(e.id=="' + n.slice(1) + '"){' + source + '}'; } break; // CSS3 dynamic pseudo-classes case 'link': source = 'if(s.isLink(e)&&!e.visited){' + source + '}'; break; case 'visited': source = 'if(s.isLink(e)&&e.visited){' + source + '}'; break; // CSS3 user action pseudo-classes IE & FF3 have native support // these capabilities may be emulated by some event managers case 'active': if (XML_DOCUMENT) break; source = 'if(e===d.activeElement){' + source + '}'; break; case 'hover': if (XML_DOCUMENT) break; source = 'if(e===d.hoverElement){' + source + '}'; break; case 'focus': if (XML_DOCUMENT) break; source = NATIVE_FOCUS ? 'if(e===d.activeElement&&d.hasFocus()&&(e.type||e.href||typeof e.tabIndex=="number")){' + source + '}' : 'if(e===d.activeElement&&(e.type||e.href)){' + source + '}'; break; // CSS2 selected pseudo-classes, not part of current CSS3 drafts // the 'selected' property is only available for option elements case 'selected': // fix Safari selectedIndex property bug expr = BUGGY_SELECTED ? '||(n=e.parentNode)&&n.options[n.selectedIndex]===e' : ''; source = 'if(/^option$/i.test(e.nodeName)&&(e.selected||e.checked' + expr + ')){' + source + '}'; break; default: break; } } else { // this is where external extensions are // invoked if expressions match selectors expr = false; status = false; for (expr in Selectors) { if ((match = selector.match(Selectors[expr].Expression)) && match[1]) { result = Selectors[expr].Callback(match, source); source = result.source; status = result.status; if (status) { break; } } } // if an extension fails to parse the selector // it must return a false boolean in "status" if (!status) { // log error but continue execution, don't throw real exceptions // because blocking following processes maybe is not a good idea emit('Unknown pseudo-class selector "' + selector + '"'); return ''; } if (!expr) { // see above, log error but continue execution emit('Unknown token in selector "' + selector + '"'); return ''; } } // error if no matches found by the pattern scan if (!match) { emit('Invalid syntax in selector "' + selector + '"'); return ''; } // ensure "match" is not null or empty since // we do not throw real DOMExceptions above selector = match && match[match.length - 1]; } return source; }, /*----------------------------- QUERY METHODS ------------------------------*/ // match element with selector // @return boolean match = function(element, selector, from, callback) { var parts; if (!(element && element.nodeName > '@')) { emit('Invalid element argument'); return false; } else if (typeof selector != 'string') { emit('Invalid selector argument'); return false; } else if (from && from.nodeType == 1 && !contains(from, element)) { return false; } else if (lastContext !== from) { // reset context data when it changes // and ensure context is set to a default switchContext(from || (from = element.ownerDocument)); } selector = selector.replace(reTrimSpaces, ''); Config.SHORTCUTS && (selector = Dom.shortcuts(selector, element, from)); if (lastMatcher != selector) { // process valid selector strings if ((parts = selector.match(reValidator)) && parts[0] == selector) { isSingleMatch = (parts = selector.match(reSplitGroup)).length < 2; // save passed selector lastMatcher = selector; lastPartsMatch = parts; } else { emit('The string "' + selector + '", is not a valid CSS selector'); return false; } } else parts = lastPartsMatch; // compile matcher resolvers if necessary if (!matchResolvers[selector] || matchContexts[selector] !== from) { matchResolvers[selector] = compile(isSingleMatch ? [selector] : parts, '', false); matchContexts[selector] = from; } return matchResolvers[selector](element, Snapshot, [ ], doc, root, from, callback, new global.Object()); }, // select only the first element // matching selector (document ordered) first = function(selector, from) { return select(selector, from, function() { return false; })[0] || null; }, // select elements matching selector // using new Query Selector API // or cross-browser client API // @return array select = function(selector, from, callback) { var i, changed, element, elements, parts, token, original = selector; if (arguments.length === 0) { emit('Not enough arguments'); return [ ]; } else if (typeof selector != 'string') { return [ ]; } else if (from && !(/1|9|11/).test(from.nodeType)) { emit('Invalid or illegal context element'); return [ ]; } else if (lastContext !== from) { // reset context data when it changes // and ensure context is set to a default switchContext(from || (from = doc)); } if (Config.CACHING && (elements = Dom.loadResults(original, from, doc, root))) { return callback ? concatCall([ ], elements, callback) : elements; } if (!OPERA_QSAPI && RE_SIMPLE_SELECTOR.test(selector)) { switch (selector.charAt(0)) { case '#': if (Config.UNIQUE_ID) { elements = (element = _byId(selector.slice(1), from)) ? [ element ] : [ ]; } break; case '.': elements = _byClass(selector.slice(1), from); break; default: elements = _byTag(selector, from); break; } } else if (!XML_DOCUMENT && Config.USE_QSAPI && !(BUGGY_QUIRKS_QSAPI && RE_CLASS.test(selector)) && !RE_BUGGY_QSAPI.test(selector)) { try { elements = from.querySelectorAll(selector); } catch(e) { } } if (elements) { elements = callback ? concatCall([ ], elements, callback) : NATIVE_SLICE_PROTO ? slice.call(elements) : concatList([ ], elements); Config.CACHING && Dom.saveResults(original, from, doc, elements); return elements; } selector = selector.replace(reTrimSpaces, ''); Config.SHORTCUTS && (selector = Dom.shortcuts(selector, from)); if ((changed = lastSelector != selector)) { // process valid selector strings if ((parts = selector.match(reValidator)) && parts[0] == selector) { isSingleSelect = (parts = selector.match(reSplitGroup)).length < 2; // save passed selector lastSelector = selector; lastPartsSelect = parts; } else { emit('The string "' + selector + '", is not a valid CSS selector'); return [ ]; } } else parts = lastPartsSelect; // commas separators are treated sequentially to maintain order if (from.nodeType == 11) { elements = byTagRaw('*', from); } else if (!XML_DOCUMENT && isSingleSelect) { if (changed) { // get right most selector token parts = selector.match(reSplitToken); token = parts[parts.length - 1]; // only last slice before :not rules lastSlice = token.split(':not')[0]; // position where token was found lastPosition = selector.length - token.length; } // ID optimization RTL, to reduce number of elements to visit if (Config.UNIQUE_ID && (parts = lastSlice.match(Optimize.ID)) && (token = parts[1])) { if ((element = _byId(token, from))) { if (match(element, selector)) { callback && callback(element); elements = new global.Array(element); } else elements = new global.Array(); } } // ID optimization LTR, to reduce selection context searches else if (Config.UNIQUE_ID && (parts = selector.match(Optimize.ID)) && (token = parts[1])) { if ((element = _byId(token, doc))) { if ('#' + token == selector) { callback && callback(element); elements = new global.Array(element); } else if (/[>+~]/.test(selector)) { from = element.parentNode; } else { from = element; } } else elements = new global.Array(); } if (elements) { Config.CACHING && Dom.saveResults(original, from, doc, elements); return elements; } if (!NATIVE_GEBCN && (parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) { if ((elements = _byTag(token, from)).length === 0) { return [ ]; } selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace(token, '*'); } else if ((parts = lastSlice.match(Optimize.CLASS)) && (token = parts[1])) { if ((elements = _byClass(token, from)).length === 0) { return [ ]; } if (reOptimizeSelector.test(selector.charAt(selector.indexOf(token) - 1))) { selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, ''); } else { selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, '*'); } } else if ((parts = selector.match(Optimize.CLASS)) && (token = parts[1])) { if ((elements = _byClass(token, from)).length === 0) { return [ ]; } for (i = 0, els = new global.Array(); elements.length > i; ++i) { els = concatList(els, elements[i].getElementsByTagName('*')); } elements = els; if (reOptimizeSelector.test(selector.charAt(selector.indexOf(token) - 1))) { selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, ''); } else { selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, '*'); } } else if (NATIVE_GEBCN && (parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) { if ((elements = _byTag(token, from)).length === 0) { return [ ]; } selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace(token, '*'); } } if (!elements) { elements = /^(?:applet|object)$/i.test(from.nodeName) ? from.childNodes : _byTag('*', from); } // end of prefiltering pass // compile selector resolver if necessary if (!selectResolvers[selector] || selectContexts[selector] !== from) { selectResolvers[selector] = compile(isSingleSelect ? [selector] : parts, '', true); selectContexts[selector] = from; } elements = selectResolvers[selector](elements, Snapshot, [ ], doc, root, from, callback, new global.Object()); Config.CACHING && Dom.saveResults(original, from, doc, elements); return elements; }, /*-------------------------------- STORAGE ---------------------------------*/ // empty function handler FN = function(x) { return x; }, // compiled match functions returning booleans matchContexts = new global.Object(), matchResolvers = new global.Object(), // compiled select functions returning collections selectContexts = new global.Object(), selectResolvers = new global.Object(), // used to pass methods to compiled functions Snapshot = new global.Object({ // element indexing methods nthElement: nthElement, nthOfType: nthOfType, // element inspection methods getAttribute: getAttribute, hasAttribute: hasAttribute, // element selection methods byClass: _byClass, byName: byName, byTag: _byTag, byId: _byId, // helper/check methods contains: contains, isEmpty: isEmpty, isLink: isLink, // selection/matching select: select, match: match }), Tokens = new global.Object({ prefixes: prefixes, encoding: encoding, operators: operators, whitespace: whitespace, identifier: identifier, attributes: attributes, combinators: combinators, pseudoclass: pseudoclass, pseudoparms: pseudoparms, quotedvalue: quotedvalue }); /*------------------------------- PUBLIC API -------------------------------*/ // code referenced by extensions Dom.ACCEPT_NODE = ACCEPT_NODE; // retrieve element by id attr Dom.byId = byId; // retrieve elements by tag name Dom.byTag = byTag; // retrieve elements by name attr Dom.byName = byName; // retrieve elements by class name Dom.byClass = byClass; // read the value of the attribute // as was in the original HTML code Dom.getAttribute = getAttribute; // check for the attribute presence // as was in the original HTML code Dom.hasAttribute = hasAttribute; // element match selector, return boolean true/false Dom.match = match; // first element match only, return element or null Dom.first = first; // elements matching selector, starting from element Dom.select = select; // compile selector into ad-hoc javascript resolver Dom.compile = compile; // check that two elements are ancestor/descendant Dom.contains = contains; // handle selector engine configuration settings Dom.configure = configure; // initialize caching for each document Dom.setCache = FN; // load previously collected result set Dom.loadResults = FN; // save previously collected result set Dom.saveResults = FN; // handle missing context in selector strings Dom.shortcuts = FN; // log resolvers errors/warnings Dom.emit = emit; // options enabing specific engine functionality Dom.Config = Config; // pass methods references to compiled resolvers Dom.Snapshot = Snapshot; // operators descriptor // for attribute operators extensions Dom.Operators = Operators; // selectors descriptor // for pseudo-class selectors extensions Dom.Selectors = Selectors; // export string patterns Dom.Tokens = Tokens; // export version string Dom.Version = version; // add or overwrite user defined operators Dom.registerOperator = function(symbol, resolver) { Operators[symbol] || (Operators[symbol] = resolver); }; // add selector patterns for user defined callbacks Dom.registerSelector = function(name, rexp, func) { Selectors[name] || (Selectors[name] = new global.Object({ Expression: rexp, Callback: func })); }; /*---------------------------------- INIT ----------------------------------*/ // init context specific variables switchContext(doc, true); }); provide("nwmatcher", module.exports(this)); !function (doc, $) { // a bunch of this code is borrowed from Qwery so NW is a drop-in replacement var nw = require('nwmatcher') , isNode = function (el, t) { return el && typeof el === 'object' && (t = el.nodeType) && (t == 1 || t == 9) } , arrayLike = function (o) { return (typeof o === 'object' && isFinite(o.length)) } , flatten = function (ar) { for (var r = [], i = 0, l = ar.length; i < l; ++i) arrayLike(ar[i]) ? (r = r.concat(ar[i])) : (r[r.length] = ar[i]) return r } , uniq = function (ar) { var a = [], i, j o: for (i = 0; i < ar.length; ++i) { for (j = 0; j < a.length; ++j) { if (a[j] == ar[i]) { continue o } } a[a.length] = ar[i] } return a } , normalizeRoot = function (root) { if (!root) return doc if (typeof root == 'string') return nw.select(root)[0] if (!root.nodeType && arrayLike(root)) return root[0] return root } , select = function (selector, _root) { var root = normalizeRoot(_root) if (!root || !selector) return [] if (selector === window || isNode(selector)) { return !_root || (selector !== window && isNode(root) && nw.contains(root, container)) ? [selector] : [] } if (selector && arrayLike(selector)) return flatten(selector) return nw.select(selector, root) } , is = function (s, r) { var i, l for (i = 0, l = this.length; i < l; i++) { if (nw.match(this[i], s, r)) { return true } } return false } $._select = function (selector, root) { // if 'bonzo' is available at run-time use it for creation return ($._select = (function(bonzo) { try { bonzo = require('bonzo') return function (selector, root) { return /^\s* 20 && (results[results.length] = "...")){ break; } } return "[" + results.join(", ") + "]"; case "[object Function]": return "function " + (object.displayName || object.name || "anonymous") + "(){...}"; default: if("nodeName" in object && "nodeValue" in object && "nodeType" in object){ nodeName = object.nodeName.toLowerCase(); nodeValue = object.nodeValue; switch(object.nodeType){ case 1: switch(nodeName){ case "a": if(object.name){ nodeName += ' name="' + object.name + '"'; } if(object.href){ nodeName += ' href="' + object.href + '"'; } break; case "img": case "iframe": if(object.src){ nodeName += ' src="' + object.src + '"'; } break; case "input": if(object.name){ nodeName += ' name="' + object.name + '"'; } if(object.type){ nodeName += ' type="' + object.type + '"'; } break; case "form": if(object.action){ nodeName += ' action="' + object.action + '"'; } break; } if(object.id){ nodeName += ' id="' + object.id + '"'; } if(object.className){ nodeName += ' class="' + object.className + '"'; } return "<" + nodeName + ">"; case 3: return (!nodeValue || (/^[\s\xA0]+$/).test(nodeValue)) ? "(whitespace)" : '"' + nodeValue + '"'; case 8: return ""; case 9: return "Document"; case 10: return ""; default: return nodeName; } } if("name" in object && "message" in object){ return object.message + " (" + object.name + ")"; } results = []; for(index in object){ results[results.length] = index + ": " + inspect(object[index], ++depth); if(depth > 10 && (results[results.length] = "...")){ break; } } return "{" + results.join(", ") + "}"; } }catch(exception){} return object + ""; } function sprintf(string){ var pattern = /%?%[a-zA-Z]/; sprintf = function(string){ var result, index, match, argument, substitution; string = string + ""; if(arguments.length < 2 || string.indexOf("%") === -1){ return string; } result = ""; index = 1; while((match = pattern.exec(string))){ result += string.slice(0, match.index); if((argument = match[0]).indexOf("%%") === 0){ result += argument.slice(1); }else{ if(index in arguments){ substitution = arguments[index]; switch(argument){ case "%i": case "%d": result += ~~substitution || 0; break; case "%f": result += +substitution || 0; break; case "%o": result += inspect(substitution); break; default: result += substitution; break; } }else{ result += argument; } index++; } string = string.slice(match.index + argument.length); } return cleanWhitespace.call(result + string); }; return sprintf.apply(null, arguments); } function scotch(name, options){ return new scotch.Runner(name, options); } scotch.version = "1.0.0_rc3"; scotch.runners = []; scotch.run = function(){ var runners = scotch.runners, index = 0, length = runners.length; for(; index < length; index++){ runners[index].run(); } return runners; }; document = isHostType(global, "document") && global.document; scotch.assertions = (function(){ function assert(expression, message){ return expression ? this.addAssertion() : this.addFailure("`assert`: Expression: %o, Message: %s.", expression, message ? sprintf(message, toArray.call(arguments, 2)) : "expression == false"); } function refute(expression, message){ return expression ? this.addFailure("`refute`: Expression: %o, Message: %s.", expression, message ? sprintf(message, toArray.call(arguments, 2)) : "expression == true") : this.addAssertion(); } function assertLike(expected, actual, message){ return expected == actual ? this.addAssertion() : this.addFailure("`assertLike`: Expected: %o, Actual: %o, Message: %s.", expected, actual, message ? sprintf(message, toArray.call(arguments, 2)) : "expected != actual"); } function refuteLike(expected, actual, message){ return expected != actual ? this.addAssertion() : this.addFailure("`refuteLike`: Expected: %o, Actual: %o, Message: %s.", expected, actual, message ? sprintf(message, toArray.call(arguments, 3)) : "expected == actual"); } function assertEqual(expected, actual, message){ return expected === actual ? this.addAssertion() : this.addFailure("`assertEqual`: Expected: %o, Actual: %o, Message: %s.", expected, actual, message ? sprintf(message, toArray.call(arguments, 3)) : "expected !== actual"); } function refuteEqual(expected, actual, message){ return expected !== actual ? this.addAssertion() : this.addFailure("`refuteEqual`: Expected: %o, Actual: %o, Message: %s.", expected, actual, message ? sprintf(message, toArray.call(arguments, 3)) : "expected === actual"); } function size(object){ var count = 0, property; for(property in object){ count++; } return count; } function equivalent(expected, actual){ var index, length; if(expected === actual){ return true; } if(expected === null){ return actual === null; } if(typeof expected === "undefined"){ return typeof actual === "undefined"; } switch(getClass.call(expected)){ case "[object Function]": return expected === actual; case "[object String]": case "[object Boolean]": return expected.valueOf() === actual.valueOf(); case "[object Number]": return isNaN(expected) ? isNaN(actual) : expected.valueOf() === actual.valueOf(); case "[object Date]": return getClass.call(actual) === "[object Date]" && +expected === +actual; case "[object RegExp]": return getClass.call(actual) === "[object RegExp]" && expected.source === actual.source && expected.global === actual.global && expected.ignoreCase === actual.ignoreCase && expected.multiline === actual.multiline && expected.sticky === actual.sticky; case "[object Array]": if(getClass.call(actual) !== "[object Array]" || (length = expected.length) !== actual.length){ return false; } for(index = 0; index < length; index++){ if(!equivalent(expected[index], actual[index])){ return false; } } return true; default: if(size(expected) !== size(actual)){ return false; } for(index in expected){ if(!(index in actual) || !equivalent(expected[index], actual[index])){ return false; } } return true; } return false; } function assertEquivalent(expected, actual, message){ return equivalent(expected, actual) ? this.addAssertion() : this.addFailure("`assertEquivalent`: Expected: %o, Actual: %o, Message: %s.", expected, actual, message ? sprintf(message, toArray.call(arguments, 3)) : "The two objects are not equivalent"); } function refuteEquivalent(expected, actual, message){ return equivalent(expected, actual) ? this.addFailure("`refuteEquivalent`: Expected: %o, Actual: %o, Message: %s.", expected, actual, message ? sprintf(message, toArray.call(arguments, 3)) : "The two objects are equivalent") : this.addAssertion(); } function assertThrowsException(expected, callback, message) { var isRegExp = expected && getClass.call(expected) == '[object RegExp]', isFunction = !isRegExp && typeof expected == 'function'; try { callback(); return this.addFailure("`assertThrowsException`: Function: %o, Message: %s.", method, message ? sprintf(message, toArray.call(arguments, 3)) : "The function did not throw any exceptions"); } catch (exception) { return ((isRegExp && (expected.test(exception) || expected.test(exception.message))) || (isFunction && expected.call(this, exception, this))) ? this.addAssertion() : this.addError(exception); } } function assertThrowsNothing(method, message){ try{ method.call(global); return this.addAssertion(); }catch(exception){ return this.addFailure("`assertThrowsNothing`: Function: %o, Exception: %o, Message: %s.", method, exception, message ? sprintf(message, toArray.call(arguments, 2)) : "The function threw an exception"); } } return { "assert": assert, "refute": refute, "assertLike": assertLike, "refuteLike": refuteLike, "assertEqual": assertEqual, "refuteEqual": refuteEqual, "assertEquivalent": assertEquivalent, "refuteEquivalent": refuteEquivalent, "assertThrowsException": assertThrowsException, "assertThrowsNothing": assertThrowsNothing }; }()); scotch.Case = (function(){ var Prototype; function Case(name, test, setup, teardown){ this.name = name; this.test = test; this.setup = setup; this.teardown = teardown; this.assertions = 0; this.failures = 0; this.errors = 0; this.warnings = 0; this.paused = false; this.timeout = Case.defaultTimeout; this.messages = []; } Case.defaultTimeout = 3000; Case.PASSED = 1; Case.WARNING = 2; Case.FAILED = 3; Case.CRITICAL = 4; function Mixin(){} Mixin.prototype = scotch.assertions; Prototype = Case.prototype = new Mixin(); Mixin = null; Prototype.constructor = Case; function run(){ try{ if(!this.paused && this.setup){ this.setup(this); } this.paused = false; this.test(this); }catch(testException){ this.addError(testException); }finally{ try{ if(!this.paused && this.teardown){ this.teardown(this); } }catch(teardownException){ this.addError(teardownException); } } return this; } Prototype.run = run; function benchmark(block, iterations, name){ var startTime = (new Date()).getTime(), count = iterations, endTime; while(iterations--){ block(); } endTime = (new Date()).getTime(); this.messages[this.messages.length] = sprintf("Benchmark: %s finished %i iterations in %ims.", name || this.name, count, endTime - startTime); return this; } Prototype.benchmark = benchmark; function wait(block, milliseconds){ this.paused = true; this.test = block; this.timeout = milliseconds; } Prototype.wait = wait; function addInfo(){ this.messages[this.messages.length] = "Info: " + sprintf.apply(null, arguments); return this; } Prototype.addInfo = addInfo; function addAssertion(){ this.assertions++; return this; } Prototype.addAssertion = addAssertion; function addFailure(){ this.failures++; this.messages[this.messages.length] = "Failure: " + sprintf.apply(null, arguments); return this; } Prototype.addFailure = addFailure; function addWarning(){ this.warnings++; this.messages[this.messages.length] = "Warning: " + sprintf.apply(null, arguments); return this; } Prototype.addWarning = addWarning; function addError(exception){ this.errors++; this.messages[this.messages.length] = "Error: " + inspect(exception); return this; } Prototype.addError = addError; function summarize(){ return { "status": this.errors ? Case.CRITICAL : this.failures ? Case.FAILED : this.warnings ? Case.WARNING : Case.PASSED, "assertions": this.assertions, "warnings": this.warnings, "failures": this.failures, "errors": this.errors, "messages": this.messages }; } Prototype.summarize = summarize; return Case; }()); scotch.Group = (function(){ var Prototype; function alphabetize(left, right){ return (left.name < right.name ? -1 : left.name > right.name ? 1 : 0); } function Group(){ this.tests = {}; this.groups = {}; } Prototype = Group.prototype; function addTests(setup, tests, teardown){ for(var test in tests){ this.tests[test] = tests[test]; } this.setup = setup; this.teardown = teardown; return this; } Prototype.addTests = addTests; function addGroup(name){ return (this.groups[name] || (this.groups[name] = new Group())); } Prototype.addGroup = addGroup; function collect(prefix){ var results = [], name, groups, subgroups, length, extension, tests; (prefix || (prefix = "")); for(name in (groups = this.groups)){ subgroups = groups[name].collect(prefix + name + "::"); length = results.length; extension = subgroups.length; while(extension--){ results[length + extension] = subgroups[extension]; } } for(name in (tests = this.tests)){ results[results.length] = new scotch.Case(prefix + name, tests[name], this.setup, this.teardown); } return results.sort(alphabetize); } Prototype.collect = collect; return Group; }()); scotch.Runner = (function(){ var Prototype, MODE = isHostType(global, "setTimeout") ? 2 : isHostType(global, "java") && isHostType(global.java, "lang") ? 1 : false; function Runner(name, options){ this.name = name; this.options = Object(options); scotch.Group.call(this); scotch.runners[scotch.runners.length] = this; } function Subclass(){} Subclass.prototype = scotch.Group.prototype; Prototype = Runner.prototype = new Subclass(); Subclass = null; Prototype.constructor = Runner; function next(){ var runner = this, testcase = runner.testcases[runner.currentTest], timeout; if(!testcase){ runner.finishTime = (new Date()).getTime(); return runner.options.logger.summarize(runner.summarize()); } if(!testcase.paused){ runner.options.logger.start(testcase.name); } testcase.run(); if(testcase.paused){ if(MODE){ timeout = testcase.timeout; runner.options.logger.write("Testing paused for " + timeout + "ms; waiting for test `" + testcase.name + "`..."); return MODE === 2 ? global.setTimeout(function(){ runner.next(); }, timeout) : (new global.java.lang.Thread(new global.java.lang.Runnable({ "run": function(){ global.java.lang.Thread.currentThread().sleep(timeout); runner.next(); } }))).start(); }else{ testcase.addWarning("Asynchronous test skipped; not supported by the current environment."); } } runner.options.logger.finish(testcase.summarize()); runner.currentTest++; runner.next(); } Prototype.next = next; function run(){ this.testcases = this.collect(); this.currentTest = 0; (this.options.logger || (this.options.logger = new scotch.Logger())).setup(this.name); this.startTime = (new Date()).getTime(); this.next(); return this; } Prototype.run = run; function summarize(){ var testcases = this.testcases, index = 0, length = testcases.length, results = { "tests": length, "assertions": 0, "warnings": 0, "failures": 0, "errors": 0, "time": (this.finishTime - this.startTime) / 1000 }; for(; index < length; index++){ results.assertions += testcases[index].assertions; results.warnings += testcases[index].warnings; results.failures += testcases[index].failures; results.errors += testcases[index].errors; } return results; } Prototype.summarize = summarize; return Runner; }()); scotch.loggers = {}; scotch.loggers.Web = (function(){ var Prototype, LAYOUT = '
    Running...<\/div><\/tbody><\/table>'; function Web(element){ this.element = element || Web.defaultElement; } Web.defaultElement = "testlog"; Prototype = Web.prototype; function setup(suite){ var element = this.element; if(getClass.call(element) === "[object String]" && !(element = this.element = document.getElementById(element))){ throw new Error("scotch.loggers.Web: The logger element was not found."); } element.innerHTML = "

    " + suite + "<\/h1>" + LAYOUT; this.tbody = element.getElementsByTagName("tbody")[0]; return this; } Prototype.setup = setup; function start(test){ var row = document.createElement("tr"), first = document.createElement("td"); first.appendChild(document.createTextNode(test)); row.appendChild(first); row.appendChild(document.createElement("td")); row.appendChild(document.createElement("td")); this.tbody.appendChild(row); return this; } Prototype.start = start; function write(message){ var rows = this.element.getElementsByTagName("tr"); rows[rows.length - 1].getElementsByTagName("td")[1].innerHTML = cleanWhitespace.call(message); return this; } Prototype.write = write; function finish(summary){ var rows = this.element.getElementsByTagName("tr"), lastLine = rows[rows.length - 1], status; switch(summary.status){ case scotch.Case.CRITICAL: lastLine.className = "critical"; status = "Failed"; break; case scotch.Case.FAILED: lastLine.className = "failed"; status = "Failed"; break; case scotch.Case.WARNING: lastLine.className = "warning"; status = "Passed"; break; default: lastLine.className = "passed"; status = "Passed"; break; } return this.write(sprintf("%s; %i assertions, %i warnings, %i failures, %i errors.
    ", status, summary.assertions, summary.warnings, summary.failures, summary.errors) + summary.messages.join("\n").replace(/&/g, "&").replace(//g, ">").replace(/[\r|\n]/g, "
    ")); } Prototype.finish = finish; function summarize(summary){ this.element.getElementsByTagName("div")[0].innerHTML = sprintf("%i tests, %i assertions, %i warnings, %i failures, %i errors; completed in %fs", summary.tests, summary.assertions, summary.warnings, summary.failures, summary.errors, summary.time); return this; } Prototype.summarize = summarize; return Web; }()); scotch.loggers.Console = (function(){ var Prototype, print, FIREBUG_API; if(isHostType(global, "console") && isHostType(global.console, "log")){ FIREBUG_API = isHostType(global.console, "info") && isHostType(global.console, "warn") && isHostType(global.console, "error"); print = function(message, level){ global.console[FIREBUG_API ? level >= scotch.Case.FAILED ? "error" : level === scotch.Case.WARNING ? "warn" : level === scotch.Case.PASSED ? "info" : "log" : "log"](message); }; }else if(isHostType(global, "print") && !document){ print = function(message){ global.print(message); }; }else{ print = function(){ throw new Error("scotch.loggers.Console: Printing output to a console is not supported by the current environment."); }; } function Console(){ this.tests = []; } Prototype = Console.prototype; function setup(suite){ print("Started suite `" + (this.suite = suite) + "`."); return this; } Prototype.setup = setup; function start(test){ print("Started test `" + (this.tests[this.tests.length] = test) + "`."); return this; } Prototype.start = start; function write(message){ print(cleanWhitespace.call(message)); return this; } Prototype.write = write; function finish(summary){ var status = summary.status, messages = summary.messages, index = 0, length = summary.messages.length; print(sprintf("Finished test `%s` with %i assertions, %i warnings, %i failures, and %i errors.", this.tests[this.tests.length - 1], summary.assertions, summary.warnings, summary.failures, summary.errors), status); for(; index < length; index++){ print(cleanWhitespace.call(messages[index]), status); } return this; } Prototype.finish = finish; function summarize(summary){ print(sprintf("Finished suite `%s` in %fs with %i tests, %i assertions, %i warnings, %i failures, and %i errors.", this.suite, summary.time, summary.tests, summary.assertions, summary.warnings, summary.failures, summary.errors)); return this; } Prototype.summarize = summarize; return Console; }()); scotch.Logger = scotch.loggers[document ? "Web" : "Console"]; scotch.noConflict = function(){ delete scotch.noConflict; if(typeof previousScotch === "undefined"){ delete global.scotch; }else{ global.scotch = previousScotch; } return scotch; }; if(isHostType(global, "addEventListener")){ global.addEventListener("load", scotch.run, false); }else if(isHostType(global, "attachEvent")){ global.attachEvent("onload", scotch.run); } global.scotch = scotch; }(this)); nwmatcher/test/scotch/assets/0000755000175000017500000000000012316015515014745 5ustar wmbwmbnwmatcher/test/scotch/assets/style.css0000644000175000017500000000202012316015515016611 0ustar wmbwmbbody{ margin-top: 0; padding: 0; background-color: #f0f0f0; font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, sans-serif; font-size: 13px; color: #333; } div#container{ margin: 0 auto; background-color: white; border: 3px solid #aaa; border-top: none; padding: 25px; width: 75%; } div.log{ padding: 5px 5px 15px; margin-bottom: 15px; border-bottom: 2px solid #000; } div.log h1{ margin: 5px 0 10px; font-size: 28px; color: #800; } div.log div.logsummary{ margin: 5px 0 10px; padding: 7px; border: 1px solid #000; font-weight: bold; } div.log table.logtable{ width: 100%; border-collapse: collapse; border: 1px dotted #666; } div.log table.logtable td, div.log table.logtable th{ text-align: left; padding: 3px 8px; border: 1px dotted #666; } div.log table.logtable tr.passed{ background-color: #cfc; } div.log table.logtable tr.failed, div.log table.logtable tr.critical{ background-color: #fcc; } div.log table.logtable tr.warning{ background-color: #ff8; } nwmatcher/test/scotch/test.html0000644000175000017500000000731312316015515015314 0ustar wmbwmb NWMatcher Tests
    nwmatcher/test/scotch/test-cli.js0000644000175000017500000001163412316015515015532 0ustar wmbwmb/* Load the library */ load("../../dist/scotch.js"); var caseRunner = scotch("scotch.Case Unit Tests"), identifier = 0; /* Custom assertion */ scotch.assertions.assertSuccessiveList = function(array, message){ var index = 1, length = array.length, value; for(; index < length; index++){ value = array[index]; if(!(Object.prototype.toString.call(value) === "[object Number]" && value - 1 === array[index - 1])){ return this.addFailure("`assertSuccessiveList`: List: %o, Message: %s.", array, message || "The array is not successive"); } } return this.addAssertion(); }; caseRunner.addTests(function(){ //Setup function this.array = [1, 2, 3, 4, 5, 6, 7]; this.assertEqual(identifier, 0); }, { "benchmark": function(){ identifier++; var str = "12.5"; this.assert(~~(1 * str) === 12); this.assert(parseInt(str, 10) === 12); this.benchmark(function(){ ~~(1 * str); }, 1000000, "~~"); this.benchmark(function(){ parseInt(str, 10); }, 1000000, "parseInt"); }, "assert": function(testcase){ testcase.assertEquivalent(this.array, [1, 2, 3, 4, 5, 6, 7]); this.assertSuccessiveList(testcase.array); identifier++; }, "wait": function(){ identifier++; var timeout = 0; this.assertEqual(0, timeout); this.wait(function(){ timeout += this.timeout; this.assertEqual(150, timeout); this.wait(function(){ timeout += this.timeout; this.assertEqual(300, this.timeout); this.assertEqual(450, timeout); }, 300); }, 150); } }, function(){ //Teardown function this.refuteEqual(identifier, 0); identifier = 0; }); var assertionsRunner = scotch("scotch.assertions Unit Tests"); assertionsRunner.addTests(null, { "assert": function(){ this.assert(true); this.assert(!false, "test"); this.assert(true).assert(5 + 5 === 10, "`scotch.assertions.assert` should be chainable"); }, "refute": function(){ this.refute(false); this.refute(!true, "test"); this.refute(false).refute(5 % 2 === 2, "`scotch.assertions.refute` should be chainable"); } }); /* Basic equality */ assertionsRunner.addGroup("Equality").addTests(null, { "assertLike": function(){ this.assertLike(0, 0); this.assertLike(0, 0, "test"); this.assertLike(0, "0"); this.assertLike(65.0, 65); this.assertLike("a", "a"); this.assertLike("a", "a", "test"); }, "refuteLike": function(){ this.refuteLike(0, 1); this.refuteLike("a", "b"); this.refuteLike({}, {}); this.refuteLike([], []); this.refuteLike([], {}); } }); /* Basic identity */ assertionsRunner.addGroup("Identity").addTests(null, { "assertEqual": function(){ var undef, object = {"a": "b"}; this.assertEqual(0, 0); this.assertEqual(0, 0, "test"); this.assertEqual(1, 1); this.assertEqual(1, 1.0); this.assertEqual("a", "a"); this.assertEqual("a", "a", "test"); this.assertEqual("", ""); this.assertEqual(undef, undef); this.assertEqual(null, null); this.assertEqual(true, true); this.assertEqual(false, false); this.assertEqual(object, object); }, "refuteEqual": function(){ this.refuteEqual({1:2,3:4}, {1:2,3:4}); this.refuteEqual(1, "1"); this.refuteEqual(1.0, "1"); } }); /* Equivalence */ assertionsRunner.addGroup("Equivalence").addTests(null, { "assertEquivalent": function(){ /* Lists/Arrays */ this.assertEquivalent([], []); this.assertEquivalent(["a", "b"], ["a", "b"]); this.assertEquivalent([1, 2], [1, 2]); this.assertEquivalent(["1", "2"], ["1", "2"]); this.assertEquivalent([7, 8, 9], [7, 8, new Number(9)]); this.assertEquivalent([1, [2, 3, [4, [5]]]], [1, [2, 3, [4, [5]]]], "Deep comparison failed"); /* Hashes/Objects */ this.assertEquivalent({}, {}); this.assertEquivalent({"a": "b"}, {"a": "b"}); this.assertEquivalent({"a": "b", "c": "d"}, {"a": "b", "c": "d"}); this.assertEquivalent({"a": 1, "z": 2}, {"z": 2, "a": 1}, "Order shouldn't matter"); this.assertEquivalent({"a": {"b": "c", "d": "e"}, "f": "g"}, {"a": {"b": "c", "d": "e"}, "f": "g"}, "Deep comparison failed"); }, "refuteEquivalent": function(){ /* Lists/Arrays */ this.refuteEquivalent(["a"], ["b"]); this.refuteEquivalent([1, 2], [1, 2, 3]); this.refuteEquivalent(["1", "2"], [1, 2]); this.refuteEquivalent([7, 8, 9], ["7", 8, new Number(9)]); /* Hashes/Objects */ this.refuteEquivalent({"a": "b", "c": "d"}, {"c": "d", "a": "boo!"}); this.refuteEquivalent({"a": "1", "z": "2"}, {"z": 2, "a": 1}); } }); /* Functions */ assertionsRunner.addGroup("Functions").addTests(null, { "assertThrowsException": function(){ function testError(){ throw new Error(); } this.assertThrowsException("Error", testError); }, "assertThrowsNothing": function(){ function testNoError(){ return true; } this.assertThrowsNothing(testNoError); } }); /* Run all test runners */ scotch.run(); nwmatcher/test/scotch/test-browser.js0000644000175000017500000001164212316015515016445 0ustar wmbwmbvar caseRunner = scotch("scotch.Case Unit Tests", { "logger": new scotch.loggers.Web("case") }), identifier = 0; /* Custom assertion */ scotch.assertions.assertSuccessiveList = function(array, message){ var index = 1, length = array.length, value; for(; index < length; index++){ value = array[index]; if(!(Object.prototype.toString.call(value) === "[object Number]" && value - 1 === array[index - 1])){ return this.addFailure("`assertSuccessiveList`: List: %o, Message: %s.", array, message || "The array is not successive"); } } return this.addAssertion(); }; caseRunner.addTests(function(){ //Setup function this.array = [1, 2, 3, 4, 5, 6, 7]; this.assertEqual(identifier, 0); }, { "benchmark": function(){ identifier++; var str = "12.5"; this.assert(~~(1 * str) === 12); this.assert(parseInt(str, 10) === 12); this.benchmark(function(){ ~~(1 * str); }, 1000000, "~~"); this.benchmark(function(){ parseInt(str, 10); }, 1000000, "parseInt"); }, "assert": function(testcase){ testcase.assertEquivalent(this.array, [1, 2, 3, 4, 5, 6, 7]); this.assertSuccessiveList(testcase.array); identifier++; }, "wait": function(){ identifier++; var timeout = 0; this.assertEqual(0, timeout); this.wait(function(){ timeout += this.timeout; this.assertEqual(150, timeout); this.wait(function(){ timeout += this.timeout; this.assertEqual(300, this.timeout); this.assertEqual(450, timeout); }, 300); }, 150); } }, function(){ //Teardown function this.refuteEqual(identifier, 0); identifier = 0; }); var assertionsRunner = scotch("scotch.assertions Unit Tests", { "logger": new scotch.loggers.Web("assertions") }); assertionsRunner.addTests(null, { "assert": function(){ this.assert(true); this.assert(!false, "test"); this.assert(true).assert(5 + 5 === 10, "`scotch.assertions.assert` should be chainable"); }, "refute": function(){ this.refute(false); this.refute(!true, "test"); this.refute(false).refute(5 % 2 === 2, "`scotch.assertions.refute` should be chainable"); } }); /* Basic equality */ assertionsRunner.addGroup("Equality").addTests(null, { "assertLike": function(){ this.assertLike(0, 0); this.assertLike(0, 0, "test"); this.assertLike(0, "0"); this.assertLike(65.0, 65); this.assertLike("a", "a"); this.assertLike("a", "a", "test"); }, "refuteLike": function(){ this.refuteLike(0, 1); this.refuteLike("a", "b"); this.refuteLike({}, {}); this.refuteLike([], []); this.refuteLike([], {}); } }); /* Basic identity */ assertionsRunner.addGroup("Identity").addTests(null, { "assertEqual": function(){ var undef, object = {"a": "b"}; this.assertEqual(0, 0); this.assertEqual(0, 0, "test"); this.assertEqual(1, 1); this.assertEqual(1, 1.0); this.assertEqual("a", "a"); this.assertEqual("a", "a", "test"); this.assertEqual("", ""); this.assertEqual(undef, undef); this.assertEqual(null, null); this.assertEqual(true, true); this.assertEqual(false, false); this.assertEqual(object, object); }, "refuteEqual": function(){ this.refuteEqual({1:2,3:4}, {1:2,3:4}); this.refuteEqual(1, "1"); this.refuteEqual(1.0, "1"); } }); /* Equivalence */ assertionsRunner.addGroup("Equivalence").addTests(null, { "assertEquivalent": function(){ /* Lists/Arrays */ this.assertEquivalent([], []); this.assertEquivalent(["a", "b"], ["a", "b"]); this.assertEquivalent([1, 2], [1, 2]); this.assertEquivalent(["1", "2"], ["1", "2"]); this.assertEquivalent([7, 8, 9], [7, 8, new Number(9)]); this.assertEquivalent([1, [2, 3, [4, [5]]]], [1, [2, 3, [4, [5]]]], "Deep comparison failed"); /* Hashes/Objects */ this.assertEquivalent({}, {}); this.assertEquivalent({"a": "b"}, {"a": "b"}); this.assertEquivalent({"a": "b", "c": "d"}, {"a": "b", "c": "d"}); this.assertEquivalent({"a": 1, "z": 2}, {"z": 2, "a": 1}, "Order shouldn't matter"); this.assertEquivalent({"a": {"b": "c", "d": "e"}, "f": "g"}, {"a": {"b": "c", "d": "e"}, "f": "g"}, "Deep comparison failed"); }, "refuteEquivalent": function(){ /* Lists/Arrays */ this.refuteEquivalent(["a"], ["b"]); this.refuteEquivalent([1, 2], [1, 2, 3]); this.refuteEquivalent(["1", "2"], [1, 2]); this.refuteEquivalent([7, 8, 9], ["7", 8, new Number(9)]); /* Hashes/Objects */ this.refuteEquivalent({"a": "b", "c": "d"}, {"c": "d", "a": "boo!"}); this.refuteEquivalent({"a": "1", "z": "2"}, {"z": 2, "a": 1}); } }); /* Functions */ assertionsRunner.addGroup("Functions").addTests(null, { "assertThrowsException": function(){ function testError(){ throw new Error(); } this.assertThrowsException(/Error/, testError); }, "assertThrowsNothing": function(){ function testNoError(){ return true; } this.assertThrowsNothing(testNoError); } }); nwmatcher/test/scotch/test.js0000644000175000017500000005053612316015515014771 0ustar wmbwmbNW.Dom.configure({ /* Disable complex selectors nested in :not() pseudo-classes to comply with specs See */ "SIMPLENOT": true, "VERBOSITY": true, "USE_QSAPI": true }); var getClass = Object.prototype.toString, /* Setting `RUN_BENCHMARKS` runs benchmarks on the following selectors: * * E[foo^="bar"] * E[foo$="bar"] * E[foo*="bar"] * E:first-child * E:last-child * E:only-child * E > F * E + F * E ~ F * ------------------------*/ RUN_BENCHMARKS = false, //The test runner runner = scotch("NWMatcher Unit Tests"); //Prototype's `$` function function getById(element){ var index, length, elements; if((length = arguments.length) > 1){ for(index = 0, elements = []; index < length; index++){ elements[elements.length] = getById(arguments[index]); } return elements; } if(getClass.call(element) === "[object String]"){ element = document.getElementById(element); } return element; } //The tests... (function(runner){ //NWMatcher methods; aliased for convenience var select = NW.Dom.select, match = NW.Dom.match; runner.addGroup("Basic Selectors").addTests(null, { "*": function(){ //Universal selector var results = [], nodes = document.getElementsByTagName("*"), index = 0, length = nodes.length, node; //Collect all element nodes, excluding comments (IE) for(; index < length; index++){ if((node = nodes[index]).tagName !== "!"){ results[results.length] = node; } } this.assertEquivalent(select("*"), results, "Comment nodes should be ignored."); }, "E": function(){ //Type selector var results = [], index = 0, nodes = document.getElementsByTagName("li"); while((results[index] = nodes[index++])){} results.length--; this.assertEquivalent(select("li"), results); this.assertEqual(select("strong", getById("fixtures"))[0], getById("strong")); this.assertEquivalent(select("nonexistent"), []); }, "#id": function(){ //ID selector this.assertEqual(select("#fixtures")[0], getById("fixtures")); this.assertEquivalent(select("nonexistent"), []); this.assertEqual(select("#troubleForm")[0], getById("troubleForm")); }, ".class": function(){ //Class selector this.assertEquivalent(select(".first"), getById('p', 'link_1', 'item_1')); this.assertEquivalent(select(".second"), []); }, "E#id": function(){ this.assertEqual(select("strong#strong")[0], getById("strong")); this.assertEquivalent(select("p#strong"), []); }, "E.class": function(){ var secondLink = getById("link_2"); this.assertEquivalent(select('a.internal'), getById('link_1', 'link_2')); this.assertEqual(select('a.internal.highlight')[0], secondLink); this.assertEqual(select('a.highlight.internal')[0], secondLink); this.assertEquivalent(select('a.highlight.internal.nonexistent'), []); }, "#id.class": function(){ var secondLink = getById('link_2'); this.assertEqual(select('#link_2.internal')[0], secondLink); this.assertEqual(select('.internal#link_2')[0], secondLink); this.assertEqual(select('#link_2.internal.highlight')[0], secondLink); this.assertEquivalent(select('#link_2.internal.nonexistent'), []); }, "E#id.class": function(){ var secondLink = getById('link_2'); this.assertEqual(select('a#link_2.internal')[0], secondLink); this.assertEqual(select('a.internal#link_2')[0], secondLink); this.assertEqual(select('li#item_1.first')[0], getById("item_1")); this.assertEquivalent(select('li#item_1.nonexistent'), []); this.assertEquivalent(select('li#item_1.first.nonexistent'), []); } }); runner.addGroup("Attribute Selectors").addTests(null, { "[foo]": function(){ this.assertEquivalent(select('[href]', document.body), select('a[href]', document.body)); this.assertEquivalent(select('[class~=internal]'), select('a[class~="internal"]')); this.assertEquivalent(select('[id]'), select('*[id]')); this.assertEquivalent(select('[type=radio]'), getById('checked_radio', 'unchecked_radio')); this.assertEquivalent(select('[type=checkbox]'), select('*[type=checkbox]')); this.assertEquivalent(select('[title]'), getById('with_title', 'commaParent')); this.assertEquivalent(select('#troubleForm [type=radio]'), select('#troubleForm *[type=radio]')); this.assertEquivalent(select('#troubleForm [type]'), select('#troubleForm *[type]')); }, "E[foo]": function(){ this.assertEquivalent(select('h1[class]'), select('#fixtures h1'), "h1[class]"); this.assertEquivalent(select('h1[CLASS]'), select('#fixtures h1'), "h1[CLASS]"); this.assertEqual(select('li#item_3[class]')[0], getById('item_3'), "li#item_3[class]"); this.assertEquivalent(select('#troubleForm2 input[name="brackets[5][]"]'), getById('chk_1', 'chk_2')); //Brackets in attribute value this.assertEqual(select('#troubleForm2 input[name="brackets[5][]"]:checked')[0], getById('chk_1')); //Space in attribute value this.assertEqual(select('cite[title="hello world!"]')[0], getById('with_title')); //Namespaced attributes this.assertEquivalent(select('[xml:lang]'), [document.documentElement, getById("item_3")]); this.assertEquivalent(select('*[xml:lang]'), [document.documentElement, getById("item_3")]); }, 'E[foo="bar"]': function(){ this.assertEquivalent(select('a[href="#"]'), getById('link_1', 'link_2', 'link_3')); this.assertThrowsException(/Error/, function(){ select('a[href=#]'); }); this.assertEqual(select('#troubleForm2 input[name="brackets[5][]"][value="2"]')[0], getById('chk_2')); }, 'E[foo~="bar"]': function(){ this.assertEquivalent(select('a[class~="internal"]'), getById('link_1', 'link_2'), "a[class~=\"internal\"]"); this.assertEquivalent(select('a[class~=internal]'), getById('link_1', 'link_2'), "a[class~=internal]"); this.assertEqual(select('a[class~=external][href="#"]')[0], getById('link_3'), 'a[class~=external][href="#"]'); }, 'E[foo|="en"]': function(){ this.assertEqual(select('*[xml:lang|="es"]')[0], getById('item_3')); this.assertEqual(select('*[xml:lang|="ES"]')[0], getById('item_3')); }, 'E[foo^="bar"]': function(){ this.assertEquivalent(select('div[class^=bro]'), getById('father', 'uncle'), 'matching beginning of string'); this.assertEquivalent(select('#level1 *[id^="level2_"]'), getById('level2_1', 'level2_2', 'level2_3')); this.assertEquivalent(select('#level1 *[id^=level2_]'), getById('level2_1', 'level2_2', 'level2_3')); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *[id^=level2_]'); }, 1000); }, 500); } }, 'E[foo$="bar"]': function(){ this.assertEquivalent(select('div[class$=men]'), getById('father', 'uncle'), 'matching end of string'); this.assertEquivalent(select('#level1 *[id$="_1"]'), getById('level2_1', 'level3_1')); this.assertEquivalent(select('#level1 *[id$=_1]'), getById('level2_1', 'level3_1')); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *[id$=_1]'); }, 1000); }, 500); } }, 'E[foo*="bar"]': function(){ this.assertEquivalent(select('div[class*="ers m"]'), getById('father', 'uncle'), 'matching substring'); this.assertEquivalent(select('#level1 *[id*="2"]'), getById('level2_1', 'level3_2', 'level2_2', 'level2_3')); this.assertThrowsException(/Error/, function(){ select('#level1 *[id*=2]'); }); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *[id*=2]'); }, 1000); }, 500); } }, // *** these should throw SYNTAX_ERR *** 'E[id=-1]': function(){ this.assertThrowsException(/Error/, function(){ select('#level1 *[id=-1]'); }); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *[id=9]'); }, 1000); }, 500); } }, 'E[class=-45deg]': function(){ this.assertThrowsException(/Error/, function(){ select('#level1 *[class=-45deg]'); }); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *[class=-45deg]'); }, 1000); }, 500); } }, 'E[class=8mm]': function(){ this.assertThrowsException(/Error/, function(){ select('#level1 *[class=8mm]'); }); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *[class=8mm]'); }, 1000); }, 500); } } }); runner.addGroup("Structural pseudo-classes").addTests(null, { "E:first-child": function(){ this.assertEqual(select('#level1>*:first-child')[0], getById('level2_1')); this.assertEquivalent(select('#level1 *:first-child'), getById('level2_1', 'level3_1', 'level_only_child')); this.assertEquivalent(select('#level1>div:first-child'), []); this.assertEquivalent(select('#level1 span:first-child'), getById('level2_1', 'level3_1')); this.assertEquivalent(select('#level1:first-child'), []); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *:first-child'); }, 1000); }, 500); } }, "E:last-child": function(){ this.assertEqual(select('#level1>*:last-child')[0], getById('level2_3')); this.assertEquivalent(select('#level1 *:last-child'), getById('level3_2', 'level_only_child', 'level2_3')); this.assertEqual(select('#level1>div:last-child')[0], getById('level2_3')); this.assertEqual(select('#level1 div:last-child')[0], getById('level2_3')); this.assertEquivalent(select('#level1>span:last-child'), []); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *:last-child'); }, 1000); }, 500); } }, "E:nth-child(n)": function(){ this.assertEqual(select('#p *:nth-child(3)')[0], getById('link_2')); this.assertEqual(select('#p a:nth-child(3)')[0], getById('link_2'), 'nth-child'); this.assertEquivalent(select('#list > li:nth-child(n+2)'), getById('item_2', 'item_3')); this.assertEquivalent(select('#list > li:nth-child(-n+2)'), getById('item_1', 'item_2')); }, "E:nth-of-type(n)": function(){ this.assertEqual(select('#p a:nth-of-type(2)')[0], getById('link_2'), 'nth-of-type'); this.assertEqual(select('#p a:nth-of-type(1)')[0], getById('link_1'), 'nth-of-type'); }, "E:nth-last-of-type(n)": function(){ this.assertEqual(select('#p a:nth-last-of-type(1)')[0], getById('link_2'), 'nth-last-of-type'); }, "E:first-of-type": function(){ this.assertEqual(select('#p a:first-of-type')[0], getById('link_1'), 'first-of-type'); }, "E:last-of-type": function(){ this.assertEqual(select('#p a:last-of-type')[0], getById('link_2'), 'last-of-type'); }, "E:only-child": function(){ this.assertEqual(select('#level1 *:only-child')[0], getById('level_only_child')); //Shouldn't return anything this.assertEquivalent(select('#level1>*:only-child'), []); this.assertEquivalent(select('#level1:only-child'), []); this.assertEquivalent(select('#level2_2 :only-child:not(:last-child)'), []); this.assertEquivalent(select('#level2_2 :only-child:not(:first-child)'), []); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 *:only-child'); }, 1000); }, 500); } }, "E:empty": function(){ getById('level3_1').innerHTML = ""; if(document.createEvent){ this.assertEquivalent(select('#level1 *:empty'), getById('level3_1', 'level3_2', 'level2_3'), '#level1 *:empty'); this.assertEquivalent(select('#level_only_child:empty'), [], 'newlines count as content!'); }else{ this.assertEqual(select('#level3_1:empty')[0], getById('level3_1'), 'IE forced empty content!'); //this.skip("IE forced empty content!"); } //Shouldn't return anything this.assertEquivalent(select('span:empty > *'), []); } }); runner.addTests(null, { "E:not(s)": function(){ //Negation pseudo-class this.assertEquivalent(select('a:not([href="#"])'), []); this.assertEquivalent(select('div.brothers:not(.brothers)'), []); this.assertEquivalent(select('a[class~=external]:not([href="#"])'), [], 'a[class~=external][href!="#"]'); this.assertEqual(select('#p a:not(:first-of-type)')[0], getById('link_2'), 'first-of-type'); this.assertEqual(select('#p a:not(:last-of-type)')[0], getById('link_1'), 'last-of-type'); this.assertEqual(select('#p a:not(:nth-of-type(1))')[0], getById('link_2'), 'nth-of-type'); this.assertEqual(select('#p a:not(:nth-last-of-type(1))')[0], getById('link_1'), 'nth-last-of-type'); this.assertEqual(select('#p a:not([rel~=nofollow])')[0], getById('link_2'), 'attribute 1'); this.assertEqual(select('#p a:not([rel^=external])')[0], getById('link_2'), 'attribute 2'); this.assertEqual(select('#p a:not([rel$=nofollow])')[0], getById('link_2'), 'attribute 3'); this.assertEqual(select('#p a:not([rel$="nofollow"]) > em')[0], getById('em'), 'attribute 4'); this.assertEqual(select('#list li:not(#item_1):not(#item_3)')[0], getById('item_2'), 'adjacent :not clauses'); this.assertEqual(select('#grandfather > div:not(#uncle) #son')[0], getById('son')); this.assertEqual(select('#p a:not([rel$="nofollow"]) em')[0], getById('em'), 'attribute 4 + all descendants'); this.assertEqual(select('#p a:not([rel$="nofollow"])>em')[0], getById('em'), 'attribute 4 (without whitespace)'); } }); runner.addGroup("UI element states pseudo-classes").addTests(null, { "E:disabled": function(){ this.assertEqual(select('#troubleForm > p > *:disabled')[0], getById('disabled_text_field')); }, "E:checked": function(){ this.assertEquivalent(select('#troubleForm *:checked'), getById('checked_box', 'checked_radio')); } }); runner.addGroup("Combinators").addTests(null, { "E F": function(){ //Descendant this.assertEquivalent(select('#fixtures a *'), getById('em2', 'em', 'span')); this.assertEqual(select('div#fixtures p')[0], getById("p")); }, "E + F": function(){ //Adjacent sibling this.assertEqual(select('div.brothers + div.brothers')[0], getById("uncle")); this.assertEqual(select('div.brothers + div')[0], getById('uncle')); this.assertEqual(select('#level2_1+span')[0], getById('level2_2')); this.assertEqual(select('#level2_1 + span')[0], getById('level2_2')); this.assertEqual(select('#level2_1 + *')[0], getById('level2_2')); this.assertEquivalent(select('#level2_2 + span'), []); this.assertEqual(select('#level3_1 + span')[0], getById('level3_2')); this.assertEqual(select('#level3_1 + *')[0], getById('level3_2')); this.assertEquivalent(select('#level3_2 + *'), []); this.assertEquivalent(select('#level3_1 + em'), []); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level3_1 + span'); }, 1000); }, 500); } }, "E > F": function(){ //Child this.assertEquivalent(select('p.first > a'), getById('link_1', 'link_2')); this.assertEquivalent(select('div#grandfather > div'), getById('father', 'uncle')); this.assertEquivalent(select('#level1>span'), getById('level2_1', 'level2_2')); this.assertEquivalent(select('#level1 > span'), getById('level2_1', 'level2_2')); this.assertEquivalent(select('#level2_1 > *'), getById('level3_1', 'level3_2')); this.assertEquivalent(select('div > #nonexistent'), []); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level1 > span'); }, 1000); }, 500); } }, "E ~ F": function(){ //General sibling this.assertEqual(select('h1 ~ ul')[0], getById('list')); this.assertEquivalent(select('#level2_2 ~ span'), []); this.assertEquivalent(select('#level3_2 ~ *'), []); this.assertEquivalent(select('#level3_1 ~ em'), []); this.assertEquivalent(select('div ~ #level3_2'), []); this.assertEquivalent(select('div ~ #level2_3'), []); this.assertEqual(select('#level2_1 ~ span')[0], getById('level2_2')); this.assertEquivalent(select('#level2_1 ~ *'), getById('level2_2', 'level2_3')); this.assertEqual(select('#level3_1 ~ #level3_2')[0], getById('level3_2')); this.assertEqual(select('span ~ #level3_2')[0], getById('level3_2')); if(RUN_BENCHMARKS){ this.wait(function(){ this.benchmark(function(){ select('#level2_1 ~ span'); }, 1000); }, 500); } } }); runner.addTests(null, { "NW.Dom.match": function(){ var element = getById('dupL1'); //Assertions this.assert(match(element, 'span')); this.assert(match(element, "span#dupL1")); this.assert(match(element, "div > span"), "child combinator"); this.assert(match(element, "#dupContainer span"), "descendant combinator"); this.assert(match(element, "#dupL1"), "ID only"); this.assert(match(element, "span.span_foo"), "class name 1"); this.assert(match(element, "span.span_bar"), "class name 2"); this.assert(match(element, "span:first-child"), "first-child pseudoclass"); //Refutations this.refute(match(element, "span.span_wtf"), "bogus class name"); this.refute(match(element, "#dupL2"), "different ID"); this.refute(match(element, "div"), "different tag name"); this.refute(match(element, "span span"), "different ancestry"); this.refute(match(element, "span > span"), "different parent"); this.refute(match(element, "span:nth-child(5)"), "different pseudoclass"); //Misc. this.refute(match(getById('link_2'), 'a[rel^=external]')); this.assert(match(getById('link_1'), 'a[rel^=external]')); this.assert(match(getById('link_1'), 'a[rel^="external"]')); this.assert(match(getById('link_1'), "a[rel^='external']")); }, "Equivalent Selectors": function(){ this.assertEquivalent(select('div.brothers'), select('div[class~=brothers]')); this.assertEquivalent(select('div.brothers'), select('div[class~=brothers].brothers')); this.assertEquivalent(select('div:not(.brothers)'), select('div:not([class~=brothers])')); this.assertEquivalent(select('li ~ li'), select('li:not(:first-child)')); this.assertEquivalent(select('ul > li'), select('ul > li:nth-child(n)')); this.assertEquivalent(select('ul > li:nth-child(even)'), select('ul > li:nth-child(2n)')); this.assertEquivalent(select('ul > li:nth-child(odd)'), select('ul > li:nth-child(2n+1)')); this.assertEquivalent(select('ul > li:first-child'), select('ul > li:nth-child(1)')); this.assertEquivalent(select('ul > li:last-child'), select('ul > li:nth-last-child(1)')); /* Opera 10 does not accept values > 128 as a parameter to :nth-child See */ this.assertEquivalent(select('ul > li:nth-child(n-128)'), select('ul > li')); this.assertEquivalent(select('ul>li'), select('ul > li')); this.assertEquivalent(select('#p a:not([rel$="nofollow"])>em'), select('#p a:not([rel$="nofollow"]) > em')); }, "Multiple Selectors": function(){ //The next two assertions should return document-ordered lists of matching elements --Diego Perini this.assertEquivalent(select('#list, .first,*[xml:lang="es-us"] , #troubleForm'), getById('p', 'link_1', 'list', 'item_1', 'item_3', 'troubleForm')); this.assertEquivalent(select('#list, .first, *[xml:lang="es-us"], #troubleForm'), getById('p', 'link_1', 'list', 'item_1', 'item_3', 'troubleForm')); this.assertEquivalent(select('form[title*="commas,"], input[value="#commaOne,#commaTwo"]'), getById('commaParent', 'commaChild')); this.assertEquivalent(select('form[title*="commas,"], input[value="#commaOne,#commaTwo"]'), getById('commaParent', 'commaChild')); } }); }(runner)); nwmatcher/test/scotch/test-browser.html0000644000175000017500000000077112316015515016776 0ustar wmbwmb Scotch Unit Tests (Browser)
    nwmatcher/test/jquery/0000755000175000017500000000000012316015515013477 5ustar wmbwmbnwmatcher/test/jquery/qunit/0000755000175000017500000000000012316015515014637 5ustar wmbwmbnwmatcher/test/jquery/qunit/testrunner.js0000644000175000017500000002547212316015515017420 0ustar wmbwmb/* * QUnit - jQuery unit testrunner * * http://docs.jquery.com/QUnit * * Copyright (c) 2008 John Resig, Jörn Zaefferer * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * $Id: testrunner.js 5827 2008-08-13 17:14:48Z joern.zaefferer $ * * Modified to run selector test standalone (diego.perini@gmail.com) * */ var _config = { fixture: null, Test: [], stats: { all: 0, bad: 0 }, queue: [], blocking: true, timeout: null, expected: null, currentModule: null, asyncTimeout: 2 // seconds for async timeout }; if (location.search.length > 1) { //restrict modules/tests by get parameters var parms = location.search.slice(1).split('&'); for (var i = 0; parms.length > i; i++) { parms[i] = decodeURIComponent(parms[i]); } _config.filters = parms; } else { _config.filters = false; } var isLocal = !!(window.location.protocol == 'file:'); window.onload = function() { document.getElementById('userAgent').innerHTML = navigator.userAgent; runTest(); } function synchronize(callback) { _config.queue[_config.queue.length] = callback; if(!_config.blocking) { process(); } } function process() { while(_config.queue.length && !_config.blocking) { var call = _config.queue[0]; _config.queue = _config.queue.slice(1); call(); } } function stop(allowFailure) { _config.blocking = true; var handler = allowFailure ? start : function() { ok( false, "Test timed out" ); start(); }; // Disabled, caused too many random errors //_config.timeout = setTimeout(handler, _config.asyncTimeout * 1000); } function start() { // A slight delay, to avoid any current callbacks setTimeout(function(){ if(_config.timeout) clearTimeout(_config.timeout); _config.blocking = false; process(); }, 13); } function validTest( name ) { var filters = _config.filters; if( !filters ) return true; var i = filters.length, run = false; while( i-- ){ var filter = filters[i], not = filter.charAt(0) == '!'; if( not ) filter = filter.slice(1); if( name.indexOf(filter) != -1 ) return !not; if( not ) run = true; } return run; } function runTest() { _config.blocking = false; var started = +new Date; _config.fixture = document.getElementById('main').innerHTML; // _config.ajaxSettings = jQuery.ajaxSettings; synchronize(function() { var output = '

    ' + ['Tests completed in ', +new Date - started, ' milliseconds.
    ', '', _config.stats.bad, ' tests of ', _config.stats.all, ' failed.

    '].join(''); document.body.appendChild(toDOMFragment(output)); document.getElementById('banner').className = _config.stats.bad ? "fail" : "pass"; }); } function test(name, callback, nowait) { if(_config.currentModule) name = _config.currentModule + " module: " + name; if ( !validTest(name) ) return; synchronize(function() { _config.Test = []; try { callback(); } catch(e) { if( typeof console != "undefined" && console.error && console.warn ) { console.error("Test " + name + " died, exception and test follows"); console.error(e); console.warn(callback.toString()); } _config.Test.push( [ false, "Died on test #" + (_config.Test.length+1) + ": " + e.message ] ); } }); synchronize(function() { try { reset(); } catch(e) { if( typeof console != "undefined" && console.error && console.warn ) { console.error("reset() failed, following Test " + name + ", exception and reset fn follows"); console.error(e); console.warn(reset.toString()); } } // don't output pause tests if(nowait) return; if(_config.expected && _config.expected != _config.Test.length) { _config.Test.push( [ false, "Expected " + _config.expected + " assertions, but " + _config.Test.length + " were run" ] ); } _config.expected = null; var good = 0, bad = 0; var ol = document.createElement("ol"); ol.style.display = "none"; var li = "", state = "pass"; for ( var i = 0; i < _config.Test.length; i++ ) { var li = document.createElement("li"); li.className = _config.Test[i][0] ? "pass" : "fail"; li.appendChild( document.createTextNode(_config.Test[i][1]) ); ol.appendChild( li ); _config.stats.all++; if ( !_config.Test[i][0] ) { state = "fail"; bad++; _config.stats.bad++; } else good++; } var li = document.createElement("li"); li.className = state; var b = document.createElement("strong"); b.innerHTML = name + " (" + bad + ", " + good + ", " + _config.Test.length + ")"; b.onclick = function(){ var n = this.nextSibling; if ( n.style.display == "none" ) n.style.display = "block"; else n.style.display = "none"; }; if (b.addEventListener) b.addEventListener('dblclick', function(event) { var target = event.target.parentNode.getElementsByTagName("strong"); if ( target.length ) { location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(target[0].textContent); } }, false); else b.attachEvent('ondblclick', function(event) { var target = event.srcElement.parentNode.getElementsByTagName("strong"); if ( target.length ) { location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(target[0].innerText); } }, false); li.appendChild( b ); li.appendChild( ol ); document.getElementById("tests").appendChild( li ); }); } // call on start of module test to prepend name to all tests function module(moduleName) { _config.currentModule = moduleName; } /** * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. */ function expect(asserts) { _config.expected = asserts; } /** * Resets the test setup. Useful for tests that modify the DOM. */ function reset() { document.getElementById('main').innerHTML = _config.fixture; // jQuery.ajaxSettings = jQuery.extend({}, _config.ajaxSettings); } /** * Asserts true. * @example ok( $("a").length > 5, "There must be at least 5 anchors" ); */ function ok(a, msg) { _config.Test.push( [ !!a, msg ] ); } /** * Asserts that two arrays are the same */ function isSet(a, b, msg) { var ret = true; if ( a && b && a.length != undefined && a.length == b.length ) { for ( var i = 0; i < a.length; i++ ) if ( a[i] != b[i] ) ret = false; } else ret = false; if ( !ret ) _config.Test.push( [ ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) ] ); else _config.Test.push( [ ret, msg ] ); } /** * Asserts that two objects are equivalent */ function isObj(a, b, msg) { var ret = true; if ( a && b ) { for ( var i in a ) if ( a[i] != b[i] ) ret = false; for ( i in b ) if ( a[i] != b[i] ) ret = false; } else ret = false; _config.Test.push( [ ret, msg ] ); } function serialArray( a ) { var r = []; if ( a && a.length ) for ( var i = 0; i < a.length; i++ ) { var str = a[i].nodeName; if ( str ) { str = str.toLowerCase(); if ( a[i].id ) str += "#" + a[i].id; } else str = a[i]; r.push( str ); } return "[ " + r.join(", ") + " ]"; } function flatMap(a, block) { var result = []; $.each(a, function() { var x = block.apply(this, arguments); if (x !== false) result.push(x); }) return result; } function serialObject( a ) { return "{ " + flatMap(a, function(key, value) { return key + ": " + value; }).join(", ") + " }"; } function compare(a, b, msg) { var ret = true; if ( a && b && a.length != undefined && a.length == b.length ) { for ( var i = 0; i < a.length; i++ ) for(var key in a[i]) { if (a[i][key].constructor == Array) { for (var arrayKey in a[i][key]) { if (a[i][key][arrayKey] != b[i][key][arrayKey]) { ret = false; } } } else if (a[i][key] != b[i][key]) { ret = false } } } else ret = false; ok( ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) ); } function compare2(a, b, msg) { var ret = true; if ( a && b ) { for(var key in a) { if (a[key].constructor == Array) { for (var arrayKey in a[key]) { if (a[key][arrayKey] != b[key][arrayKey]) { ret = false; } } } else if (a[key] != b[key]) { ret = false } } for(key in b) { if (b[key].constructor == Array) { for (var arrayKey in b[key]) { if (a[key][arrayKey] != b[key][arrayKey]) { ret = false; } } } else if (a[key] != b[key]) { ret = false } } } else ret = false; ok( ret, msg + " expected: " + serialObject(b) + " result: " + serialObject(a) ); } /** * Returns an array of elements with the given IDs, eg. * @example q("main", "foo", "bar") * @result [
    , , ] */ function q() { var r = []; for ( var i = 0; i < arguments.length; i++ ) r.push( document.getElementById( arguments[i] ) ); return r; } /** * Asserts that a select matches the given IDs * @example t("Check for something", "//[a]", ["foo", "baar"]); * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' */ function t(a,b,c) { var f = NW.Dom.select(b); var s = ""; for ( var i = 0; i < f.length; i++ ) s += (s && ",") + '"' + f[i].id + '"'; isSet(f, q.apply(q,c), a + " (" + b + ")"); } /** * Add random number to url to stop IE from caching * * @example url("data/test.html") * @result "data/test.html?10538358428943" * * @example url("data/test.php?foo=bar") * @result "data/test.php?foo=bar&10538358345554" */ function url(value) { return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); } /** * Checks that the first two arguments are equal, with an optional message. * Prints out both actual and expected values. * * Prefered to ok( actual == expected, message ) * * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." ); * * @param Object actual * @param Object expected * @param String message (optional) */ function equals(actual, expected, message) { var result = expected == actual; message = message || (result ? "okay" : "failed"); _config.Test.push( [ result, result ? message + ": " + expected : message + " expected: " + expected + " actual: " + actual ] ); } /** * Trigger an event on an element. * * @example triggerEvent( document.body, "click" ); * * @param DOMElement elem * @param String type */ function triggerEvent( elem, type, event ) { if ( document.createEvent ) { event = document.createEvent("MouseEvents"); event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null); elem.dispatchEvent( event ); } else if ( document.createEventObject ) { elem.fireEvent("on"+type); } } nwmatcher/test/jquery/qunit/testsuite.css0000644000175000017500000000404512316015515017405 0ustar wmbwmbbody, div, h1 { font-family: 'trebuchet ms', verdana, arial; margin: 0; padding: 0 } body {font-size: 10pt; } h1 { padding: 15px; font-size: large; background-color: #06b; color: white; } h1 a { color: white; } h2 { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal } .pass { color: green; } .fail { color: red; } p.result { margin-left: 1em; } #banner { height: 2em; border-bottom: 1px solid white; } h2.pass { background-color: green; } h2.fail { background-color: red; } ol#tests > li > strong { cursor:pointer; } div#fx-tests h4 { background: red; } div#fx-tests h4.pass { background: green; } div#fx-tests div.box { background: red url(data/cow.jpg) no-repeat; overflow: hidden; border: 2px solid #000; } div#fx-tests div.overflow { overflow: visible; } div.inline { display: inline; } div.autoheight { height: auto; } div.autowidth { width: auto; } div.autoopacity { opacity: inherit; } div.largewidth { width: 100px; } div.largeheight { height: 100px; } div.largeopacity { _filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100); } div.medwidth { width: 50px; } div.medheight { height: 50px; } div.medopacity { opacity: 0.5; _filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50); } div.nowidth { width: 0px; } div.noheight { height: 0px; } div.noopacity { opacity: 0; _filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0); } div.hidden { display: none; } div#fx-tests div.widewidth { background-repeat: repeat-x; } div#fx-tests div.wideheight { background-repeat: repeat-y; } div#fx-tests div.widewidth.wideheight { background-repeat: repeat; } div#fx-tests div.noback { background-image: none; } div.chain, div.chain div { width: 100px; height: 20px; position: relative; float: left; } div.chain div { position: absolute; top: 0px; left: 0px; } div.chain.test { background: red; } div.chain.test div { background: green; } div.chain.out { background: green; } div.chain.out div { background: red; display: none; } div#show-tests * { display: none; }nwmatcher/test/jquery/jquery.html0000644000175000017500000002327212316015515015712 0ustar wmbwmb jQuery Test Suite

    jQuery Test Suite

    Test<\/th>Results<\/th><\/tr><\/thead>
    hi there
    1. Rice
    2. Beans
    3. Blinis
    4. Tofu
    I'm hungry. I should...
    ...Eat lots of food... | ...Eat a little food... | ...Eat no food... ...Eat a burger... ...Eat some funyuns... ...Eat some funyuns...
    fadeIn
    fadeIn
    fadeOut
    fadeOut
    show
    show
    hide
    hide
    togglein
    togglein
    toggleout
    toggleout
    slideUp
    slideUp
    slideDown
    slideDown
    slideToggleIn
    slideToggleIn
    slideToggleOut
    slideToggleOut
      nwmatcher/test/jquery/unit/0000755000175000017500000000000012316015515014456 5ustar wmbwmbnwmatcher/test/jquery/unit/selector.js0000644000175000017500000005761512316015515016652 0ustar wmbwmbmodule("selector"); // convert HTML Fragment (string) into a DOM Fragment (dom nodes) var toDOMFragment = function(html, context) { var l, nodes, fragment, orphan; context || (context = document); orphan = context.createElement('div'); orphan.innerHTML = html;// write fragment fragment = context.createDocumentFragment(); nodes = orphan.childNodes; l = nodes.length; while (l--) fragment.insertBefore(nodes[l], fragment.firstChild) return fragment; }; test("element", function() { expect(18); reset(); ok( NW.Dom.select("*").length >= 30, "Select all" ); var all = NW.Dom.select("*"), good = true; for ( var i = 0; i < all.length; i++ ) if ( all[i].nodeType == 8 ) good = false; ok( good, "Select all elements, no comment nodes" ); t( "Element Selector", "p", ["firstp","ap","sndp","en","sap","first"] ); t( "Element Selector", "body", ["body"] ); t( "Element Selector", "html", ["html"] ); t( "Parent Element", "div p", ["firstp","ap","sndp","en","sap","first"] ); equals( NW.Dom.select("param", document.getElementById("object1")).length, 2, "Object/param as context" ); isSet( NW.Dom.select("div p"), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." ); isSet( NW.Dom.select("div p"), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." ); isSet( NW.Dom.select("div p"), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." ); isSet( NW.Dom.select("div p"), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." ); ok( NW.Dom.select("#length").length, '<input name="length"> cannot be found under IE, see #945' ); ok( NW.Dom.select("#lengthtest input").length, '<input name="length"> cannot be found under IE, see #945' ); // Check for unique-ness and sort order isSet( NW.Dom.select("*"), NW.Dom.select("*, *"), "Check for duplicates: *, *" ); isSet( NW.Dom.select("p"), NW.Dom.select("p, div p"), "Check for duplicates: p, div p" ); t( "Checking sort order", "h2, h1", ["header", "banner", "userAgent"] ); t( "Checking sort order", "h2:first, h1:first", ["header", "banner"] ); t( "Checking sort order", "p, p a", ["firstp", "simon1", "ap", "google", "groups", "anchor1", "mark", "sndp", "en", "yahoo", "sap", "anchor2", "simon", "first"] ); }); /* if ( location.protocol != "file:" ) { test("XML Document Selectors", function() { expect(7); stop(); jQuery.get("data/with_fries.xml", function(xml) { equals( jQuery("foo_bar", xml).length, 1, "Element Selector with underscore" ); equals( jQuery(".component", xml).length, 1, "Class selector" ); equals( jQuery("[class*=component]", xml).length, 1, "Attribute selector for class" ); equals( jQuery("property[name=prop2]", xml).length, 1, "Attribute selector with name" ); equals( jQuery("[name=prop2]", xml).length, 1, "Attribute selector with name" ); equals( jQuery("#seite1", xml).length, 1, "Attribute selector with ID" ); equals( jQuery("component#seite1", xml).length, 1, "Attribute selector with ID" ); start(); }); }); } */ test("broken", function() { expect(13); function broken(name, selector) { try { t(name, selector, [ ]); } catch(e){ ok( /error/i.test(e.name), name + ": " + selector ); } } broken( "Broken Selector", "[", [] ); broken( "Broken Selector", "(", [] ); broken( "Broken Selector", "{", [] ); broken( "Broken Selector", "<", [] ); broken( "Broken Selector", "()", [] ); broken( "Broken Selector", "<>", [] ); // curly braces could be used in extensions //broken( "Broken Selector", "{}", [] ); broken( "Nth-child", ":nth-child(2n+-0)", [] ); broken( "Nth-child", ":nth-child(- 1n)", [] ); broken( "Nth-child", ":nth-child(-1 n)", [] ); broken( "First-child", ":first-child(n)", [] ); broken( "Last-child", ":last-child(n)", [] ); broken( "Only-child", ":only-child(n)", [] ); broken( "Nth-child", ":nth-child(2+0)", [] ); }); test("id", function() { expect(28); t( "ID Selector", "#body", ["body"] ); t( "ID Selector w/ Element", "body#body", ["body"] ); t( "ID Selector w/ Element", "ul#first", [] ); t( "ID selector with existing ID descendant", "#firstp #simon1", ["simon1"] ); t( "ID selector with non-existant descendant", "#firstp #foobar", [] ); t( "ID selector using UTF8", "#台北Táiběi", ["台北Táiběi"] ); t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", ["台北Táiběi","台北"] ); t( "Descendant ID selector using UTF8", "div #台北", ["台北"] ); t( "Child ID selector using UTF8", "form > #台北", ["台北"] ); t( "Escaped ID", "#foo\\:bar", ["foo:bar"] ); t( "Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "Descendant escaped ID", "div #foo\\:bar", ["foo:bar"] ); t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "Child escaped ID", "form > #foo\\:bar", ["foo:bar"] ); t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] ); // bug #267 t( "ID Selector, not an ancestor ID", "#form #first", [] ); t( "ID Selector, not a child ID", "#form > #option1a", [] ); t( "All Children of ID", "#foo > *", ["sndp", "en", "sap"] ); t( "All Children of ID with no children", "#firstUL > *", [] ); var main = document.getElementById('main'); main.appendChild(toDOMFragment('tName1 AtName2 A
      tName1 Div
      ')); equals( NW.Dom.select("#tName1")[0].id, 'tName1', "ID selector with same value for a name attribute" ); equals( NW.Dom.select("#tName2").length, 0, "ID selector non-existing but name attribute on an A tag" ); t( "ID Selector on Form with an input that has a name of 'id'", "#lengthtest", ["lengthtest"] ); t( "ID selector with non-existant ancestor", "#asdfasdf #foobar", [] ); // bug #986 isSet( NW.Dom.select("body div#form"), [], "ID selector within the context of another element" ); t( "Underscore ID", "#types_all", ["types_all"] ); t( "Dash ID", "#fx-queue", ["fx-queue"] ); t( "ID with weird characters in it", "#name\\+value", ["name+value"] ); }); test("class", function() { expect(23); t( "Class Selector", ".blog", ["mark","simon"] ); t( "Class Selector", ".GROUPS", ["groups"] ); t( "Class Selector", ".blog.link", ["simon"] ); t( "Class Selector w/ Element", "a.blog", ["mark","simon"] ); t( "Parent Class Selector", "p .blog", ["mark","simon"] ); isSet( NW.Dom.select("p .blog"), q("mark", "simon"), "Finding elements with a context." ); isSet( NW.Dom.select("p .blog"), q("mark", "simon"), "Finding elements with a context." ); isSet( NW.Dom.select("p .blog"), q("mark", "simon"), "Finding elements with a context." ); isSet( NW.Dom.select("p .blog"), q("mark", "simon"), "Finding elements with a context." ); t( "Class selector using UTF8", ".台北Táiběi", ["utf8class1"] ); t( "Class selector using UTF8", ".台北", ["utf8class1","utf8class2"] ); t( "Class selector using UTF8", ".台北Táiběi.台北", ["utf8class1"] ); t( "Class selector using UTF8", ".台北Táiběi, .台北", ["utf8class1","utf8class2"] ); t( "Descendant class selector using UTF8", "div .台北Táiběi", ["utf8class1"] ); t( "Child class selector using UTF8", "form > .台北Táiběi", ["utf8class1"] ); t( "Escaped Class", ".foo\\:bar", ["foo:bar"] ); t( "Escaped Class", ".test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "Descendant scaped Class", "div .foo\\:bar", ["foo:bar"] ); t( "Descendant scaped Class", "div .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "Child escaped Class", "form > .foo\\:bar", ["foo:bar"] ); t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); var div = document.createElement("div"); div.innerHTML = "
      "; isSet( NW.Dom.select(".e", div), [ div.firstChild ], "Finding a second class." ); div.lastChild.className = "e"; isSet( NW.Dom.select(".e", div), [ div.firstChild, div.lastChild ], "Finding a modified class." ); }); test("name", function() { expect(11); t( "Name selector", "input[name=action]", ["text1"] ); t( "Name selector with single quotes", "input[name='action']", ["text1"] ); t( "Name selector with double quotes", 'input[name="action"]', ["text1"] ); t( "Name selector non-input", "[name=test]", ["length", "fx-queue"] ); t( "Name selector non-input", "[name=div]", ["fadein"] ); t( "Name selector non-input", "*[name=iframe]", ["iframe"] ); t( "Name selector for grouped input", "input[name='types[]']", ["types_all", "types_anime", "types_movie"] ) isSet( NW.Dom.select("#form input[name=action]"), q("text1"), "Name selector within the context of another element" ); isSet( NW.Dom.select("#form input[name='foo[bar]']"), q("hidden2"), "Name selector for grouped form element within the context of another element" ); var main = document.getElementById('main'); var f = main.appendChild(toDOMFragment('tName1 AtName2 A
      tName1 Div
      ')); t( "Find elements that have similar IDs", "[name=tName1]", ["tName1ID"] ); t( "Find elements that have similar IDs", "[name=tName2]", ["tName2ID"] ); // main.removeChild(f); }); test("multiple", function() { expect(4); t( "Comma Support", "h2, p", ["banner","userAgent","firstp","ap","sndp","en","sap","first"]); t( "Comma Support", "h2 , p", ["banner","userAgent","firstp","ap","sndp","en","sap","first"]); t( "Comma Support", "h2 , p", ["banner","userAgent","firstp","ap","sndp","en","sap","first"]); t( "Comma Support", "h2,p", ["banner","userAgent","firstp","ap","sndp","en","sap","first"]); }); test("child and adjacent", function() { expect(49); t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] ); t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] ); t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] ); t( "Child", "p>a", ["simon1","google","groups","mark","yahoo","simon"] ); t( "Child w/ Class", "p > a.blog", ["mark","simon"] ); t( "All Children", "code > *", ["anchor1","anchor2"] ); t( "All Grandchildren", "p > * > *", ["anchor1","anchor2"] ); t( "Adjacent", "a + a", ["groups"] ); t( "Adjacent", "a +a", ["groups"] ); t( "Adjacent", "a+ a", ["groups"] ); t( "Adjacent", "a+a", ["groups"] ); t( "Adjacent", "p + p", ["ap","en","sap"] ); t( "Adjacent", "p#firstp + p", ["ap"] ); t( "Adjacent", "p[lang=en] + p", ["sap"] ); t( "Adjacent", "a.GROUPS + code + a", ["mark"] ); t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] ); t( "Verify deep class selector", "div.blah > p > a", [] ); t( "No element deep selector", "div.foo > span > a", [] ); t( "No element not selector", ".container div:not(.excluded) div", [] ); // NWMatcher accepts syntax shortcuts like "> *" but querySelectorAll() does not, so we use correct syntax here isSet( NW.Dom.select("* > :first-child", document.getElementById("nothiddendiv")), q("nothiddendivchild"), "Verify child context positional selector" ); isSet( NW.Dom.select("* > :nth-child(1)", document.getElementById("nothiddendiv")), q("nothiddendivchild"), "Verify child context positional selector" ); isSet( NW.Dom.select("* > *:first-child", document.getElementById("nothiddendiv")), q("nothiddendivchild"), "Verify child context positional selector" ); t( "Non-existant ancestors", ".fototab > .thumbnails > a", [] ); t( "First Child", "p:first-child", ["firstp","sndp"] ); t( "Nth Child", "p:nth-child(1)", ["firstp","sndp"] ); t( "Not Nth Child", "p:not(:nth-child(1))", ["ap","en","sap","first"] ); // Verify that the child position isn't being cached improperly var div = document.createElement('div'), divs; divs = NW.Dom.select("p:first-child", null, null); for(var i = 0; i < divs.length; i++) { divs[i].parentNode.insertBefore(div.cloneNode(false), divs[i].nextSibling); } // function(e) { e.parentNode.insertBefore(div.cloneNode(false), e.nextSibling); }); divs = NW.Dom.select("p:first-child", null, null); for(var i = 0, p; i < divs.length; i++) { p = divs[i].parentNode.insertBefore(div.cloneNode(false), divs[i]).nextSibling; p.parentNode.removeChild(p); } // function(e) { var p = e.parentNode.insertBefore(div.cloneNode(false), e).nextSibling; p.parentNode.removeChild(p); }); t( "First Child", "p:first-child", [ ] ); reset(); t( "Last Child", "p:last-child", ["sap"] ); t( "Last Child", "a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon","liveLink1","liveLink2"] ); t( "Nth-child", "#main form#form > *:nth-child(2)", ["text1"] ); t( "Nth-child", "#main form#form > :nth-child(2)", ["text1"] ); t( "Nth-child", "#form select:first option:nth-child(3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(0n+3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(1n+0)", ["option1a", "option1b", "option1c", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(1n)", ["option1a", "option1b", "option1c", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(n)", ["option1a", "option1b", "option1c", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(even)", ["option1b", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(odd)", ["option1a", "option1c"] ); t( "Nth-child", "#form select:first option:nth-child(2n)", ["option1b", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(2n+1)", ["option1a", "option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n+1)", ["option1a", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(3n+2)", ["option1b"] ); t( "Nth-child", "#form select:first option:nth-child(3n+3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n-1)", ["option1b"] ); t( "Nth-child", "#form select:first option:nth-child(3n-2)", ["option1a", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(3n-3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n+0)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(-n+3)", ["option1a", "option1b", "option1c"] ); }); test("attributes", function() { expect(37); t( "Attribute Exists", "a[title]", ["google"] ); t( "Attribute Exists", "*[title]", ["google"] ); t( "Attribute Exists", "[title]", ["google"] ); t( "Attribute Exists", "a[ title ]", ["google"] ); t( "Attribute Equals", "a[rel='bookmark']", ["simon1"] ); t( "Attribute Equals", 'a[rel="bookmark"]', ["simon1"] ); t( "Attribute Equals", "a[rel=bookmark]", ["simon1"] ); t( "Attribute Equals", "a[href='http://www.google.com/']", ["google"] ); t( "Attribute Equals", "a[ rel = 'bookmark' ]", ["simon1"] ); document.getElementById("anchor2").href = "#2"; t( "href Attribute", "p a[href^='#']", ["anchor2"] ); t( "href Attribute", "p a[href*=\"#\"]", ["simon1", "anchor2"] ); t( "for Attribute", "form label[for]", ["label-for"] ); t( "for Attribute in form", "#form [for=action]", ["label-for"] ); NW.Dom.select("form input")[0].test = 0; NW.Dom.select("form input")[1].test = 1; // Disabled tests - expandos don't work in all browsers //t( "Expando attribute", "form input[test]", ["text1", "text2"] ); //t( "Expando attribute value", "form input[test=0]", ["text1"] ); //t( "Expando attribute value", "form input[test=1]", ["text2"] ); t( "Attribute containing []", "input[name^='foo[']", ["hidden2"] ); t( "Attribute containing []", "input[name^='foo[bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name*='[bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name$='bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name$='[bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name$='foo[bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name*='foo[bar]']", ["hidden2"] ); t( "Multiple Attribute Equals", "#form input[type='radio'], #form input[type='hidden']", ["radio1", "radio2", "hidden1"] ); t( "Multiple Attribute Equals", "#form input[type='radio'], #form input[type=\"hidden\"]", ["radio1", "radio2", "hidden1"] ); t( "Multiple Attribute Equals", "#form input[type='radio'], #form input[type=hidden]", ["radio1", "radio2", "hidden1"] ); t( "Attribute selector using UTF8", "span[lang=中文]", ["台北"] ); t( "Attribute Begins With", "a[href ^= 'http://www']", ["google","yahoo"] ); t( "Attribute Ends With", "a[href $= 'org/']", ["mark"] ); t( "Attribute Contains", "a[href *= 'google']", ["google","groups"] ); t( "Attribute Is Not Equal", "#ap a:not([hreflang='en'])", ["google","groups","anchor1"] ); t("Empty values", "#select1 option[value='']", ["option1a"]); t("Empty values", "#select1 option:not([value=''])", ["option1b","option1c","option1d"]); t("Select options via :selected", "#select1 option:selected", ["option1a"] ); t("Select options via :selected", "#select2 option:selected", ["option2d"] ); t("Select options via :selected", "#select3 option:selected", ["option3b", "option3c"] ); t( "Grouped Form Elements", "input[name='foo[bar]']", ["hidden2"] ); t( ":not() Existing attribute", "#form select:not([multiple])", ["select1", "select2"]); t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3"]); t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3"]); }); test("pseudo (:) selectors", function() { expect(49); t( "First Child", "p:first-child", ["firstp","sndp"] ); t( "Last Child", "p:last-child", ["sap"] ); t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2","liveLink1","liveLink2"] ); t( "Empty", "ul:empty", ["firstUL"] ); t( "Enabled UI Element", "#form input:not([type=hidden]):enabled", ["text1","radio1","radio2","check1","check2","hidden2","name","search"] ); t( "Disabled UI Element", "#form input:disabled", ["text2"] ); t( "Checked UI Element", "#form input:checked", ["radio2","check1"] ); t( "Selected Option Element", "#form option:selected", ["option1a","option2d","option3b","option3c"] ); //t( "Text Contains", "a:contains('Google')", ["google","groups"] ); //t( "Text Contains", "a:contains('Google Groups')", ["groups"] ); //t( "Text Contains", "a:contains('Google Groups (Link)')", ["groups"] ); //t( "Text Contains", "a:contains('(Link)')", ["groups"] ); t( "Element Preceded By", "p ~ div", ["foo", "moretests","tabindex-tests", "liveHandlerOrder"] ); t( "Not", "a.blog:not(.link)", ["mark"] ); //t( "Not - multiple", "#form option:not(:contains('Nothing'),#option1b,:selected)", ["option1c", "option1d", "option2b", "option2c", "option3d", "option3e"] ); //t( "Not - complex", "#form option:not([id^='opt']:nth-child(-n+3))", [ "option1d", "option2d", "option3d", "option3e"] ); //t( "Not - recursive", "#form option:not(:not(:selected))[id^='option3']", [ "option3b", "option3c"] ); t( ":not() failing interior", "p:not(.foo)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not() failing interior", "p:not(div.foo)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not() failing interior", "p:not(p.foo)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not() failing interior", "p:not(#blargh)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not() failing interior", "p:not(div#blargh)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not() failing interior", "p:not(p#blargh)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not Multiple", "p:not(a)", ["firstp","ap","sndp","en","sap","first"] ); //t( ":not Multiple", "p:not(a, b)", ["firstp","ap","sndp","en","sap","first"] ); //t( ":not Multiple", "p:not(a, b, div)", ["firstp","ap","sndp","en","sap","first"] ); t( ":not Multiple", "p:not(p)", [] ); //t( ":not Multiple", "p:not(a,p)", [] ); //t( ":not Multiple", "p:not(p,a)", [] ); //t( ":not Multiple", "p:not(a,p,b)", [] ); //t( ":not Multiple", ":input:not(:image,:input,:submit)", [] ); t( "nth Element", "p:nth(1)", ["ap"] ); t( "First Element", "p:first", ["firstp"] ); t( "Last Element", "p:last", ["first"] ); t( "Even Elements", "p:even", ["firstp","sndp","sap"] ); t( "Odd Elements", "p:odd", ["ap","en","first"] ); t( "Position Equals", "p:eq(1)", ["ap"] ); t( "Position Greater Than", "p:gt(0)", ["ap","sndp","en","sap","first"] ); t( "Position Less Than", "p:lt(3)", ["firstp","ap","sndp"] ); t( "Is A Parent", "p:parent", ["firstp","ap","sndp","en","sap","first"] ); t( "Is Visible", "#form input:visible", [] ); t( "Is Visible", "div:visible:not(.testrunner-toolbar):lt(2)", ["nothiddendiv", "nothiddendivchild"] ); t( "Is Hidden", "#form input:hidden", ["text1","text2","radio1","radio2","check1","check2","hidden1","hidden2","name","search"] ); t( "Is Hidden", "#main:hidden", ["main"] ); t( "Is Hidden", "#dl:hidden", ["dl"] ); var div = NW.Dom.select('#nothiddendivchild')[0]; div.style.fontSize = '0'; div.style.lineHeight = '0'; // $div.css({ fontSize: 0, lineHeight: 0 });// IE also needs to set font-size and line-height to 0 div.style.width = '0'; div.style.height = '0'; // $div.width(0).height(0); t( "Is Hidden", '#nothiddendivchild:hidden', ['nothiddendivchild'] ); t( "Is Not Hidden", '#nothiddendivchild:visible', [] ); div.style.width = '1px'; div.style.height = '0'; // $div.width(1).height(0); t( "Is Visible", '#nothiddendivchild:visible', ['nothiddendivchild'] ); t( "Is Not Visible", '#nothiddendivchild:hidden', [] ); div.style.width = '0'; div.style.height = '1px'; // $div.width(0).height(1); t( "Is Visible", '#nothiddendivchild:visible', ['nothiddendivchild'] ); t( "Is Not Visible", '#nothiddendivchild:hidden', [] ); div.style.width = '1px'; div.style.height = '1px'; // $div.width(1).height(1); t( "Is Visible", '#nothiddendivchild:visible', ['nothiddendivchild'] ); t( "Is Not Visible", '#nothiddendivchild:hidden', [] ); div.style.width = ''; div.style.height = ''; div.style.fontSize = ''; div.style.lineHeight = ''; // $div.width('').height('').css({ fontSize: '', lineHeight: '' }); /* t( "Check position filtering", "div#nothiddendiv:eq(0)", ["nothiddendiv"] ); t( "Check position filtering", "div#nothiddendiv:last", ["nothiddendiv"] ); t( "Check position filtering", "div#nothiddendiv:not(:gt(0))", ["nothiddendiv"] ); t( "Check position filtering", "#foo > :not(:first)", ["en", "sap"] ); t( "Check position filtering", "select > :not(:gt(2))", ["option1a", "option1b", "option1c"] ); t( "Check position filtering", "select:lt(2) :not(:first)", ["option1b", "option1c", "option1d", "option2a", "option2b", "option2c", "option2d"] ); t( "Check position filtering", "div.nothiddendiv:eq(0)", ["nothiddendiv"] ); t( "Check position filtering", "div.nothiddendiv:last", ["nothiddendiv"] ); t( "Check position filtering", "div.nothiddendiv:not(:lt(0))", ["nothiddendiv"] ); t( "Check element position", "div div:eq(0)", ["nothiddendivchild"] ); t( "Check element position", "div div:eq(5)", ["t2037"] ); t( "Check element position", "div div:eq(27)", ["hide"] ); t( "Check element position", "div div:first", ["nothiddendivchild"] ); t( "Check element position", "div > div:first", ["nothiddendivchild"] ); t( "Check element position", "#dl div:first div:first", ["foo"] ); t( "Check element position", "#dl div:first > div:first", ["foo"] ); t( "Check element position", "div#nothiddendiv:first > div:first", ["nothiddendivchild"] ); */ t( "Form element :input", "#form :input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "search", "button", "area1", "select1", "select2", "select3"] ); t( "Form element :radio", "#form :radio", ["radio1", "radio2"] ); t( "Form element :checkbox", "#form :checkbox", ["check1", "check2"] ); t( "Form element :text", "#form :text:not(#search)", ["text1", "text2", "hidden2", "name"] ); t( "Form element :radio:checked", "#form :radio:checked", ["radio2"] ); t( "Form element :checkbox:checked", "#form :checkbox:checked", ["check1"] ); t( "Form element :radio:checked, :checkbox:checked", "#form :radio:checked, #form :checkbox:checked", ["radio2", "check1"] ); t( "Headers", ":header", ["header", "banner", "userAgent"] ); t( "Has Children - :has()", "p:has(a)", ["firstp","ap","en","sap"] ); }); nwmatcher/test/jquery/data/0000755000175000017500000000000012316015515014410 5ustar wmbwmbnwmatcher/test/jquery/data/iframe.html0000644000175000017500000000016512316015515016543 0ustar wmbwmb iframe
      span text
      nwmatcher/test/W3C-Selector-tests/0000755000175000017500000000000012316015515015472 5ustar wmbwmbnwmatcher/test/W3C-Selector-tests/W3C-Selector-tests-nwmatcher.html0000644000175000017500000016666112316015515023700 0ustar wmbwmb selectorTest

      Selectors API Test Suite

      Testrunner by John Resig, tests by John Resig, Disruptive Innovations, W3C CSS Working Group, jQuery JavaScript Library.

      CSS 3 Selectors tests

      (c) Disruptive Innovations 2008
      Last update: 2008-06-06

       

       
      the previous square should be green when the checkbox is checked and become red when you uncheck it
      the previous square should be green when the checkbox is NOT checked and become red when you check it
      the three last squares should be green and become red when the pointer hovers over the white square
      the last square should be green and become red when the pointer hovers over the FIRST white square

      CSS 3 Selectors tests

      (c) Disruptive Innovations 2008
      Last update: 2008-06-06

       

       
      the previous square should be green when the checkbox is checked and become red when you uncheck it
      the previous square should be green when the checkbox is NOT checked and become red when you check it
      the three last squares should be green and become red when the pointer hovers over the white square
      the last square should be green and become red when the pointer hovers over the FIRST white square
      Example circle01 - circle filled with red and stroked with blue Example circle01 - circle filled with red and stroked with blue Example circle01 - circle filled with red and stroked with blue

      jQuery Test Suite

          nwmatcher/test/W3C-Selector-tests/W3C-Selector-tests-github.html0000644000175000017500000016714512316015515023170 0ustar wmbwmb selectorTest

          Selectors API Test Suite

          Testrunner by John Resig, tests by John Resig, Disruptive Innovations, W3C CSS Working Group, jQuery JavaScript Library.

          CSS 3 Selectors tests

          (c) Disruptive Innovations 2008
          Last update: 2008-06-06

           

           
          the previous square should be green when the checkbox is checked and become red when you uncheck it
          the previous square should be green when the checkbox is NOT checked and become red when you check it
          the three last squares should be green and become red when the pointer hovers over the white square
          the last square should be green and become red when the pointer hovers over the FIRST white square

          CSS 3 Selectors tests

          (c) Disruptive Innovations 2008
          Last update: 2008-06-06

           

           
          the previous square should be green when the checkbox is checked and become red when you uncheck it
          the previous square should be green when the checkbox is NOT checked and become red when you check it
          the three last squares should be green and become red when the pointer hovers over the white square
          the last square should be green and become red when the pointer hovers over the FIRST white square
          Example circle01 - circle filled with red and stroked with blue Example circle01 - circle filled with red and stroked with blue Example circle01 - circle filled with red and stroked with blue

          jQuery Test Suite

              nwmatcher/test/prototype/0000755000175000017500000000000012316015515014225 5ustar wmbwmbnwmatcher/test/prototype/lib_assets/0000755000175000017500000000000012316015515016355 5ustar wmbwmbnwmatcher/test/prototype/lib_assets/unittest.js0000644000175000017500000005172412316015515020603 0ustar wmbwmb// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005 Jon Tirsen (http://www.tirsen.com) // (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/) // // 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. // experimental, Firefox-only Event.simulateMouse = function(element, eventName) { var options = Object.extend({ pointerX: 0, pointerY: 0, buttons: 0 }, arguments[2] || {}); var oEvent = document.createEvent("MouseEvents"); oEvent.initMouseEvent(eventName, true, true, document.defaultView, options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, false, false, false, false, 0, $(element)); if(this.mark) Element.remove(this.mark); var style = 'position: absolute; width: 5px; height: 5px;' + 'top: #{pointerY}px; left: #{pointerX}px;'.interpolate(options) + 'border-top: 1px solid red; border-left: 1px solid red;' this.mark = new Element('div', { style: style }); this.mark.appendChild(document.createTextNode(" ")); document.body.appendChild(this.mark); if(this.step) alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options)); $(element).dispatchEvent(oEvent); }; // Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2. // You need to downgrade to 1.0.4 for now to get this working // See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much Event.simulateKey = function(element, eventName) { var options = Object.extend({ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: 0, charCode: 0 }, arguments[2] || {}); var oEvent = document.createEvent("KeyEvents"); oEvent.initKeyEvent(eventName, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode ); $(element).dispatchEvent(oEvent); }; Event.simulateKeys = function(element, command) { for(var i=0; i' + 'StatusTestMessage' + '' + ''; this.element.innerHTML = html; }, appendActionButtons: function(actions) { /* actions = $H(actions); if (!actions.any()) return; var div = new Element("div", {className: 'action_buttons'}); actions.inject(div, function(container, action) { var button = new Element("input").setValue(action.key).observe("click", action.value); button.type = "button"; return container.insert(button); }); this.getMessageCell().insert(div); */ }, _toHTML: function(txt) { return txt.escapeHTML().replace(/\n/g,"
              "); } }); Test.Unit.runners = []; Test.Unit.run = true; Test.Unit.AutoRunner = { run: function() { if (!Test.Unit.run) return; Test.Unit.run = false; for (var i=0; i < Test.Unit.runners.length; i++) { Test.Unit.runners[i].run(); }; } }; Event.observe(window, "load", Test.Unit.AutoRunner.run); Test.Unit.Runner = Class.create({ initialize: function(testcases) { var options = this.options = Object.extend({ testLog: 'testlog' }, arguments[1] || {}); options.resultsURL = this.queryParams.resultsURL; this.tests = this.getTests(testcases); this.currentTest = 0; Test.Unit.runners.push(this); }, run: function() { this.logger = new Test.Unit.Logger(this.options.testLog); this.runTests.bind(this).delay(0.1); }, queryParams: window.location.search.parseQuery(), getTests: function(testcases) { var tests, options = this.options; if (this.queryParams.tests) tests = this.queryParams.tests.split(','); else if (options.tests) tests = options.tests; else if (options.test) tests = [option.test]; else tests = Object.keys(testcases).grep(/^test/); return tests.map(function(test) { if (testcases[test]) return new Test.Unit.Testcase(test, testcases[test], testcases.setup, testcases.teardown); }).compact(); }, getResult: function() { var results = { tests: this.tests.length, assertions: 0, failures: 0, errors: 0 }; return this.tests.inject(results, function(results, test) { results.assertions += test.assertions; results.failures += test.failures; results.errors += test.errors; return results; }); }, postResults: function() { if (window.postUnittestResults) { window.postUnittestResults(this.getResult()); } else if (this.options.resultsURL) { new Ajax.Request(this.options.resultsURL, { method: 'get', parameters: this.getResult(), asynchronous: false }); } }, runTests: function() { var test = this.tests[this.currentTest], actions; if (!test) return this.finish(); if (!test.isWaiting) this.logger.start(test.name); test.run(); if(test.isWaiting) { this.logger.message("Waiting for " + test.timeToWait + "ms"); setTimeout(this.runTests.bind(this), test.timeToWait || 1000); return; } this.logger.finish(test.status(), test.summary()); if (actions = test.actions) this.logger.appendActionButtons(actions); this.currentTest++; // tail recursive, hopefully the browser will skip the stackframe this.runTests(); }, finish: function() { this.postResults(); this.logger.summary(this.summary()); }, summary: function() { return '#{tests} tests, #{assertions} assertions, #{failures} failures, #{errors} errors' .interpolate(this.getResult()); } }); Test.Unit.MessageTemplate = Class.create({ initialize: function(string) { var parts = []; (string || '').scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/, function(part) { parts.push(part[0]); }); this.parts = parts; }, evaluate: function(params) { return this.parts.map(function(part) { return part == '?' ? Test.Unit.inspect(params.shift()) : part.replace(/\\\?/, '?'); }).join(''); } }); Test.Unit.Assertions = (function() { var MessageTemplate = Test.Unit.MessageTemplate; function buildMessage(message, template) { var args = Array.prototype.slice.call(arguments, 2); return (message ? message + '\n' : '') + new MessageTemplate(template).evaluate(args); } function flunk(message) { this.assertBlock(message || 'Flunked', function() { return false }); } function assertBlock(message, block) { try { block.call(this) ? this.pass() : this.fail(message); } catch(e) { this.error(e) } } function assert(expression, message) { message = buildMessage(message || 'assert', 'got ', expression); this.assertBlock(message, function() { return expression }); } function assertEqual(expected, actual, message) { message = buildMessage(message || 'assertEqual', 'expected: , actual: ', expected, actual); this.assertBlock(message, function() { return expected == actual }); } function assertNotEqual(expected, actual, message) { message = buildMessage(message || 'assertNotEqual', 'expected: , actual: ', expected, actual); this.assertBlock(message, function() { return expected != actual }); } function assertEnumEqual(expected, actual, message) { expected = $A(expected); actual = $A(actual); message = buildMessage(message || 'assertEnumEqual', 'expected: , actual: ', expected, actual); this.assertBlock(message, function() { return expected.length == actual.length && expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }); }); } function assertEnumNotEqual(expected, actual, message) { expected = $A(expected); actual = $A(actual); message = buildMessage(message || 'assertEnumNotEqual', ' was the same as ', expected, actual); this.assertBlock(message, function() { return expected.length != actual.length || expected.zip(actual).any(function(pair) { return pair[0] != pair[1] }); }); } function assertPairEqual(pair) { return pair.all(Object.isArray) ? pair[0].zip(pair[1]).all(assertPairEqual) : pair[0] == pair[1]; } function assertHashEqual(expected, actual, message) { expected = $H(expected); actual = $H(actual); var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort(); message = buildMessage(message || 'assertHashEqual', 'expected: , actual: ', expected, actual); // from now we recursively zip & compare nested arrays function block() { return expected_array.length == actual_array.length && expected_array.zip(actual_array).all(assertPairEqual); } this.assertBlock(message, block); } function assertHashNotEqual(expected, actual, message) { expected = $H(expected); actual = $H(actual); var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort(); message = buildMessage(message || 'assertHashNotEqual', ' was the same as ', expected, actual); // from now we recursively zip & compare nested arrays function block() { return !(expected_array.length == actual_array.length && expected_array.zip(actual_array).all(assertPairEqual)); }; this.assertBlock(message, block); } function assertIdentical(expected, actual, message) { message = buildMessage(message || 'assertIdentical', 'expected: , actual: ', expected, actual); this.assertBlock(message, function() { return expected === actual }); } function assertNotIdentical(expected, actual, message) { message = buildMessage(message || 'assertNotIdentical', 'expected: , actual: ', expected, actual); this.assertBlock(message, function() { return expected !== actual }); } function assertNull(obj, message) { message = buildMessage(message || 'assertNull', 'got ', obj); this.assertBlock(message, function() { return obj === null }); } function assertNotNull(obj, message) { message = buildMessage(message || 'assertNotNull', 'got ', obj); this.assertBlock(message, function() { return obj !== null }); } function assertUndefined(obj, message) { message = buildMessage(message || 'assertUndefined', 'got ', obj); this.assertBlock(message, function() { return typeof obj == "undefined" }); } function assertNotUndefined(obj, message) { message = buildMessage(message || 'assertNotUndefined', 'got ', obj); this.assertBlock(message, function() { return typeof obj != "undefined" }); } function assertNullOrUndefined(obj, message) { message = buildMessage(message || 'assertNullOrUndefined', 'got ', obj); this.assertBlock(message, function() { return obj == null }); } function assertNotNullOrUndefined(obj, message) { message = buildMessage(message || 'assertNotNullOrUndefined', 'got ', obj); this.assertBlock(message, function() { return obj != null }); } function assertMatch(expected, actual, message) { message = buildMessage(message || 'assertMatch', 'regex did not match ', expected, actual); this.assertBlock(message, function() { return new RegExp(expected).exec(actual) }); } function assertNoMatch(expected, actual, message) { message = buildMessage(message || 'assertNoMatch', 'regex matched ', expected, actual); this.assertBlock(message, function() { return !(new RegExp(expected).exec(actual)) }); } function assertHidden(element, message) { message = buildMessage(message || 'assertHidden', '? isn\'t hidden.', element); this.assertBlock(message, function() { return element.style.display == 'none' }); } function assertInstanceOf(expected, actual, message) { message = buildMessage(message || 'assertInstanceOf', ' was not an instance of the expected type', actual); this.assertBlock(message, function() { return actual instanceof expected }); } function assertNotInstanceOf(expected, actual, message) { message = buildMessage(message || 'assertNotInstanceOf', ' was an instance of the expected type', actual); this.assertBlock(message, function() { return !(actual instanceof expected) }); } function assertRespondsTo(method, obj, message) { message = buildMessage(message || 'assertRespondsTo', 'object doesn\'t respond to ', method); this.assertBlock(message, function() { return (method in obj && typeof obj[method] == 'function') }); } function assertRaise(exceptionName, method, message) { message = buildMessage(message || 'assertRaise', ' exception expected but none was raised', exceptionName); var block = function() { try { method(); return false; } catch(e) { if (e.name == exceptionName) return true; else throw e; } }; this.assertBlock(message, block); } function assertNothingRaised(method, message) { try { method(); this.assert(true, "Expected nothing to be thrown"); } catch(e) { message = buildMessage(message || 'assertNothingRaised', ' was thrown when nothing was expected.', e); this.flunk(message); } } function isVisible(element) { element = $(element); if(!element.parentNode) return true; this.assertNotNull(element); if(element.style && Element.getStyle(element, 'display') == 'none') return false; return isVisible.call(this, element.parentNode); } function assertVisible(element, message) { message = buildMessage(message, '? was not visible.', element); this.assertBlock(message, function() { return isVisible.call(this, element) }); } function assertNotVisible(element, message) { message = buildMessage(message, '? was not hidden and didn\'t have a hidden parent either.', element); this.assertBlock(message, function() { return !isVisible.call(this, element) }); } function assertElementsMatch() { var message, pass = true, expressions = $A(arguments), elements = $A(expressions.shift()); if (elements.length != expressions.length) { message = buildMessage('assertElementsMatch', 'size mismatch: ? elements, ? expressions (?).', elements.length, expressions.length, expressions); this.flunk(message); pass = false; } elements.zip(expressions).all(function(pair, index) { var element = $(pair.first()), expression = pair.last(); if (element.match(expression)) return true; message = buildMessage('assertElementsMatch', 'In index : expected but got ?', index, expression, element); this.flunk(message); pass = false; }.bind(this)) if (pass) this.assert(true, "Expected all elements to match."); } function assertElementMatches(element, expression, message) { this.assertElementsMatch([element], expression); } return { buildMessage: buildMessage, flunk: flunk, assertBlock: assertBlock, assert: assert, assertEqual: assertEqual, assertNotEqual: assertNotEqual, assertEnumEqual: assertEnumEqual, assertEnumNotEqual: assertEnumNotEqual, assertHashEqual: assertHashEqual, assertHashNotEqual: assertHashNotEqual, assertIdentical: assertIdentical, assertNotIdentical: assertNotIdentical, assertNull: assertNull, assertNotNull: assertNotNull, assertUndefined: assertUndefined, assertNotUndefined: assertNotUndefined, assertNullOrUndefined: assertNullOrUndefined, assertNotNullOrUndefined: assertNotNullOrUndefined, assertMatch: assertMatch, assertNoMatch: assertNoMatch, assertHidden: assertHidden, assertInstanceOf: assertInstanceOf, assertNotInstanceOf: assertNotInstanceOf, assertRespondsTo: assertRespondsTo, assertRaise: assertRaise, assertNothingRaised: assertNothingRaised, assertVisible: assertVisible, assertNotVisible: assertNotVisible, assertElementsMatch: assertElementsMatch, assertElementMatches: assertElementMatches } })(); Test.Unit.Testcase = Class.create(Test.Unit.Assertions, { initialize: function(name, test, setup, teardown) { this.name = name; this.test = test || Prototype.emptyFunction; this.setup = setup || Prototype.emptyFunction; this.teardown = teardown || Prototype.emptyFunction; this.messages = []; this.actions = {}; }, isWaiting: false, timeToWait: 1000, assertions: 0, failures: 0, errors: 0, isRunningFromRake: window.location.port == 4711, wait: function(time, nextPart) { this.isWaiting = true; this.test = nextPart; this.timeToWait = time; }, run: function(rethrow) { try { try { if (!this.isWaiting) this.setup(); this.isWaiting = false; this.test(); } finally { if(!this.isWaiting) { this.teardown(); } } } catch(e) { if (rethrow) throw e; this.error(e, this); } }, summary: function() { var msg = '#{assertions} assertions, #{failures} failures, #{errors} errors\n'; return msg.interpolate(this) + this.messages.join("\n"); }, pass: function() { this.assertions++; }, fail: function(message) { this.failures++; var line = ""; try { throw new Error("stack"); } catch(e){ line = (/\.html:(\d+)/.exec(e.stack || '') || ['',''])[1]; } this.messages.push("Failure: " + message + (line ? " Line #" + line : "")); }, info: function(message) { this.messages.push("Info: " + message); }, error: function(error, test) { this.errors++; this.actions['retry with throw'] = function() { test.run(true) }; this.messages.push(error.name + ": "+ error.message + ", error=(" + Test.Unit.inspect(error) + ")"); }, status: function() { if (this.failures > 0) return 'failed'; if (this.errors > 0) return 'error'; return 'passed'; }, benchmark: function(operation, iterations) { var startAt = new Date(); (iterations || 1).times(operation); var timeTaken = ((new Date())-startAt); this.info((arguments[2] || 'Operation') + ' finished ' + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); return timeTaken; } }); nwmatcher/test/prototype/lib_assets/unittest.css0000644000175000017500000000140312316015515020744 0ustar wmbwmbbody, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li { font-family: sans-serif; } body { font-size:0.8em; } #log { padding-bottom: 1em; border-bottom: 2px solid #000; margin-bottom: 2em; } .logsummary { margin-top: 1em; margin-bottom: 1em; padding: 1ex; border: 1px solid #000; font-weight: bold; } .logtable { width:100%; border-collapse: collapse; border: 1px dotted #666; } .logtable td, .logtable th { text-align: left; padding: 3px 8px; border: 1px dotted #666; } .logtable .passed { background-color: #cfc; } .logtable .failed, .logtable .error { background-color: #fcc; } .logtable td div.action_buttons { display: inline; } .logtable td div.action_buttons input { margin: 0 5px; font-size: 10px; }nwmatcher/test/prototype/selector_test.html0000644000175000017500000001115512316015515017775 0ustar wmbwmb Unit test file | Selector | default template | 2010-03-04 16:13
              nwmatcher/test/prototype/selector_engine_test.html0000644000175000017500000000313312316015515021317 0ustar wmbwmb Unit test file | Selector Engine | default template | 2010-03-04 16:13
              nwmatcher/test/prototype/assets/0000755000175000017500000000000012316015515015527 5ustar wmbwmbnwmatcher/test/prototype/assets/prototype.js0000644000175000017500000046746312316015515020156 0ustar wmbwmb/* Prototype JavaScript framework, version 1.6.1 * (c) 2005-2009 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. * For details, see the Prototype web site: http://www.prototypejs.org/ * *--------------------------------------------------------------------------*/ var Prototype = { Version: '1.6.1', Browser: (function(){ var ua = navigator.userAgent; var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; return { IE: !!window.attachEvent && !isOpera, Opera: isOpera, WebKit: ua.indexOf('AppleWebKit/') > -1, Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, MobileSafari: /Apple.*Mobile/.test(ua) } })(), BrowserFeatures: { XPath: !!document.evaluate, SelectorsAPI: !!document.querySelector, ElementExtensions: (function() { var constructor = window.Element || window.HTMLElement; return !!(constructor && constructor.prototype); })(), SpecificElementExtensions: (function() { if (typeof window.HTMLDivElement !== 'undefined') return true; var div = document.createElement('div'), form = document.createElement('form'), isSupported = false; if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { isSupported = true; } div = form = null; return isSupported; })() }, ScriptFragment: ']*>([\\S\\s]*?)<\/script>', JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } }; if (Prototype.Browser.MobileSafari) Prototype.BrowserFeatures.SpecificElementExtensions = false; var Abstract = { }; var Try = { these: function() { var returnValue; for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) { } } return returnValue; } }; /* Based on Alex Arnell's inheritance implementation. */ var Class = (function() { var IS_DONTENUM_BUGGY = (function(){ for (var p in { toString: 1 }) { if (p === 'toString') return false; } return true; })(); function subclass() {}; function create() { var parent = null, properties = $A(arguments); if (Object.isFunction(properties[0])) parent = properties.shift(); function klass() { this.initialize.apply(this, arguments); } Object.extend(klass, Class.Methods); klass.superclass = parent; klass.subclasses = []; if (parent) { subclass.prototype = parent.prototype; klass.prototype = new subclass; parent.subclasses.push(klass); } for (var i = 0, length = properties.length; i < length; i++) klass.addMethods(properties[i]); if (!klass.prototype.initialize) klass.prototype.initialize = Prototype.emptyFunction; klass.prototype.constructor = klass; return klass; } function addMethods(source) { var ancestor = this.superclass && this.superclass.prototype, properties = Object.keys(source); if (IS_DONTENUM_BUGGY) { if (source.toString != Object.prototype.toString) properties.push("toString"); if (source.valueOf != Object.prototype.valueOf) properties.push("valueOf"); } for (var i = 0, length = properties.length; i < length; i++) { var property = properties[i], value = source[property]; if (ancestor && Object.isFunction(value) && value.argumentNames()[0] == "$super") { var method = value; value = (function(m) { return function() { return ancestor[m].apply(this, arguments); }; })(property).wrap(method); value.valueOf = method.valueOf.bind(method); value.toString = method.toString.bind(method); } this.prototype[property] = value; } return this; } return { create: create, Methods: { addMethods: addMethods } }; })(); (function() { var _toString = Object.prototype.toString, NULL_TYPE = 'Null', UNDEFINED_TYPE = 'Undefined', BOOLEAN_TYPE = 'Boolean', NUMBER_TYPE = 'Number', STRING_TYPE = 'String', OBJECT_TYPE = 'Object', BOOLEAN_CLASS = '[object Boolean]', NUMBER_CLASS = '[object Number]', STRING_CLASS = '[object String]', ARRAY_CLASS = '[object Array]', NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && typeof JSON.stringify === 'function' && JSON.stringify(0) === '0' && typeof JSON.stringify(Prototype.K) === 'undefined'; function Type(o) { switch(o) { case null: return NULL_TYPE; case (void 0): return UNDEFINED_TYPE; } var type = typeof o; switch(type) { case 'boolean': return BOOLEAN_TYPE; case 'number': return NUMBER_TYPE; case 'string': return STRING_TYPE; } return OBJECT_TYPE; } function extend(destination, source) { for (var property in source) destination[property] = source[property]; return destination; } function inspect(object) { try { if (isUndefined(object)) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : String(object); } catch (e) { if (e instanceof RangeError) return '...'; throw e; } } function toJSON(value) { return Str('', { '': value }, []); } function Str(key, holder, stack) { var value = holder[key], type = typeof value; if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { value = value.toJSON(key); } var _class = _toString.call(value); switch (_class) { case NUMBER_CLASS: case BOOLEAN_CLASS: case STRING_CLASS: value = value.valueOf(); } switch (value) { case null: return 'null'; case true: return 'true'; case false: return 'false'; } type = typeof value; switch (type) { case 'string': return value.inspect(true); case 'number': return isFinite(value) ? String(value) : 'null'; case 'object': for (var i = 0, length = stack.length; i < length; i++) { if (stack[i] === value) { throw new TypeError(); } } stack.push(value); var partial = []; if (_class === ARRAY_CLASS) { for (var i = 0, length = value.length; i < length; i++) { var str = Str(i, value, stack); partial.push(typeof str === 'undefined' ? 'null' : str); } partial = '[' + partial.join(',') + ']'; } else { var keys = Object.keys(value); for (var i = 0, length = keys.length; i < length; i++) { var key = keys[i], str = Str(key, value, stack); if (typeof str !== "undefined") { partial.push(key.inspect(true)+ ':' + str); } } partial = '{' + partial.join(',') + '}'; } stack.pop(); return partial; } } function stringify(object) { return JSON.stringify(object); } function toQueryString(object) { return $H(object).toQueryString(); } function toHTML(object) { return object && object.toHTML ? object.toHTML() : String.interpret(object); } function keys(object) { if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } var results = []; for (var property in object) { if (object.hasOwnProperty(property)) { results.push(property); } } return results; } function values(object) { var results = []; for (var property in object) results.push(object[property]); return results; } function clone(object) { return extend({ }, object); } function isElement(object) { return !!(object && object.nodeType == 1); } function isArray(object) { return _toString.call(object) === ARRAY_CLASS; } var hasNativeIsArray = (typeof Array.isArray == 'function') && Array.isArray([]) && !Array.isArray({}); if (hasNativeIsArray) { isArray = Array.isArray; } function isHash(object) { return object instanceof Hash; } function isFunction(object) { return typeof object === "function"; } function isString(object) { return _toString.call(object) === STRING_CLASS; } function isNumber(object) { return _toString.call(object) === NUMBER_CLASS; } function isUndefined(object) { return typeof object === "undefined"; } extend(Object, { extend: extend, inspect: inspect, toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, toQueryString: toQueryString, toHTML: toHTML, keys: Object.keys || keys, values: values, clone: clone, isElement: isElement, isArray: isArray, isHash: isHash, isFunction: isFunction, isString: isString, isNumber: isNumber, isUndefined: isUndefined }); })(); Object.extend(Function.prototype, (function() { var slice = Array.prototype.slice; function update(array, args) { var arrayLength = array.length, length = args.length; while (length--) array[arrayLength + length] = args[length]; return array; } function merge(array, args) { array = slice.call(array, 0); return update(array, args); } function argumentNames() { var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') .replace(/\s+/g, '').split(','); return names.length == 1 && !names[0] ? [] : names; } function bind(context) { if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; var __method = this, args = slice.call(arguments, 1); return function() { var a = merge(args, arguments); return __method.apply(context, a); } } function bindAsEventListener(context) { var __method = this, args = slice.call(arguments, 1); return function(event) { var a = update([event || window.event], args); return __method.apply(context, a); } } function curry() { if (!arguments.length) return this; var __method = this, args = slice.call(arguments, 0); return function() { var a = merge(args, arguments); return __method.apply(this, a); } } function delay(timeout) { var __method = this, args = slice.call(arguments, 1); timeout = timeout * 1000; return window.setTimeout(function() { return __method.apply(__method, args); }, timeout); } function defer() { var args = update([0.01], arguments); return this.delay.apply(this, args); } function wrap(wrapper) { var __method = this; return function() { var a = update([__method.bind(this)], arguments); return wrapper.apply(this, a); } } function methodize() { if (this._methodized) return this._methodized; var __method = this; return this._methodized = function() { var a = update([this], arguments); return __method.apply(null, a); }; } return { argumentNames: argumentNames, bind: bind, bindAsEventListener: bindAsEventListener, curry: curry, delay: delay, defer: defer, wrap: wrap, methodize: methodize } })()); (function(proto) { function toISOString() { return this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + this.getUTCDate().toPaddedString(2) + 'T' + this.getUTCHours().toPaddedString(2) + ':' + this.getUTCMinutes().toPaddedString(2) + ':' + this.getUTCSeconds().toPaddedString(2) + 'Z'; } function toJSON() { return this.toISOString(); } if (!proto.toISOString) proto.toISOString = toISOString; if (!proto.toJSON) proto.toJSON = toJSON; })(Date.prototype); RegExp.prototype.match = RegExp.prototype.test; RegExp.escape = function(str) { return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }; var PeriodicalExecuter = Class.create({ initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; this.currentlyExecuting = false; this.registerCallback(); }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, execute: function() { this.callback(this); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.execute(); this.currentlyExecuting = false; } catch(e) { this.currentlyExecuting = false; throw e; } } } }); Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); Object.extend(String.prototype, (function() { var NATIVE_JSON_PARSE_SUPPORT = window.JSON && typeof JSON.parse === 'function' && JSON.parse('{"test": true}').test; function prepareReplacement(replacement) { if (Object.isFunction(replacement)) return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; } function gsub(pattern, replacement) { var result = '', source = this, match; replacement = prepareReplacement(replacement); if (Object.isString(pattern)) pattern = RegExp.escape(pattern); if (!(pattern.length || pattern.source)) { replacement = replacement(''); return replacement + source.split('').join(replacement) + replacement; } while (source.length > 0) { if (match = source.match(pattern)) { result += source.slice(0, match.index); result += String.interpret(replacement(match)); source = source.slice(match.index + match[0].length); } else { result += source, source = ''; } } return result; } function sub(pattern, replacement, count) { replacement = prepareReplacement(replacement); count = Object.isUndefined(count) ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); } function scan(pattern, iterator) { this.gsub(pattern, iterator); return String(this); } function truncate(length, truncation) { length = length || 30; truncation = Object.isUndefined(truncation) ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation : String(this); } function strip() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); } function stripTags() { return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); } function stripScripts() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); } function extractScripts() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); } function evalScripts() { return this.extractScripts().map(function(script) { return eval(script) }); } function escapeHTML() { return this.replace(/&/g,'&').replace(//g,'>'); } function unescapeHTML() { return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); } function toQueryParams(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); if (!match) return { }; return match[1].split(separator || '&').inject({ }, function(hash, pair) { if ((pair = pair.split('='))[0]) { var key = decodeURIComponent(pair.shift()), value = pair.length > 1 ? pair.join('=') : pair[0]; if (value != undefined) value = decodeURIComponent(value); if (key in hash) { if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; } return hash; }); } function toArray() { return this.split(''); } function succ() { return this.slice(0, this.length - 1) + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); } function times(count) { return count < 1 ? '' : new Array(count + 1).join(this); } function camelize() { return this.replace(/-+(.)?/g, function(match, chr) { return chr ? chr.toUpperCase() : ''; }); } function capitalize() { return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); } function underscore() { return this.replace(/::/g, '/') .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') .replace(/([a-z\d])([A-Z])/g, '$1_$2') .replace(/-/g, '_') .toLowerCase(); } function dasherize() { return this.replace(/_/g, '-'); } function inspect(useDoubleQuotes) { var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { if (character in String.specialChar) { return String.specialChar[character]; } return '\\u00' + character.charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; return "'" + escapedString.replace(/'/g, '\\\'') + "'"; } function unfilterJSON(filter) { return this.replace(filter || Prototype.JSONFilter, '$1'); } function isJSON() { var str = this; if (str.blank()) return false; str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); return (/^[\],:{}\s]*$/).test(str); } function evalJSON(sanitize) { var json = this.unfilterJSON(), cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; if (cx.test(json)) { json = json.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } try { if (!sanitize || json.isJSON()) return eval('(' + json + ')'); } catch (e) { } throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); } function parseJSON() { var json = this.unfilterJSON(); return JSON.parse(json); } function include(pattern) { return this.indexOf(pattern) > -1; } function startsWith(pattern) { return this.lastIndexOf(pattern, 0) === 0; } function endsWith(pattern) { var d = this.length - pattern.length; return d >= 0 && this.indexOf(pattern, d) === d; } function empty() { return this == ''; } function blank() { return /^\s*$/.test(this); } function interpolate(object, pattern) { return new Template(this, pattern).evaluate(object); } return { gsub: gsub, sub: sub, scan: scan, truncate: truncate, strip: String.prototype.trim || strip, stripTags: stripTags, stripScripts: stripScripts, extractScripts: extractScripts, evalScripts: evalScripts, escapeHTML: escapeHTML, unescapeHTML: unescapeHTML, toQueryParams: toQueryParams, parseQuery: toQueryParams, toArray: toArray, succ: succ, times: times, camelize: camelize, capitalize: capitalize, underscore: underscore, dasherize: dasherize, inspect: inspect, unfilterJSON: unfilterJSON, isJSON: isJSON, evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, include: include, startsWith: startsWith, endsWith: endsWith, empty: empty, blank: blank, interpolate: interpolate }; })()); var Template = Class.create({ initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { if (object && Object.isFunction(object.toTemplateReplacements)) object = object.toTemplateReplacements(); return this.template.gsub(this.pattern, function(match) { if (object == null) return (match[1] + ''); var before = match[1] || ''; if (before == '\\') return match[2]; var ctx = object, expr = match[3], pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; match = pattern.exec(expr); if (match == null) return before; while (match != null) { var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; ctx = ctx[comp]; if (null == ctx || '' == match[3]) break; expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); match = pattern.exec(expr); } return before + String.interpret(ctx); }); } }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = { }; var Enumerable = (function() { function each(iterator, context) { var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; } return this; } function eachSlice(number, iterator, context) { var index = -number, slices = [], array = this.toArray(); if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); } function all(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; } function any(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator.call(context, value, index)) throw $break; }); return result; } function collect(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; } function detect(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; } function findAll(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; } function grep(filter, iterator, context) { iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(RegExp.escape(filter)); this.each(function(value, index) { if (filter.match(value)) results.push(iterator.call(context, value, index)); }); return results; } function include(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true; var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; } function inGroupsOf(number, fillWith) { fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); } function inject(memo, iterator, context) { this.each(function(value, index) { memo = iterator.call(context, memo, value, index); }); return memo; } function invoke(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); } function max(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); return result; } function min(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); return result; } function partition(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator.call(context, value, index) ? trues : falses).push(value); }); return [trues, falses]; } function pluck(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; } function reject(iterator, context) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; } function sortBy(iterator, context) { return this.map(function(value, index) { return { value: value, criteria: iterator.call(context, value, index) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); } function toArray() { return this.map(); } function zip() { var iterator = Prototype.K, args = $A(arguments); if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); } function size() { return this.toArray().length; } function inspect() { return '#'; } return { each: each, eachSlice: eachSlice, all: all, every: all, any: any, some: any, collect: collect, map: collect, detect: detect, findAll: findAll, select: findAll, filter: findAll, grep: grep, include: include, member: include, inGroupsOf: inGroupsOf, inject: inject, invoke: invoke, max: max, min: min, partition: partition, pluck: pluck, reject: reject, sortBy: sortBy, toArray: toArray, entries: toArray, zip: zip, size: size, inspect: inspect, find: detect }; })(); function $A(iterable) { if (!iterable) return []; if ('toArray' in Object(iterable)) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; } function $w(string) { if (!Object.isString(string)) return []; string = string.strip(); return string ? string.split(/\s+/) : []; } Array.from = $A; (function() { var arrayProto = Array.prototype, slice = arrayProto.slice, _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available function each(iterator) { for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); } if (!_each) _each = each; function clear() { this.length = 0; return this; } function first() { return this[0]; } function last() { return this[this.length - 1]; } function compact() { return this.select(function(value) { return value != null; }); } function flatten() { return this.inject([], function(array, value) { if (Object.isArray(value)) return array.concat(value.flatten()); array.push(value); return array; }); } function without() { var values = slice.call(arguments, 0); return this.select(function(value) { return !values.include(value); }); } function reverse(inline) { return (inline === false ? this.toArray() : this)._reverse(); } function uniq(sorted) { return this.inject([], function(array, value, index) { if (0 == index || (sorted ? array.last() != value : !array.include(value))) array.push(value); return array; }); } function intersect(array) { return this.uniq().findAll(function(item) { return array.detect(function(value) { return item === value }); }); } function clone() { return slice.call(this, 0); } function size() { return this.length; } function inspect() { return '[' + this.map(Object.inspect).join(', ') + ']'; } function indexOf(item, i) { i || (i = 0); var length = this.length; if (i < 0) i = length + i; for (; i < length; i++) if (this[i] === item) return i; return -1; } function lastIndexOf(item, i) { i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; var n = this.slice(0, i).reverse().indexOf(item); return (n < 0) ? n : i - n - 1; } function concat() { var array = slice.call(this, 0), item; for (var i = 0, length = arguments.length; i < length; i++) { item = arguments[i]; if (Object.isArray(item) && !('callee' in item)) { for (var j = 0, arrayLength = item.length; j < arrayLength; j++) array.push(item[j]); } else { array.push(item); } } return array; } Object.extend(arrayProto, Enumerable); if (!arrayProto._reverse) arrayProto._reverse = arrayProto.reverse; Object.extend(arrayProto, { _each: _each, clear: clear, first: first, last: last, compact: compact, flatten: flatten, without: without, reverse: reverse, uniq: uniq, intersect: intersect, clone: clone, toArray: clone, size: size, inspect: inspect }); var CONCAT_ARGUMENTS_BUGGY = (function() { return [].concat(arguments)[0][0] !== 1; })(1,2) if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; })(); function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function() { function initialize(object) { this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); } function _each(iterator) { for (var key in this._object) { var value = this._object[key], pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } } function set(key, value) { return this._object[key] = value; } function get(key) { if (this._object[key] !== Object.prototype[key]) return this._object[key]; } function unset(key) { var value = this._object[key]; delete this._object[key]; return value; } function toObject() { return Object.clone(this._object); } function keys() { return this.pluck('key'); } function values() { return this.pluck('value'); } function index(value) { var match = this.detect(function(pair) { return pair.value === value; }); return match && match.key; } function merge(object) { return this.clone().update(object); } function update(object) { return new Hash(object).inject(this, function(result, pair) { result.set(pair.key, pair.value); return result; }); } function toQueryPair(key, value) { if (Object.isUndefined(value)) return key; return key + '=' + encodeURIComponent(String.interpret(value)); } function toQueryString() { return this.inject([], function(results, pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) return results.concat(values.map(toQueryPair.curry(key))); } else results.push(toQueryPair(key, values)); return results; }).join('&'); } function inspect() { return '#'; } function clone() { return new Hash(this); } return { initialize: initialize, _each: _each, set: set, get: get, unset: unset, toObject: toObject, toTemplateReplacements: toObject, keys: keys, values: values, index: index, merge: merge, update: update, toQueryString: toQueryString, inspect: inspect, toJSON: toObject, clone: clone }; })()); Hash.from = $H; Object.extend(Number.prototype, (function() { function toColorPart() { return this.toPaddedString(2, 16); } function succ() { return this + 1; } function times(iterator, context) { $R(0, this, true).each(iterator, context); return this; } function toPaddedString(length, radix) { var string = this.toString(radix || 10); return '0'.times(length - string.length) + string; } function abs() { return Math.abs(this); } function round() { return Math.round(this); } function ceil() { return Math.ceil(this); } function floor() { return Math.floor(this); } return { toColorPart: toColorPart, succ: succ, times: times, toPaddedString: toPaddedString, abs: abs, round: round, ceil: ceil, floor: floor }; })()); function $R(start, end, exclusive) { return new ObjectRange(start, end, exclusive); } var ObjectRange = Class.create(Enumerable, (function() { function initialize(start, end, exclusive) { this.start = start; this.end = end; this.exclusive = exclusive; } function _each(iterator) { var value = this.start; while (this.include(value)) { iterator(value); value = value.succ(); } } function include(value) { if (value < this.start) return false; if (this.exclusive) return value < this.end; return value <= this.end; } return { initialize: initialize, _each: _each, include: include }; })()); var Ajax = { getTransport: function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; }, activeRequestCount: 0 }; Ajax.Responders = { responders: [], _each: function(iterator) { this.responders._each(iterator); }, register: function(responder) { if (!this.include(responder)) this.responders.push(responder); }, unregister: function(responder) { this.responders = this.responders.without(responder); }, dispatch: function(callback, request, transport, json) { this.each(function(responder) { if (Object.isFunction(responder[callback])) { try { responder[callback].apply(responder, [request, transport, json]); } catch (e) { } } }); } }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++ }, onComplete: function() { Ajax.activeRequestCount-- } }); Ajax.Base = Class.create({ initialize: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '', evalJSON: true, evalJS: true }; Object.extend(this.options, options || { }); this.options.method = this.options.method.toLowerCase(); if (Object.isString(this.options.parameters)) this.options.parameters = this.options.parameters.toQueryParams(); else if (Object.isHash(this.options.parameters)) this.options.parameters = this.options.parameters.toObject(); } }); Ajax.Request = Class.create(Ajax.Base, { _complete: false, initialize: function($super, url, options) { $super(options); this.transport = Ajax.getTransport(); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { params['_method'] = this.method; this.method = 'post'; } this.parameters = params; if (params = Object.toQueryString(params)) { if (this.method == 'get') this.url += (this.url.include('?') ? '&' : '?') + params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='; } try { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); } catch (e) { this.dispatchException(e); } }, onStateChange: function() { var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete)) this.respondToReadyState(this.transport.readyState); }, setRequestHeaders: function() { var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post') { headers['Content-type'] = this.options.contentType + (this.options.encoding ? '; charset=' + this.options.encoding : ''); /* Force "Connection: close" for older Mozilla browsers to work * around a bug where XMLHttpRequest sends an incorrect * Content-length header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) headers['Connection'] = 'close'; } if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; if (Object.isFunction(extras.push)) for (var i = 0, length = extras.length; i < length; i += 2) headers[extras[i]] = extras[i+1]; else $H(extras).each(function(pair) { headers[pair.key] = pair.value }); } for (var name in headers) this.transport.setRequestHeader(name, headers[name]); }, success: function() { var status = this.getStatus(); return !status || (status >= 200 && status < 300); }, getStatus: function() { try { return this.transport.status || 0; } catch (e) { return 0 } }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); if (state == 'Complete') { try { this._complete = true; (this.options['on' + response.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(response, response.headerJSON); } catch (e) { this.dispatchException(e); } var contentType = response.getHeader('Content-type'); if (this.options.evalJS == 'force' || (this.options.evalJS && this.isSameOrigin() && contentType && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) this.evalResponse(); } try { (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { this.transport.onreadystatechange = Prototype.emptyFunction; } }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, getHeader: function(name) { try { return this.transport.getResponseHeader(name) || null; } catch (e) { return null; } }, evalResponse: function() { try { return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } }, dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Response = Class.create({ initialize: function(request){ this.request = request; var transport = this.transport = request.transport, readyState = this.readyState = transport.readyState; if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { this.status = this.getStatus(); this.statusText = this.getStatusText(); this.responseText = String.interpret(transport.responseText); this.headerJSON = this._getHeaderJSON(); } if (readyState == 4) { var xml = transport.responseXML; this.responseXML = Object.isUndefined(xml) ? null : xml; this.responseJSON = this._getResponseJSON(); } }, status: 0, statusText: '', getStatus: Ajax.Request.prototype.getStatus, getStatusText: function() { try { return this.transport.statusText || ''; } catch (e) { return '' } }, getHeader: Ajax.Request.prototype.getHeader, getAllHeaders: function() { try { return this.getAllResponseHeaders(); } catch (e) { return null } }, getResponseHeader: function(name) { return this.transport.getResponseHeader(name); }, getAllResponseHeaders: function() { return this.transport.getAllResponseHeaders(); }, _getHeaderJSON: function() { var json = this.getHeader('X-JSON'); if (!json) return null; json = decodeURIComponent(escape(json)); try { return json.evalJSON(this.request.options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } }, _getResponseJSON: function() { var options = this.request.options; if (!options.evalJSON || (options.evalJSON != 'force' && !(this.getHeader('Content-type') || '').include('application/json')) || this.responseText.blank()) return null; try { return this.responseText.evalJSON(options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } } }); Ajax.Updater = Class.create(Ajax.Request, { initialize: function($super, container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) }; options = Object.clone(options); var onComplete = options.onComplete; options.onComplete = (function(response, json) { this.updateContent(response.responseText); if (Object.isFunction(onComplete)) onComplete(response, json); }).bind(this); $super(url, options); }, updateContent: function(responseText) { var receiver = this.container[this.success() ? 'success' : 'failure'], options = this.options; if (!options.evalScripts) responseText = responseText.stripScripts(); if (receiver = $(receiver)) { if (options.insertion) { if (Object.isString(options.insertion)) { var insertion = { }; insertion[options.insertion] = responseText; receiver.insert(insertion); } else options.insertion(receiver, responseText); } else receiver.update(responseText); } } }); Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { initialize: function($super, container, url, options) { $super(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); this.updater = { }; this.container = container; this.url = url; this.start(); }, start: function() { this.options.onComplete = this.updateComplete.bind(this); this.onTimerEvent(); }, stop: function() { this.updater.options.onComplete = undefined; clearTimeout(this.timer); (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(response) { if (this.options.decay) { this.decay = (response.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = response.responseText; } this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (Object.isString(element)) element = document.getElementById(element); return Element.extend(element); } if (Prototype.BrowserFeatures.XPath) { document._getElementsByXPath = function(expression, parentElement) { var results = []; var query = document.evaluate(expression, $(parentElement) || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0, length = query.snapshotLength; i < length; i++) results.push(Element.extend(query.snapshotItem(i))); return results; }; } /*--------------------------------------------------------------------------*/ if (!Node) var Node = { }; if (!Node.ELEMENT_NODE) { Object.extend(Node, { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12 }); } (function(global) { var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ try { var el = document.createElement(''); return el.tagName.toLowerCase() === 'input' && el.name === 'x'; } catch(err) { return false; } })(); var element = global.Element; global.Element = function(tagName, attributes) { attributes = attributes || { }; tagName = tagName.toLowerCase(); var cache = Element.cache; if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { tagName = '<' + tagName + ' name="' + attributes.name + '">'; delete attributes.name; return Element.writeAttribute(document.createElement(tagName), attributes); } if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); }; Object.extend(global.Element, element || { }); if (element) global.Element.prototype = element.prototype; })(this); Element.idCounter = 1; Element.cache = { }; Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, toggle: function(element) { element = $(element); Element[Element.visible(element) ? 'hide' : 'show'](element); return element; }, hide: function(element) { element = $(element); element.style.display = 'none'; return element; }, show: function(element) { element = $(element); element.style.display = ''; return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); return element; }, update: (function(){ var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ var el = document.createElement("select"), isBuggy = true; el.innerHTML = ""; if (el.options && el.options[0]) { isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; } el = null; return isBuggy; })(); var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ try { var el = document.createElement("table"); if (el && el.tBodies) { el.innerHTML = "test"; var isBuggy = typeof el.tBodies[0] == "undefined"; el = null; return isBuggy; } } catch (e) { return true; } })(); var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { var s = document.createElement("script"), isBuggy = false; try { s.appendChild(document.createTextNode("")); isBuggy = !s.firstChild || s.firstChild && s.firstChild.nodeType !== 3; } catch (e) { isBuggy = true; } s = null; return isBuggy; })(); function update(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); var tagName = element.tagName.toUpperCase(); if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { element.text = content; return element; } if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { if (tagName in Element._insertionTranslations.tags) { while (element.firstChild) { element.removeChild(element.firstChild); } Element._getContentFromAnonymousElement(tagName, content.stripScripts()) .each(function(node) { element.appendChild(node) }); } else { element.innerHTML = content.stripScripts(); } } else { element.innerHTML = content.stripScripts(); } content.evalScripts.bind(content).defer(); return element; } return update; })(), replace: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); else if (!Object.isElement(content)) { content = Object.toHTML(content); var range = element.ownerDocument.createRange(); range.selectNode(element); content.evalScripts.bind(content).defer(); content = range.createContextualFragment(content.stripScripts()); } element.parentNode.replaceChild(content, element); return element; }, insert: function(element, insertions) { element = $(element); if (Object.isString(insertions) || Object.isNumber(insertions) || Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) insertions = {bottom:insertions}; var content, insert, tagName, childNodes; for (var position in insertions) { content = insertions[position]; position = position.toLowerCase(); insert = Element._insertionTranslations[position]; if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { insert(element, content); continue; } content = Object.toHTML(content); tagName = ((position == 'before' || position == 'after') ? element.parentNode : element).tagName.toUpperCase(); childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); if (position == 'top' || position == 'after') childNodes.reverse(); childNodes.each(insert.curry(element)); content.evalScripts.bind(content).defer(); } return element; }, wrap: function(element, wrapper, attributes) { element = $(element); if (Object.isElement(wrapper)) $(wrapper).writeAttribute(attributes || { }); else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); else wrapper = new Element('div', wrapper); if (element.parentNode) element.parentNode.replaceChild(wrapper, element); wrapper.appendChild(element); return wrapper; }, inspect: function(element) { element = $(element); var result = '<' + element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { var property = pair.first(), attribute = pair.last(), value = (element[property] || '').toString(); if (value) result += ' ' + attribute + '=' + value.inspect(true); }); return result + '>'; }, recursivelyCollect: function(element, property, maximumLength) { element = $(element); maximumLength = maximumLength || -1; var elements = []; while (element = element[property]) { if (element.nodeType == 1) elements.push(Element.extend(element)); if (elements.length == maximumLength) break; } return elements; }, ancestors: function(element) { return Element.recursivelyCollect(element, 'parentNode'); }, descendants: function(element) { return Element.select(element, "*"); }, firstDescendant: function(element) { element = $(element).firstChild; while (element && element.nodeType != 1) element = element.nextSibling; return $(element); }, immediateDescendants: function(element) { var results = [], child = $(element).firstChild; while (child) { if (child.nodeType === 1) { results.push(Element.extend(child)); } child = child.nextSibling; } return results; }, previousSiblings: function(element, maximumLength) { return Element.recursivelyCollect(element, 'previousSibling'); }, nextSiblings: function(element) { return Element.recursivelyCollect(element, 'nextSibling'); }, siblings: function(element) { element = $(element); return Element.previousSiblings(element).reverse() .concat(Element.nextSiblings(element)); }, match: function(element, selector) { element = $(element); if (Object.isString(selector)) return Prototype.Selector.match(element, selector); return selector.match(element); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); var ancestors = Element.ancestors(element); return Object.isNumber(expression) ? ancestors[expression] : Prototype.Selector.find(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return Element.firstDescendant(element); return Object.isNumber(expression) ? Element.descendants(element)[expression] : Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (Object.isNumber(expression)) index = expression, expression = false; if (!Object.isNumber(index)) index = 0; if (expression) { return Prototype.Selector.find(element.previousSiblings(), expression, index); } else { return element.recursivelyCollect("previousSibling", index + 1)[index]; } }, next: function(element, expression, index) { element = $(element); if (Object.isNumber(expression)) index = expression, expression = false; if (!Object.isNumber(index)) index = 0; if (expression) { return Prototype.Selector.find(element.nextSiblings(), expression, index); } else { var maximumLength = Object.isNumber(index) ? index + 1 : 1; return element.recursivelyCollect("nextSibling", index + 1)[index]; } }, select: function(element) { element = $(element); var expressions = Array.prototype.slice.call(arguments, 1).join(', '); return Prototype.Selector.select(expressions, element); }, adjacent: function(element) { element = $(element); var expressions = Array.prototype.slice.call(arguments, 1).join(', '); return Prototype.Selector.select(expressions, element.parentNode).without(element); }, identify: function(element) { element = $(element); var id = Element.readAttribute(element, 'id'); if (id) return id; do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); Element.writeAttribute(element, 'id', id); return id; }, readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { var t = Element._attributeTranslations.read; if (t.values[name]) return t.values[name](element, name); if (t.names[name]) name = t.names[name]; if (name.include(':')) { return (!element.attributes || !element.attributes[name]) ? null : element.attributes[name].value; } } return element.getAttribute(name); }, writeAttribute: function(element, name, value) { element = $(element); var attributes = { }, t = Element._attributeTranslations.write; if (typeof name == 'object') attributes = name; else attributes[name] = Object.isUndefined(value) ? true : value; for (var attr in attributes) { name = t.names[attr] || attr; value = attributes[attr]; if (t.values[attr]) name = t.values[attr](element, value); if (value === false || value === null) element.removeAttribute(name); else if (value === true) element.setAttribute(name, name); else element.setAttribute(name, value); } return element; }, getHeight: function(element) { return Element.getDimensions(element).height; }, getWidth: function(element) { return Element.getDimensions(element).width; }, classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; var elementClassName = element.className; return (elementClassName.length > 0 && (elementClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); }, addClassName: function(element, className) { if (!(element = $(element))) return; if (!Element.hasClassName(element, className)) element.className += (element.className ? ' ' : '') + className; return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; element.className = element.className.replace( new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); return element; }, toggleClassName: function(element, className) { if (!(element = $(element))) return; return Element[Element.hasClassName(element, className) ? 'removeClassName' : 'addClassName'](element, className); }, cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; while (node) { var nextNode = node.nextSibling; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) element.removeChild(node); node = nextNode; } return element; }, empty: function(element) { return $(element).innerHTML.blank(); }, descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains) return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode) if (element == ancestor) return true; return false; }, scrollTo: function(element) { element = $(element); var pos = Element.cumulativeOffset(element); window.scrollTo(pos[0], pos[1]); return element; }, getStyle: function(element, style) { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; if (!value || value == 'auto') { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } if (style == 'opacity') return value ? parseFloat(value) : 1.0; return value == 'auto' ? null : value; }, getOpacity: function(element) { return $(element).getStyle('opacity'); }, setStyle: function(element, styles) { element = $(element); var elementStyle = element.style, match; if (Object.isString(styles)) { element.style.cssText += ';' + styles; return styles.include('opacity') ? element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; } for (var property in styles) if (property == 'opacity') element.setOpacity(styles[property]); else elementStyle[(property == 'float' || property == 'cssFloat') ? (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : property] = styles[property]; return element; }, setOpacity: function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }, makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; } } return element; }, undoPositioned: function(element) { element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; } return element; }, makeClipping: function(element) { element = $(element); if (element._overflow) return element; element._overflow = Element.getStyle(element, 'overflow') || 'auto'; if (element._overflow !== 'hidden') element.style.overflow = 'hidden'; return element; }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; if (element.parentNode) { do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); } return Element._returnOffset(valueL, valueT); }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (element.tagName.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (Element.getStyle(element, 'position') == 'absolute') return element; var offsets = Element.positionedOffset(element), top = offsets[1], left = offsets[0], width = element.clientWidth, height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; return element; }, relativize: function(element) { element = $(element); if (Element.getStyle(element, 'position') == 'relative') return element; element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0), left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; return element; }, cumulativeScrollOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return Element._returnOffset(valueL, valueT); }, getOffsetParent: function(element) { if (element.offsetParent) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }, viewportOffset: function(forElement) { var valueT = 0, valueL = 0, element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return Element._returnOffset(valueL, valueT); }, clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || { }); source = $(source); var p = Element.viewportOffset(source), delta = [0, 0], parent = null; element = $(element); if (Element.getStyle(element, 'position') == 'absolute') { parent = Element.getOffsetParent(element); delta = Element.viewportOffset(parent); } if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; if (options.setHeight) element.style.height = source.offsetHeight + 'px'; return element; } }; Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, childElements: Element.Methods.immediateDescendants }); Element._attributeTranslations = { write: { names: { className: 'class', htmlFor: 'for' }, values: { } } }; if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { case 'left': case 'top': case 'right': case 'bottom': if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': if (!Element.visible(element)) return null; var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()]) return dim + 'px'; var properties; if (style === 'height') { properties = ['border-top-width', 'padding-top', 'padding-bottom', 'border-bottom-width']; } else { properties = ['border-left-width', 'padding-left', 'padding-right', 'border-right-width']; } return properties.inject(dim, function(memo, property) { var val = proceed(element, property); return val === null ? memo : memo - parseInt(val, 10); }) + 'px'; default: return proceed(element, style); } } ); Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( function(proceed, element, attribute) { if (attribute === 'title') return element.title; return proceed(element, attribute); } ); } else if (Prototype.Browser.IE) { Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); if (!element.parentNode) return $(document.body); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); $w('positionedOffset viewportOffset').each(function(method) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); if (!element.parentNode) return Element._returnOffset(0, 0); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); }); Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity') { if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) if (value[1]) return parseFloat(value[1]) / 100; return 1.0; } if (value == 'auto') { if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) return element['offset' + style.capitalize()] + 'px'; return null; } return value; }; Element.Methods.setOpacity = function(element, value) { function stripAlpha(filter){ return filter.replace(/alpha\([^\)]*\)/gi,''); } element = $(element); var currentStyle = element.currentStyle; if ((currentStyle && !currentStyle.hasLayout) || (!currentStyle && element.style.zoom == 'normal')) element.style.zoom = 1; var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { (filter = stripAlpha(filter)) ? style.filter = filter : style.removeAttribute('filter'); return element; } else if (value < 0.00001) value = 0; style.filter = stripAlpha(filter) + 'alpha(opacity=' + (value * 100) + ')'; return element; }; Element._attributeTranslations = (function(){ var classProp = 'className', forProp = 'for', el = document.createElement('div'); el.setAttribute(classProp, 'x'); if (el.className !== 'x') { el.setAttribute('class', 'x'); if (el.className === 'x') { classProp = 'class'; } } el = null; el = document.createElement('label'); el.setAttribute(forProp, 'x'); if (el.htmlFor !== 'x') { el.setAttribute('htmlFor', 'x'); if (el.htmlFor === 'x') { forProp = 'htmlFor'; } } el = null; return { read: { names: { 'class': classProp, 'className': classProp, 'for': forProp, 'htmlFor': forProp }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute); }, _getAttr2: function(element, attribute) { return element.getAttribute(attribute, 2); }, _getAttrNode: function(element, attribute) { var node = element.getAttributeNode(attribute); return node ? node.value : ""; }, _getEv: (function(){ var el = document.createElement('div'), f; el.onclick = Prototype.emptyFunction; var value = el.getAttribute('onclick'); if (String(value).indexOf('{') > -1) { f = function(element, attribute) { attribute = element.getAttribute(attribute); if (!attribute) return null; attribute = attribute.toString(); attribute = attribute.split('{')[1]; attribute = attribute.split('}')[0]; return attribute.strip(); }; } else if (value === '') { f = function(element, attribute) { attribute = element.getAttribute(attribute); if (!attribute) return null; return attribute.strip(); }; } el = null; return f; })(), _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { return element.title; } } } } })(); Element._attributeTranslations.write = { names: Object.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, Element._attributeTranslations.read.names), values: { checked: function(element, value) { element.checked = !!value; }, style: function(element, value) { element.style.cssText = value ? value : ''; } } }; Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); (function(v) { Object.extend(v, { href: v._getAttr2, src: v._getAttr2, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, checked: v._flag, readonly: v._flag, multiple: v._flag, onload: v._getEv, onunload: v._getEv, onclick: v._getEv, ondblclick: v._getEv, onmousedown: v._getEv, onmouseup: v._getEv, onmouseover: v._getEv, onmousemove: v._getEv, onmouseout: v._getEv, onfocus: v._getEv, onblur: v._getEv, onkeypress: v._getEv, onkeydown: v._getEv, onkeyup: v._getEv, onsubmit: v._getEv, onreset: v._getEv, onselect: v._getEv, onchange: v._getEv }); })(Element._attributeTranslations.read.values); if (Prototype.BrowserFeatures.ElementExtensions) { (function() { function _descendants(element) { var nodes = element.getElementsByTagName('*'), results = []; for (var i = 0, node; node = nodes[i]; i++) if (node.tagName !== "!") // Filter out comment nodes. results.push(node); return results; } Element.Methods.down = function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? _descendants(element)[expression] : Element.select(element, expression)[index || 0]; } })(); } } else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; } else if (Prototype.Browser.WebKit) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; if (value == 1) if (element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { } return element; }; Element.Methods.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }; } if ('outerHTML' in document.documentElement) { Element.Methods.replace = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { element.parentNode.replaceChild(content, element); return element; } content = Object.toHTML(content); var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName]) { var nextSibling = element.next(), fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling) fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); else fragments.each(function(node) { parent.appendChild(node) }); } else element.outerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } Element._returnOffset = function(l, t) { var result = [l, t]; result.left = l; result.top = t; return result; }; Element._getContentFromAnonymousElement = function(tagName, html) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; for (var i = t[2]; i--; ) { div = div.firstChild; } } else { div.innerHTML = html; } return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['', '
              ', 1], TBODY: ['', '
              ', 2], TR: ['', '
              ', 3], TD: ['
              ', '
              ', 4], SELECT: ['', 1] } }; (function() { var tags = Element._insertionTranslations.tags; Object.extend(tags, { THEAD: tags.TBODY, TFOOT: tags.TBODY, TH: tags.TD }); })(); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); return !!(node && node.specified); } }; Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); (function(div) { if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { window.HTMLElement = { }; window.HTMLElement.prototype = div['__proto__']; Prototype.BrowserFeatures.ElementExtensions = true; } div = null; })(document.createElement('div')); Element.extend = (function() { function checkDeficiency(tagName) { if (typeof window.Element != 'undefined') { var proto = window.Element.prototype; if (proto) { var id = '_' + (Math.random()+'').slice(2), el = document.createElement(tagName); proto[id] = 'x'; var isBuggy = (el[id] !== 'x'); delete proto[id]; el = null; return isBuggy; } } return false; } function extendElementWith(element, methods) { for (var property in methods) { var value = methods[property]; if (Object.isFunction(value) && !(property in element)) element[property] = value.methodize(); } } var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); if (Prototype.BrowserFeatures.SpecificElementExtensions) { if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { return function(element) { if (element && typeof element._extendedByPrototype == 'undefined') { var t = element.tagName; if (t && (/^(?:object|applet|embed)$/i.test(t))) { extendElementWith(element, Element.Methods); extendElementWith(element, Element.Methods.Simulated); extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); } } return element; } } return Prototype.K; } var Methods = { }, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element) { if (!element || typeof element._extendedByPrototype != 'undefined' || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), tagName = element.tagName.toUpperCase(); if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); extendElementWith(element, methods); element._extendedByPrototype = Prototype.emptyFunction; return element; }, { refresh: function() { if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); } } }); extend.refresh(); return extend; })(); if (document.documentElement.hasAttribute) { Element.hasAttribute = function(element, attribute) { return element.hasAttribute(attribute); }; } else { Element.hasAttribute = Element.Methods.Simulated.hasAttribute; } Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); } if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; } if (!tagName) Object.extend(Element.Methods, methods || { }); else { if (Object.isArray(tagName)) tagName.each(extend); else extend(tagName); } function extend(tagName) { tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName]) Element.Methods.ByTag[tagName] = { }; Object.extend(Element.Methods.ByTag[tagName], methods); } function copy(methods, destination, onlyIfAbsent) { onlyIfAbsent = onlyIfAbsent || false; for (var property in methods) { var value = methods[property]; if (!Object.isFunction(value)) continue; if (!onlyIfAbsent || !(property in destination)) destination[property] = value.methodize(); } } function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; var element = document.createElement(tagName), proto = element['__proto__'] || element.constructor.prototype; element = null; return proto; } var elementPrototype = window.HTMLElement ? HTMLElement.prototype : Element.prototype; if (F.ElementExtensions) { copy(Element.Methods, elementPrototype); copy(Element.Methods.Simulated, elementPrototype, true); } if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (Object.isUndefined(klass)) continue; copy(T[tag], klass.prototype); } } Object.extend(Element, Element.Methods); delete Element.ByTag; if (Element.extend.refresh) Element.extend.refresh(); Element.cache = { }; }; document.viewport = { getDimensions: function() { return { width: this.getWidth(), height: this.getHeight() }; }, getScrollOffsets: function() { return Element._returnOffset( window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; (function(viewport) { var B = Prototype.Browser, doc = document, element, property = {}; function getRootElement() { if (B.WebKit && !doc.evaluate) return document; if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) return document.body; return document.documentElement; } function define(D) { if (!element) element = getRootElement(); property[D] = 'client' + D; viewport['get' + D] = function() { return element[property[D]] }; return viewport['get' + D](); } viewport.getWidth = define.curry('Width'); viewport.getHeight = define.curry('Height'); })(document.viewport); Element.Storage = { UID: 1 }; Element.addMethods({ getStorage: function(element) { if (!(element = $(element))) return; var uid; if (element === window) { uid = 0; } else { if (typeof element._prototypeUID === "undefined") element._prototypeUID = [Element.Storage.UID++]; uid = element._prototypeUID[0]; } if (!Element.Storage[uid]) Element.Storage[uid] = $H(); return Element.Storage[uid]; }, store: function(element, key, value) { if (!(element = $(element))) return; if (arguments.length === 2) { Element.getStorage(element).update(key); } else { Element.getStorage(element).set(key, value); } return element; }, retrieve: function(element, key, defaultValue) { if (!(element = $(element))) return; var hash = Element.getStorage(element), value = hash.get(key); if (Object.isUndefined(value)) { hash.set(key, defaultValue); value = defaultValue; } return value; }, clone: function(element, deep) { if (!(element = $(element))) return; var clone = element.cloneNode(deep); clone._prototypeUID = void 0; if (deep) { var descendants = Element.select(clone, '*'), i = descendants.length; while (i--) { descendants[i]._prototypeUID = void 0; } } return Element.extend(clone); } }); Prototype._original_property = window.Sizzle; /*! * Sizzle CSS Selector Engine - v1.0 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true; [0, 0].sort(function(){ baseHasDuplicate = false; return 0; }); var Sizzle = function(selector, context, results, seed) { results = results || []; var origContext = context = context || document; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), soFar = selector; while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) selector += parts.shift(); set = posProcess( selector, set ); } } } else { if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { var ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { var ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray(set); } else { prune = false; } while ( parts.length ) { var cur = parts.pop(), pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { throw "Syntax error, unrecognized expression: " + (cur || selector); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function(results){ if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort(sortOrder); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[i-1] ) { results.splice(i--, 1); } } } } return results; }; Sizzle.matches = function(expr, set){ return Sizzle(expr, null, null, set); }; Sizzle.find = function(expr, context, isXML){ var set, match; if ( !expr ) { return []; } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var type = Expr.order[i], match; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; match.splice(1,1); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace(/\\/g, ""); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = context.getElementsByTagName("*"); } return {set: set, expr: expr}; }; Sizzle.filter = function(expr, set, inplace, not){ var old = expr, result = [], curLoop = set, match, anyFound, isXMLFilter = set && set[0] && isXML(set[0]); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.match[ type ].exec( expr )) != null ) { var filter = Expr.filter[ type ], found, item; anyFound = false; if ( curLoop == result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( var i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); var pass = not ^ !!found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } if ( expr == old ) { if ( anyFound == null ) { throw "Syntax error, unrecognized expression: " + expr; } else { break; } } old = expr; } return curLoop; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function(elem){ return elem.getAttribute("href"); } }, relative: { "+": function(checkSet, part, isXML){ var isPartStr = typeof part === "string", isTag = isPartStr && !/\W/.test(part), isPartStrNotTag = isPartStr && !isTag; if ( isTag && !isXML ) { part = part.toUpperCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function(checkSet, part, isXML){ var isPartStr = typeof part === "string"; if ( isPartStr && !/\W/.test(part) ) { part = isXML ? part : part.toUpperCase(); for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName === part ? parent : false; } } } else { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck; if ( !/\W/.test(part) ) { var nodeCheck = part = isXML ? part : part.toUpperCase(); checkFn = dirNodeCheck; } checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); }, "~": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !/\W/.test(part) ) { var nodeCheck = part = isXML ? part : part.toUpperCase(); checkFn = dirNodeCheck; } checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); } }, find: { ID: function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? [m] : []; } }, NAME: function(match, context, isXML){ if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName(match[1]); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function(match, context){ return context.getElementsByTagName(match[1]); } }, preFilter: { CLASS: function(match, curLoop, inplace, result, not, isXML){ match = " " + match[1].replace(/\\/g, "") + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { if ( !inplace ) result.push( elem ); } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function(match){ return match[1].replace(/\\/g, ""); }, TAG: function(match, curLoop){ for ( var i = 0; curLoop[i] === false; i++ ){} return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); }, CHILD: function(match){ if ( match[1] == "nth" ) { var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } match[0] = done++; return match; }, ATTR: function(match, curLoop, inplace, result, not, isXML){ var name = match[1].replace(/\\/g, ""); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function(match, curLoop, inplace, result, not){ if ( match[1] === "not" ) { if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function(match){ match.unshift( true ); return match; } }, filters: { enabled: function(elem){ return elem.disabled === false && elem.type !== "hidden"; }, disabled: function(elem){ return elem.disabled === true; }, checked: function(elem){ return elem.checked === true; }, selected: function(elem){ elem.parentNode.selectedIndex; return elem.selected === true; }, parent: function(elem){ return !!elem.firstChild; }, empty: function(elem){ return !elem.firstChild; }, has: function(elem, i, match){ return !!Sizzle( match[3], elem ).length; }, header: function(elem){ return /h\d/i.test( elem.nodeName ); }, text: function(elem){ return "text" === elem.type; }, radio: function(elem){ return "radio" === elem.type; }, checkbox: function(elem){ return "checkbox" === elem.type; }, file: function(elem){ return "file" === elem.type; }, password: function(elem){ return "password" === elem.type; }, submit: function(elem){ return "submit" === elem.type; }, image: function(elem){ return "image" === elem.type; }, reset: function(elem){ return "reset" === elem.type; }, button: function(elem){ return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; }, input: function(elem){ return /input|select|textarea|button/i.test(elem.nodeName); } }, setFilters: { first: function(elem, i){ return i === 0; }, last: function(elem, i, match, array){ return i === array.length - 1; }, even: function(elem, i){ return i % 2 === 0; }, odd: function(elem, i){ return i % 2 === 1; }, lt: function(elem, i, match){ return i < match[3] - 0; }, gt: function(elem, i, match){ return i > match[3] - 0; }, nth: function(elem, i, match){ return match[3] - 0 == i; }, eq: function(elem, i, match){ return match[3] - 0 == i; } }, filter: { PSEUDO: function(elem, match, i, array){ var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var i = 0, l = not.length; i < l; i++ ) { if ( not[i] === elem ) { return false; } } return true; } }, CHILD: function(elem, match){ var type = match[1], node = elem; switch (type) { case 'only': case 'first': while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) return false; } if ( type == 'first') return true; node = elem; case 'last': while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) return false; } return true; case 'nth': var first = match[2], last = match[3]; if ( first == 1 && last == 0 ) { return true; } var doneName = match[0], parent = elem.parentNode; if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent.sizcache = doneName; } var diff = elem.nodeIndex - last; if ( first == 0 ) { return diff == 0; } else { return ( diff % first == 0 && diff / first >= 0 ); } } }, ID: function(elem, match){ return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function(elem, match){ return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; }, CLASS: function(elem, match){ return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function(elem, match){ var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value != check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function(elem, match, i, array){ var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); } var makeArray = function(array, results) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; try { Array.prototype.slice.call( document.documentElement.childNodes, 0 ); } catch(e){ makeArray = function(array, results) { var ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var i = 0, l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( var i = 0; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { if ( a == b ) { hasDuplicate = true; } return 0; } var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( "sourceIndex" in document.documentElement ) { sortOrder = function( a, b ) { if ( !a.sourceIndex || !b.sourceIndex ) { if ( a == b ) { hasDuplicate = true; } return 0; } var ret = a.sourceIndex - b.sourceIndex; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( document.createRange ) { sortOrder = function( a, b ) { if ( !a.ownerDocument || !b.ownerDocument ) { if ( a == b ) { hasDuplicate = true; } return 0; } var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.setStart(a, 0); aRange.setEnd(a, 0); bRange.setStart(b, 0); bRange.setEnd(b, 0); var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } (function(){ var form = document.createElement("div"), id = "script" + (new Date).getTime(); form.innerHTML = ""; var root = document.documentElement; root.insertBefore( form, root.firstChild ); if ( !!document.getElementById( id ) ) { Expr.find.ID = function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function(elem, match){ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); root = form = null; // release memory in IE })(); (function(){ var div = document.createElement("div"); div.appendChild( document.createComment("") ); if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function(match, context){ var results = context.getElementsByTagName(match[1]); if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function(elem){ return elem.getAttribute("href", 2); }; } div = null; // release memory in IE })(); if ( document.querySelectorAll ) (function(){ var oldSizzle = Sizzle, div = document.createElement("div"); div.innerHTML = "

              "; if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function(query, context, extra, seed){ context = context || document; if ( !seed && context.nodeType === 9 && !isXML(context) ) { try { return makeArray( context.querySelectorAll(query), extra ); } catch(e){} } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } div = null; // release memory in IE })(); if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ var div = document.createElement("div"); div.innerHTML = "
              "; if ( div.getElementsByClassName("e").length === 0 ) return; div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) return; Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function(match, context, isXML) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; div = null; // release memory in IE })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { var sibDir = dir == "previousSibling" && !isXML; for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { if ( sibDir && elem.nodeType === 1 ){ elem.sizcache = doneName; elem.sizset = i; } elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem.sizcache = doneName; elem.sizset = i; } if ( elem.nodeName === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { var sibDir = dir == "previousSibling" && !isXML; for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { if ( sibDir && elem.nodeType === 1 ) { elem.sizcache = doneName; elem.sizset = i; } elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem.sizcache = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } var contains = document.compareDocumentPosition ? function(a, b){ return a.compareDocumentPosition(b) & 16; } : function(a, b){ return a !== b && (a.contains ? a.contains(b) : true); }; var isXML = function(elem){ return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; }; var posProcess = function(selector, context){ var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context; while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); }; window.Sizzle = Sizzle; })(); Prototype.Selector = (function(engine) { function extend(elements) { for (var i = 0, length = elements.length; i < length; i++) { Element.extend(elements[i]); } return elements; } function select(selector, scope) { return extend(engine(selector, scope || document)); } function match(element, selector) { return engine.matches(selector, [element]).length == 1; } return { engine: engine, select: select, match: match }; })(Sizzle); window.Sizzle = Prototype._original_property; delete Prototype._original_property; (function() { function toDecimal(pctString) { var match = pctString.match(/^(\d+)%?$/i); if (!match) return null; return (Number(match[1]) / 100); } function getPixelValue(value, property) { if (Object.isElement(value)) { element = value; value = element.getStyle(property); } if (value === null) { return null; } if ((/^\d+(px)?$/i).test(value)) { return window.parseInt(value, 10); } if (/\d/.test(value) && element.runtimeStyle) { var style = element.style.left, rStyle = element.runtimeStyle.left; element.runtimeStyle.left = element.currentStyle.left; element.style.left = value || 0; value = element.style.pixelLeft; element.style.left = style; element.runtimeStyle.left = rStyle; return value; } if (value.include('%')) { var decimal = toDecimal(value); var whole; if (property.include('left') || property.include('right') || property.include('width')) { whole = $(element.parentNode).measure('width'); } else if (property.include('top') || property.include('bottom') || property.include('height')) { whole = $(element.parentNode).measure('height'); } return whole * decimal; } return 0; } function toCSSPixels(number) { if (Object.isString(number) && number.endsWith('px')) { return number; } return number + 'px'; } function isDisplayed(element) { var originalElement = element; while (element && element.parentNode) { var display = element.getStyle('display'); if (display === 'none') { return false; } element = $(element.parentNode); } return true; } var hasLayout = Prototype.K; if ('currentStyle' in document.documentElement) { hasLayout = function(element) { if (!element.currentStyle.hasLayout) { element.style.zoom = 1; } return element; }; } function cssNameFor(key) { if (key.includes('border')) return key + '-width'; return key; } Element.Layout = Class.create(Hash, { initialize: function($super, element, preCompute) { $super(); this.element = $(element); Element.Layout.PROPERTIES.each( function(property) { this._set(property, null); }, this); if (preCompute) { this._preComputing = true; this._begin(); Element.Layout.PROPERTIES.each( this._compute, this ); this._end(); this._preComputing = false; } }, _set: function(property, value) { return Hash.prototype.set.call(this, property, value); }, set: function(property, value) { throw "Properties of Element.Layout are read-only."; }, get: function($super, property) { var value = $super(property); return value === null ? this._compute(property) : value; }, _begin: function() { if (this._prepared) return; var element = this.element; if (isDisplayed(element)) { this._prepared = true; return; } var originalStyles = { position: element.style.position || '', width: element.style.width || '', visibility: element.style.visibility || '', display: element.style.display || '' }; element.store('prototype_original_styles', originalStyles); var position = element.getStyle('position'), width = element.getStyle('width'); element.setStyle({ position: 'absolute', visibility: 'hidden', display: 'block' }); var positionedWidth = element.getStyle('width'); var newWidth; if (width && (positionedWidth === width)) { newWidth = window.parseInt(width, 10); } else if (width && (position === 'absolute' || position === 'fixed')) { newWidth = window.parseInt(width, 10); } else { var parent = element.parentNode, pLayout = $(parent).getLayout(); newWidth = pLayout.get('width') - this.get('margin-left') - this.get('border-left') - this.get('padding-left') - this.get('padding-right') - this.get('border-right') - this.get('margin-right'); } element.setStyle({ width: newWidth + 'px' }); this._prepared = true; }, _end: function() { var element = this.element; var originalStyles = element.retrieve('prototype_original_styles'); element.store('prototype_original_styles', null); element.setStyle(originalStyles); this._prepared = false; }, _compute: function(property) { var COMPUTATIONS = Element.Layout.COMPUTATIONS; if (!(property in COMPUTATIONS)) { throw "Property not found."; } return this._set(property, COMPUTATIONS[property].call(this, this.element)); }, toCSS: function() { var args = $A(arguments); var keys = (args.length === 0) ? Element.Layout.PROPERTIES : args.join(' ').split(' '); var css = {}; keys.each( function(key) { if (!Element.Layout.PROPERTIES.include(key)) return; if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; var value = this.get(key); if (value) css[cssNameFor(key)] = value + 'px'; }); return css; }, inspect: function() { return "#"; } }); Object.extend(Element.Layout, { PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), COMPUTATIONS: { 'height': function(element) { if (!this._preComputing) this._begin(); var bHeight = this.get('border-box-height'); if (bHeight <= 0) return 0; var bTop = this.get('border-top'), bBottom = this.get('border-bottom'); var pTop = this.get('padding-top'), pBottom = this.get('padding-bottom'); if (!this._preComputing) this._end(); return bHeight - bTop - bBottom - pTop - pBottom; }, 'width': function(element) { if (!this._preComputing) this._begin(); var bWidth = this.get('border-box-width'); if (bWidth <= 0) return 0; var bLeft = this.get('border-left'), bRight = this.get('border-right'); var pLeft = this.get('padding-left'), pRight = this.get('padding-right'); if (!this._preComputing) this._end(); return bWidth - bLeft - bRight - pLeft - pRight; }, 'padding-box-height': function(element) { var height = this.get('height'), pTop = this.get('padding-top'), pBottom = this.get('padding-bottom'); return height + pTop + pBottom; }, 'padding-box-width': function(element) { var width = this.get('width'), pLeft = this.get('padding-left'), pRight = this.get('padding-right'); return width + pLeft + pRight; }, 'border-box-height': function(element) { return element.offsetHeight; }, 'border-box-width': function(element) { return element.offsetWidth; }, 'margin-box-height': function(element) { var bHeight = this.get('border-box-height'), mTop = this.get('margin-top'), mBottom = this.get('margin-bottom'); if (bHeight <= 0) return 0; return bHeight + mTop + mBottom; }, 'margin-box-width': function(element) { var bWidth = this.get('border-box-width'), mLeft = this.get('margin-left'), mRight = this.get('margin-right'); if (bWidth <= 0) return 0; return bWidth + mLeft + mRight; }, 'top': function(element) { var offset = element.positionedOffset(); return offset.top; }, 'bottom': function(element) { var offset = element.positionedOffset(), parent = element.getOffsetParent(), pHeight = parent.measure('height'); var mHeight = this.get('border-box-height'); return pHeight - mHeight - offset.top; }, 'left': function(element) { var offset = element.positionedOffset(); return offset.left; }, 'right': function(element) { var offset = element.positionedOffset(), parent = element.getOffsetParent(), pWidth = parent.measure('width'); var mWidth = this.get('border-box-width'); return pWidth - mWidth - offset.left; }, 'padding-top': function(element) { return getPixelValue(element, 'paddingTop'); }, 'padding-bottom': function(element) { return getPixelValue(element, 'paddingBottom'); }, 'padding-left': function(element) { return getPixelValue(element, 'paddingLeft'); }, 'padding-right': function(element) { return getPixelValue(element, 'paddingRight'); }, 'border-top': function(element) { return Object.isNumber(element.clientTop) ? element.clientTop : getPixelValue(element, 'borderTopWidth'); }, 'border-bottom': function(element) { return Object.isNumber(element.clientBottom) ? element.clientBottom : getPixelValue(element, 'borderBottomWidth'); }, 'border-left': function(element) { return Object.isNumber(element.clientLeft) ? element.clientLeft : getPixelValue(element, 'borderLeftWidth'); }, 'border-right': function(element) { return Object.isNumber(element.clientRight) ? element.clientRight : getPixelValue(element, 'borderRightWidth'); }, 'margin-top': function(element) { return getPixelValue(element, 'marginTop'); }, 'margin-bottom': function(element) { return getPixelValue(element, 'marginBottom'); }, 'margin-left': function(element) { return getPixelValue(element, 'marginLeft'); }, 'margin-right': function(element) { return getPixelValue(element, 'marginRight'); } } }); if ('getBoundingClientRect' in document.documentElement) { Object.extend(Element.Layout.COMPUTATIONS, { 'right': function(element) { var parent = hasLayout(element.getOffsetParent()); var rect = element.getBoundingClientRect(), pRect = parent.getBoundingClientRect(); return (pRect.right - rect.right).round(); }, 'bottom': function(element) { var parent = hasLayout(element.getOffsetParent()); var rect = element.getBoundingClientRect(), pRect = parent.getBoundingClientRect(); return (pRect.bottom - rect.bottom).round(); } }); } Element.Offset = Class.create({ initialize: function(left, top) { this.left = left.round(); this.top = top.round(); this[0] = this.left; this[1] = this.top; }, relativeTo: function(offset) { return new Element.Offset( this.left - offset.left, this.top - offset.top ); }, inspect: function() { return "#".interpolate(this); }, toString: function() { return "[#{left}, #{top}]".interpolate(this); }, toArray: function() { return [this.left, this.top]; } }); function getLayout(element, preCompute) { return new Element.Layout(element, preCompute); } function measure(element, property) { return $(element).getLayout().get(property); } function getDimensions(element) { var layout = $(element).getLayout(); return { width: layout.get('width'), height: layout.get('height') }; } function getOffsetParent(element) { if (element.offsetParent) return $(element.offsetParent); if (element === document.body) return $(element); while ((element = element.parentNode) && element !== document.body) { if (Element.getStyle(element, 'position') !== 'static') { return (element.nodeName === 'HTML') ? $(document.body) : $(element); } } return $(document.body); } function cumulativeOffset(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return new Element.Offset(valueL, valueT); } function positionedOffset(element) { var layout = element.getLayout(); var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (isBody(element)) break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); valueL -= layout.get('margin-top'); valueT -= layout.get('margin-left'); return new Element.Offset(valueL, valueT); } function cumulativeScrollOffset(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return new Element.Offset(valueL, valueT); } function viewportOffset(forElement) { var valueT = 0, valueL = 0, docBody = document.body; var element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == docBody && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (element != docBody) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return new Element.Offset(valueL, valueT); } function absolutize(element) { element = $(element); if (Element.getStyle(element, 'position') === 'absolute') { return element; } var offsetParent = getOffsetParent(element); var eOffset = element.viewportOffset(), pOffset = offsetParent.viewportOffset(); var offset = eOffset.relativeTo(pOffset); var layout = element.get('layout'); element.store('prototype_absolutize_original_styles', { left: element.getStyle('left'), top: element.getStyle('top'), width: element.getStyle('width'), height: element.getStyle('height') }); element.setStyle({ position: 'absolute', top: offset.top + 'px', left: offset.left + 'px', width: layout.get('width') + 'px', height: layout.get('height') + 'px' }); return element; } function relativize(element) { element = $(element); if (Element.getStyle(element, 'position') === 'relative') { return element; } var originalStyles = element.retrieve('prototype_absolutize_original_styles'); if (originalStyles) element.setStyle(originalStyles); return element; } Element.addMethods({ getLayout: getLayout, measure: measure, getDimensions: getDimensions, getOffsetParent: getOffsetParent, cumulativeOffset: cumulativeOffset, positionedOffset: positionedOffset, cumulativeScrollOffset: cumulativeScrollOffset, viewportOffset: viewportOffset, absolutize: absolutize, relativize: relativize }); function isBody(element) { return element.nodeName.toUpperCase() === 'BODY'; } if ('getBoundingClientRect' in document.documentElement) { Element.addMethods({ viewportOffset: function(element) { element = $(element); var rect = element.getBoundingClientRect(), docEl = document.documentElement; return new Element.Offset(rect.left - docEl.clientLeft, rect.top - docEl.clientTop); }, cumulativeOffset: function(element) { element = $(element); var docOffset = $(document.documentElement).viewportOffset(), elementOffset = element.viewportOffset(); return elementOffset.relativeTo(docOffset); }, positionedOffset: function(element) { element = $(element); var parent = element.getOffsetParent(); if (element.offsetParent && element.offsetParent.nodeName.toUpperCase() === 'HTML') { return positionedOffset(element); } var eOffset = element.viewportOffset(), pOffset = isBody(parent) ? viewportOffset(parent) : parent.viewportOffset(); var retOffset = eOffset.relativeTo(pOffset); var layout = element.getLayout(); var top = retOffset.top - layout.get('margin-top'); var left = retOffset.left - layout.get('margin-left'); return new Element.Offset(left, top); } }); } })(); window.$$ = function() { var expression = $A(arguments).join(', '); return Prototype.Selector.select(expression, document); }; if (!Prototype.Selector.find) { Prototype.Selector.find = function(elements, expression, index) { if (Object.isUndefined(index)) index = 0; var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; for (i = 0; i < length; i++) { if (match(elements[i], expression) && index == matchIndex++) { return Element.extend(elements[i]); } } } } var Form = { reset: function(form) { form = $(form); form.reset(); return form; }, serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; var key, value, submitted = false, submit = options.submit; var data = elements.inject({ }, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { if (key in result) { if (!Object.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); } else result[key] = value; } } return result; }); return options.hash ? data : Object.toQueryString(data); } }; Form.Methods = { serialize: function(form, options) { return Form.serializeElements(Form.getElements(form), options); }, getElements: function(form) { var elements = $(form).getElementsByTagName('*'), element, arr = [ ], serializers = Form.Element.Serializers; for (var i = 0; element = elements[i]; i++) { arr.push(element); } return arr.inject([], function(elements, child) { if (serializers[child.tagName.toLowerCase()]) elements.push(Element.extend(child)); return elements; }) }, getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { var elements = $(form).getElements().findAll(function(element) { return 'hidden' != element.type && !element.disabled; }); var firstByIndex = elements.findAll(function(element) { return element.hasAttribute('tabIndex') && element.tabIndex >= 0; }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { return /^(?:input|select|textarea)$/i.test(element.tagName); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options) { form = $(form), options = Object.clone(options || { }); var params = options.parameters, action = form.readAttribute('action') || ''; if (action.blank()) action = window.location.href; options.parameters = form.serialize(true); if (params) { if (Object.isString(params)) params = params.toQueryParams(); Object.extend(options.parameters, params); } if (form.hasAttribute('method') && !options.method) options.method = form.method; return new Ajax.Request(action, options); } }; /*--------------------------------------------------------------------------*/ Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } }; Form.Element.Methods = { serialize: function(element) { element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = { }; pair[element.name] = value; return Object.toQueryString(pair); } } return ''; }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, setValue: function(element, value) { element = $(element); var method = element.tagName.toLowerCase(); Form.Element.Serializers[method](element, value); return element; }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element) { element = $(element); try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !(/^(?:button|reset|submit)$/i.test(element.type)))) element.select(); } catch (e) { } return element; }, disable: function(element) { element = $(element); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } }; /*--------------------------------------------------------------------------*/ var Field = Form.Element; var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ Form.Element.Serializers = { input: function(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element, value); default: return Form.Element.Serializers.textarea(element, value); } }, inputSelector: function(element, value) { if (Object.isUndefined(value)) return element.checked ? element.value : null; else element.checked = !!value; }, textarea: function(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; }, select: function(element, value) { if (Object.isUndefined(value)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; currentValue = this.optionValue(opt); if (single) { if (currentValue == value) { opt.selected = true; return; } } else opt.selected = value.include(currentValue); } } }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); } return values; }, optionValue: function(opt) { return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } }; /*--------------------------------------------------------------------------*/ Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); this.element = $(element); this.lastValue = this.getValue(); }, execute: function() { var value = this.getValue(); if (Object.isString(this.lastValue) && Object.isString(value) ? this.lastValue != value : String(this.lastValue) != String(value)) { this.callback(this.element, value); this.lastValue = value; } } }); Form.Element.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.serialize(this.element); } }); /*--------------------------------------------------------------------------*/ Abstract.EventObserver = Class.create({ initialize: function(element, callback) { this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback, this); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } }); Form.Element.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.serialize(this.element); } }); (function() { var Event = { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_INSERT: 45, cache: {} }; var docEl = document.documentElement; var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl && 'onmouseleave' in docEl; var _isButton; if (Prototype.Browser.IE) { var buttonMap = { 0: 1, 1: 4, 2: 2 }; _isButton = function(event, code) { return event.button === buttonMap[code]; }; } else if (Prototype.Browser.WebKit) { _isButton = function(event, code) { switch (code) { case 0: return event.which == 1 && !event.metaKey; case 1: return event.which == 1 && event.metaKey; default: return false; } }; } else { _isButton = function(event, code) { return event.which ? (event.which === code + 1) : (event.button === code); }; } function isLeftClick(event) { return _isButton(event, 0) } function isMiddleClick(event) { return _isButton(event, 1) } function isRightClick(event) { return _isButton(event, 2) } function element(event) { event = Event.extend(event); var node = event.target, type = event.type, currentTarget = event.currentTarget; if (currentTarget && currentTarget.tagName) { if (type === 'load' || type === 'error' || (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' && currentTarget.type === 'radio')) node = currentTarget; } if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; return Element.extend(node); } function findElement(event, expression) { var element = Event.element(event); if (!expression) return element; while (element) { if (Prototype.Selector.match(element, expression)) { return Element.extend(element); } element = element.parentNode; } } function pointer(event) { return { x: pointerX(event), y: pointerY(event) }; } function pointerX(event) { var docElement = document.documentElement, body = document.body || { scrollLeft: 0 }; return event.pageX || (event.clientX + (docElement.scrollLeft || body.scrollLeft) - (docElement.clientLeft || 0)); } function pointerY(event) { var docElement = document.documentElement, body = document.body || { scrollTop: 0 }; return event.pageY || (event.clientY + (docElement.scrollTop || body.scrollTop) - (docElement.clientTop || 0)); } function stop(event) { Event.extend(event); event.preventDefault(); event.stopPropagation(); event.stopped = true; } Event.Methods = { isLeftClick: isLeftClick, isMiddleClick: isMiddleClick, isRightClick: isRightClick, element: element, findElement: findElement, pointer: pointer, pointerX: pointerX, pointerY: pointerY, stop: stop }; var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); if (Prototype.Browser.IE) { function _relatedTarget(event) { var element; switch (event.type) { case 'mouseover': element = event.fromElement; break; case 'mouseout': element = event.toElement; break; default: return null; } return Element.extend(element); } Object.extend(methods, { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return '[object Event]' } }); Event.extend = function(event, element) { if (!event) return false; if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; var pointer = Event.pointer(event); Object.extend(event, { target: event.srcElement || element, relatedTarget: _relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); return Object.extend(event, methods); }; } else { Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; Object.extend(Event.prototype, methods); Event.extend = Prototype.K; } function _createResponder(element, eventName, handler) { var registry = Element.retrieve(element, 'prototype_event_registry'); if (Object.isUndefined(registry)) { CACHE.push(element); registry = Element.retrieve(element, 'prototype_event_registry', $H()); } var respondersForEvent = registry.get(eventName); if (Object.isUndefined(respondersForEvent)) { respondersForEvent = []; registry.set(eventName, respondersForEvent); } if (respondersForEvent.pluck('handler').include(handler)) return false; var responder; if (eventName.include(":")) { responder = function(event) { if (Object.isUndefined(event.eventName)) return false; if (event.eventName !== eventName) return false; Event.extend(event, element); handler.call(element, event); }; } else { if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && (eventName === "mouseenter" || eventName === "mouseleave")) { if (eventName === "mouseenter" || eventName === "mouseleave") { responder = function(event) { Event.extend(event, element); var parent = event.relatedTarget; while (parent && parent !== element) { try { parent = parent.parentNode; } catch(e) { parent = element; } } if (parent === element) return; handler.call(element, event); }; } } else { responder = function(event) { Event.extend(event, element); handler.call(element, event); }; } } responder.handler = handler; respondersForEvent.push(responder); return responder; } function _destroyCache() { for (var i = 0, length = CACHE.length; i < length; i++) { Event.stopObserving(CACHE[i]); CACHE[i] = null; } } var CACHE = []; if (Prototype.Browser.IE) window.attachEvent('onunload', _destroyCache); if (Prototype.Browser.WebKit) window.addEventListener('unload', Prototype.emptyFunction, false); var _getDOMEventName = Prototype.K, translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { _getDOMEventName = function(eventName) { return (translations[eventName] || eventName); }; } function observe(element, eventName, handler) { element = $(element); var responder = _createResponder(element, eventName, handler); if (!responder) return element; if (eventName.include(':')) { if (element.addEventListener) element.addEventListener("dataavailable", responder, false); else { element.attachEvent("ondataavailable", responder); element.attachEvent("onfilterchange", responder); } } else { var actualEventName = _getDOMEventName(eventName); if (element.addEventListener) element.addEventListener(actualEventName, responder, false); else element.attachEvent("on" + actualEventName, responder); } return element; } function stopObserving(element, eventName, handler) { element = $(element); var registry = Element.retrieve(element, 'prototype_event_registry'); if (!registry) return element; if (!eventName) { registry.each( function(pair) { var eventName = pair.key; stopObserving(element, eventName); }); return element; } var responders = registry.get(eventName); if (!responders) return element; if (!handler) { responders.each(function(r) { stopObserving(element, eventName, r.handler); }); return element; } var responder = responders.find( function(r) { return r.handler === handler; }); if (!responder) return element; if (eventName.include(':')) { if (element.removeEventListener) element.removeEventListener("dataavailable", responder, false); else { element.detachEvent("ondataavailable", responder); element.detachEvent("onfilterchange", responder); } } else { var actualEventName = _getDOMEventName(eventName); if (element.removeEventListener) element.removeEventListener(actualEventName, responder, false); else element.detachEvent('on' + actualEventName, responder); } registry.set(eventName, responders.without(responder)); return element; } function fire(element, eventName, memo, bubble) { element = $(element); if (Object.isUndefined(bubble)) bubble = true; if (element == document && document.createEvent && !element.dispatchEvent) element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent('HTMLEvents'); event.initEvent('dataavailable', true, true); } else { event = document.createEventObject(); event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; } event.eventName = eventName; event.memo = memo || { }; if (document.createEvent) element.dispatchEvent(event); else element.fireEvent(event.eventType, event); return Event.extend(event); } Object.extend(Event, Event.Methods); Object.extend(Event, { fire: fire, observe: observe, stopObserving: stopObserving }); Element.addMethods({ fire: fire, observe: observe, stopObserving: stopObserving }); Object.extend(document, { fire: fire.methodize(), observe: observe.methodize(), stopObserving: stopObserving.methodize(), loaded: false }); if (window.Event) Object.extend(window.Event, Event); else window.Event = Event; })(); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearTimeout(timer); document.loaded = true; document.fire('dom:loaded'); } function checkReadyState() { if (document.readyState === 'complete') { document.stopObserving('readystatechange', checkReadyState); fireContentLoadedEvent(); } } function pollDoScroll() { try { document.documentElement.doScroll('left'); } catch(e) { timer = pollDoScroll.defer(); return; } fireContentLoadedEvent(); } if (document.addEventListener) { document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); } else { document.observe('readystatechange', checkReadyState); if (window == top) timer = pollDoScroll.defer(); } Event.observe(window, 'load', fireContentLoadedEvent); })(); Element.addMethods(); /*------------------------------- DEPRECATED -------------------------------*/ Hash.toQueryString = Object.toQueryString; var Toggle = { display: Element.toggle }; Element.Methods.childOf = Element.Methods.descendantOf; var Insertion = { Before: function(element, content) { return Element.insert(element, {before:content}); }, Top: function(element, content) { return Element.insert(element, {top:content}); }, Bottom: function(element, content) { return Element.insert(element, {bottom:content}); }, After: function(element, content) { return Element.insert(element, {after:content}); } }; var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); var Position = { includeScrollOffsets: false, prepare: function() { this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; }, within: function(element, x, y) { if (this.includeScrollOffsets) return this.withinIncludingScrolloffsets(element, x, y); this.xcomp = x; this.ycomp = y; this.offset = Element.cumulativeOffset(element); return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && x >= this.offset[0] && x < this.offset[0] + element.offsetWidth); }, withinIncludingScrolloffsets: function(element, x, y) { var offsetcache = Element.cumulativeScrollOffset(element); this.xcomp = x + offsetcache[0] - this.deltaX; this.ycomp = y + offsetcache[1] - this.deltaY; this.offset = Element.cumulativeOffset(element); return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight && this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth); }, overlap: function(mode, element) { if (!mode) return 0; if (mode == 'vertical') return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal') return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth; }, cumulativeOffset: Element.Methods.cumulativeOffset, positionedOffset: Element.Methods.positionedOffset, absolutize: function(element) { Position.prepare(); return Element.absolutize(element); }, relativize: function(element) { Position.prepare(); return Element.relativize(element); }, realOffset: Element.Methods.cumulativeScrollOffset, offsetParent: Element.Methods.getOffsetParent, page: Element.Methods.viewportOffset, clone: function(source, target, options) { options = options || { }; return Element.clonePosition(target, source, options); } }; /*--------------------------------------------------------------------------*/ if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ function iter(name) { return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; } instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? function(element, className) { className = className.toString().strip(); var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); return cond ? document._getElementsByXPath('.//*' + cond, element) : []; } : function(element, className) { className = className.toString().strip(); var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); if (!classNames && !className) return elements; var nodes = $(element).getElementsByTagName('*'); className = ' ' + className + ' '; for (var i = 0, child, cn; child = nodes[i]; i++) { if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || (classNames && classNames.all(function(name) { return !name.toString().blank() && cn.include(' ' + name + ' '); })))) elements.push(Element.extend(child)); } return elements; }; return function(className, parentElement) { return $(parentElement || document.body).getElementsByClassName(className); }; }(Element.Methods); /*--------------------------------------------------------------------------*/ Element.ClassNames = Class.create(); Element.ClassNames.prototype = { initialize: function(element) { this.element = $(element); }, _each: function(iterator) { this.element.className.split(/\s+/).select(function(name) { return name.length > 0; })._each(iterator); }, set: function(className) { this.element.className = className; }, add: function(classNameToAdd) { if (this.include(classNameToAdd)) return; this.set($A(this).concat(classNameToAdd).join(' ')); }, remove: function(classNameToRemove) { if (!this.include(classNameToRemove)) return; this.set($A(this).without(classNameToRemove).join(' ')); }, toString: function() { return $A(this).join(' '); } }; Object.extend(Element.ClassNames.prototype, Enumerable); /*--------------------------------------------------------------------------*/ (function() { window.Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); }, findElements: function(rootElement) { return Prototype.Selector.select(this.expression, rootElement); }, match: function(element) { return Prototype.Selector.match(element, this.expression); }, toString: function() { return this.expression; }, inspect: function() { return "#"; } }); Object.extend(Selector, { matchElements: function(elements, expression) { var match = Prototype.Selector.match, results = []; for (var i = 0, length = elements.length; i < length; i++) { var element = elements[i]; if (match(element, expression)) { results.push(Element.extend(element)); } } return results; }, findElement: function(elements, expression, index) { index = index || 0; var matchIndex = 0, element; for (var i = 0, length = elements.length; i < length; i++) { element = elements[i]; if (Prototype.Selector.match(element, expression) && index === matchIndex++) { return Element.extend(element); } } }, findChildElements: function(element, expressions) { var selector = expressions.toArray().join(', '); return Prototype.Selector.select(selector, element || document); } }); })(); nwmatcher/test/prototype/nwmatcher-proto-test.html0000644000175000017500000006410012316015515021222 0ustar wmbwmb NWMatcher Unit Test
              nwmatcher/test/prototype/tests/0000755000175000017500000000000012316015515015367 5ustar wmbwmbnwmatcher/test/prototype/tests/nwmatcher-test.js0000644000175000017500000000314612316015515020676 0ustar wmbwmb(function(global) { var param, select; getQueryParam = function(key, defaultValue) { var pattern = new RegExp('[?&]' + key + '=([^&]+)'); return (global.location.href.match(pattern) || [0, defaultValue])[1]; }, refresh = function() { var loc = global.location; loc.replace(loc.protocol + '//' + loc.hostname + loc.pathname + '?engine=' + select.options[select.selectedIndex].text); }, change = function(options, value) { var i = -1, option; while ((option = options[++i])) { if (option.text == value) { options[0].parentNode.selectedIndex = i; break; } } }; global.$$ = function $$() { var context, args = $A(arguments); if (typeof args[args.length - 1] != 'string') { context = args.pop(); } return (param == 'NWMatcher') ? NW.Dom.select(args.join(', '), context) : Prototype.Selector.select(args.join(', '), context); }; global.onload = function() { var d = document; select = d.createElement('select'); select.appendChild(d.createElement('option')).appendChild(d.createTextNode('NWMatcher')); select.appendChild(d.createElement('option')).appendChild(d.createTextNode('Sizzle')); d.body.insertBefore(select, d.body.firstChild.nextSibling); d.body.insertBefore(d.createElement('b'), d.body.firstChild). appendChild(d.createTextNode('Choose selector engine\xa0')); param = getQueryParam('engine', 'NWMatcher'); change(select.options, param); select.onchange = refresh; }; })(this); nwmatcher/test/prototype/tests/selector_engine_test.js0000644000175000017500000000300412316015515022126 0ustar wmbwmb/*
              */ new Test.Unit.Runner({ testEngine: function() { this.assert(Prototype.Selector.engine); }, testSelect: function() { var elements = Prototype.Selector.select('.test_class'); this.assert(Object.isArray(elements)); this.assertEqual(2, elements.length); this.assertEqual('test_div_parent', elements[0].id); this.assertEqual('test_div_child', elements[1].id); }, testSelectWithContext: function() { var elements = Prototype.Selector.select('.test_class', $('test_div_parent')); this.assert(Object.isArray(elements)); this.assertEqual(1, elements.length); this.assertEqual('test_div_child', elements[0].id); }, testSelectWithEmptyResult: function() { var elements = Prototype.Selector.select('.non_existent'); this.assert(Object.isArray(elements)); this.assertEqual(0, elements.length); }, testMatch: function() { var element = $('test_div_parent'); this.assertEqual(true, Prototype.Selector.match(element, '.test_class')); this.assertEqual(false, Prototype.Selector.match(element, '.non_existent')); }, testFind: function() { var elements = document.getElementsByTagName('*'), expression = '.test_class'; this.assertEqual('test_div_parent', Prototype.Selector.find(elements, expression).id); this.assertEqual('test_div_child', Prototype.Selector.find(elements, expression, 1).id); } });nwmatcher/test/prototype/tests/selector_test.js0000644000175000017500000005043612316015515020614 0ustar wmbwmbvar $RunBenchmarks = false; function reduce(arr) { return arr.length > 1 ? arr : arr[0]; } new Test.Unit.Runner({ testSelectorWithTagName: function() { this.assertEnumEqual($A(document.getElementsByTagName('li')), $$('li')); this.assertEnumEqual([$('strong')], $$('strong')); this.assertEnumEqual([], $$('nonexistent')); var allNodes = $A(document.getElementsByTagName('*')).select( function(node) { return node.tagName !== '!'; }); this.assertEnumEqual(allNodes, $$('*')); }, testSelectorWithId: function() { this.assertEnumEqual([$('fixtures')], $$('#fixtures')); this.assertEnumEqual([], $$('#nonexistent')); this.assertEnumEqual([$('troubleForm')], $$('#troubleForm')); }, testSelectorWithClassName: function() { this.assertEnumEqual($('p', 'link_1', 'item_1'), $$('.first')); this.assertEnumEqual([], $$('.second')); }, testSelectorWithTagNameAndId: function() { this.assertEnumEqual([$('strong')], $$('strong#strong')); this.assertEnumEqual([], $$('p#strong')); }, testSelectorWithTagNameAndClassName: function() { this.assertEnumEqual($('link_1', 'link_2'), $$('a.internal')); this.assertEnumEqual([$('link_2')], $$('a.internal.highlight')); this.assertEnumEqual([$('link_2')], $$('a.highlight.internal')); this.assertEnumEqual([], $$('a.highlight.internal.nonexistent')); }, testSelectorWithIdAndClassName: function() { this.assertEnumEqual([$('link_2')], $$('#link_2.internal')); this.assertEnumEqual([$('link_2')], $$('.internal#link_2')); this.assertEnumEqual([$('link_2')], $$('#link_2.internal.highlight')); this.assertEnumEqual([], $$('#link_2.internal.nonexistent')); }, testSelectorWithTagNameAndIdAndClassName: function() { this.assertEnumEqual([$('link_2')], $$('a#link_2.internal')); this.assertEnumEqual([$('link_2')], $$('a.internal#link_2')); this.assertEnumEqual([$('item_1')], $$('li#item_1.first')); this.assertEnumEqual([], $$('li#item_1.nonexistent')); this.assertEnumEqual([], $$('li#item_1.first.nonexistent')); }, test$$MatchesAncestryWithTokensSeparatedByWhitespace: function() { this.assertEnumEqual($('em2', 'em', 'span'), $$('#fixtures a *')); this.assertEnumEqual([$('p')], $$('div#fixtures p')); }, test$$CombinesResultsWhenMultipleExpressionsArePassed: function() { this.assertEnumEqual($('link_1', 'link_2', 'item_1', 'item_2', 'item_3'), $$('#p a', ' ul#list li ')); }, testSelectorWithTagNameAndAttributeExistence: function() { this.assertEnumEqual($$('#fixtures h1'), $$('h1[class]'), 'h1[class]'); this.assertEnumEqual($$('#fixtures h1'), $$('h1[CLASS]'), 'h1[CLASS]'); this.assertEnumEqual([$('item_3')], $$('li#item_3[class]'), 'li#item_3[class]'); }, testSelectorWithTagNameAndSpecificAttributeValue: function() { this.assertEnumEqual($('link_1', 'link_2', 'link_3'), $$('a[href="#"]')); this.assertEnumEqual($('link_1', 'link_2', 'link_3'), $$("a[href='#']")); }, testSelectorWithTagNameAndWhitespaceTokenizedAttributeValue: function() { this.assertEnumEqual($('link_1', 'link_2'), $$('a[class~="internal"]'), "a[class~=\"internal\"]"); this.assertEnumEqual($('link_1', 'link_2'), $$('a[class~=internal]'), "a[class~=internal]"); }, testSelectorWithAttributeAndNoTagName: function() { this.assertEnumEqual($(document.body).select('a[href]'), $(document.body).select('[href]')); this.assertEnumEqual($$('a[class~="internal"]'), $$('[class~=internal]')); this.assertEnumEqual($$('*[id]'), $$('[id]')); this.assertEnumEqual($('checked_radio', 'unchecked_radio'), $$('[type=radio]')); this.assertEnumEqual($$('*[type=checkbox]'), $$('[type=checkbox]')); this.assertEnumEqual($('with_title', 'commaParent'), $$('[title]')); this.assertEnumEqual($$('#troubleForm *[type=radio]'), $$('#troubleForm [type=radio]')); this.assertEnumEqual($$('#troubleForm *[type]'), $$('#troubleForm [type]')); }, testSelectorWithAttributeContainingDash: function() { this.assertEnumEqual([$('attr_with_dash')], $$('[foo-bar]'), "attribute with hyphen"); }, testSelectorWithUniversalAndHyphenTokenizedAttributeValue: function() { this.assertEnumEqual([$('item_3')], $$('*[xml:lang|="es"]')); this.assertEnumEqual([$('item_3')], $$('*[xml:lang|="ES"]')); }, testSelectorWithTagNameAndNegatedAttributeValue: function() { this.assertEnumEqual([], $$('a:not([href="#"])')); }, testSelectorWithBracketAttributeValue: function() { this.assertEnumEqual($('chk_1', 'chk_2'), $$('#troubleForm2 input[name="brackets[5][]"]')); this.assertEnumEqual([$('chk_1')], $$('#troubleForm2 input[name="brackets[5][]"]:checked')); this.assertEnumEqual([$('chk_2')], $$('#troubleForm2 input[name="brackets[5][]"][value="2"]')); this.assertEnumEqual($('chk_1', 'chk_2'), $$('#troubleForm2 input[name=brackets\\[5\\]\\[\\]]')); }, test$$WithNestedAttributeSelectors: function() { this.assertEnumEqual([$('strong')], $$('div[style] p[id] strong'), 'div[style] p[id] strong'); }, testSelectorWithMultipleConditions: function() { this.assertEnumEqual([$('link_3')], $$('a[class~=external][href="#"]'), 'a[class~=external][href="#"]'); this.assertEnumEqual([], $$('a[class~=external]:not([href="#"])'), 'a[class~=external]:not([href="#"])'); }, testSelectorMatchElements: function() { this.assertElementsMatch(Selector.matchElements($('list').descendants(), 'li'), '#item_1', '#item_2', '#item_3'); this.assertElementsMatch(Selector.matchElements($('fixtures').descendants(), 'a.internal'), '#link_1', '#link_2'); this.assertEnumEqual([], Selector.matchElements($('fixtures').descendants(), 'p.last')); this.assertElementsMatch(Selector.matchElements($('fixtures').descendants(), '.inexistant, a.internal'), '#link_1', '#link_2'); }, testSelectorFindElement: function() { this.assertElementMatches(Selector.findElement($('list').descendants(), 'li'), 'li#item_1.first'); this.assertElementMatches(Selector.findElement($('list').descendants(), 'li', 1), 'li#item_2'); this.assertElementMatches(Selector.findElement($('list').descendants(), 'li#item_3'), 'li'); this.assertEqual(undefined, Selector.findElement($('list').descendants(), 'em')); }, testElementMatch: function() { var span = $('dupL1'); // tests that should pass this.assert(span.match('span')); this.assert(span.match('span#dupL1')); this.assert(span.match('div > span'), 'child combinator'); this.assert(span.match('#dupContainer span'), 'descendant combinator'); this.assert(span.match('#dupL1'), 'ID only'); this.assert(span.match('span.span_foo'), 'class name 1'); this.assert(span.match('span.span_bar'), 'class name 2'); this.assert(span.match('span:first-child'), 'first-child pseudoclass'); this.assert(!span.match('span.span_wtf'), 'bogus class name'); this.assert(!span.match('#dupL2'), 'different ID'); this.assert(!span.match('div'), 'different tag name'); this.assert(!span.match('span span'), 'different ancestry'); this.assert(!span.match('span > span'), 'different parent'); this.assert(!span.match('span:nth-child(5)'), 'different pseudoclass'); this.assert(!$('link_2').match('a[rel^=external]')); this.assert($('link_1').match('a[rel^=external]')); this.assert($('link_1').match('a[rel^="external"]')); this.assert($('link_1').match("a[rel^='external']")); this.assert(span.match({ match: function(element) { return true }}), 'custom selector'); this.assert(!span.match({ match: function(element) { return false }}), 'custom selector'); }, testSelectorWithSpaceInAttributeValue: function() { this.assertEnumEqual([$('with_title')], $$('cite[title="hello world!"]')); }, // AND NOW COME THOSE NEW TESTS AFTER ANDREW'S REWRITE! testSelectorWithNamespacedAttributes: function() { if (Prototype.BrowserFeatures.XPath) { this.assertUndefined(new Selector('html[xml:lang]').xpath); this.assertUndefined(new Selector('body p[xml:lang]').xpath); } else this.info("Could not test XPath bypass: no XPath to begin with!"); this.assertElementsMatch($$('[xml:lang]'), 'html', '#item_3'); this.assertElementsMatch($$('*[xml:lang]'), 'html', '#item_3'); }, testSelectorWithChild: function() { this.assertEnumEqual($('link_1', 'link_2'), $$('p.first > a')); this.assertEnumEqual($('father', 'uncle'), $$('div#grandfather > div')); this.assertEnumEqual($('level2_1', 'level2_2'), $$('#level1>span')); this.assertEnumEqual($('level2_1', 'level2_2'), $$('#level1 > span')); this.assertEnumEqual($('level3_1', 'level3_2'), $$('#level2_1 > *')); this.assertEnumEqual([], $$('div > #nonexistent')); $RunBenchmarks && this.wait(500, function() { this.benchmark(function() { $$('#level1 > span') }, 1000); }); }, testSelectorWithAdjacence: function() { this.assertEnumEqual([$('uncle')], $$('div.brothers + div.brothers')); this.assertEnumEqual([$('uncle')], $$('div.brothers + div')); this.assertEqual($('level2_2'), reduce($$('#level2_1+span'))); this.assertEqual($('level2_2'), reduce($$('#level2_1 + span'))); this.assertEqual($('level2_2'), reduce($$('#level2_1 + *'))); this.assertEnumEqual([], $$('#level2_2 + span')); this.assertEqual($('level3_2'), reduce($$('#level3_1 + span'))); this.assertEqual($('level3_2'), reduce($$('#level3_1 + *'))); this.assertEnumEqual([], $$('#level3_2 + *')); this.assertEnumEqual([], $$('#level3_1 + em')); $RunBenchmarks && this.wait(500, function() { this.benchmark(function() { $$('#level3_1 + span') }, 1000); }); }, testSelectorWithLaterSibling: function() { this.assertEnumEqual([$('list')], $$('h1 ~ ul')); this.assertEqual($('level2_2'), reduce($$('#level2_1 ~ span'))); this.assertEnumEqual($('level2_2', 'level2_3'), reduce($$('#level2_1 ~ *'))); this.assertEnumEqual([], $$('#level2_2 ~ span')); this.assertEnumEqual([], $$('#level3_2 ~ *')); this.assertEnumEqual([], $$('#level3_1 ~ em')); this.assertEnumEqual([$('level3_2')], $$('#level3_1 ~ #level3_2')); this.assertEnumEqual([$('level3_2')], $$('span ~ #level3_2')); this.assertEnumEqual([], $$('div ~ #level3_2')); this.assertEnumEqual([], $$('div ~ #level2_3')); $RunBenchmarks && this.wait(500, function() { this.benchmark(function() { $$('#level2_1 ~ span') }, 1000); }); }, testSelectorWithNewAttributeOperators: function() { this.assertEnumEqual($('father', 'uncle'), $$('div[class^=bro]'), 'matching beginning of string'); this.assertEnumEqual($('father', 'uncle'), $$('div[class$=men]'), 'matching end of string'); this.assertEnumEqual($('father', 'uncle'), $$('div[class*="ers m"]'), 'matching substring') this.assertEnumEqual($('level2_1', 'level2_2', 'level2_3'), $$('#level1 *[id^="level2_"]')); this.assertEnumEqual($('level2_1', 'level2_2', 'level2_3'), $$('#level1 *[id^=level2_]')); this.assertEnumEqual($('level2_1', 'level3_1'), $$('#level1 *[id$="_1"]')); this.assertEnumEqual($('level2_1', 'level3_1'), $$('#level1 *[id$=_1]')); this.assertEnumEqual($('level2_1', 'level3_2', 'level2_2', 'level2_3'), $$('#level1 *[id*="2"]')); this.assertEnumEqual($('level2_1', 'level3_2', 'level2_2', 'level2_3'), $$("#level1 *[id*='2']")); $RunBenchmarks && this.wait(500, function() { this.benchmark(function() { $$('#level1 *[id^=level2_]') }, 1000, '[^=]'); this.benchmark(function() { $$('#level1 *[id$=_1]') }, 1000, '[$=]'); this.benchmark(function() { $$('#level1 *[id*=_2]') }, 1000, '[*=]'); }); }, testSelectorWithDuplicates: function() { this.assertEnumEqual($$('div div'), $$('div div').uniq()); this.assertEnumEqual($('dupL2', 'dupL3', 'dupL4', 'dupL5'), $$('#dupContainer span span')); $RunBenchmarks && this.wait(500, function() { this.benchmark(function() { $$('#dupContainer span span') }, 1000); }); }, testSelectorWithFirstLastOnlyNthNthLastChild: function() { this.assertEnumEqual([$('level2_1')], $$('#level1>*:first-child')); this.assertEnumEqual($('level2_1', 'level3_1', 'level_only_child'), $$('#level1 *:first-child')); this.assertEnumEqual([$('level2_3')], $$('#level1>*:last-child')); this.assertEnumEqual($('level3_2', 'level_only_child', 'level2_3'), $$('#level1 *:last-child')); this.assertEnumEqual([$('level2_3')], $$('#level1>div:last-child')); this.assertEnumEqual([$('level2_3')], $$('#level1 div:last-child')); this.assertEnumEqual([], $$('#level1>div:first-child')); this.assertEnumEqual([], $$('#level1>span:last-child')); this.assertEnumEqual($('level2_1', 'level3_1'), $$('#level1 span:first-child')); this.assertEnumEqual([], $$('#level1:first-child')); this.assertEnumEqual([], $$('#level1>*:only-child')); this.assertEnumEqual([$('level_only_child')], $$('#level1 *:only-child')); this.assertEnumEqual([], $$('#level1:only-child')); this.assertEnumEqual([$('link_2')], $$('#p *:nth-last-child(2)'), 'nth-last-child'); this.assertEnumEqual([$('link_2')], $$('#p *:nth-child(3)'), 'nth-child'); this.assertEnumEqual([$('link_2')], $$('#p a:nth-child(3)'), 'nth-child'); this.assertEnumEqual($('item_2', 'item_3'), $$('#list > li:nth-child(n+2)')); this.assertEnumEqual($('item_1', 'item_2'), $$('#list > li:nth-child(-n+2)')); $RunBenchmarks && this.wait(500, function() { this.benchmark(function() { $$('#level1 *:first-child') }, 1000, ':first-child'); this.benchmark(function() { $$('#level1 *:last-child') }, 1000, ':last-child'); this.benchmark(function() { $$('#level1 *:only-child') }, 1000, ':only-child'); }); }, testSelectorWithFirstLastNthNthLastOfType: function() { this.assertEnumEqual([$('link_2')], $$('#p a:nth-of-type(2)'), 'nth-of-type'); this.assertEnumEqual([$('link_1')], $$('#p a:nth-of-type(1)'), 'nth-of-type'); this.assertEnumEqual([$('link_2')], $$('#p a:nth-last-of-type(1)'), 'nth-last-of-type'); this.assertEnumEqual([$('link_1')], $$('#p a:first-of-type'), 'first-of-type'); this.assertEnumEqual([$('link_2')], $$('#p a:last-of-type'), 'last-of-type'); }, testSelectorWithNot: function() { this.assertEnumEqual([$('link_2')], $$('#p a:not(:first-of-type)'), 'first-of-type'); this.assertEnumEqual([$('link_1')], $$('#p a:not(:last-of-type)'), 'last-of-type'); this.assertEnumEqual([$('link_2')], $$('#p a:not(:nth-of-type(1))'), 'nth-of-type'); this.assertEnumEqual([$('link_1')], $$('#p a:not(:nth-last-of-type(1))'), 'nth-last-of-type'); this.assertEnumEqual([$('link_2')], $$('#p a:not([rel~=nofollow])'), 'attribute 1'); this.assertEnumEqual([$('link_2')], $$('#p a:not([rel^=external])'), 'attribute 2'); this.assertEnumEqual([$('link_2')], $$('#p a:not([rel$=nofollow])'), 'attribute 3'); this.assertEnumEqual([$('em')], $$('#p a:not([rel$="nofollow"]) > em'), 'attribute 4') this.assertEnumEqual([$('item_2')], $$('#list li:not(#item_1):not(#item_3)'), 'adjacent :not clauses'); this.assertEnumEqual([$('son')], $$('#grandfather > div:not(#uncle) #son')); this.assertEnumEqual([$('em')], $$('#p a:not([rel$="nofollow"]) em'), 'attribute 4 + all descendants'); this.assertEnumEqual([$('em')], $$('#p a:not([rel$="nofollow"])>em'), 'attribute 4 (without whitespace)'); }, testSelectorWithEnabledDisabledChecked: function() { this.assertEnumEqual([$('disabled_text_field')], $$('#troubleForm > *:disabled')); this.assertEnumEqual($('troubleForm').getInputs().without($('disabled_text_field')), $$('#troubleForm > *:enabled')); this.assertEnumEqual($('checked_box', 'checked_radio'), $$('#troubleForm *:checked')); }, testSelectorWithEmpty: function() { $('level3_1').innerHTML = ""; this.assertEnumEqual($('level3_1', 'level3_2', 'level2_3'), $$('#level1 *:empty'), '#level1 *:empty'); this.assertEnumEqual([], $$('#level_only_child:empty'), 'newlines count as content!'); }, testIdenticalResultsFromEquivalentSelectors: function() { this.assertEnumEqual($$('div.brothers'), $$('div[class~=brothers]')); this.assertEnumEqual($$('div.brothers'), $$('div[class~=brothers].brothers')); this.assertEnumEqual($$('div:not(.brothers)'), $$('div:not([class~=brothers])')); this.assertEnumEqual($$('li ~ li'), $$('li:not(:first-child)')); this.assertEnumEqual($$('ul > li'), $$('ul > li:nth-child(n)')); this.assertEnumEqual($$('ul > li:nth-child(even)'), $$('ul > li:nth-child(2n)')); this.assertEnumEqual($$('ul > li:nth-child(odd)'), $$('ul > li:nth-child(2n+1)')); this.assertEnumEqual($$('ul > li:first-child'), $$('ul > li:nth-child(1)')); this.assertEnumEqual($$('ul > li:last-child'), $$('ul > li:nth-last-child(1)')); this.assertEnumEqual($$('ul > li:nth-child(n-999)'), $$('ul > li')); this.assertEnumEqual($$('ul>li'), $$('ul > li')); this.assertEnumEqual($$('#p a:not([rel$="nofollow"])>em'), $$('#p a:not([rel$="nofollow"]) > em')) }, testSelectorsThatShouldReturnNothing: function() { this.assertEnumEqual([], $$('span:empty > *')); this.assertEnumEqual([], $$('div.brothers:not(.brothers)')); this.assertEnumEqual([], $$('#level2_2 :only-child:not(:last-child)')); this.assertEnumEqual([], $$('#level2_2 :only-child:not(:first-child)')); }, testCommasFor$$: function() { this.assertEnumEqual($('p', 'link_1', 'list', 'item_1', 'item_3', 'troubleForm'), $$('#list, .first,*[xml:lang="es-us"] , #troubleForm')); this.assertEnumEqual($('p', 'link_1', 'list', 'item_1', 'item_3', 'troubleForm'), $$('#list, .first,', '*[xml:lang="es-us"] , #troubleForm')); this.assertEnumEqual($('commaParent', 'commaChild'), $$('form[title*="commas,"], input[value="#commaOne,#commaTwo"]')); this.assertEnumEqual($('commaParent', 'commaChild'), $$('form[title*="commas,"]', 'input[value="#commaOne,#commaTwo"]')); }, testSelectorExtendsAllNodes: function(){ var element = document.createElement('div'); (3).times(function(){ element.appendChild(document.createElement('div')); }); element.setAttribute('id','scratch_element'); $$('body')[0].appendChild(element); var results = $$('#scratch_element div'); this.assert(typeof results[0].show == 'function'); this.assert(typeof results[1].show == 'function'); this.assert(typeof results[2].show == 'function'); }, testCopiedNodesGetIncluded: function() { this.assertElementsMatch( Selector.matchElements($('counted_container').descendants(), 'div'), 'div.is_counted' ); $('counted_container').innerHTML += $('counted_container').innerHTML; this.assertElementsMatch( Selector.matchElements($('counted_container').descendants(), 'div'), 'div.is_counted', 'div.is_counted' ); }, testSelectorNotInsertedNodes: function() { window.debug = true; var wrapper = new Element("div"); wrapper.update("
              "); this.assertNotNullOrUndefined(wrapper.select('[id=myTD]')[0], 'selecting: [id=myTD]'); this.assertNotNullOrUndefined(wrapper.select('#myTD')[0], 'selecting: #myTD'); this.assertNotNullOrUndefined(wrapper.select('td')[0], 'selecting: td'); this.assert($$('#myTD').length == 0, 'should not turn up in document-rooted search'); window.debug = false; }, testElementDown: function() { var a = $('dupL4'); var b = $('dupContainer').down('#dupL4'); this.assertEqual(a, b); }, testElementDownWithDotAndColon: function() { var a = $('dupL4_dotcolon'); var b = $('dupContainer.withdot:active').down('#dupL4_dotcolon'); var c = $('dupContainer.withdot:active').select('#dupL4_dotcolon'); this.assertEqual(a, b); this.assertEnumEqual([a], c); }, testDescendantSelectorBuggy: function() { var el = document.createElement('div'); el.innerHTML = '
              '; document.body.appendChild(el); this.assertEqual(2, $(el).select('ul li').length); document.body.removeChild(el); }, testFindElementWithIndexWhenElementsAreNotInDocumentOrder: function() { var ancestors = $("target_1").ancestors(); this.assertEqual($("container_2"), Selector.findElement(ancestors, "[container], .container", 0)); this.assertEqual($("container_1"), Selector.findElement(ancestors, "[container], .container", 1)); } });nwmatcher/test/prototype/test.css0000644000175000017500000000140312316015515015714 0ustar wmbwmbbody, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li { font-family: sans-serif; } body { font-size:0.8em; } #log { padding-bottom: 1em; border-bottom: 2px solid #000; margin-bottom: 2em; } .logsummary { margin-top: 1em; margin-bottom: 1em; padding: 1ex; border: 1px solid #000; font-weight: bold; } .logtable { width:100%; border-collapse: collapse; border: 1px dotted #666; } .logtable td, .logtable th { text-align: left; padding: 3px 8px; border: 1px dotted #666; } .logtable .passed { background-color: #cfc; } .logtable .failed, .logtable .error { background-color: #fcc; } .logtable td div.action_buttons { display: inline; } .logtable td div.action_buttons input { margin: 0 5px; font-size: 10px; }nwmatcher/test/jsvm/0000755000175000017500000000000012316015515013137 5ustar wmbwmbnwmatcher/test/jsvm/env.js0000644000175000017500000226270412316015515014302 0ustar wmbwmb/* * Envjs core-env.1.2.0.11 * 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 */ (function(){ /** * 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){}; /** * * @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 and the Envjs Team * Copyright 2008-2010 John Resig, under the MIT License */ (function(){ /** * @author envjs team * borrowed 99%-ish with love from firebug-lite */ 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 */ })(); /* * Envjs dom.1.2.0.11 * 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.0.11 * Pure JavaScript Browser Environment * By John Resig and the Envjs Team * Copyright 2008-2010 John Resig, under the MIT License */ (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; }; /** * @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 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 inode; var nodesToRemove = new NodeList(); if (this.nodeType == Node.ELEMENT_NODE || this.nodeType == Node.DOCUMENT_NODE) { var adjacentTextNode = null; // loop through all childNodes for(var 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(var 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++) { nodeList = __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 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(var 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(var 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(var 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(var 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(var 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 __ownerDocument__ = function(node){ return (node.nodeType == Node.DOCUMENT_NODE)?node:node.ownerDocument; }; 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 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); } var 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; }; // Local Variables: // espresso-indent-level:4 // c-basic-offset:4 // tab-width:4 // End: /** * @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; /** * @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; this.location = null; }; 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; }; /** * @author thatcher */ DOMParser = function(principle, documentURI, baseURI){}; __extend__(DOMParser.prototype,{ parseFromString: function(xmlstring, mimetype){ var doc = new Document(new DOMImplementation()), e4; XML.ignoreComments = false; XML.ignoreProcessingInstructions = false; XML.ignoreWhitespace = false; 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; //console.log('converting e4x node list \n %s', e4) for(xnode in e4){ kind = xnode.nodeKind(); //console.log('treating node kind %s', kind); switch(kind){ case 'element': //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); __toDomNode__(xnode.attributes(), domnode, doc); length = xnode.children().length(); //console.log('recursing? %s', length?"yes":"no"); if(xnode.children().length()>0){ __toDomNode__(xnode.children(), domnode, doc); } break; case 'attribute': //console.log('setting attribute %s %s %s', // xnode.localName(), xnode.namespace(), xnode.text()); if(xnode.namespace() && xnode.namespace().prefix){ //console.log("%s", xnode.namespace().prefix); parent.setAttributeNS(xnode.namespace()+'', xnode.namespace().prefix+':'+xnode.localName(), xnode.text()); }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.text()); } }else{ parent.setAttribute(xnode.localName()+'', xnode.text()); } 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; } } }; /** * @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 */ })(); /* * Envjs event.1.2.0.11 * 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.0.11 * Pure JavaScript Browser Environment * By John Resig and the Envjs Team * Copyright 2008-2010 John Resig, under the MIT License */ (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; } }; })(); /** * * // Introduced in DOM Level 2: * interface DocumentEvent { * Event createEvent (in DOMString eventType) * raises (DOMException); * }; */ DocumentEvent = function(){}; DocumentEvent.prototype.createEvent = function(eventType){ //console.debug('createEvent(%s)', eventType); switch (eventType){ case 'Events': return new Event(); break; case 'HTMLEvents': return new Event(); break; case 'UIEvents': return new UIEvent(); break; case 'MouseEvents': return new MouseEvent(); break; case 'KeyEvents': return new KeyboardEvent(); break; case 'KeyboardEvent': return new KeyboardEvent(); break; case 'MutationEvents': return new MutationEvent(); break; default: throw(new DOMException(DOMException.NOT_SUPPORTED_ERR)); } }; Document.prototype.createEvent = DocumentEvent.prototype.createEvent; /** * @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]; $events[target.uuid] = null; 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; /** * @author john resig & the envjs team * @uri http://www.envjs.com/ * @copyright 2008-2010 * @license MIT */ })(); /* * Envjs timer.1.2.0.11 * 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.0.11 * Pure JavaScript Browser Environment * By John Resig and the Envjs Team * Copyright 2008-2010 John Resig, under the MIT License */ (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(fn); } 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 */ })(); /* * Envjs html.1.2.0.11 * 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, HTMLButtonElement, HTMLCanvasElement, HTMLTableColElement, HTMLModElement, HTMLDivElement, HTMLFieldSetElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement, HTMLHeadElement, HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLLabelElement, HTMLLegendElement, HTMLLinkElement, HTMLMapElement, HTMLMetaElement, HTMLObjectElement, HTMLOptGroupElement, HTMLOptionElement, HTMLParamElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement, HTMLTableElement, HTMLTableSectionElement, HTMLTableCellElement, HTMLTableRowElement, HTMLTextAreaElement, HTMLTitleElement, HTMLUnknownElement; /* * Envjs html.1.2.0.11 * Pure JavaScript Browser Environment * By John Resig and the Envjs Team * Copyright 2008-2010 John Resig, under the MIT License */ (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; this.head; this.body; }; HTMLDocument.prototype = new Document; __extend__(HTMLDocument.prototype, { createElement: function(tagName){ 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 "Q": node = new HTMLQuoteElement(this);break; case "BODY": node = new HTMLBodyElement(this);break; case "BR": node = new HTMLElement(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 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 HTMLHeadElement(this);break; case "H2": node = new HTMLHeadElement(this);break; case "H3": node = new HTMLHeadElement(this);break; case "H4": node = new HTMLHeadElement(this);break; case "H5": node = new HTMLHeadElement(this);break; case "H6": node = new HTMLHeadElement(this);break; case "HR": node = new HTMLElement(this);break; case "HTML": node = new HTMLElement(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 HTMLElement(this);break; case "LINK": node = new HTMLLinkElement(this);break; case "MAP": node = new HTMLMapElement(this);break; case "META": node = new HTMLObjectElement(this);break; case "OBJECT": node = new HTMLMapElement(this);break; case "OPTGROUP": node = new HTMLOptGroupElement(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 HTMLElement(this);break; case "SCRIPT": node = new HTMLScriptElement(this);break; case "SELECT": node = new HTMLSelectElement(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 HTMLTableCellElement(this);break; case "TH": node = new HTMLTableCellElement(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 HTMLElement(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')); }, //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){ // 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 '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; 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; }); /** * @name HTMLEvents * @w3c:domlevel 2 * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html */ 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); } }; 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); } } }; //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 */ HTMLElement = function(ownerDocument) { Element.apply(this, arguments); }; HTMLElement.prototype = new Element; //TODO: Not sure where HTMLEvents belongs in the chain // but putting it here satisfies a lowest common // denominator. __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 +">"; default: ret += "<" + name + ns + attrstring +"/>"; } } return ret; } }); /* * HTMLCollection - DOM Level 2 * Implementation Provided by Steven Wood */ HTMLCollection = function(nodelist, type){ __setArray__(this, []); for (var i=0; i= 0) && (idx < this.length)) { ret = this[idx]; } return ret; }, namedItem : function (name) { if(name in this){ return this[name]; } return null; } }; /* * 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: * * * HTMLInputCommon: common to all elements * .form * * * [common plus:] * .align * *
              * [identical to "legend" plus:] * .margin * * * **** * *