diff --git a/Makefile b/Makefile index 06cee5de..cfd2a975 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ update_submodules: # update the submodules to the latest at the most logical branch pull_submodules: - @@git submodule foreach "git pull \$$(git config remote.origin.url)" + @@git submodule foreach "git pull origin \$$(git branch --no-color --contains \$$(git rev-parse HEAD) | grep -v \( | head -1)" @@git submodule summary pull: pull_submodules diff --git a/README.md b/README.md index a54a02df..d56576c8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[jQuery](http://jquery.com/) - New Wave JavaScript +[jQuery](http://jquery.com/) - New Wave Javascript ================================================== What you need to build your own jQuery @@ -56,89 +56,6 @@ Sometimes, the various git repositories get into an inconsistent state where bui (usually this results in the jquery.js or jquery.min.js being 0 bytes). If this happens, run `make clean`, then run `make` again. -Git for dummies ---------------- - -As the source code is handled by the version control system Git, it's useful to know some features used. - -### Submodules ### - -The repository uses submodules, which normally are handled directly by the Makefile, but sometimes you want to -be able to work with them manually. - -Following are the steps to manually get the submodules: - -1. `git clone https://github.com/jquery/jquery.git` -2. `git submodule init` -3. `git submodule update` - -Or: - -1. `git clone https://github.com/jquery/jquery.git` -2. `git submodule update --init` - -Or: - -1. `git clone --recursive https://github.com/jquery/jquery.git` - -If you want to work inside a submodule, it is possible, but first you need to checkout a branch: - -1. `cd src/sizzle` -2. `git checkout master` - -After you've committed your changes to the submodule, you'll update the jquery project to point to the new commit, -but remember to push the submodule changes before pushing the new jquery commit: - -1. `cd src/sizzle` -2. `git push origin master` -3. `cd ..` -4. `git add src/sizzle` -5. `git commit` - -The makefile has some targets to simplify submodule handling: - -#### `make update_submodules` #### - -checks out the commit pointed to by jquery, but merges your local changes, if any. This target is executed -when you are doing a normal `make`. - -#### `make pull_submodules` #### - -updates the content of the submodules to what is probably the latest upstream code. - -#### `make pull` #### - -make a `make pull_submodules` and after that a `git pull`. if you have no remote tracking in your master branch, you can -execute this command as `make pull REMOTE=origin BRANCH=master` instead. - -### cleaning ### - -If you want to purge your working directory back to the status of upstream, following commands can be used (remember everything you've worked on is gone after these): - -1. `git reset --hard upstream/master` -2. `git clean -fdx` - -### rebasing ### - -For feature/topic branches, you should always used the `--rebase` flag to `git pull`, or if you are usually handling many temporary "to be in a github pull request" branches, run following to automate this: - -* `git config branch.autosetuprebase local` (see `man git-config` for more information) - -### handling merge conflicts ### - -If you're getting merge conflicts when merging, instead of editing the conflicted files manually, you can use the feature -`git mergetool`. Even though the default tool `xxdiff` looks awful/old, it's rather useful. - -Following are some commands that can be used there: - -* `Ctrl + Alt + M` - automerge as much as possible -* `b` - jump to next merge conflict -* `s` - change the order of the conflicted lines -* `u` - undo an merge -* `left mouse button` - mark a block to be the winner -* `middle mouse button` - mark a line to be the winner -* `Ctrl + S` - save -* `Ctrl + Q` - quit Questions? ---------- diff --git a/build/lib/parse-js.js b/build/lib/parse-js.js index 8edecb73..7e4fd0e2 100644 --- a/build/lib/parse-js.js +++ b/build/lib/parse-js.js @@ -182,6 +182,8 @@ var OPERATORS = array_to_hash([ ">>=", "<<=", ">>>=", + "~=", + "%=", "|=", "^=", "&=", @@ -189,7 +191,7 @@ var OPERATORS = array_to_hash([ "||" ]); -var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t\u200b")); +var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t")); var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); @@ -199,47 +201,20 @@ var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); /* -----[ Tokenizer ]----- */ -// regexps adapted from http://xregexp.com/plugins/#unicode -var UNICODE = { - letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), - non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), - space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), - connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") +function is_alphanumeric_char(ch) { + ch = ch.charCodeAt(0); + return (ch >= 48 && ch <= 57) || + (ch >= 65 && ch <= 90) || + (ch >= 97 && ch <= 122); }; -function is_letter(ch) { - return UNICODE.letter.test(ch); +function is_identifier_char(ch) { + return is_alphanumeric_char(ch) || ch == "$" || ch == "_"; }; function is_digit(ch) { ch = ch.charCodeAt(0); - return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9 -}; - -function is_alphanumeric_char(ch) { - return is_digit(ch) || is_letter(ch); -}; - -function is_unicode_combining_mark(ch) { - return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); -}; - -function is_unicode_connector_punctuation(ch) { - return UNICODE.connector_punctuation.test(ch); -}; - -function is_identifier_start(ch) { - return ch == "$" || ch == "_" || is_letter(ch); -}; - -function is_identifier_char(ch) { - return is_identifier_start(ch) - || is_unicode_combining_mark(ch) - || is_digit(ch) - || is_unicode_connector_punctuation(ch) - || ch == "\u200c" // zero-width non-joiner - || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c) - ; + return ch >= 48 && ch <= 57; }; function parse_js_number(num) { @@ -278,19 +253,18 @@ function is_token(token, type, val) { var EX_EOF = {}; -function tokenizer($TEXT) { +function tokenizer($TEXT, skip_comments) { var S = { - text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), - pos : 0, - tokpos : 0, - line : 0, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false, - comments_before : [] + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false }; function peek() { return S.text.charAt(S.pos); }; @@ -325,7 +299,7 @@ function tokenizer($TEXT) { S.tokpos = S.pos; }; - function token(type, value, is_comment) { + function token(type, value) { S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); @@ -337,10 +311,6 @@ function tokenizer($TEXT) { pos : S.tokpos, nlb : S.newline_before }; - if (!is_comment) { - ret.comments_before = S.comments_before; - S.comments_before = []; - } S.newline_before = false; return ret; }; @@ -381,7 +351,7 @@ function tokenizer($TEXT) { if (ch == "+") return after_e; after_e = false; if (ch == ".") { - if (!has_dot && !has_x) + if (!has_dot) return has_dot = true; return false; } @@ -447,7 +417,7 @@ function tokenizer($TEXT) { ret = S.text.substring(S.pos, i); S.pos = i; } - return token("comment1", ret, true); + return token("comment1", ret); }; function read_multiline_comment() { @@ -455,41 +425,14 @@ function tokenizer($TEXT) { return with_eof_error("Unterminated multiline comment", function(){ var i = find("*/", true), text = S.text.substring(S.pos, i), - tok = token("comment2", text, true); + tok = token("comment2", text); S.pos = i + 2; S.line += text.split("\n").length - 1; S.newline_before = text.indexOf("\n") >= 0; - - // https://github.com/mishoo/UglifyJS/issues/#issue/100 - if (/^@cc_on/i.test(text)) { - warn("WARNING: at line " + S.line); - warn("*** Found \"conditional comment\": " + text); - warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer."); - } - return tok; }); }; - function read_name() { - var backslash = false, name = "", ch; - while ((ch = peek()) != null) { - if (!backslash) { - if (ch == "\\") backslash = true, next(); - else if (is_identifier_char(ch)) name += next(); - else break; - } - else { - if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); - ch = read_escaped_char(); - if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); - name += ch; - backslash = false; - } - } - return name; - }; - function read_regexp() { return with_eof_error("Unterminated regular expression", function(){ var prev_backslash = false, regexp = "", ch, in_class = false; @@ -509,14 +452,15 @@ function tokenizer($TEXT) { } else { regexp += ch; } - var mods = read_name(); + var mods = read_while(function(ch){ + return HOP(REGEXP_MODIFIERS, ch); + }); return token("regexp", [ regexp, mods ]); }); }; function read_operator(prefix) { function grow(op) { - if (!peek()) return op; var bigger = op + peek(); if (HOP(OPERATORS, bigger)) { next(); @@ -528,18 +472,19 @@ function tokenizer($TEXT) { return token("operator", grow(prefix || next())); }; - function handle_slash() { + var handle_slash = skip_comments ? function() { next(); var regex_allowed = S.regex_allowed; switch (peek()) { - case "/": - S.comments_before.push(read_line_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - case "*": - S.comments_before.push(read_multiline_comment()); - S.regex_allowed = regex_allowed; - return next_token(); + case "/": read_line_comment(); S.regex_allowed = regex_allowed; return next_token(); + case "*": read_multiline_comment(); S.regex_allowed = regex_allowed; return next_token(); + } + return S.regex_allowed ? read_regexp() : read_operator("/"); + } : function() { + next(); + switch (peek()) { + case "/": return read_line_comment(); + case "*": return read_multiline_comment(); } return S.regex_allowed ? read_regexp() : read_operator("/"); }; @@ -552,7 +497,7 @@ function tokenizer($TEXT) { }; function read_word() { - var word = read_name(); + var word = read_while(is_identifier_char); return !HOP(KEYWORDS, word) ? token("name", word) : HOP(OPERATORS, word) @@ -584,7 +529,7 @@ function tokenizer($TEXT) { if (ch == ".") return handle_dot(); if (ch == "/") return handle_slash(); if (HOP(OPERATOR_CHARS, ch)) return read_operator(); - if (ch == "\\" || is_identifier_start(ch)) return read_word(); + if (is_identifier_char(ch)) return read_word(); parse_error("Unexpected character '" + ch + "'"); }; @@ -620,7 +565,7 @@ var ASSIGNMENT = (function(a, ret, i){ } return ret; })( - ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "~=", "%=", "|=", "^=", "&="], { "=": true }, 0 ); @@ -663,16 +608,16 @@ function NodeWithToken(str, start, end) { NodeWithToken.prototype.toString = function() { return this.name; }; -function parse($TEXT, exigent_mode, embed_tokens) { +function parse($TEXT, strict_mode, embed_tokens) { var S = { - input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, - token : null, - prev : null, - peeked : null, - in_function : 0, - in_loop : 0, - labels : [] + input: tokenizer($TEXT, true), + token: null, + prev: null, + peeked: null, + in_function: 0, + in_loop: 0, + labels: [] }; S.token = next(); @@ -726,7 +671,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { function expect(punc) { return expect_token("punc", punc); }; function can_insert_semicolon() { - return !exigent_mode && ( + return !strict_mode && ( S.token.nlb || is("eof") || is("punc", "}") ); }; @@ -748,20 +693,17 @@ function parse($TEXT, exigent_mode, embed_tokens) { }; function add_tokens(str, start, end) { - return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); + return new NodeWithToken(str, start, end); }; - function maybe_embed_tokens(parser) { - if (embed_tokens) return function() { - var start = S.token; - var ast = parser.apply(this, arguments); - ast[0] = add_tokens(ast[0], start, prev()); - return ast; - }; - else return parser; - }; + var statement = embed_tokens ? function() { + var start = S.token; + var stmt = $statement(); + stmt[0] = add_tokens(stmt[0], start, prev()); + return stmt; + } : $statement; - var statement = maybe_embed_tokens(function() { + function $statement() { if (is("operator", "/")) { S.peeked = null; S.token = S.input(true); // force regexp @@ -855,12 +797,12 @@ function parse($TEXT, exigent_mode, embed_tokens) { unexpected(); } } - }); + }; function labeled_statement(label) { S.labels.push(label); var start = S.token, stat = statement(); - if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) + if (strict_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) unexpected(start); S.labels.pop(); return as("label", label, stat); @@ -885,35 +827,29 @@ function parse($TEXT, exigent_mode, embed_tokens) { function for_() { expect("("); - var init = null; - if (!is("punc", ";")) { - init = is("keyword", "var") - ? (next(), var_(true)) - : expression(true, true); - if (is("operator", "in")) - return for_in(init); + var has_var = is("keyword", "var"); + if (has_var) + next(); + if (is("name") && is_token(peek(), "operator", "in")) { + // for (i in foo) + var name = S.token.value; + next(); next(); + var obj = expression(); + expect(")"); + return as("for-in", has_var, name, obj, in_loop(statement)); + } else { + // classic for + var init = is("punc", ";") ? null : has_var ? var_() : expression(); + expect(";"); + var test = is("punc", ";") ? null : expression(); + expect(";"); + var step = is("punc", ")") ? null : expression(); + expect(")"); + return as("for", init, test, step, in_loop(statement)); } - return regular_for(init); }; - function regular_for(init) { - expect(";"); - var test = is("punc", ";") ? null : expression(); - expect(";"); - var step = is("punc", ")") ? null : expression(); - expect(")"); - return as("for", init, test, step, in_loop(statement)); - }; - - function for_in(init) { - var lhs = init[0] == "var" ? as("name", init[1][0]) : init; - next(); - var obj = expression(); - expect(")"); - return as("for-in", init, lhs, obj, in_loop(statement)); - }; - - var function_ = maybe_embed_tokens(function(in_statement) { + function function_(in_statement) { var name = is("name") ? prog1(S.token.value, next) : null; if (in_statement && !name) unexpected(); @@ -941,7 +877,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { S.in_loop = loop; return a; })()); - }); + }; function if_() { var cond = parenthesised(), body = statement(), belse; @@ -1010,7 +946,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return as("try", body, bcatch, bfinally); }; - function vardefs(no_in) { + function vardefs() { var a = []; for (;;) { if (!is("name")) @@ -1019,7 +955,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { next(); if (is("operator", "=")) { next(); - a.push([ name, expression(false, no_in) ]); + a.push([ name, expression(false) ]); } else { a.push([ name ]); } @@ -1030,8 +966,8 @@ function parse($TEXT, exigent_mode, embed_tokens) { return a; }; - function var_(no_in) { - return as("var", vardefs(no_in)); + function var_() { + return as("var", vardefs()); }; function const_() { @@ -1049,7 +985,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return subscripts(as("new", newexp, args), true); }; - var expr_atom = maybe_embed_tokens(function(allow_calls) { + function expr_atom(allow_calls) { if (is("operator", "new")) { next(); return new_(); @@ -1084,32 +1020,29 @@ function parse($TEXT, exigent_mode, embed_tokens) { return subscripts(prog1(atom, next), allow_calls); } unexpected(); - }); + }; - function expr_list(closing, allow_trailing_comma, allow_empty) { + function expr_list(closing, allow_trailing_comma) { var first = true, a = []; while (!is("punc", closing)) { if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push([ "atom", "undefined" ]); - } else { - a.push(expression(false)); - } + if (allow_trailing_comma && is("punc", closing)) + break; + a.push(expression(false)); } next(); return a; }; function array_() { - return as("array", expr_list("]", !exigent_mode, true)); + return as("array", expr_list("]", !strict_mode)); }; function object_() { var first = true, a = []; while (!is("punc", "}")) { if (first) first = false; else expect(","); - if (!exigent_mode && is("punc", "}")) + if (!strict_mode && is("punc", "}")) // allow trailing comma break; var type = S.token.type; @@ -1172,68 +1105,64 @@ function parse($TEXT, exigent_mode, embed_tokens) { return as(tag, op, expr); }; - function expr_op(left, min_prec, no_in) { + function expr_op(left, min_prec) { var op = is("operator") ? S.token.value : null; - if (op && op == "in" && no_in) op = null; var prec = op != null ? PRECEDENCE[op] : null; if (prec != null && prec > min_prec) { next(); - var right = expr_op(expr_atom(true), prec, no_in); - return expr_op(as("binary", op, left, right), min_prec, no_in); + var right = expr_op(expr_atom(true), prec); + return expr_op(as("binary", op, left, right), min_prec); } return left; }; - function expr_ops(no_in) { - return expr_op(expr_atom(true), 0, no_in); + function expr_ops() { + return expr_op(expr_atom(true), 0); }; - function maybe_conditional(no_in) { - var expr = expr_ops(no_in); + function maybe_conditional() { + var expr = expr_ops(); if (is("operator", "?")) { next(); var yes = expression(false); expect(":"); - return as("conditional", expr, yes, expression(false, no_in)); + return as("conditional", expr, yes, expression(false)); } return expr; }; function is_assignable(expr) { - if (!exigent_mode) return true; switch (expr[0]) { case "dot": case "sub": - case "new": - case "call": return true; case "name": return expr[1] != "this"; } }; - function maybe_assign(no_in) { - var left = maybe_conditional(no_in), val = S.token.value; + function maybe_assign() { + var left = maybe_conditional(), val = S.token.value; if (is("operator") && HOP(ASSIGNMENT, val)) { if (is_assignable(left)) { next(); - return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); + return as("assign", ASSIGNMENT[val], left, maybe_assign()); } croak("Invalid assignment"); } return left; }; - var expression = maybe_embed_tokens(function(commas, no_in) { + function expression(commas) { if (arguments.length == 0) commas = true; - var expr = maybe_assign(no_in); + var expr = maybe_assign(); if (commas && is("punc", ",")) { next(); - return as("seq", expr, expression(true, no_in)); + return as("seq", expr, expression()); } return expr; - }); + }; function in_loop(cont) { try { @@ -1293,8 +1222,6 @@ function HOP(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; -var warn = function() {}; - /* -----[ Exports ]----- */ exports.tokenizer = tokenizer; @@ -1310,6 +1237,3 @@ exports.KEYWORDS = KEYWORDS; exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN; exports.OPERATORS = OPERATORS; exports.is_alphanumeric_char = is_alphanumeric_char; -exports.set_logger = function(logger) { - warn = logger; -}; diff --git a/build/lib/process.js b/build/lib/process.js index 3878c8d6..edcf599d 100644 --- a/build/lib/process.js +++ b/build/lib/process.js @@ -10,13 +10,14 @@ Exported functions: - - ast_mangle(ast, options) -- mangles the variable/function names - in the AST. Returns an AST. + - ast_mangle(ast, include_toplevel) -- mangles the + variable/function names in the AST. Returns an AST. Pass true + as second argument to mangle toplevel names too. - ast_squeeze(ast) -- employs various optimizations to make the final generated code even smaller. Returns an AST. - - gen_code(ast, options) -- generates JS code from the AST. Pass + - gen_code(ast, beautify) -- generates JS code from the AST. Pass true (or an object, see the code for some options) as second argument to get "pretty" (indented) code. @@ -68,137 +69,139 @@ var jsp = require("./parse-js"), function ast_walker(ast) { function _vardefs(defs) { - return [ this[0], MAP(defs, function(def){ + return MAP(defs, function(def){ var a = [ def[0] ]; if (def.length > 1) a[1] = walk(def[1]); return a; - }) ]; - }; - function _block(statements) { - var out = [ this[0] ]; - if (statements != null) - out.push(MAP(statements, walk)); - return out; + }); }; var walkers = { "string": function(str) { - return [ this[0], str ]; + return [ "string", str ]; }, "num": function(num) { - return [ this[0], num ]; + return [ "num", num ]; }, "name": function(name) { - return [ this[0], name ]; + return [ "name", name ]; }, "toplevel": function(statements) { - return [ this[0], MAP(statements, walk) ]; + return [ "toplevel", MAP(statements, walk) ]; + }, + "block": function(statements) { + var out = [ "block" ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; + }, + "var": function(defs) { + return [ "var", _vardefs(defs) ]; + }, + "const": function(defs) { + return [ "const", _vardefs(defs) ]; }, - "block": _block, - "splice": _block, - "var": _vardefs, - "const": _vardefs, "try": function(t, c, f) { return [ - this[0], + "try", MAP(t, walk), c != null ? [ c[0], MAP(c[1], walk) ] : null, f != null ? MAP(f, walk) : null ]; }, "throw": function(expr) { - return [ this[0], walk(expr) ]; + return [ "throw", walk(expr) ]; }, "new": function(ctor, args) { - return [ this[0], walk(ctor), MAP(args, walk) ]; + return [ "new", walk(ctor), MAP(args, walk) ]; }, "switch": function(expr, body) { - return [ this[0], walk(expr), MAP(body, function(branch){ + return [ "switch", walk(expr), MAP(body, function(branch){ return [ branch[0] ? walk(branch[0]) : null, MAP(branch[1], walk) ]; }) ]; }, "break": function(label) { - return [ this[0], label ]; + return [ "break", label ]; }, "continue": function(label) { - return [ this[0], label ]; + return [ "continue", label ]; }, "conditional": function(cond, t, e) { - return [ this[0], walk(cond), walk(t), walk(e) ]; + return [ "conditional", walk(cond), walk(t), walk(e) ]; }, "assign": function(op, lvalue, rvalue) { - return [ this[0], op, walk(lvalue), walk(rvalue) ]; + return [ "assign", op, walk(lvalue), walk(rvalue) ]; }, "dot": function(expr) { - return [ this[0], walk(expr) ].concat(slice(arguments, 1)); + return [ "dot", walk(expr) ].concat(slice(arguments, 1)); }, "call": function(expr, args) { - return [ this[0], walk(expr), MAP(args, walk) ]; + return [ "call", walk(expr), MAP(args, walk) ]; }, "function": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; + return [ "function", name, args.slice(), MAP(body, walk) ]; }, "defun": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; + return [ "defun", name, args.slice(), MAP(body, walk) ]; }, "if": function(conditional, t, e) { - return [ this[0], walk(conditional), walk(t), walk(e) ]; + return [ "if", walk(conditional), walk(t), walk(e) ]; }, "for": function(init, cond, step, block) { - return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; + return [ "for", walk(init), walk(cond), walk(step), walk(block) ]; }, - "for-in": function(vvar, key, hash, block) { - return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; + "for-in": function(has_var, key, hash, block) { + return [ "for-in", has_var, key, walk(hash), walk(block) ]; }, "while": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; + return [ "while", walk(cond), walk(block) ]; }, "do": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; + return [ "do", walk(cond), walk(block) ]; }, "return": function(expr) { - return [ this[0], walk(expr) ]; + return [ "return", walk(expr) ]; }, "binary": function(op, left, right) { - return [ this[0], op, walk(left), walk(right) ]; + return [ "binary", op, walk(left), walk(right) ]; }, "unary-prefix": function(op, expr) { - return [ this[0], op, walk(expr) ]; + return [ "unary-prefix", op, walk(expr) ]; }, "unary-postfix": function(op, expr) { - return [ this[0], op, walk(expr) ]; + return [ "unary-postfix", op, walk(expr) ]; }, "sub": function(expr, subscript) { - return [ this[0], walk(expr), walk(subscript) ]; + return [ "sub", walk(expr), walk(subscript) ]; }, "object": function(props) { - return [ this[0], MAP(props, function(p){ + return [ "object", MAP(props, function(p){ return p.length == 2 ? [ p[0], walk(p[1]) ] : [ p[0], walk(p[1]), p[2] ]; // get/set-ter }) ]; }, "regexp": function(rx, mods) { - return [ this[0], rx, mods ]; + return [ "regexp", rx, mods ]; }, "array": function(elements) { - return [ this[0], MAP(elements, walk) ]; + return [ "array", MAP(elements, walk) ]; }, "stat": function(stat) { - return [ this[0], walk(stat) ]; + return [ "stat", walk(stat) ]; }, "seq": function() { - return [ this[0] ].concat(MAP(slice(arguments), walk)); + return [ "seq" ].concat(MAP(slice(arguments), walk)); }, "label": function(name, block) { - return [ this[0], name, walk(block) ]; + return [ "label", name, walk(block) ]; }, "with": function(expr, block) { - return [ this[0], walk(expr), walk(block) ]; + return [ "with", walk(expr), walk(block) ]; }, "atom": function(name) { - return [ this[0], name ]; + return [ "atom", name ]; } }; @@ -257,8 +260,8 @@ function Scope(parent) { this.rev_mangled = {}; // reverse lookup (mangled => orig.name) this.cname = -1; // current mangled name this.refs = {}; // names referenced from this scope - this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes - this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes + this.uses_with = false; // will become TRUE if eval() is detected in this or any subscopes + this.uses_eval = false; // will become TRUE if with() is detected in this or any subscopes this.parent = parent; // parent scope this.children = []; // sub-scopes if (parent) { @@ -379,9 +382,7 @@ function ast_add_scope(ast) { }; function _lambda(name, args, body) { - var is_defun = this[0] == "defun"; - return [ this[0], is_defun ? define(name) : name, args, with_new_scope(function(){ - if (!is_defun) define(name); + return [ this[0], define(name), args, with_new_scope(function(){ MAP(args, define); return MAP(body, walk); })]; @@ -404,7 +405,7 @@ function ast_add_scope(ast) { }, "try": function(t, c, f) { if (c != null) return [ - this[0], + "try", MAP(t, walk), [ define(c[0]), MAP(c[1], walk) ], f != null ? MAP(f, walk) : null @@ -414,6 +415,10 @@ function ast_add_scope(ast) { if (name == "eval") having_eval.push(current_scope); reference(name); + }, + "for-in": function(has_var, name) { + if (has_var) define(name); + else reference(name); } }, function(){ return walk(ast); @@ -456,33 +461,17 @@ function ast_add_scope(ast) { /* -----[ mangle names ]----- */ -function ast_mangle(ast, options) { +function ast_mangle(ast, do_toplevel) { var w = ast_walker(), walk = w.walk, scope; - options = options || {}; function get_mangled(name, newMangle) { - if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel - if (options.except && member(name, options.except)) - return name; + if (!do_toplevel && !scope.parent) return name; // don't mangle toplevel return scope.get_mangled(name, newMangle); }; - function get_define(name) { - // we always lookup a defined symbol for the current scope FIRST, so declared - // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value - if (!scope.has(name)) { - if (HOP(options.defines, name)) { - return options.defines[name]; - } - } - return null; - }; - function _lambda(name, args, body) { - var is_defun = this[0] == "defun"; - if (is_defun && name) name = get_mangled(name); + if (name) name = get_mangled(name); body = with_scope(body.scope, function(){ - if (!is_defun && name) name = get_mangled(name); args = MAP(args, function(name){ return get_mangled(name) }); return MAP(body, walk); }); @@ -502,9 +491,9 @@ function ast_mangle(ast, options) { }; function _vardefs(defs) { - return [ this[0], MAP(defs, function(d){ + return MAP(defs, function(d){ return [ get_mangled(d[0]), walk(d[1]) ]; - }) ]; + }); }; return w.with_walkers({ @@ -521,22 +510,28 @@ function ast_mangle(ast, options) { } return ast; }, - "var": _vardefs, - "const": _vardefs, + "var": function(defs) { + return [ "var", _vardefs(defs) ]; + }, + "const": function(defs) { + return [ "const", _vardefs(defs) ]; + }, "name": function(name) { - return get_define(name) || [ this[0], get_mangled(name) ]; + return [ "name", get_mangled(name) ]; }, "try": function(t, c, f) { - return [ this[0], + return [ "try", MAP(t, walk), c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null, f != null ? MAP(f, walk) : null ]; }, "toplevel": function(body) { - var self = this; - return with_scope(self.scope, function(){ - return [ self[0], MAP(body, walk) ]; + return with_scope(this.scope, function(){ + return [ "toplevel", MAP(body, walk) ]; }); + }, + "for-in": function(has_var, name, obj, stat) { + return [ "for-in", has_var, get_mangled(name), walk(obj), walk(stat) ]; } }, function() { return walk(ast_add_scope(ast)); @@ -574,199 +569,52 @@ function aborts(t) { } }; -function boolean_expr(expr) { - return ( (expr[0] == "unary-prefix" - && member(expr[1], [ "!", "delete" ])) || - - (expr[0] == "binary" - && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) || - - (expr[0] == "binary" - && member(expr[1], [ "&&", "||" ]) - && boolean_expr(expr[2]) - && boolean_expr(expr[3])) || - - (expr[0] == "conditional" - && boolean_expr(expr[2]) - && boolean_expr(expr[3])) || - - (expr[0] == "assign" - && expr[1] === true - && boolean_expr(expr[3])) || - - (expr[0] == "seq" - && boolean_expr(expr[expr.length - 1])) - ); +function negate(c) { + var not_c = [ "unary-prefix", "!", c ]; + switch (c[0]) { + case "unary-prefix": + return c[1] == "!" ? c[2] : not_c; + case "binary": + var op = c[1], left = c[2], right = c[3]; + switch (op) { + case "<=": return [ "binary", ">", left, right ]; + case "<": return [ "binary", ">=", left, right ]; + case ">=": return [ "binary", "<", left, right ]; + case ">": return [ "binary", "<=", left, right ]; + case "==": return [ "binary", "!=", left, right ]; + case "!=": return [ "binary", "==", left, right ]; + case "===": return [ "binary", "!==", left, right ]; + case "!==": return [ "binary", "===", left, right ]; + case "&&": return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); + case "||": return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); + } + break; + } + return not_c; }; function make_conditional(c, t, e) { - var make_real_conditional = function() { if (c[0] == "unary-prefix" && c[1] == "!") { - return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; + return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; } else { - return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ]; + return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ]; } - }; - // shortcut the conditional if the expression has a constant value - return when_constant(c, function(ast, val){ - warn_unreachable(val ? e : t); - return (val ? t : e); - }, make_real_conditional); }; function empty(b) { return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); }; -function is_string(node) { - return (node[0] == "string" || - node[0] == "unary-prefix" && node[1] == "typeof" || - node[0] == "binary" && node[1] == "+" && - (is_string(node[2]) || is_string(node[3]))); -}; - -var when_constant = (function(){ - - var $NOT_CONSTANT = {}; - - // this can only evaluate constant expressions. If it finds anything - // not constant, it throws $NOT_CONSTANT. - function evaluate(expr) { - switch (expr[0]) { - case "string": - case "num": - return expr[1]; - case "name": - case "atom": - switch (expr[1]) { - case "true": return true; - case "false": return false; - } - break; - case "unary-prefix": - switch (expr[1]) { - case "!": return !evaluate(expr[2]); - case "typeof": return typeof evaluate(expr[2]); - case "~": return ~evaluate(expr[2]); - case "-": return -evaluate(expr[2]); - case "+": return +evaluate(expr[2]); - } - break; - case "binary": - var left = expr[2], right = expr[3]; - switch (expr[1]) { - case "&&" : return evaluate(left) && evaluate(right); - case "||" : return evaluate(left) || evaluate(right); - case "|" : return evaluate(left) | evaluate(right); - case "&" : return evaluate(left) & evaluate(right); - case "^" : return evaluate(left) ^ evaluate(right); - case "+" : return evaluate(left) + evaluate(right); - case "*" : return evaluate(left) * evaluate(right); - case "/" : return evaluate(left) / evaluate(right); - case "-" : return evaluate(left) - evaluate(right); - case "<<" : return evaluate(left) << evaluate(right); - case ">>" : return evaluate(left) >> evaluate(right); - case ">>>" : return evaluate(left) >>> evaluate(right); - case "==" : return evaluate(left) == evaluate(right); - case "===" : return evaluate(left) === evaluate(right); - case "!=" : return evaluate(left) != evaluate(right); - case "!==" : return evaluate(left) !== evaluate(right); - case "<" : return evaluate(left) < evaluate(right); - case "<=" : return evaluate(left) <= evaluate(right); - case ">" : return evaluate(left) > evaluate(right); - case ">=" : return evaluate(left) >= evaluate(right); - case "in" : return evaluate(left) in evaluate(right); - case "instanceof" : return evaluate(left) instanceof evaluate(right); - } - } - throw $NOT_CONSTANT; - }; - - return function(expr, yes, no) { - try { - var val = evaluate(expr), ast; - switch (typeof val) { - case "string": ast = [ "string", val ]; break; - case "number": ast = [ "num", val ]; break; - case "boolean": ast = [ "name", String(val) ]; break; - default: throw new Error("Can't handle constant of type: " + (typeof val)); - } - return yes.call(expr, ast, val); - } catch(ex) { - if (ex === $NOT_CONSTANT) { - if (expr[0] == "binary" - && (expr[1] == "===" || expr[1] == "!==") - && ((is_string(expr[2]) && is_string(expr[3])) - || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) { - expr[1] = expr[1].substr(0, 2); - } - else if (no && expr[0] == "binary" - && (expr[1] == "||" || expr[1] == "&&")) { - // the whole expression is not constant but the lval may be... - try { - var lval = evaluate(expr[2]); - expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) || - (expr[1] == "||" && (lval ? lval : expr[3])) || - expr); - } catch(ex2) { - // IGNORE... lval is not constant - } - } - return no ? no.call(expr, expr) : null; - } - else throw ex; - } - }; - -})(); - -function warn_unreachable(ast) { - if (!empty(ast)) - warn("Dropping unreachable code: " + gen_code(ast, true)); -}; - function ast_squeeze(ast, options) { options = defaults(options, { make_seqs : true, dead_code : true, - keep_comps : true, - no_warnings : false + no_warnings : false, + extra : false }); var w = ast_walker(), walk = w.walk, scope; - function negate(c) { - var not_c = [ "unary-prefix", "!", c ]; - switch (c[0]) { - case "unary-prefix": - return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c; - case "seq": - c = slice(c); - c[c.length - 1] = negate(c[c.length - 1]); - return c; - case "conditional": - return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]); - case "binary": - var op = c[1], left = c[2], right = c[3]; - if (!options.keep_comps) switch (op) { - case "<=" : return [ "binary", ">", left, right ]; - case "<" : return [ "binary", ">=", left, right ]; - case ">=" : return [ "binary", "<", left, right ]; - case ">" : return [ "binary", "<=", left, right ]; - } - switch (op) { - case "==" : return [ "binary", "!=", left, right ]; - case "!=" : return [ "binary", "==", left, right ]; - case "===" : return [ "binary", "!==", left, right ]; - case "!==" : return [ "binary", "===", left, right ]; - case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); - case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); - } - break; - } - return not_c; - }; - function with_scope(s, cont) { var _scope = scope; scope = s; @@ -776,25 +624,95 @@ function ast_squeeze(ast, options) { return ret; }; - function rmblock(block) { - if (block != null && block[0] == "block" && block[1]) { - if (block[1].length == 1) - block = block[1][0]; - else if (block[1].length == 0) - block = [ "block" ]; + function is_constant(node) { + return node[0] == "string" || node[0] == "num"; + }; + + function find_first_execute(node) { + if (!node) + return false; + + switch (node[0]) { + case "num": + case "string": + case "name": + return node; + case "call": + case "conditional": + case "for": + case "if": + case "new": + case "return": + case "stat": + case "switch": + case "throw": + return find_first_execute(node[1]); + case "binary": + return find_first_execute(node[2]); + case "assign": + if (node[1] === true) + return find_first_execute(node[3]); + break; + case "var": + if (node[1][0].length > 1) + return find_first_execute(node[1][0][1]); + break; } + return null; + } + + function find_assign_recursive(p, v) { + if (p[0] == "assign" && p[1] != true || p[0] == "unary-prefix") { + if (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1]) + return true; + return false; + } + + if (p[0] != "assign" || p[1] !== true) + return false; + + if ((is_constant(p[3]) && p[3][0] == v[0] && p[3][1] == v[1]) || + (p[3][0] == "name" && v[0] == "name" && p[3][1] == v[1]) || + (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1])) + return true; + + return find_assign_recursive(p[3], v); + }; + + function rmblock(block) { + if (block != null && block[0] == "block" && block[1] && block[1].length == 1) + block = block[1][0]; return block; }; + function clone(obj) { + if (obj && obj.constructor == Array) + return MAP(obj, clone); + return obj; + }; + + function make_seq_to_statements(node) { + if (node[0] != "seq") { + switch (node[0]) { + case "var": + case "const": + return [ node ]; + default: + return [ [ "stat", node ] ]; + } + } + + var ret = []; + for (var i = 1; i < node.length; i++) + ret.push.apply(ret, make_seq_to_statements(node[i])); + + return ret; + }; + function _lambda(name, args, body) { - var is_defun = this[0] == "defun"; - body = with_scope(body.scope, function(){ - var ret = tighten(MAP(body, walk), "lambda"); - if (!is_defun && name && !HOP(scope.refs, name)) - name = null; - return ret; - }); - return [ this[0], name, args, body ]; + return [ this[0], name, args, with_scope(body.scope, function(){ + return tighten(MAP(body, walk), "lambda"); + }) ]; }; // we get here for blocks that have been already transformed. @@ -816,6 +734,64 @@ function ast_squeeze(ast, options) { return a; }, []); + if (options.extra) { + // Detightening things. We do this because then we can assume that the + // statements are structured in a specific way. + statements = (function(a, prev) { + statements.forEach(function(cur) { + switch (cur[0]) { + case "for": + if (cur[1] != null) { + a.push.apply(a, make_seq_to_statements(cur[1])); + cur[1] = null; + } + a.push(cur); + break; + case "stat": + var stats = make_seq_to_statements(cur[1]); + stats.forEach(function(s) { + if (s[1][0] == "unary-postfix") + s[1][0] = "unary-prefix"; + }); + a.push.apply(a, stats); + break; + default: + a.push(cur); + } + }); + return a; + })([]); + + statements = (function(a, prev) { + statements.forEach(function(cur) { + if (!(prev && prev[0] == "stat")) { + a.push(cur); + prev = cur; + return; + } + + var p = prev[1]; + var c = find_first_execute(cur); + if (c && find_assign_recursive(p, c)) { + var old_cur = clone(cur); + c.splice(0, c.length); + c.push.apply(c, p); + var tmp_cur = best_of(cur, [ "toplevel", [ prev, old_cur ] ]); + if (tmp_cur == cur) { + a[a.length -1] = cur; + } else { + cur = old_cur; + a.push(cur); + } + } else { + a.push(cur); + } + prev = cur; + }); + return a; + })([]); + } + statements = (function(a, prev){ statements.forEach(function(cur){ if (prev && ((cur[0] == "var" && prev[0] == "var") || @@ -836,7 +812,7 @@ function ast_squeeze(ast, options) { a.push(st); } else if (!options.no_warnings) - warn_unreachable(st); + warn("Removing unreachable code: " + gen_code(st, true)); } else { a.push(st); @@ -859,6 +835,22 @@ function ast_squeeze(ast, options) { return a; })([]); + if (options.extra) { + statements = (function(a, prev){ + statements.forEach(function(cur){ + var replaced = false; + if (prev && cur[0] == "for" && cur[1] == null && (prev[0] == "var" || prev[0] == "const" || prev[0] == "stat")) { + cur[1] = prev; + a[a.length - 1] = cur; + } else { + a.push(cur); + } + prev = cur; + }); + return a; + })([]); + } + if (block_type == "lambda") statements = (function(i, a, stat){ while (i < statements.length) { stat = statements[i++]; @@ -882,20 +874,6 @@ function ast_squeeze(ast, options) { }; function make_if(c, t, e) { - return when_constant(c, function(ast, val){ - if (val) { - warn_unreachable(e); - return t; - } else { - warn_unreachable(t); - return e; - } - }, function() { - return make_real_if(c, t, e); - }); - }; - - function make_real_if(c, t, e) { c = walk(c); t = walk(t); e = walk(e); @@ -923,10 +901,7 @@ function ast_squeeze(ast, options) { if (empty(e) && empty(t)) return [ "stat", c ]; var ret = [ "if", c, t, e ]; - if (t[0] == "if" && empty(t[3]) && empty(e)) { - ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ])); - } - else if (t[0] == "stat") { + if (t[0] == "stat") { if (e) { if (e[0] == "stat") { ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]); @@ -936,7 +911,7 @@ function ast_squeeze(ast, options) { ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]); } } - else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) { + else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw")) { ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]); } else if (e && aborts(t)) { @@ -961,25 +936,13 @@ function ast_squeeze(ast, options) { return ret; }; - function _do_while(cond, body) { - return when_constant(cond, function(cond, val){ - if (!val) { - warn_unreachable(body); - return [ "block" ]; - } else { - return [ "for", null, null, null, walk(body) ]; - } - }); - }; - return w.with_walkers({ "sub": function(expr, subscript) { if (subscript[0] == "string") { var name = subscript[1]; - if (is_identifier(name)) + if (is_identifier(name)) { return [ "dot", walk(expr), name ]; - else if (/^[1-9][0-9]*$/.test(name) || name === "0") - return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ]; + } } }, "if": make_if, @@ -1006,11 +969,29 @@ function ast_squeeze(ast, options) { if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]); }, "binary": function(op, left, right) { - return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){ - return best_of(walk(c), this); - }, function no() { - return this; - }); + left = walk(left); + right = walk(right); + var best = [ "binary", op, left, right ]; + if (is_constant(right)) { + if (is_constant(left)) { + var val = null; + switch (op) { + case "+": val = left[1] + right[1]; break; + case "*": val = left[1] * right[1]; break; + case "/": val = left[1] / right[1]; break; + case "-": val = left[1] - right[1]; break; + case "<<": val = left[1] << right[1]; break; + case ">>": val = left[1] >> right[1]; break; + case ">>>": val = left[1] >>> right[1]; break; + } + if (val != null) { + best = best_of(best, [ typeof val == "string" ? "string" : "num", val ]); + } + } else if (left[0] == "binary" && left[1] == "+" && left[3][0] == "string") { + best = best_of(best, [ "binary", "+", left[2], [ "string", left[3][1] + right[1] ] ]); + } + } + return best; }, "conditional": function(c, t, e) { return make_conditional(walk(c), walk(t), walk(e)); @@ -1023,14 +1004,17 @@ function ast_squeeze(ast, options) { f != null ? tighten(MAP(f, walk)) : null ]; }, - "unary-prefix": function(op, expr) { - expr = walk(expr); - var ret = [ "unary-prefix", op, expr ]; - if (op == "!") - ret = best_of(ret, negate(expr)); - return when_constant(ret, function(ast, val){ - return walk(ast); // it's either true or false, so minifies to !0 or !1 - }, function() { return ret }); + "unary-prefix": function(op, cond) { + if (op == "!") { + cond = walk(cond); + if (cond[0] == "unary-prefix" && cond[1] == "!") { + var p = w.parent(); + if (p[0] == "unary-prefix" && p[1] == "!") + return cond[2]; + return [ "unary-prefix", "!", cond ]; + } + return best_of(this, negate(cond)); + } }, "name": function(name) { switch (name) { @@ -1051,9 +1035,7 @@ function ast_squeeze(ast, options) { if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { return [ "array", args ]; } - }, - "while": _do_while, - "do": _do_while + } }, function() { return walk(ast_add_scope(ast)); }); @@ -1064,7 +1046,6 @@ function ast_squeeze(ast, options) { var DOT_CALL_NO_PARENS = jsp.array_to_hash([ "name", "array", - "object", "string", "dot", "sub", @@ -1072,9 +1053,9 @@ var DOT_CALL_NO_PARENS = jsp.array_to_hash([ "regexp" ]); -function make_string(str, ascii_only) { +function make_string(str) { var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029]/g, function(s){ + str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){ switch (s) { case "\\": return "\\\\"; case "\b": return "\\b"; @@ -1082,58 +1063,34 @@ function make_string(str, ascii_only) { case "\n": return "\\n"; case "\r": return "\\r"; case "\t": return "\\t"; - case "\u2028": return "\\u2028"; - case "\u2029": return "\\u2029"; case '"': ++dq; return '"'; case "'": ++sq; return "'"; } return s; }); - if (ascii_only) str = to_ascii(str); - if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; - else return '"' + str.replace(/\x22/g, '\\"') + '"'; + if (dq > sq) { + return "'" + str.replace(/\x27/g, "\\'") + "'"; + } else { + return '"' + str.replace(/\x22/g, '\\"') + '"'; + } }; -function to_ascii(str) { - return str.replace(/[\u0080-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); - while (code.length < 4) code = "0" + code; - return "\\u" + code; - }); -}; - -var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); - -function gen_code(ast, options) { - options = defaults(options, { +function gen_code(ast, beautify) { + if (beautify) beautify = defaults(beautify, { indent_start : 0, indent_level : 4, quote_keys : false, - space_colon : false, - beautify : false, - ascii_only : false + space_colon : false }); - var beautify = !!options.beautify; var indentation = 0, newline = beautify ? "\n" : "", space = beautify ? " " : ""; - function encode_string(str) { - return make_string(str, options.ascii_only); - }; - - function make_name(name) { - name = name.toString(); - if (options.ascii_only) - name = to_ascii(name); - return name; - }; - function indent(line) { if (line == null) line = ""; if (beautify) - line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; + line = repeat_string(" ", beautify.indent_start + indentation * beautify.indent_level) + line; return line; }; @@ -1187,7 +1144,7 @@ function gen_code(ast, options) { }; function needs_parens(expr) { - if (expr[0] == "function" || expr[0] == "object") { + if (expr[0] == "function") { // dot/call on a literal function requires the // function literal itself to be parenthesized // only if it's the first "thing" in a @@ -1199,8 +1156,9 @@ function gen_code(ast, options) { var a = slice($stack), self = a.pop(), p = a.pop(); while (p) { if (p[0] == "stat") return true; - if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || - ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { + if ((p[0] == "seq" && p[1] === self) || + (p[0] == "call" && p[1] === self) || + (p[0] == "binary" && p[2] === self)) { self = p; p = a.pop(); } else { @@ -1227,26 +1185,13 @@ function gen_code(ast, options) { }; var generators = { - "string": encode_string, + "string": make_string, "num": make_num, "name": make_name, "toplevel": function(statements) { return make_block_statements(statements) .join(newline + newline); }, - "splice": function(statements) { - var parent = $stack[$stack.length - 2][0]; - if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { - // we need block brackets in this case - return make_block.apply(this, arguments); - } else { - return MAP(make_block_statements(statements, true), - function(line, i) { - // the first line is already indented - return i > 0 ? indent(line) : line; - }).join(newline); - } - }, "block": make_block, "var": function(defs) { return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; @@ -1308,10 +1253,9 @@ function gen_code(ast, options) { }, "dot": function(expr) { var out = make(expr), i = 1; - if (expr[0] == "num") { - if (!/\./.test(expr[1])) - out += "."; - } else if (needs_parens(expr)) + if (expr[0] == "num") + out += "."; + else if (needs_parens(expr)) out = "(" + out + ")"; while (i < arguments.length) out += "." + make_name(arguments[i++]); @@ -1344,11 +1288,12 @@ function gen_code(ast, options) { out.push("(" + args + ")", make(block)); return add_spaces(out); }, - "for-in": function(vvar, key, hash, block) { - return add_spaces([ "for", "(" + - (vvar ? make(vvar).replace(/;+$/, "") : make(key)), - "in", - make(hash) + ")", make(block) ]); + "for-in": function(has_var, key, hash, block) { + var out = add_spaces([ "for", "(" ]); + if (has_var) + out += "var "; + out += add_spaces([ make_name(key) + " in " + make(hash) + ")", make(block) ]); + return out; }, "while": function(condition, block) { return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); @@ -1371,8 +1316,7 @@ function gen_code(ast, options) { left = "(" + left + ")"; } if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || - rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && - !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]]) { right = "(" + right + ")"; } return add_spaces([ left, operator, right ]); @@ -1406,15 +1350,14 @@ function gen_code(ast, options) { return indent(make_function(p[0], p[1][2], p[1][3], p[2])); } var key = p[0], val = make(p[1]); - if (options.quote_keys) { - key = encode_string(key); - } else if ((typeof key == "number" || !beautify && +key + "" == key) - && parseFloat(key) >= 0) { + if (beautify && beautify.quote_keys) { + key = make_string(key); + } else if (typeof key == "number" || !beautify && +key + "" == key) { key = make_num(+key); } else if (!is_identifier(key)) { - key = encode_string(key); + key = make_string(key); } - return indent(add_spaces(beautify && options.space_colon + return indent(add_spaces(beautify && beautify.space_colon ? [ key, ":", val ] : [ key + ":", val ])); }).join("," + newline); @@ -1426,7 +1369,6 @@ function gen_code(ast, options) { "array": function(elements) { if (elements.length == 0) return "[]"; return add_spaces([ "[", add_commas(MAP(elements, function(el){ - if (!beautify && el[0] == "atom" && el[1] == "undefined") return ""; return parenthesize(el, "seq"); })), "]" ]); }, @@ -1444,6 +1386,12 @@ function gen_code(ast, options) { }, "atom": function(name) { return make_name(name); + }, + "comment1": function(text) { + return "//" + text + "\n"; + }, + "comment2": function(text) { + return "/*" + text + "*/"; } }; @@ -1487,25 +1435,21 @@ function gen_code(ast, options) { return add_spaces([ out, make_block(body) ]); }; - function make_block_statements(statements, noindent) { + function make_name(name) { + return name.toString(); + }; + + function make_block_statements(statements) { for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { var stat = statements[i]; var code = make(stat); if (code != ";") { - if (!beautify && i == last) { - if ((stat[0] == "while" && empty(stat[2])) || - (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) || - (stat[0] == "if" && empty(stat[2]) && !stat[3]) || - (stat[0] == "if" && stat[3] && empty(stat[3]))) { - code = code.replace(/;*\s*$/, ";"); - } else { - code = code.replace(/;+\s*$/, ""); - } - } + if (!beautify && i == last) + code = code.replace(/;+\s*$/, ""); a.push(code); } } - return noindent ? a : MAP(a, indent); + return MAP(a, indent); }; function make_switch_block(body) { @@ -1536,7 +1480,7 @@ function gen_code(ast, options) { function make_1vardef(def) { var name = def[0], val = def[1]; if (val != null) - name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); + name = add_spaces([ name, "=", make(val) ]); return name; }; @@ -1556,49 +1500,6 @@ function gen_code(ast, options) { return make(ast); }; -function split_lines(code, max_line_length) { - var splits = [ 0 ]; - jsp.parse(function(){ - var next_token = jsp.tokenizer(code); - var last_split = 0; - var prev_token; - function current_length(tok) { - return tok.pos - last_split; - }; - function split_here(tok) { - last_split = tok.pos; - splits.push(last_split); - }; - function custom(){ - var tok = next_token.apply(this, arguments); - out: { - if (prev_token) { - if (prev_token.type == "keyword") break out; - } - if (current_length(tok) > max_line_length) { - switch (tok.type) { - case "keyword": - case "atom": - case "name": - case "punc": - split_here(tok); - break out; - } - } - } - prev_token = tok; - return tok; - }; - custom.context = function() { - return next_token.context.apply(this, arguments); - }; - return custom; - }()); - return splits.map(function(pos, i){ - return code.substring(pos, splits[i + 1] || code.length); - }).join("\n"); -}; - /* -----[ Utilities ]----- */ function repeat_string(str, i) { @@ -1657,10 +1558,5 @@ exports.ast_mangle = ast_mangle; exports.ast_squeeze = ast_squeeze; exports.gen_code = gen_code; exports.ast_add_scope = ast_add_scope; -exports.set_logger = function(logger) { warn = logger }; -exports.make_string = make_string; -exports.split_lines = split_lines; -exports.MAP = MAP; - -// keep this last! exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; +exports.set_logger = function(logger) { warn = logger }; diff --git a/build/post-compile.js b/build/post-compile.js index 1bbeaa6f..4bcafe81 100644 --- a/build/post-compile.js +++ b/build/post-compile.js @@ -4,4 +4,4 @@ var print = require("sys").print, src = require("fs").readFileSync(process.argv[2], "utf8"); // Previously done in sed but reimplemented here due to portability issues -print( src.replace( /^(\s*\*\/)(.+)/m, "$1\n$2" ) + ";" ); +print(src.replace(/^(\s*\*\/)(.+)/m, "$1\n$2;")); diff --git a/build/release-notes.js b/build/release-notes.js deleted file mode 100644 index b112d998..00000000 --- a/build/release-notes.js +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env node -/* - * jQuery Release Note Generator - */ - -var fs = require("fs"), - http = require("http"), - tmpl = require("mustache"), - extract = /(.*?)<[^"]+"component">\s*(\S+)/g; - -var opts = { - version: "1.6.2 RC 1", - short_version: "1.6.2rc1", - final_version: "1.6.2", - categories: [] -}; - -http.request({ - host: "bugs.jquery.com", - port: 80, - method: "GET", - path: "/query?status=closed&resolution=fixed&component=!web&order=component&milestone=" + opts.final_version -}, function (res) { - var data = []; - - res.on( "data", function( chunk ) { - data.push( chunk ); - }); - - res.on( "end", function() { - var match, - file = data.join(""), - cur; - - while ( (match = extract.exec( file )) ) { - if ( "#" + match[1] !== match[2] ) { - var cat = match[3]; - - if ( !cur || cur.name !== cat ) { - cur = { name: match[3], niceName: match[3].replace(/^./, function(a){ return a.toUpperCase(); }), bugs: [] }; - opts.categories.push( cur ); - } - - cur.bugs.push({ ticket: match[1], title: match[2] }); - } - } - - buildNotes(); - }); -}).end(); - -function buildNotes() { - console.log( tmpl.to_html( fs.readFileSync("release-notes.txt", "utf8"), opts ) ); -} diff --git a/build/release-notes.txt b/build/release-notes.txt deleted file mode 100644 index 1d0ae746..00000000 --- a/build/release-notes.txt +++ /dev/null @@ -1,27 +0,0 @@ -

jQuery {{version}} Released

- -

This is a preview release of jQuery. We're releasing it so that everyone can start testing the code in their applications, making sure that there are no major problems.

- -

You can get the code from the jQuery CDN:

- -
- -

You can help us by dropping that code into your existing application and letting us know that if anything no longer works. Please file a bug and be sure to mention that you're testing against jQuery {{version}}.

- -

We want to encourage everyone from the community to try and get involved in contributing back to jQuery core. We've set up a full page of information dedicated towards becoming more involved with the team. The team is here and ready to help you help us!

- -

jQuery {{version}} Change Log

- -

The current change log of the {{version}} release.

- -{{#categories}} -

{{niceName}}

- - -{{/categories}} diff --git a/build/release.js b/build/release.js deleted file mode 100644 index 7a42f998..00000000 --- a/build/release.js +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env node -/* - * jQuery Release Management - */ - -var fs = require("fs"), - child = require("child_process"), - debug = false; - -var scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/", - cdnURL = "http://code.origin.jquery.com/", - - version = /^[\d.]+(?:(?:a|b|rc)\d+|pre)?$/, - versionFile = "version.txt", - - file = "dist/jquery.js", - minFile = "dist/jquery.min.js", - - files = { - "jquery-VER.js": file, - "jquery-VER.min.js": minFile - }, - - finalFiles = { - "jquery.js": file, - "jquery-latest.js": file, - "jquery.min.js": minFile, - "jquery-latest.min.js": minFile - }; - -exec( "git pull && git status", function( error, stdout, stderr ) { - if ( /Changes to be committed/i.test( stdout ) ) { - exit( "Please commit changed files before attemping to push a release." ); - - } else if ( /Changes not staged for commit/i.test( stdout ) ) { - exit( "Please stash files before attempting to push a release." ); - - } else { - setVersion(); - } -}); - -function setVersion() { - var oldVersion = fs.readFileSync( versionFile, "utf8" ); - - prompt( "New Version (was " + oldVersion + "): ", function( data ) { - if ( data && version.test( data ) ) { - fs.writeFileSync( versionFile, data ); - - exec( "git commit -a -m 'Tagging the " + data + " release.' && git push && " + - "git tag " + data + " && git push origin " + data, function() { - make( data ); - }); - - } else { - console.error( "Malformed version number, please try again." ); - setVersion(); - } - }); -} - -function make( newVersion ) { - exec( "make clean && make", function( error, stdout, stderr ) { - // TODO: Verify JSLint - - Object.keys( files ).forEach(function( oldName ) { - var value = files[ oldName ], name = oldName.replace( /VER/g, newVersion ); - - copy( value, name ); - - delete files[ oldName ]; - files[ name ] = value; - }); - - exec( "scp " + Object.keys( files ).join( " " ) + " " + scpURL, function() { - setNextVersion( newVersion ); - }); - }); -} - -function setNextVersion( newVersion ) { - var isFinal = false; - - if ( /(?:a|b|rc)\d+$/.test( newVersion ) ) { - newVersion = newVersion.replace( /(?:a|b|rc)\d+$/, "pre" ); - - } else if ( /^\d+\.\d+\.?(\d*)$/.test( newVersion ) ) { - newVersion = newVersion.replace( /^(\d+\.\d+\.?)(\d*)$/, function( all, pre, num ) { - return pre + (pre.charAt( pre.length - 1 ) !== "." ? "." : "") + (num ? parseFloat( num ) + 1 : 1) + "pre"; - }); - - isFinal = true; - } - - prompt( "Next Version [" + newVersion + "]: ", function( data ) { - if ( !data ) { - data = newVersion; - } - - if ( version.test( data ) ) { - fs.writeFileSync( versionFile, data ); - - exec( "git commit -a -m 'Updating the source version to " + data + "' && git push", function() { - if ( isFinal ) { - makeFinal( newVersion ); - } - }); - - } else { - console.error( "Malformed version number, please try again." ); - setNextVersion( newVersion ); - } - }); -} - -function makeFinal( newVersion ) { - var all = Object.keys( finalFiles ); - - // Copy all the files - all.forEach(function( name ) { - copy( finalFiles[ name ], name ); - }); - - // Upload files to CDN - exec( "scp " + all.join( " " ) + " " + scpURL, function() { - exec( "curl '" + cdnURL + "{" + all.join( "," ) + "}?reload'", function() { - console.log( "Done." ); - }); - }); -} - -function copy( oldFile, newFile ) { - if ( debug ) { - console.log( "Copying " + oldFile + " to " + newFile ); - - } else { - fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) ); - } -} - -function prompt( msg, callback ) { - process.stdout.write( msg ); - - process.stdin.resume(); - process.stdin.setEncoding( "utf8" ); - - process.stdin.once( "data", function( chunk ) { - process.stdin.pause(); - callback( chunk.replace( /\n*$/g, "" ) ); - }); -} - -function exec( cmd, fn ) { - if ( debug ) { - console.log( cmd ); - fn(); - - } else { - child.exec( cmd, fn ); - } -} - -function exit( msg ) { - if ( msg ) { - console.error( "\nError: " + msg ); - } - - process.exit( 1 ); -} diff --git a/build/uglify.js b/build/uglify.js index aad18e8c..943ddd80 100644 --- a/build/uglify.js +++ b/build/uglify.js @@ -1,10 +1,14 @@ #! /usr/bin/env node -// -*- js -*- +// -*- js2 -*- global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util"); -var fs = require("fs"); -var jsp = require("./lib/parse-js"), - pro = require("./lib/process"); +var fs = require("fs"), + jsp = require("./lib/parse-js"), + pro = require("./lib/process"); + +pro.set_logger(function(msg){ + sys.debug(msg); +}); var options = { ast: false, @@ -13,16 +17,13 @@ var options = { squeeze: true, make_seqs: true, dead_code: true, + beautify: false, verbose: false, show_copyright: true, out_same_file: false, - max_line_length: 32 * 1024, - unsafe: false, - reserved_names: null, - defines: { }, - codegen_options: { - ascii_only: false, - beautify: false, + extra: false, + unsafe: false, // XXX: extra & unsafe? but maybe we don't want both, so.... + beautify_options: { indent_level: 4, indent_start: 0, quote_keys: false, @@ -39,15 +40,15 @@ out: while (args.length > 0) { switch (v) { case "-b": case "--beautify": - options.codegen_options.beautify = true; + options.beautify = true; break; case "-i": case "--indent": - options.codegen_options.indent_level = args.shift(); + options.beautify_options.indent_level = args.shift(); break; case "-q": case "--quote-keys": - options.codegen_options.quote_keys = true; + options.beautify_options.quote_keys = true; break; case "-mt": case "--mangle-toplevel": @@ -85,109 +86,23 @@ out: while (args.length > 0) { case "--ast": options.ast = true; break; + case "--extra": + options.extra = true; + break; case "--unsafe": options.unsafe = true; break; - case "--max-line-len": - options.max_line_length = parseInt(args.shift(), 10); - break; - case "--reserved-names": - options.reserved_names = args.shift().split(","); - break; - case "-d": - case "--define": - var defarg = args.shift(); - try { - var defsym = function(sym) { - // KEYWORDS_ATOM doesn't include NaN or Infinity - should we check - // for them too ?? We don't check reserved words and the like as the - // define values are only substituted AFTER parsing - if (jsp.KEYWORDS_ATOM.hasOwnProperty(sym)) { - throw "Don't define values for inbuilt constant '"+sym+"'"; - } - return sym; - }, - defval = function(v) { - if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) { - return [ "string", RegExp.$1 ]; - } - else if (!isNaN(parseFloat(v))) { - return [ "num", parseFloat(v) ]; - } - else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) { - return [ "name", v ]; - } - else if (!v.match(/"/)) { - return [ "string", v ]; - } - else if (!v.match(/'/)) { - return [ "string", v ]; - } - throw "Can't understand the specified value: "+v; - }; - if (defarg.match(/^([a-z_\$][a-z_\$0-9]*)(=(.*))?$/i)) { - var sym = defsym(RegExp.$1), - val = RegExp.$2 ? defval(RegExp.$2.substr(1)) : [ 'name', 'true' ]; - options.defines[sym] = val; - } - else { - throw "The --define option expects SYMBOL[=value]"; - } - } catch(ex) { - sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n"); - process.exit(1); - } - break; - case "--define-from-module": - var defmodarg = args.shift(), - defmodule = require(defmodarg), - sym, - val; - for (sym in defmodule) { - if (defmodule.hasOwnProperty(sym)) { - options.defines[sym] = function(val) { - if (typeof val == "string") - return [ "string", val ]; - if (typeof val == "number") - return [ "num", val ]; - if (val === true) - return [ 'name', 'true' ]; - if (val === false) - return [ 'name', 'false' ]; - if (val === null) - return [ 'name', 'null' ]; - if (val === undefined) - return [ 'name', 'undefined' ]; - sys.print("ERROR: In option --define-from-module "+defmodarg+"\n"); - sys.print("ERROR: Unknown object type for: "+sym+"="+val+"\n"); - process.exit(1); - return null; - }(defmodule[sym]); - } - } - break; - case "--ascii": - options.codegen_options.ascii_only = true; - break; default: filename = v; break out; } } -if (options.verbose) { - pro.set_logger(function(msg){ - sys.debug(msg); - }); -} - -jsp.set_logger(function(msg){ - sys.debug(msg); -}); - if (filename) { fs.readFile(filename, "utf8", function(err, text){ - if (err) throw err; + if (err) { + throw err; + } output(squeeze_it(text)); }); } else { @@ -216,9 +131,7 @@ function output(text) { }); } out.write(text); - if (options.output !== true) { - out.end(); - } + out.end(); }; // --------- main ends here. @@ -239,35 +152,36 @@ function show_copyright(comments) { function squeeze_it(code) { var result = ""; if (options.show_copyright) { - var tok = jsp.tokenizer(code), c; + var initial_comments = []; + // keep first comment + var tok = jsp.tokenizer(code, false), c; c = tok(); - result += show_copyright(c.comments_before); + var prev = null; + while (/^comment/.test(c.type) && (!prev || prev == c.type)) { + initial_comments.push(c); + prev = c.type; + c = tok(); + } + result += show_copyright(initial_comments); } try { var ast = time_it("parse", function(){ return jsp.parse(code); }); - if (options.mangle) ast = time_it("mangle", function(){ - return pro.ast_mangle(ast, { - toplevel: options.mangle_toplevel, - defines: options.defines, - except: options.reserved_names + if (options.mangle) + ast = time_it("mangle", function(){ return pro.ast_mangle(ast, options.mangle_toplevel); }); + if (options.squeeze) + ast = time_it("squeeze", function(){ + ast = pro.ast_squeeze(ast, { + make_seqs : options.make_seqs, + dead_code : options.dead_code, + extra : options.extra + }); + if (options.unsafe) + ast = pro.ast_squeeze_more(ast); + return ast; }); - }); - if (options.squeeze) ast = time_it("squeeze", function(){ - ast = pro.ast_squeeze(ast, { - make_seqs : options.make_seqs, - dead_code : options.dead_code, - keep_comps : !options.unsafe - }); - if (options.unsafe) - ast = pro.ast_squeeze_more(ast); - return ast; - }); if (options.ast) return sys.inspect(ast, null, null); - result += time_it("generate", function(){ return pro.gen_code(ast, options.codegen_options) }); - if (!options.codegen_options.beautify && options.max_line_length) { - result = time_it("split", function(){ return pro.split_lines(result, options.max_line_length) }); - } + result += time_it("generate", function(){ return pro.gen_code(ast, options.beautify && options.beautify_options) }); return result; } catch(ex) { sys.debug(ex.stack); diff --git a/src/ajax.js b/src/ajax.js index 355fd7e4..d94abd6f 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -5,9 +5,9 @@ var r20 = /%20/g, rCRLF = /\r?\n/g, rhash = /#.*$/, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rquery = /\?/, @@ -15,6 +15,10 @@ var r20 = /%20/g, rselectTextarea = /^(?:select|textarea)/i, rspacesAjax = /\s+/, rts = /([?&])_=[^&]*/, + rucHeaders = /(^|\-)([a-z])/g, + rucHeadersFunc = function( _, $1, $2 ) { + return $1 + $2.toUpperCase(); + }, rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, // Keep a copy of the old load method @@ -45,9 +49,9 @@ var r20 = /%20/g, ajaxLocParts; // #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set +// a field from document.location if document.domain has been set try { - ajaxLocation = location.href; + ajaxLocation = document.location.href; } catch( e ) { // Use the href attribute of an A element // since IE will modify it given document.location @@ -95,7 +99,7 @@ function addToPrefiltersOrTransports( structure ) { }; } -// Base inspection function for prefilters and transports +//Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, dataType /* internal */, inspected /* internal */ ) { @@ -244,7 +248,7 @@ jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".sp jQuery.fn[ o ] = function( f ){ return this.bind( o, f ); }; -}); +} ); jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { @@ -263,7 +267,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { dataType: type }); }; -}); +} ); jQuery.extend({ @@ -389,7 +393,6 @@ jQuery.extend({ ifModifiedKey, // Headers (they are sent all at once) requestHeaders = {}, - requestHeadersNames = {}, // Response headers responseHeadersString, responseHeaders, @@ -413,9 +416,7 @@ jQuery.extend({ // Caches the header setRequestHeader: function( name, value ) { if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; + requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value; } return this; }, @@ -644,8 +645,6 @@ jQuery.extend({ // If data is available, append data to url if ( s.data ) { s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; } // Get ifModifiedKey before adding the anti-cache parameter @@ -665,27 +664,24 @@ jQuery.extend({ // Set the correct header, if data is being sent if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); + requestHeaders[ "Content-Type" ] = s.contentType; } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { ifModifiedKey = ifModifiedKey || s.url; if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); + requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ]; } if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); + requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ]; } } // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : - s.accepts[ "*" ] - ); + requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : + s.accepts[ "*" ]; // Check for headers option for ( i in s.headers ) { @@ -729,7 +725,7 @@ jQuery.extend({ transport.send( requestHeaders, done ); } catch (e) { // Propagate exception as error if not done - if ( state < 2 ) { + if ( status < 2 ) { done( -1, e ); // Simply rethrow otherwise } else { @@ -761,7 +757,7 @@ jQuery.extend({ // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); - }); + } ); } else { // If traditional, encode the "old" way (the way 1.3.2 or older @@ -777,7 +773,7 @@ jQuery.extend({ }); function buildParams( prefix, obj, traditional, add ) { - if ( jQuery.isArray( obj ) ) { + if ( jQuery.isArray( obj ) && obj.length ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { @@ -797,9 +793,16 @@ function buildParams( prefix, obj, traditional, add ) { }); } else if ( !traditional && obj != null && typeof obj === "object" ) { + // If we see an array here, it is empty and should be treated as an empty + // object + if ( jQuery.isArray( obj ) || jQuery.isEmptyObject( obj ) ) { + add( prefix, "" ); + // Serialize object item. - for ( var name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } else { + for ( var name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } } } else { diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js index 6b0f95d5..c70aeb7d 100644 --- a/src/ajax/jsonp.js +++ b/src/ajax/jsonp.js @@ -14,12 +14,13 @@ jQuery.ajaxSetup({ // Detect, normalize options and install callbacks for jsonp requests jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - var inspectData = s.contentType === "application/x-www-form-urlencoded" && - ( typeof s.data === "string" ); + var dataIsString = ( typeof s.data === "string" ); if ( s.dataTypes[ 0 ] === "jsonp" || + originalSettings.jsonpCallback || + originalSettings.jsonp != null || s.jsonp !== false && ( jsre.test( s.url ) || - inspectData && jsre.test( s.data ) ) ) { + dataIsString && jsre.test( s.data ) ) ) { var responseContainer, jsonpCallback = s.jsonpCallback = @@ -27,12 +28,20 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { previous = window[ jsonpCallback ], url = s.url, data = s.data, - replace = "$1" + jsonpCallback + "$2"; + replace = "$1" + jsonpCallback + "$2", + cleanUp = function() { + // Set callback back to previous value + window[ jsonpCallback ] = previous; + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( previous ) ) { + window[ jsonpCallback ]( responseContainer[ 0 ] ); + } + }; if ( s.jsonp !== false ) { url = url.replace( jsre, replace ); if ( s.url === url ) { - if ( inspectData ) { + if ( dataIsString ) { data = data.replace( jsre, replace ); } if ( s.data === data ) { @@ -50,15 +59,8 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { responseContainer = [ response ]; }; - // Clean-up function - jqXHR.always(function() { - // Set callback back to previous value - window[ jsonpCallback ] = previous; - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( previous ) ) { - window[ jsonpCallback ]( responseContainer[ 0 ] ); - } - }); + // Install cleanUp function + jqXHR.then( cleanUp, cleanUp ); // Use data converter to retrieve json after script execution s.converters["script json"] = function() { @@ -74,6 +76,6 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { // Delegate to script return "script"; } -}); +} ); })( jQuery ); diff --git a/src/ajax/script.js b/src/ajax/script.js index f7a91801..34ddd046 100644 --- a/src/ajax/script.js +++ b/src/ajax/script.js @@ -25,7 +25,7 @@ jQuery.ajaxPrefilter( "script", function( s ) { s.type = "GET"; s.global = false; } -}); +} ); // Bind script tag hack transport jQuery.ajaxTransport( "script", function(s) { @@ -53,7 +53,7 @@ jQuery.ajaxTransport( "script", function(s) { // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) { // Handle memory leak in IE script.onload = script.onreadystatechange = null; @@ -84,6 +84,6 @@ jQuery.ajaxTransport( "script", function(s) { } }; } -}); +} ); })( jQuery ); diff --git a/src/ajax/xhr.js b/src/ajax/xhr.js index a87c3239..5dbc33d3 100644 --- a/src/ajax/xhr.js +++ b/src/ajax/xhr.js @@ -1,14 +1,21 @@ (function( jQuery ) { -var // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { +var // #5280: next active xhr id and list of active xhrs' callbacks + xhrId = jQuery.now(), + xhrCallbacks, + + // XHR used to determine supports properties + testXHR; + +// #5280: Internet Explorer will keep connections alive if we don't abort on unload +function xhrOnUnloadAbort() { + jQuery( window ).unload(function() { // Abort all pending requests for ( var key in xhrCallbacks ) { xhrCallbacks[ key ]( 0, 1 ); } - } : false, - xhrId = 0, - xhrCallbacks; + }); +} // Functions to create xhrs function createStandardXHR() { @@ -38,13 +45,15 @@ jQuery.ajaxSettings.xhr = window.ActiveXObject ? // For all other browsers, use the standard XMLHttpRequest object createStandardXHR; -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); +// Test if we can create an xhr object +testXHR = jQuery.ajaxSettings.xhr(); +jQuery.support.ajax = !!testXHR; + +// Does this browser support crossDomain XHR requests +jQuery.support.cors = testXHR && ( "withCredentials" in testXHR ); + +// No need for the temporary xhr anymore +testXHR = undefined; // Create transport if the browser can provide an xhr if ( jQuery.support.ajax ) { @@ -127,9 +136,7 @@ if ( jQuery.support.ajax ) { // Do not keep as active anymore if ( handle ) { xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } + delete xhrCallbacks[ handle ]; } // If it's an abort @@ -190,18 +197,15 @@ if ( jQuery.support.ajax ) { if ( !s.async || xhr.readyState === 4 ) { callback(); } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + xhrOnUnloadAbort(); } - xhr.onreadystatechange = callback; + // Add to list of active xhrs callbacks + handle = xhrId++; + xhr.onreadystatechange = xhrCallbacks[ handle ] = callback; } }, diff --git a/src/attributes.js b/src/attributes.js index 1e0e79f4..59972105 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -1,67 +1,66 @@ (function( jQuery ) { var rclass = /[\n\t\r]/g, - rspace = /\s+/, + rspaces = /\s+/, rreturn = /\r/g, + rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - rinvalidChar = /\:|^on/, - formHook, boolHook; + rradiocheck = /^(?:radio|checkbox)$/i; + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.prop ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } }); }, addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); }); } if ( value && typeof value === "string" ) { - classNames = value.split( rspace ); + var classNames = (value || "").split( rspaces ); - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { + if ( !elem.className ) { elem.className = value; } else { - setClass = " " + elem.className + " "; + var className = " " + elem.className + " ", + setClass = elem.className; - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; } } elem.className = jQuery.trim( setClass ); @@ -74,25 +73,24 @@ jQuery.fn.extend({ }, removeClass: function( value ) { - var classNames, i, l, elem, className, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); }); } if ( (value && typeof value === "string") || value === undefined ) { - classNames = (value || "").split( rspace ); + var classNames = (value || "").split( rspaces ); - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { - className = (" " + elem.className + " ").replace( rclass, " " ); - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[ c ] + " ", " "); + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); } elem.className = jQuery.trim( className ); @@ -111,8 +109,9 @@ jQuery.fn.extend({ isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); }); } @@ -123,7 +122,7 @@ jQuery.fn.extend({ i = 0, self = jQuery( this ), state = stateVal, - classNames = value.split( rspace ); + classNames = value.split( rspaces ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list @@ -155,42 +154,82 @@ jQuery.fn.extend({ }, val: function( value ) { - var hooks, ret, - elem = this[0]; - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + var elem = this[0]; - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; } - ret = elem.value; + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; } return undefined; } - var isFunction = jQuery.isFunction( value ); + var isFunction = jQuery.isFunction(value); - return this.each(function( i ) { - var self = jQuery(this), val; + return this.each(function(i) { + var self = jQuery(this), val = value; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; + val = value.call(this, i, self.val()); } // Treat null/undefined as ""; convert numbers to string @@ -198,16 +237,27 @@ jQuery.fn.extend({ val = ""; } else if ( typeof val === "number" ) { val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { + } else if ( jQuery.isArray(val) ) { + val = jQuery.map(val, function (value) { return value == null ? "" : value + ""; }); } - hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { this.value = val; } }); @@ -215,72 +265,6 @@ jQuery.fn.extend({ }); jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - attrFn: { val: true, css: true, @@ -291,340 +275,115 @@ jQuery.extend({ height: true, offset: true }, - - attrFix: { - // Always normalize to ensure hook usage - tabindex: "tabIndex" - }, - + attr: function( elem, name, value, pass ) { - var nType = elem.nodeType; - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { - return jQuery( elem )[ name ]( value ); + return jQuery(elem)[name](value); } - // Fallback to prop when attributes are not supported - if ( !("getAttribute" in elem) ) { - return jQuery.prop( elem, name, value ); - } + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; - var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; - // Normalize the name if needed - if ( notxml ) { - name = jQuery.attrFix[ name ] || name; - - hooks = jQuery.attrHooks[ name ]; - - if ( !hooks ) { - // Use boolHook for boolean attributes - if ( rboolean.test( name ) ) { - - hooks = boolHook; - - // Use formHook for forms and if the name contains certain characters - } else if ( formHook && name !== "className" && - (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { - - hooks = formHook; - } - } - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return undefined; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, name ) { - var propName; + // Only do all the following if this is a node (faster for style) if ( elem.nodeType === 1 ) { - name = jQuery.attrFix[ name ] || name; - - if ( jQuery.support.getSetAttribute ) { - // Use removeAttribute in browsers that support it - elem.removeAttribute( name ); - } else { - jQuery.attr( elem, name, "" ); - elem.removeAttributeNode( elem.getAttributeNode( name ) ); - } + // These attributes require special treatment + var special = rspecialurl.test( name ); - // Set corresponding property to false for boolean attributes - if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { - elem[ propName ] = false; - } - } - }, + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; } - return value; } } - }, - tabIndex: { - get: function( elem ) { + + // If applicable, access the attribute via the DOM 0 way + // 'in' checks fail in Blackberry 4.7 #6931 + if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + if ( value === null ) { + if ( elem.nodeType === 1 ) { + elem.removeAttribute( name ); + } + + } else { + elem[ name ] = value; + } + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabIndex"); + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - }, - // Use the value property for back compat - // Use the formHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( formHook && jQuery.nodeName( elem, "button" ) ) { - return formHook.get( elem, name ); + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( formHook && jQuery.nodeName( elem, "button" ) ) { - return formHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return (elem[ name ] = value); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { - return ret; - - } else { return elem[ name ]; } - } - }, - - propHooks: {} -}); -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - return jQuery.prop( elem, name ) ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; } - elem.setAttribute( name, name.toLowerCase() ); + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + // Ensure that missing attributes return undefined + // Blackberry 4.7 returns "" from getAttribute #6938 + if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + return undefined; + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; } - return name; + // Handle everything which isn't a DOM element node + if ( set ) { + elem[ name ] = value; + } + return elem[ name ]; } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !jQuery.support.getSetAttribute ) { - - // propFix is more comprehensive and contains all fixes - jQuery.attrFix = jQuery.propFix; - - // Use this for any attribute on a form in IE6/7 - formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - // Return undefined if nodeValue is empty string - return ret && ret.nodeValue !== "" ? - ret.nodeValue : - undefined; - }, - set: function( elem, value, name ) { - // Check form objects in IE (multiple bugs related) - // Only use nodeValue if the attribute node exists on the form - var ret = elem.getAttributeNode( name ); - if ( ret ) { - ret.nodeValue = value; - return value; - } - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return (elem.style.cssText = "" + value); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }); -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); - } - } - }); }); })( jQuery ); diff --git a/src/core.js b/src/core.js index ab0d9f7b..9312ee28 100644 --- a/src/core.js +++ b/src/core.js @@ -17,7 +17,7 @@ var jQuery = function( selector, context ) { // A simple way to check for HTML strings or ID strings // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, @@ -44,14 +44,6 @@ var jQuery = function( selector, context ) { rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, - // Matches dashed string for camelizing - rdashAlpha = /-([a-z])/ig, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }, - // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, @@ -96,7 +88,7 @@ jQuery.fn = jQuery.prototype = { if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; - this.selector = selector; + this.selector = "body"; this.length = 1; return this; } @@ -104,13 +96,7 @@ jQuery.fn = jQuery.prototype = { // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = quickExpr.exec( selector ); - } + match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { @@ -367,11 +353,9 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } + window.$ = _$; - if ( deep && window.jQuery === jQuery ) { + if ( deep ) { window.jQuery = _jQuery; } @@ -385,19 +369,15 @@ jQuery.extend({ // the ready event fires. See #6781 readyWait: 1, - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - // Handle when the DOM is ready ready: function( wait ) { - // Either a released hold or an DOMready/load event and not yet ready - if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // A third-party is pushing the ready event forwards + if ( wait === true ) { + jQuery.readyWait--; + } + + // Make sure that the DOM is not already loaded + if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); @@ -447,7 +427,7 @@ jQuery.extend({ } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); + document.attachEvent("onreadystatechange", DOMContentLoaded); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); @@ -535,21 +515,20 @@ jQuery.extend({ // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { + if ( rvalidchars.test(data.replace(rvalidescape, "@") + .replace(rvalidtokens, "]") + .replace(rvalidbraces, "")) ) { - return (new Function( "return " + data ))(); + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + } else { + jQuery.error( "Invalid JSON: " + data ); } - jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing @@ -576,24 +555,25 @@ jQuery.extend({ noop: function() {}, - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + // Evalulates a script in a global context globalEval: function( data ) { - if ( data && rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, + script = document.createElement( "script" ); - // Converts a dashed string to camelCased string; - // Used by both the css and data modules - camelCase: function( string ) { - return string.replace( rdashAlpha, fcamelCase ); + if ( jQuery.support.scriptEval() ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } }, nodeName: function( elem, name ) { @@ -604,7 +584,7 @@ jQuery.extend({ each: function( object, callback, args ) { var name, i = 0, length = object.length, - isObj = length === undefined || jQuery.isFunction( object ); + isObj = length === undefined || jQuery.isFunction(object); if ( args ) { if ( isObj ) { @@ -630,11 +610,8 @@ jQuery.extend({ } } } else { - for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { - break; - } - } + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} } } @@ -665,7 +642,7 @@ jQuery.extend({ // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type( array ); + var type = jQuery.type(array); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); @@ -678,9 +655,8 @@ jQuery.extend({ }, inArray: function( elem, array ) { - - if ( indexOf ) { - return indexOf.call( array, elem ); + if ( array.indexOf ) { + return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { @@ -730,30 +706,15 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var value, key, ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + var ret = [], value; // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } + if ( value != null ) { + ret[ ret.length ] = value; } } @@ -764,35 +725,36 @@ jQuery.extend({ // A global GUID counter for objects guid: 1, - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - if ( typeof context === "string" ) { - var tmp = fn[ context ]; - context = fn; - fn = tmp; + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } } - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - var args = slice.call( arguments, 2 ), + if ( !proxy && fn ) { proxy = function() { - return fn.apply( context, args.concat( slice.call( arguments ) ) ); + return fn.apply( thisObject || this, arguments ); }; + } // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + // So proxy can be declared as an argument return proxy; }, // Mutifunctional method to get and set values to a collection - // The value/s can optionally be executed if it's a function + // The value/s can be optionally by executed if its a function access: function( elems, key, value, exec, fn, pass ) { var length = elems.length; @@ -839,24 +801,24 @@ jQuery.extend({ }, sub: function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); + function jQuerySubclass( selector, context ) { + return new jQuerySubclass.fn.init( selector, context ); } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); + jQuery.extend( true, jQuerySubclass, this ); + jQuerySubclass.superclass = this; + jQuerySubclass.fn = jQuerySubclass.prototype = this(); + jQuerySubclass.fn.constructor = jQuerySubclass; + jQuerySubclass.subclass = this.subclass; + jQuerySubclass.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { + context = jQuerySubclass(context); } - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; + jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; + var rootjQuerySubclass = jQuerySubclass(document); + return jQuerySubclass; }, browser: {} @@ -878,6 +840,12 @@ if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; @@ -923,6 +891,7 @@ function doScrollCheck() { jQuery.ready(); } +// Expose jQuery to the global object return jQuery; })(); diff --git a/src/css.js b/src/css.js index cb7df9f8..17ac136b 100644 --- a/src/css.js +++ b/src/css.js @@ -2,12 +2,11 @@ var ralpha = /alpha\([^)]*\)/i, ropacity = /opacity=([^)]*)/, + rdashAlpha = /-([a-z])/ig, // fixed for IE9, see #8346 rupper = /([A-Z]|^ms)/g, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/, - rrelNum = /^[+\-]=/, - rrelNumFilter = /[^+\-\.\de]+/g, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -15,7 +14,11 @@ var ralpha = /alpha\([^)]*\)/i, curCSS, getComputedStyle, - currentStyle; + currentStyle, + + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; jQuery.fn.css = function( name, value ) { // Setting 'undefined' is a no-op @@ -50,14 +53,11 @@ jQuery.extend({ // Exclude the following css properties to add px cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, "zIndex": true, - "zoom": true + "fontWeight": true, + "opacity": true, + "zoom": true, + "lineHeight": true }, // Add in properties whose names you wish to fix before @@ -75,29 +75,20 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, type, origName = jQuery.camelCase( name ), + var ret, origName = jQuery.camelCase( name ), style = elem.style, hooks = jQuery.cssHooks[ origName ]; name = jQuery.cssProps[ origName ] || origName; // Check if we're setting a value if ( value !== undefined ) { - type = typeof value; - // Make sure that NaN and null values aren't set. See: #7116 - if ( type === "number" && isNaN( value ) || value == null ) { + if ( typeof value === "number" && isNaN( value ) || value == null ) { return; } - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && rrelNum.test( value ) ) { - value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } @@ -122,17 +113,11 @@ jQuery.extend({ }, css: function( elem, name, extra ) { - var ret, hooks; - // Make sure that we're working with the right name - name = jQuery.camelCase( name ); - hooks = jQuery.cssHooks[ name ]; - name = jQuery.cssProps[ name ] || name; + var ret, origName = jQuery.camelCase( name ), + hooks = jQuery.cssHooks[ origName ]; - // cssFloat needs a special treatment - if ( name === "cssFloat" ) { - name = "float"; - } + name = jQuery.cssProps[ origName ] || origName; // If a hook was provided get the computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) { @@ -140,7 +125,7 @@ jQuery.extend({ // Otherwise, if a way to get the computed value exists, use that } else if ( curCSS ) { - return curCSS( elem, name ); + return curCSS( elem, name, origName ); } }, @@ -160,6 +145,10 @@ jQuery.extend({ for ( name in options ) { elem.style[ name ] = old[ name ]; } + }, + + camelCase: function( string ) { + return string.replace( rdashAlpha, fcamelCase ); } }); @@ -173,21 +162,44 @@ jQuery.each(["height", "width"], function( i, name ) { if ( computed ) { if ( elem.offsetWidth !== 0 ) { - return getWH( elem, name, extra ); + val = getWH( elem, name, extra ); + } else { jQuery.swap( elem, cssShow, function() { val = getWH( elem, name, extra ); }); } - return val; + if ( val <= 0 ) { + val = curCSS( elem, name, name ); + + if ( val === "0px" && currentStyle ) { + val = currentStyle( elem, name, name ); + } + + if ( val != null ) { + // Should return "auto" instead of 0, use 0 for + // temporary backwards-compat + return val === "" || val === "auto" ? "0px" : val; + } + } + + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + + // Should return "auto" instead of 0, use 0 for + // temporary backwards-compat + return val === "" || val === "auto" ? "0px" : val; + } + + return typeof val === "string" ? val : val + "px"; } }, set: function( elem, value ) { if ( rnumpx.test( value ) ) { // ignore negative width and height values #1599 - value = parseFloat( value ); + value = parseFloat(value); if ( value >= 0 ) { return value + "px"; @@ -204,28 +216,27 @@ if ( !jQuery.support.opacity ) { jQuery.cssHooks.opacity = { get: function( elem, computed ) { // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( parseFloat( RegExp.$1 ) / 100 ) + "" : + return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ? + (parseFloat(RegExp.$1) / 100) + "" : computed ? "1" : ""; }, set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle; + var style = elem.style; // IE has trouble with opacity if it does not have layout // Force it by setting the zoom level style.zoom = 1; // Set the alpha filter to set the opacity - var opacity = jQuery.isNaN( value ) ? + var opacity = jQuery.isNaN(value) ? "" : "alpha(opacity=" + value * 100 + ")", - filter = currentStyle && currentStyle.filter || style.filter || ""; + filter = style.filter || ""; - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; + style.filter = ralpha.test(filter) ? + filter.replace(ralpha, opacity) : + style.filter + ' ' + opacity; } }; } @@ -253,7 +264,7 @@ jQuery(function() { }); if ( document.defaultView && document.defaultView.getComputedStyle ) { - getComputedStyle = function( elem, name ) { + getComputedStyle = function( elem, newName, name ) { var ret, defaultView, computedStyle; name = name.replace( rupper, "-$1" ).toLowerCase(); @@ -310,50 +321,27 @@ if ( document.documentElement.currentStyle ) { curCSS = getComputedStyle || currentStyle; function getWH( elem, name, extra ) { + var which = name === "width" ? cssWidth : cssHeight, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight; - // Start with offset property - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - which = name === "width" ? cssWidth : cssHeight; + if ( extra === "border" ) { + return val; + } - if ( val > 0 ) { - if ( extra !== "border" ) { - jQuery.each( which, function() { - if ( !extra ) { - val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; - } - if ( extra === "margin" ) { - val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; - } else { - val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; - } - }); + jQuery.each( which, function() { + if ( !extra ) { + val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0; } - return val + "px"; - } + if ( extra === "margin" ) { + val += parseFloat(jQuery.css( elem, "margin" + this )) || 0; - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ] || 0; - } - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; + } else { + val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0; + } + }); - // Add padding, border, margin - if ( extra ) { - jQuery.each( which, function() { - val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; - if ( extra !== "padding" ) { - val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( extra === "margin" ) { - val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; - } - }); - } - - return val + "px"; + return val; } if ( jQuery.expr && jQuery.expr.filters ) { diff --git a/src/data.js b/src/data.js index f69d9dec..2d53a710 100644 --- a/src/data.js +++ b/src/data.js @@ -1,7 +1,6 @@ (function( jQuery ) { -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([a-z])([A-Z])/g; +var rbrace = /^(?:\{.*\}|\[.*\])$/; jQuery.extend({ cache: {}, @@ -98,7 +97,7 @@ jQuery.extend({ } if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; + thisCache[ name ] = data; } // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should @@ -108,10 +107,7 @@ jQuery.extend({ return thisCache[ internalKey ] && thisCache[ internalKey ].events; } - return getByName ? - // Check for both converted-to-camel and non-converted data property names - thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] : - thisCache; + return getByName ? thisCache[ name ] : thisCache; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { @@ -227,13 +223,12 @@ jQuery.fn.extend({ data = jQuery.data( this[0] ); if ( this[0].nodeType === 1 ) { - var attr = this[0].attributes, name; + var attr = this[0].attributes, name; for ( var i = 0, l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - + name = name.substr( 5 ); dataAttr( this[0], name, data[ name ] ); } } @@ -287,9 +282,7 @@ function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { - var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); - - data = elem.getAttribute( name ); + data = elem.getAttribute( "data-" + key ); if ( typeof data === "string" ) { try { diff --git a/src/deferred.js b/src/deferred.js index e543f151..90f9c808 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -1,7 +1,7 @@ (function( jQuery ) { var // Promise methods - promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + promiseMethods = "then done fail isResolved isRejected promise".split( " " ), // Static reference to slice sliceDeferred = [].slice; @@ -100,37 +100,10 @@ jQuery.extend({ deferred.done( doneCallbacks ).fail( failCallbacks ); return this; }, - always: function() { - return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); - }, fail: failDeferred.done, rejectWith: failDeferred.resolveWith, reject: failDeferred.resolve, isRejected: failDeferred.isResolved, - pipe: function( fnDone, fnFail ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); - } - }); - }).promise(); - }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { @@ -146,7 +119,7 @@ jQuery.extend({ } return obj; } - }); + } ); // Make sure only one callback list will be used deferred.done( failDeferred.cancel ).fail( deferred.cancel ); // Unexpose cancel @@ -196,4 +169,4 @@ jQuery.extend({ } }); -})( jQuery ); \ No newline at end of file +})( jQuery ); diff --git a/src/dimensions.js b/src/dimensions.js index 88fa1750..e2d411dd 100644 --- a/src/dimensions.js +++ b/src/dimensions.js @@ -1,23 +1,21 @@ (function( jQuery ) { -// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods +// Create innerHeight, innerWidth, outerHeight and outerWidth methods jQuery.each([ "Height", "Width" ], function( i, name ) { var type = name.toLowerCase(); // innerHeight and innerWidth - jQuery.fn[ "inner" + name ] = function() { - var elem = this[0]; - return elem && elem.style ? - parseFloat( jQuery.css( elem, type, "padding" ) ) : + jQuery.fn["inner" + name] = function() { + return this[0] ? + parseFloat( jQuery.css( this[0], type, "padding" ) ) : null; }; // outerHeight and outerWidth - jQuery.fn[ "outer" + name ] = function( margin ) { - var elem = this[0]; - return elem && elem.style ? - parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) : + jQuery.fn["outer" + name] = function( margin ) { + return this[0] ? + parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) : null; }; diff --git a/src/effects.js b/src/effects.js index a7529a0f..d9e9a8b3 100644 --- a/src/effects.js +++ b/src/effects.js @@ -1,7 +1,6 @@ (function( jQuery ) { var elemdisplay = {}, - iframe, iframeDoc, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, timerId, @@ -12,11 +11,7 @@ var elemdisplay = {}, [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], // opacity animations [ "opacity" ] - ], - fxNow, - requestAnimationFrame = window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame; + ]; jQuery.fn.extend({ show: function( speed, easing, callback ) { @@ -28,22 +23,19 @@ jQuery.fn.extend({ } else { for ( var i = 0, j = this.length; i < j; i++ ) { elem = this[i]; + display = elem.style.display; - if ( elem.style ) { - display = elem.style.display; + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { + display = elem.style.display = ""; + } - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { - display = elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { - jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); - } + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { + jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); } } @@ -51,13 +43,10 @@ jQuery.fn.extend({ // to avoid the constant reflow for ( i = 0; i < j; i++ ) { elem = this[i]; + display = elem.style.display; - if ( elem.style ) { - display = elem.style.display; - - if ( display === "" || display === "none" ) { - elem.style.display = jQuery._data(elem, "olddisplay") || ""; - } + if ( display === "" || display === "none" ) { + elem.style.display = jQuery._data(elem, "olddisplay") || ""; } } @@ -71,21 +60,17 @@ jQuery.fn.extend({ } else { for ( var i = 0, j = this.length; i < j; i++ ) { - if ( this[i].style ) { - var display = jQuery.css( this[i], "display" ); + var display = jQuery.css( this[i], "display" ); - if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { - jQuery._data( this[i], "olddisplay", display ); - } + if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { + jQuery._data( this[i], "olddisplay", display ); } } // Set the display of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - if ( this[i].style ) { - this[i].style.display = "none"; - } + this[i].style.display = "none"; } return this; @@ -123,54 +108,32 @@ jQuery.fn.extend({ var optall = jQuery.speed(speed, easing, callback); if ( jQuery.isEmptyObject( prop ) ) { - return this.each( optall.complete, [ false ] ); + return this.each( optall.complete ); } - // Do not change referenced properties as per-property easing will be lost - prop = jQuery.extend( {}, prop ); - return this[ optall.queue === false ? "each" : "queue" ](function() { // XXX 'this' does not always have a nodeName when running the // test suite - if ( optall.queue === false ) { - jQuery._mark( this ); - } - - var opt = jQuery.extend( {}, optall ), + var opt = jQuery.extend({}, optall), p, isElement = this.nodeType === 1, hidden = isElement && jQuery(this).is(":hidden"), - name, val, p, - display, e, - parts, start, end, unit; - - // will store per property easing and be used to determine when an animation is complete - opt.animatedProperties = {}; + self = this; for ( p in prop ) { + var name = jQuery.camelCase( p ); - // property name normalization - name = jQuery.camelCase( p ); if ( p !== name ) { prop[ name ] = prop[ p ]; delete prop[ p ]; + p = name; } - val = prop[ name ]; - - // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) - if ( jQuery.isArray( val ) ) { - opt.animatedProperties[ name ] = val[ 1 ]; - val = prop[ name ] = val[ 0 ]; - } else { - opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; + if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) { + return opt.complete.call(this); } - if ( val === "hide" && hidden || val === "show" && !hidden ) { - return opt.complete.call( this ); - } - - if ( isElement && ( name === "height" || name === "width" ) ) { + if ( isElement && ( p === "height" || p === "width" ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE does not // change the overflow attribute when overflowX and @@ -186,7 +149,7 @@ jQuery.fn.extend({ this.style.display = "inline-block"; } else { - display = defaultDisplay( this.nodeName ); + var display = defaultDisplay(this.nodeName); // inline-level elements accept inline-block; // block-level elements need to be inline with layout @@ -200,37 +163,44 @@ jQuery.fn.extend({ } } } + + if ( jQuery.isArray( prop[p] ) ) { + // Create (if needed) and add to specialEasing + (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1]; + prop[p] = prop[p][0]; + } } if ( opt.overflow != null ) { this.style.overflow = "hidden"; } - for ( p in prop ) { - e = new jQuery.fx( this, opt, p ); - val = prop[ p ]; + opt.curAnim = jQuery.extend({}, prop); + + jQuery.each( prop, function( name, val ) { + var e = new jQuery.fx( self, opt, name ); if ( rfxtypes.test(val) ) { - e[ val === "toggle" ? hidden ? "show" : "hide" : val ](); + e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop ); } else { - parts = rfxnum.exec( val ); - start = e.cur(); + var parts = rfxnum.exec(val), + start = e.cur(); if ( parts ) { - end = parseFloat( parts[2] ); - unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); + var end = parseFloat( parts[2] ), + unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" ) { - jQuery.style( this, p, (end || 1) + unit); + jQuery.style( self, name, (end || 1) + unit); start = ((end || 1) / e.cur()) * start; - jQuery.style( this, p, start + unit); + jQuery.style( self, name, start + unit); } // If a +=/-= token was provided, we're doing a relative animation if ( parts[1] ) { - end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; + end = ((parts[1] === "-=" ? -1 : 1) * end) + start; } e.custom( start, end, unit ); @@ -239,7 +209,7 @@ jQuery.fn.extend({ e.custom( start, val, "" ); } } - } + }); // For JS strict compliance return true; @@ -247,18 +217,15 @@ jQuery.fn.extend({ }, stop: function( clearQueue, gotoEnd ) { + var timers = jQuery.timers; + if ( clearQueue ) { this.queue([]); } this.each(function() { - var timers = jQuery.timers, - i = timers.length; - // clear marker counters if we know they won't be - if ( !gotoEnd ) { - jQuery._unmark( true, this ); - } - while ( i-- ) { + // go in reverse order so anything added to the queue during the loop is ignored + for ( var i = timers.length - 1; i >= 0; i-- ) { if ( timers[i].elem === this ) { if (gotoEnd) { // force the next step to be the last @@ -280,17 +247,6 @@ jQuery.fn.extend({ }); -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout( clearFxNow, 0 ); - return ( fxNow = jQuery.now() ); -} - -function clearFxNow() { - fxNow = undefined; -} - -// Generate parameters to create a standard animation function genFx( type, num ) { var obj = {}; @@ -329,16 +285,13 @@ jQuery.extend({ // Queueing opt.old = opt.complete; - opt.complete = function( noUnmark ) { + opt.complete = function() { + if ( opt.queue !== false ) { + jQuery(this).dequeue(); + } if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } - - if ( opt.queue !== false ) { - jQuery.dequeue( this ); - } else if ( noUnmark !== false ) { - jQuery._unmark( this ); - } }; return opt; @@ -360,7 +313,9 @@ jQuery.extend({ this.elem = elem; this.prop = prop; - options.orig = options.orig || {}; + if ( !options.orig ) { + options.orig = {}; + } } }); @@ -392,10 +347,9 @@ jQuery.fx.prototype = { // Start an animation from one number to another custom: function( from, to, unit ) { var self = this, - fx = jQuery.fx, - raf; + fx = jQuery.fx; - this.startTime = fxNow || createFxNow(); + this.startTime = jQuery.now(); this.start = from; this.end = to; this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); @@ -409,20 +363,7 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - // Use requestAnimationFrame instead of setInterval if available - if ( requestAnimationFrame ) { - timerId = true; - raf = function() { - // When timerId gets set to null at any point, this stops - if ( timerId ) { - requestAnimationFrame( raf ); - fx.tick(); - } - }; - requestAnimationFrame( raf ); - } else { - timerId = setInterval( fx.tick, fx.interval ); - } + timerId = setInterval(fx.tick, fx.interval); } }, @@ -453,64 +394,60 @@ jQuery.fx.prototype = { // Each step of an animation step: function( gotoEnd ) { - var t = fxNow || createFxNow(), - done = true, - elem = this.elem, - options = this.options, - i, n; + var t = jQuery.now(), done = true; - if ( gotoEnd || t >= options.duration + this.startTime ) { + if ( gotoEnd || t >= this.options.duration + this.startTime ) { this.now = this.end; this.pos = this.state = 1; this.update(); - options.animatedProperties[ this.prop ] = true; + this.options.curAnim[ this.prop ] = true; - for ( i in options.animatedProperties ) { - if ( options.animatedProperties[i] !== true ) { + for ( var i in this.options.curAnim ) { + if ( this.options.curAnim[i] !== true ) { done = false; } } if ( done ) { // Reset the overflow - if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { + if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { + var elem = this.elem, + options = this.options; jQuery.each( [ "", "X", "Y" ], function (index, value) { elem.style[ "overflow" + value ] = options.overflow[index]; - }); + } ); } // Hide the element if the "hide" operation was done - if ( options.hide ) { - jQuery(elem).hide(); + if ( this.options.hide ) { + jQuery(this.elem).hide(); } // Reset the properties, if the item has been hidden or shown - if ( options.hide || options.show ) { - for ( var p in options.animatedProperties ) { - jQuery.style( elem, p, options.orig[p] ); + if ( this.options.hide || this.options.show ) { + for ( var p in this.options.curAnim ) { + jQuery.style( this.elem, p, this.options.orig[p] ); } } // Execute the complete function - options.complete.call( elem ); + this.options.complete.call( this.elem ); } return false; } else { - // classical easing cannot be used with an Infinity duration - if ( options.duration == Infinity ) { - this.now = t; - } else { - n = t - this.startTime; - this.state = n / options.duration; + var n = t - this.startTime; + this.state = n / this.options.duration; + + // Perform the easing function, defaults to swing + var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop]; + var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear"); + this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration); + this.now = this.start + ((this.end - this.start) * this.pos); - // Perform the easing function, defaults to swing - this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration ); - this.now = this.start + ((this.end - this.start) * this.pos); - } // Perform the next step of the animation this.update(); } @@ -521,7 +458,9 @@ jQuery.fx.prototype = { jQuery.extend( jQuery.fx, { tick: function() { - for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) { + var timers = jQuery.timers; + + for ( var i = 0; i < timers.length; i++ ) { if ( !timers[i]() ) { timers.splice(i--, 1); } @@ -569,47 +508,17 @@ if ( jQuery.expr && jQuery.expr.filters ) { }; } -// Try to restore the default display value of an element function defaultDisplay( nodeName ) { - if ( !elemdisplay[ nodeName ] ) { - - var body = document.body, - elem = jQuery( "<" + nodeName + ">" ).appendTo( body ), - display = elem.css( "display" ); + var elem = jQuery("<" + nodeName + ">").appendTo("body"), + display = elem.css("display"); elem.remove(); - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe if ( display === "none" || display === "" ) { - // No iframe to use yet, so create it - if ( !iframe ) { - iframe = document.createElement( "iframe" ); - iframe.frameBorder = iframe.width = iframe.height = 0; - } - - body.appendChild( iframe ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "" : "" ) + "" ); - iframeDoc.close(); - } - - elem = iframeDoc.createElement( nodeName ); - - iframeDoc.body.appendChild( elem ); - - display = jQuery.css( elem, "display" ); - - body.removeChild( iframe ); + display = "block"; } - // Store the correct default display elemdisplay[ nodeName ] = display; } diff --git a/src/event.js b/src/event.js index 131739b1..bc2cf76e 100644 --- a/src/event.js +++ b/src/event.js @@ -3,7 +3,7 @@ var rnamespaces = /\.(.*)$/, rformElems = /^(?:textarea|input|select)$/i, rperiod = /\./g, - rspaces = / /g, + rspace = / /g, rescape = /[^\w\s.|`]/g, fcleanup = function( nm ) { return nm.replace(rescape, "\\$&"); @@ -23,6 +23,17 @@ jQuery.event = { return; } + // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) + // Minor release fix for bug #8018 + try { + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + } + catch ( e ) {} + if ( handler === false ) { handler = returnFalse; } else if ( !handler ) { @@ -60,9 +71,9 @@ jQuery.event = { if ( !eventHandle ) { elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; }; @@ -132,7 +143,7 @@ jQuery.event = { // Add the function to the element's handler list handlers.push( handleObj ); - // Keep track of which events have been used, for event optimization + // Keep track of which events have been used, for global triggering jQuery.event.global[ type ] = true; } @@ -265,185 +276,182 @@ jQuery.event = { } } }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - trigger: function( event, data, elem, onlyHandlers ) { + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { // Event object or event type var type = event.type || event, - namespaces = [], - exclusive; + bubbling = arguments[3]; - if ( type.indexOf("!") >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.exclusive = exclusive; - event.namespace = namespaces.join("."); - event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); - - // triggerHandler() and global events don't bubble or run the default action - if ( onlyHandlers || !elem ) { - event.preventDefault(); - event.stopPropagation(); - } - - // Handle a global trigger - if ( !elem ) { - // TODO: Stop taunting the data cache; remove global events and always attach to document - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + // XXX This code smells terrible. event.js should not be directly + // inspecting the data cache + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); } - }); - return; - } - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - event.target = elem; - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - var cur = elem, - // IE doesn't like method names with a colon (#3533, #8272) - ontype = type.indexOf(":") < 0 ? "on" + type : ""; - - // Fire event on the current element, then bubble up the DOM tree - do { - var handle = jQuery._data( cur, "handle" ); - - event.currentTarget = cur; - if ( handle ) { - handle.apply( cur, data ); } - // Trigger an inline bound script - if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { - event.result = false; - event.preventDefault(); + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; } - // Bubble up to document, then to window - cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; - } while ( cur && !event.isPropagationStopped() ); + // Clean up in case it is reused + event.result = undefined; + event.target = elem; - // If nobody prevented the default action, do it now - if ( !event.isDefaultPrevented() ) { + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery._data( elem, "handle" ); + + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + event.preventDefault(); + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (inlineError) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { var old, - special = jQuery.event.special[ type ] || {}; + target = event.target, + targetType = type.replace( rnamespaces, "" ), + isClick = jQuery.nodeName( target, "a" ) && targetType === "click", + special = jQuery.event.special[ targetType ] || {}; - if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction)() check here because IE6/7 fails that test. - // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. try { - if ( ontype && elem[ type ] ) { - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; + if ( target[ targetType ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + targetType ]; if ( old ) { - elem[ ontype ] = null; + target[ "on" + targetType ] = null; } - jQuery.event.triggered = type; - elem[ type ](); + jQuery.event.triggered = event.type; + target[ targetType ](); } - } catch ( ieError ) {} + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (triggerError) {} if ( old ) { - elem[ ontype ] = old; + target[ "on" + targetType ] = old; } jQuery.event.triggered = undefined; } } - - return event.result; }, handle: function( event ) { - event = jQuery.event.fix( event || window.event ); - // Snapshot the handlers list since a called handler may add/remove events. - var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), - run_all = !event.exclusive && !event.namespace, - args = Array.prototype.slice.call( arguments, 0 ); + var all, handlers, namespaces, namespace_re, events, + namespace_sort = [], + args = jQuery.makeArray( arguments ); - // Use the fix-ed Event rather than the (read-only) native event - args[0] = event; + event = args[0] = jQuery.event.fix( event || window.event ); event.currentTarget = this; - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; - // Triggered event must 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event. - if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace_sort = namespaces.slice(0).sort(); + namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + } - var ret = handleObj.handler.apply( this, args ); + event.namespace = event.namespace || namespace_sort.join("."); - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); + events = jQuery._data(this, "events"); + + handlers = (events || {})[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } } - } - if ( event.isImmediatePropagationStopped() ) { - break; + if ( event.isImmediatePropagationStopped() ) { + break; + } } } } + return event.result; }, @@ -482,9 +490,8 @@ jQuery.event = { // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { - var eventDocument = event.target.ownerDocument || document, - doc = eventDocument.documentElement, - body = eventDocument.body; + var doc = document.documentElement, + body = document.body; event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); @@ -563,10 +570,10 @@ jQuery.removeEvent = document.removeEventListener ? } }; -jQuery.Event = function( src, props ) { +jQuery.Event = function( src ) { // Allow instantiation without the 'new' keyword if ( !this.preventDefault ) { - return new jQuery.Event( src, props ); + return new jQuery.Event( src ); } // Event object @@ -584,11 +591,6 @@ jQuery.Event = function( src, props ) { this.type = src; } - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - // timeStamp is buggy for some events on Firefox(#3843) // So we won't rely on the native value this.timeStamp = jQuery.now(); @@ -650,27 +652,33 @@ jQuery.Event.prototype = { // Checks if an event happened on an element within another element // Used in jQuery.event.special.mouseenter and mouseleave handlers var withinElement = function( event ) { - // Check if mouse(over|out) are still within the same parent element - var related = event.relatedTarget, - inside = false, - eventType = event.type; + var parent = event.relatedTarget; - event.type = event.data; + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { - if ( related !== this ) { - - if ( related ) { - inside = jQuery.contains( this, related ); + // Chrome does something similar, the parentNode property + // can be accessed but is null. + if ( parent && parent !== document && !parent.parentNode ) { + return; + } + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; } - if ( !inside ) { + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + // handle event if we actually just moused on to a non sub-element jQuery.event.handle.apply( this, arguments ); - - event.type = eventType; } - } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } }, // In case of event delegation, we only need to rename the event.type, @@ -700,7 +708,7 @@ if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function( data, namespaces ) { - if ( !jQuery.nodeName( this, "form" ) ) { + if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { jQuery.event.add(this, "click.specialSubmit", function( e ) { var elem = e.target, type = elem.type; @@ -749,7 +757,7 @@ if ( !jQuery.support.changeBubbles ) { }).join("-") : ""; - } else if ( jQuery.nodeName( elem, "select" ) ) { + } else if ( elem.nodeName.toLowerCase() === "select" ) { val = elem.selectedIndex; } @@ -789,9 +797,9 @@ if ( !jQuery.support.changeBubbles ) { beforedeactivate: testChange, click: function( e ) { - var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + var elem = e.target, type = elem.type; - if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { testChange.call( this, e ); } }, @@ -799,9 +807,9 @@ if ( !jQuery.support.changeBubbles ) { // Change has to be called before submit // Keydown will be called before keypress, which is used in submit-event delegation keydown: function( e ) { - var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + var elem = e.target, type = elem.type; - if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || type === "select-multiple" ) { testChange.call( this, e ); @@ -858,12 +866,12 @@ function trigger( type, elem, args ) { } // Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { +if ( document.addEventListener ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - + // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0; - + jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { @@ -893,8 +901,6 @@ if ( !jQuery.support.focusinBubbles ) { jQuery.each(["bind", "one"], function( i, name ) { jQuery.fn[ name ] = function( type, data, fn ) { - var handler; - // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { @@ -903,20 +909,15 @@ jQuery.each(["bind", "one"], function( i, name ) { return this; } - if ( arguments.length === 2 || data === false ) { + if ( jQuery.isFunction( data ) || data === false ) { fn = data; data = undefined; } - if ( name === "one" ) { - handler = function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }; - handler.guid = fn.guid || jQuery.guid++; - } else { - handler = fn; - } + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; if ( type === "unload" && name !== "one" ) { this.one( type, data, fn ); @@ -954,7 +955,7 @@ jQuery.fn.extend({ undelegate: function( selector, types, fn ) { if ( arguments.length === 0 ) { - return this.unbind( "live" ); + return this.unbind( "live" ); } else { return this.die( types, null, fn, selector ); @@ -969,34 +970,35 @@ jQuery.fn.extend({ triggerHandler: function( type, data ) { if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; + i = 1; // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; while ( i < args.length ) { - args[ i++ ].guid = guid; + jQuery.proxy( fn, args[ i++ ] ); } - return this.click( toggler ); + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); }, hover: function( fnOver, fnOut ) { @@ -1025,16 +1027,8 @@ jQuery.each(["live", "die"], function( i, name ) { return this; } - if ( name === "die" && !types && - origSelector && origSelector.charAt(0) === "." ) { - - context.unbind( origSelector ); - - return this; - } - - if ( data === false || jQuery.isFunction( data ) ) { - fn = data || returnFalse; + if ( jQuery.isFunction( data ) ) { + fn = data; data = undefined; } @@ -1056,7 +1050,7 @@ jQuery.each(["live", "die"], function( i, name ) { preType = type; - if ( liveMap[ type ] ) { + if ( type === "focus" || type === "blur" ) { types.push( liveMap[ type ] + namespaces ); type = type + namespaces; @@ -1127,11 +1121,6 @@ function liveHandler( event ) { if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { event.type = handleObj.preType; related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - - // Make sure not to accidentally match a child element with the same selector - if ( related && jQuery.contains( elem, related ) ) { - related = elem; - } } if ( !related || related !== elem ) { @@ -1170,7 +1159,7 @@ function liveHandler( event ) { } function liveConvert( type, selector ) { - return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); } jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + @@ -1195,4 +1184,3 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl }); })( jQuery ); - diff --git a/src/intro.js b/src/intro.js index a81c86f9..c0a5643f 100644 --- a/src/intro.js +++ b/src/intro.js @@ -16,6 +16,4 @@ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) -var document = window.document, - navigator = window.navigator, - location = window.location; +var document = window.document; diff --git a/src/manipulation.js b/src/manipulation.js index 439b9596..27f81cc2 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -9,8 +9,6 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rnocache = /<(?:script|object|embed|option|style)/i, // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*", "" ], legend: [ 1, "
", "
" ], @@ -71,7 +69,7 @@ jQuery.fn.extend({ } return elem; - }).append( this ); + }).append(this); } return this; @@ -379,27 +377,21 @@ function cloneCopyEvent( src, dest ) { } } -function cloneFixAttributes( src, dest ) { - var nodeName; - +function cloneFixAttributes(src, dest) { // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } + var nodeName = dest.nodeName.toLowerCase(); + // clearAttributes removes the attributes, which we don't want, // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } + dest.clearAttributes(); // mergeAttributes, in contrast, only merges back on the // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); + dest.mergeAttributes(src); // IE6-8 fail to clone children inside object elements that use // the proprietary classid attribute value (rather than the type @@ -438,21 +430,8 @@ function cloneFixAttributes( src, dest ) { } jQuery.buildFragment = function( args, nodes, scripts ) { - var fragment, cacheable, cacheresults, doc; - - // nodes may contain either an explicit document object, - // a jQuery collection or context object. - // If nodes[0] contains a valid object to assign to doc - if ( nodes && nodes[0] ) { - doc = nodes[0].ownerDocument || nodes[0]; - } - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( !doc.createDocumentFragment ) { - doc = document; - } + var fragment, cacheable, cacheresults, + doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document); // Only cache "small" (1/2 KB) HTML strings that are associated with the main document // Cloning options loses the selected state, so don't cache them @@ -462,10 +441,11 @@ jQuery.buildFragment = function( args, nodes, scripts ) { args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) { cacheable = true; - cacheresults = jQuery.fragments[ args[0] ]; - if ( cacheresults && cacheresults !== 1 ) { - fragment = cacheresults; + if ( cacheresults ) { + if ( cacheresults !== 1 ) { + fragment = cacheresults; + } } } @@ -514,7 +494,7 @@ jQuery.each({ function getAll( elem ) { if ( "getElementsByTagName" in elem ) { return elem.getElementsByTagName( "*" ); - + } else if ( "querySelectorAll" in elem ) { return elem.querySelectorAll( "*" ); @@ -523,21 +503,6 @@ function getAll( elem ) { } } -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( elem.type === "checkbox" || elem.type === "radio" ) { - elem.defaultChecked = elem.checked; - } -} -// Finds all inputs and passes them to fixDefaultChecked -function findInputs( elem ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( "getElementsByTagName" in elem ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } -} - jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { var clone = elem.cloneNode(true), @@ -582,15 +547,10 @@ jQuery.extend({ } } - srcElements = destElements = null; - // Return the cloned set return clone; - }, - +}, clean: function( elems, context, fragment, scripts ) { - var checkScriptType; - context = context || document; // !context.createElement fails in IE with an error but returns typeof 'object' @@ -598,7 +558,7 @@ jQuery.extend({ context = context.ownerDocument || context[0] && context[0].ownerDocument || document; } - var ret = [], j; + var ret = []; for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { if ( typeof elem === "number" ) { @@ -610,67 +570,54 @@ jQuery.extend({ } // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); + if ( typeof elem === "string" && !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); - // Trim whitespace, otherwise indexOf won't work as expected - var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), - wrap = wrapMap[ tag ] || wrapMap._default, - depth = wrap[0], - div = context.createElement("div"); + } else if ( typeof elem === "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); - // Go to html and back, then peel off extra wrappers - div.innerHTML = wrap[1] + elem + wrap[2]; + // Trim whitespace, otherwise indexOf won't work as expected + var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), + wrap = wrapMap[ tag ] || wrapMap._default, + depth = wrap[0], + div = context.createElement("div"); - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + elem + wrap[2]; - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } - // String was a , *may* have spurious - var hasBody = rtbody.test(elem), - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { - // String was a bare or - wrap[1] === "
" && !hasBody ? - div.childNodes : - []; + // String was a
, *may* have spurious + var hasBody = rtbody.test(elem), + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; + + for ( var j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); } } - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; } - } - // Resets defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - var len; - if ( !jQuery.support.appendChecked ) { - if ( elem[0] && typeof (len = elem.length) === "number" ) { - for ( j = 0; j < len; j++ ) { - findInputs( elem[j] ); - } - } else { - findInputs( elem ); + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); } + + elem = div.childNodes; } if ( elem.nodeType ) { @@ -681,18 +628,13 @@ jQuery.extend({ } if ( fragment ) { - checkScriptType = function( elem ) { - return !elem.type || rscriptType.test( elem.type ); - }; for ( i = 0; ret[i]; i++ ) { if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); } else { if ( ret[i].nodeType === 1 ) { - var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); - - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); + ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) ); } fragment.appendChild( ret[i] ); } @@ -754,7 +696,7 @@ function evalScript( i, elem ) { dataType: "script" }); } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) ); + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); } if ( elem.parentNode ) { @@ -762,4 +704,4 @@ function evalScript( i, elem ) { } } -})( jQuery ); \ No newline at end of file +})( jQuery ); diff --git a/src/offset.js b/src/offset.js index 31f2503a..a0cd7a15 100644 --- a/src/offset.js +++ b/src/offset.js @@ -180,19 +180,17 @@ jQuery.offset = { curOffset = curElem.offset(), curCSSTop = jQuery.css( elem, "top" ), curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, + calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1, props = {}, curPosition = {}, curTop, curLeft; // need to be able to calculate position if either top or left is auto and position is either absolute or fixed if ( calculatePosition ) { curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; } + curTop = calculatePosition ? curPosition.top : parseInt( curCSSTop, 10 ) || 0; + curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0; + if ( jQuery.isFunction( options ) ) { options = options.call( elem, i, curOffset ); } @@ -261,16 +259,29 @@ jQuery.fn.extend({ jQuery.each( ["Left", "Top"], function( i, name ) { var method = "scroll" + name; - jQuery.fn[ method ] = function( val ) { - var elem, win; + jQuery.fn[ method ] = function(val) { + var elem = this[0], win; - if ( val === undefined ) { - elem = this[ 0 ]; + if ( !elem ) { + return null; + } - if ( !elem ) { - return null; - } + if ( val !== undefined ) { + // Set the scroll offset + return this.each(function() { + win = getWindow( this ); + if ( win ) { + win.scrollTo( + !i ? val : jQuery(win).scrollLeft(), + i ? val : jQuery(win).scrollTop() + ); + + } else { + this[ method ] = val; + } + }); + } else { win = getWindow( elem ); // Return the scroll offset @@ -279,21 +290,6 @@ jQuery.each( ["Left", "Top"], function( i, name ) { win.document.body[ method ] : elem[ method ]; } - - // Set the scroll offset - return this.each(function() { - win = getWindow( this ); - - if ( win ) { - win.scrollTo( - !i ? val : jQuery( win ).scrollLeft(), - i ? val : jQuery( win ).scrollTop() - ); - - } else { - this[ method ] = val; - } - }); }; }); diff --git a/src/outro.js b/src/outro.js index b49305e7..32b0d087 100644 --- a/src/outro.js +++ b/src/outro.js @@ -1,3 +1,2 @@ -// Expose jQuery to the global object window.jQuery = window.$ = jQuery; })(window); diff --git a/src/queue.js b/src/queue.js index 66383c19..9e3e2fb5 100644 --- a/src/queue.js +++ b/src/queue.js @@ -1,75 +1,34 @@ (function( jQuery ) { -function handleQueueMarkDefer( elem, type, src ) { - var deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - defer = jQuery.data( elem, deferDataKey, undefined, true ); - if ( defer && - ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && - ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { - // Give room for hard-coded callbacks to fire first - // and eventually mark/queue something else on the element - setTimeout( function() { - if ( !jQuery.data( elem, queueDataKey, undefined, true ) && - !jQuery.data( elem, markDataKey, undefined, true ) ) { - jQuery.removeData( elem, deferDataKey, true ); - defer.resolve(); - } - }, 0 ); - } -} - jQuery.extend({ - - _mark: function( elem, type ) { - if ( elem ) { - type = (type || "fx") + "mark"; - jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); - } - }, - - _unmark: function( force, elem, type ) { - if ( force !== true ) { - type = elem; - elem = force; - force = false; - } - if ( elem ) { - type = type || "fx"; - var key = type + "mark", - count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); - if ( count ) { - jQuery.data( elem, key, count, true ); - } else { - jQuery.removeData( elem, key, true ); - handleQueueMarkDefer( elem, type, "mark" ); - } - } - }, - queue: function( elem, type, data ) { - if ( elem ) { - type = (type || "fx") + "queue"; - var q = jQuery.data( elem, type, undefined, true ); - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !q || jQuery.isArray(data) ) { - q = jQuery.data( elem, type, jQuery.makeArray(data), true ); - } else { - q.push( data ); - } - } + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { return q || []; } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - defer; + fn = queue.shift(); // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { @@ -90,7 +49,6 @@ jQuery.extend({ if ( !queue.length ) { jQuery.removeData( elem, type + "queue", true ); - handleQueueMarkDefer( elem, type, "queue" ); } } }); @@ -105,7 +63,7 @@ jQuery.fn.extend({ if ( data === undefined ) { return jQuery.queue( this[0], type ); } - return this.each(function() { + return this.each(function( i ) { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { @@ -118,6 +76,7 @@ jQuery.fn.extend({ jQuery.dequeue( this, type ); }); }, + // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { @@ -131,41 +90,9 @@ jQuery.fn.extend({ }, time ); }); }, + clearQueue: function( type ) { return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, object ) { - if ( typeof type !== "string" ) { - object = type; - type = undefined; - } - type = type || "fx"; - var defer = jQuery.Deferred(), - elements = this, - i = elements.length, - count = 1, - deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - tmp; - function resolve() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - } - while( i-- ) { - if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || - ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || - jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && - jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { - count++; - tmp.done( resolve ); - } - } - resolve(); - return defer.promise(); } }); diff --git a/src/sizzle b/src/sizzle index 3ba396e4..f12b9309 160000 --- a/src/sizzle +++ b/src/sizzle @@ -1 +1 @@ -Subproject commit 3ba396e439a07c2a2facafbe07cdaa1b80a24c00 +Subproject commit f12b9309269ba7e705a99efe099f86ed1fe98d58 diff --git a/src/support.js b/src/support.js index 882b84a2..4c309562 100644 --- a/src/support.js +++ b/src/support.js @@ -1,63 +1,44 @@ (function( jQuery ) { -jQuery.support = (function() { +(function() { - var div = document.createElement( "div" ), - documentElement = document.documentElement, - all, - a, - select, - opt, - input, - marginDiv, - support, - fragment, - body, - testElementParent, - testElement, - testElementStyle, - tds, - events, - eventName, - i, - isSupported; + jQuery.support = {}; - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
a"; + var div = document.createElement("div"); - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0], + select = document.createElement("select"), + opt = select.appendChild( document.createElement("option") ), + input = div.getElementsByTagName("input")[0]; // Can't get basic test support if ( !all || !all.length || !a ) { - return {}; + return; } - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { + jQuery.support = { // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), + leadingWhitespace: div.firstChild.nodeType === 3, // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables - tbody: !div.getElementsByTagName( "tbody" ).length, + tbody: !div.getElementsByTagName("tbody").length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName( "link" ).length, + htmlSerialize: !!div.getElementsByTagName("link").length, // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), + hrefNormalized: a.getAttribute("href") === "/a", // Make sure that element opacity exists // (IE uses filter instead) @@ -71,186 +52,182 @@ jQuery.support = (function() { // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), + checkOn: input.value === "on", // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, deleteExpando: true, + optDisabled: false, + checkClone: false, noCloneEvent: true, + noCloneChecked: true, + boxModel: null, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, + reliableHiddenOffsets: true, reliableMarginRight: true }; - // Make sure checked status is properly cloned input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; + jQuery.support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) + // (WebKit marks them as diabled) select.disabled = true; - support.optDisabled = !opt.disabled; + jQuery.support.optDisabled = !opt.disabled; + + var _scriptEval = null; + jQuery.support.scriptEval = function() { + if ( _scriptEval === null ) { + var root = document.documentElement, + script = document.createElement("script"), + id = "script" + jQuery.now(); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + if ( window[ id ] ) { + _scriptEval = true; + delete window[ id ]; + } else { + _scriptEval = false; + } + + root.removeChild( script ); + } + + return _scriptEval; + }; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; - } catch( e ) { - support.deleteExpando = false; + + } catch(e) { + jQuery.support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", function() { + div.attachEvent("onclick", function click() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) - support.noCloneEvent = false; + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); }); - div.cloneNode( true ).fireEvent( "onclick" ); + div.cloneNode(true).fireEvent("onclick"); } - // Check if a radio maintains it's value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute("type", "radio"); - support.radioValue = input.value === "t"; + div = document.createElement("div"); + div.innerHTML = ""; - input.setAttribute("checked", "checked"); - div.appendChild( input ); - fragment = document.createDocumentFragment(); + var fragment = document.createDocumentFragment(); fragment.appendChild( div.firstChild ); // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - div.innerHTML = ""; + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; // Figure out if the W3C box model works as expected - div.style.width = div.style.paddingLeft = "1px"; + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"), + body = document.getElementsByTagName("body")[0]; - body = document.getElementsByTagName( "body" )[ 0 ]; - // We use our own, invisible, body unless the body is already present - // in which case we use a div (#9239) - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0 - }; - if ( body ) { - jQuery.extend( testElementStyle, { - position: "absolute", - left: -1000, - top: -1000 - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); + // Frameset documents with no body should not run this code + if ( !body ) { + return; + } - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; + div.style.width = div.style.paddingLeft = "1px"; + body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; - support.boxModel = div.offsetWidth === 2; + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; + } - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); - } + div.innerHTML = "
t
"; + var tds = div.getElementsByTagName("td"); - div.innerHTML = "
t
"; - tds = div.getElementsByTagName( "td" ); + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - isSupported = ( tds[ 0 ].offsetHeight === 0 ); + tds[0].style.display = ""; + tds[1].style.display = "none"; - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; + div.innerHTML = ""; - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - div.innerHTML = ""; + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + div.style.width = "1px"; + div.style.marginRight = "0"; + jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0; + } - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( document.defaultView && document.defaultView.getComputedStyle ) { - marginDiv = document.createElement( "div" ); - marginDiv.style.width = "0"; - marginDiv.style.marginRight = "0"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; - } - - // Remove the body element we added - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); + body.removeChild( div ).style.display = "none"; + div = tds = null; + }); // Technique from Juriy Zaytsev // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for( i in { - submit: 1, - change: 1, - focusin: 1 - } ) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( !el.attachEvent ) { + return true; } - } - // Null connected elements to avoid leaks in IE - testElement = fragment = select = opt = body = marginDiv = div = input = null; + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + return isSupported; + }; - return support; + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + div = all = a = null; })(); - -// Keep track of boxModel -jQuery.boxModel = jQuery.support.boxModel; - })( jQuery ); diff --git a/src/traversing.js b/src/traversing.js index 8c4b4ef8..fe2e33d8 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -17,30 +17,17 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { - var self = this, - i, l; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - var ret = this.pushStack( "", "find", selector ), - length, n, r; + length = 0; - for ( i = 0, l = this.length; i < l; i++ ) { + for ( var i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; @@ -73,15 +60,12 @@ jQuery.fn.extend({ }, is: function( selector ) { - return !!selector && ( typeof selector === "string" ? - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); + return !!selector && jQuery.filter( selector, this ).length > 0; }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; - - // Array + if ( jQuery.isArray( selectors ) ) { var match, selector, matches = {}, @@ -91,8 +75,8 @@ jQuery.fn.extend({ for ( i = 0, l = selectors.length; i < l; i++ ) { selector = selectors[i]; - if ( !matches[ selector ] ) { - matches[ selector ] = POS.test( selector ) ? + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? jQuery( selector, context || this.context ) : selector; } @@ -100,9 +84,9 @@ jQuery.fn.extend({ while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { - match = matches[ selector ]; + match = matches[selector]; - if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { ret.push({ selector: selector, elem: cur, level: level }); } } @@ -115,10 +99,8 @@ jQuery.fn.extend({ return ret; } - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; + var pos = POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; @@ -130,14 +112,14 @@ jQuery.fn.extend({ } else { cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + if ( !cur || !cur.ownerDocument || cur === context ) { break; } } } } - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + ret = ret.length > 1 ? jQuery.unique(ret) : ret; return this.pushStack( ret, "closest", selectors ); }, @@ -160,7 +142,7 @@ jQuery.fn.extend({ add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + jQuery.makeArray( selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? @@ -298,11 +280,6 @@ jQuery.extend({ // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); diff --git a/test/data/dashboard.xml b/test/data/dashboard.xml index 5a6f5614..10f6b334 100644 --- a/test/data/dashboard.xml +++ b/test/data/dashboard.xml @@ -1,7 +1,7 @@ - + diff --git a/test/data/readywaitloader.js b/test/data/readywaitloader.js index e07dac7a..483e07c4 100644 --- a/test/data/readywaitloader.js +++ b/test/data/readywaitloader.js @@ -1,14 +1,14 @@ -// Simple script loader that uses jQuery.readyWait via jQuery.holdReady() +// Simple script loader that uses jQuery.readyWait //Hold on jQuery! -jQuery.holdReady(true); +jQuery.readyWait++; var readyRegExp = /^(complete|loaded)$/; function assetLoaded( evt ){ var node = evt.currentTarget || evt.srcElement; if ( evt.type === "load" || readyRegExp.test(node.readyState) ) { - jQuery.holdReady(false); + jQuery.ready(true); } } diff --git a/test/data/support/bodyBackground.html b/test/data/support/bodyBackground.html deleted file mode 100644 index 9963c391..00000000 --- a/test/data/support/bodyBackground.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - diff --git a/test/data/support/boxModelIE.html b/test/data/support/boxModelIE.html deleted file mode 100644 index 1b11d2a5..00000000 --- a/test/data/support/boxModelIE.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/data/support/hiddenIFrameFF.html b/test/data/support/hiddenIFrameFF.html deleted file mode 100644 index 000ac851..00000000 --- a/test/data/support/hiddenIFrameFF.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/data/testrunner.js b/test/data/testrunner.js index 6d44b460..beb0fe2a 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -2,9 +2,8 @@ jQuery.noConflict(); // Allow the test to run with other libs or jQuery's. // jQuery-specific QUnit.reset (function() { - var reset = QUnit.reset, - ajaxSettings = jQuery.ajaxSettings; - + var reset = QUnit.reset; + var ajaxSettings = jQuery.ajaxSettings QUnit.reset = function() { reset.apply(this, arguments); jQuery.event.global = {}; @@ -25,9 +24,3 @@ jQuery.noConflict(); // Allow the test to run with other libs or jQuery's. document.write(""); })(); - -// QUnit Aliases -(function() { - window.equals = window.equal; - window.same = window.deepEqual; -})(); diff --git a/test/data/testsuite.css b/test/data/testsuite.css index 295740f5..cffaaa46 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -1,5 +1,5 @@ /* for testing opacity set in styles in IE */ -ol#empty { opacity: 0; filter:Alpha(opacity=0) progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffff0000', EndColorStr='#ffffffff'); } +ol#empty { opacity: 0; filter:Alpha(opacity=0); } div#fx-tests h4 { background: red; @@ -109,15 +109,3 @@ div#show-tests * { display: none; } #nothiddendiv { font-size: 16px; } #nothiddendivchild.em { font-size: 2em; } #nothiddendivchild.prct { font-size: 150%; } - -/* For testing type on vml in IE #7071 */ -v\:oval { behavior:url(#default#VML); display:inline-block; } - -/* 8099 changes to default styles are read correctly */ -tt { display: none; } -sup { display: none; } -dfn { display: none; } - -/* #9239 Attach a background to the body( avoid crashes in removing the test element in support ) */ -body, div { background: url(http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif) no-repeat -1000px 0; } - diff --git a/test/data/versioncheck.js b/test/data/versioncheck.js deleted file mode 100644 index f4b7790d..00000000 --- a/test/data/versioncheck.js +++ /dev/null @@ -1,8 +0,0 @@ -// Run minified source from dist (do make first) -// Should be loaded before QUnit but after src -(function() { - if ( /jquery\=min/.test( window.location.search ) ) { - jQuery.noConflict( true ); - document.write(unescape("%3Cscript%20src%3D%27../dist/jquery.min.js%27%3E%3C/script%3E")); - } -})(); \ No newline at end of file diff --git a/test/delegatetest.html b/test/delegatetest.html index 169e60f7..c4f33aae 100644 --- a/test/delegatetest.html +++ b/test/delegatetest.html @@ -183,20 +183,10 @@ DOCUMENT - -

Mouseleave Tests

- -
-

Count mouse leave event

-
-

mouse over here should not trigger the counter.

-
-

0

-
    - + diff --git a/test/index.html b/test/index.html index 4b4c9855..c7c2ae55 100644 --- a/test/index.html +++ b/test/index.html @@ -28,13 +28,10 @@ - - - @@ -51,9 +48,7 @@ -

    jQuery Test Suite - (minified) -

    +

    jQuery Test Suite

    @@ -63,10 +58,10 @@
    - + -
    -
    +
    +

    See this blog entry for more information.

    Here are some links in a normal paragraph: Google, @@ -208,10 +203,6 @@ Z - - - -

    diff --git a/test/qunit b/test/qunit index d4f23f8a..d404faf8 160000 --- a/test/qunit +++ b/test/qunit @@ -1 +1 @@ -Subproject commit d4f23f8a882d13b71768503e2db9fa33ef169ba0 +Subproject commit d404faf8f587fcbe6b8907943022e6318dd51e0c diff --git a/test/readywait.html b/test/readywait.html index b4d8111e..4f124767 100644 --- a/test/readywait.html +++ b/test/readywait.html @@ -1,13 +1,13 @@ - jQuery.holdReady Test + jQuery.readyWait Test ")); + jQuery("#main").html(valueObj("")); - equals( jQuery("#qunit-fixture").children().length, 1, "Make sure there is a child element." ); - equals( jQuery("#qunit-fixture").children()[0].nodeName.toUpperCase(), "STYLE", "And that a style element was inserted." ); + equals( jQuery("#main").children().length, 1, "Make sure there is a child element." ); + equals( jQuery("#main").children()[0].nodeName.toUpperCase(), "STYLE", "And that a style element was inserted." ); QUnit.reset(); // using contents will get comments regular, text, and comment nodes @@ -1149,18 +1088,18 @@ var testHtml = function(valueObj) { j.html(valueObj("bold")); // this is needed, or the expando added by jQuery unique will yield a different html - j.find("b").removeData(); + j.find('b').removeData(); equals( j.html().replace(/ xmlns="[^"]+"/g, "").toLowerCase(), "bold", "Check node,textnode,comment with html()" ); - jQuery("#qunit-fixture").html(valueObj("")); + jQuery("#main select").html(valueObj("")); + equals( jQuery("#main select").val(), "O2", "Selected option correct" ); - var $div = jQuery("
    "); - equals( $div.html(valueObj( 5 )).html(), "5", "Setting a number as html" ); - equals( $div.html(valueObj( 0 )).html(), "0", "Setting a zero as html" ); + var $div = jQuery('
    '); + equals( $div.html(valueObj( 5 )).html(), '5', 'Setting a number as html' ); + equals( $div.html(valueObj( 0 )).html(), '0', 'Setting a zero as html' ); - var $div2 = jQuery("
    "), insert = "<div>hello1</div>"; + var $div2 = jQuery('
    '), insert = "<div>hello1</div>"; equals( $div2.html(insert).html().replace(/>/g, ">"), insert, "Verify escaped insertion." ); equals( $div2.html("x" + insert).html().replace(/>/g, ">"), "x" + insert, "Verify escaped insertion." ); equals( $div2.html(" " + insert).html().replace(/>/g, ">"), " " + insert, "Verify escaped insertion." ); @@ -1172,23 +1111,17 @@ var testHtml = function(valueObj) { QUnit.reset(); - jQuery("#qunit-fixture").html(valueObj("
    ")); + jQuery("#main").html(valueObj('
    ')); - var child = jQuery("#qunit-fixture").find("script"); + jQuery("#main").html(valueObj("")); + jQuery("#main").html(valueObj("")); + jQuery("#main").html(valueObj("")); - equals( child.length, 2, "Make sure that two non-JavaScript script tags are left." ); - equals( child[0].type, "something/else", "Verify type of script tag." ); - equals( child[1].type, "something/else", "Verify type of script tag." ); + jQuery("#main").html(valueObj('')); - jQuery("#qunit-fixture").html(valueObj("")); - jQuery("#qunit-fixture").html(valueObj("")); - jQuery("#qunit-fixture").html(valueObj("")); + jQuery("#main").html(valueObj('foo ')); - jQuery("#qunit-fixture").html(valueObj("")); - - jQuery("#qunit-fixture").html(valueObj("foo
    ")); - - jQuery("#qunit-fixture").html(valueObj("' - ].join ( "\n" ) ).appendTo( "#qunit-fixture" ); - jQuery( [ - '' - ].join ( "\n" ) ).appendTo( "#qunit-fixture" ); - jQuery( [ - '' - ].join ( "\n" ) ).appendTo( "#qunit-fixture" ); -}); - -test("jQuery.buildFragment - plain objects are not a document #8950", function() { - expect(1); - - try { - jQuery('', {}); - ok( true, "Does not allow attribute object to be treated like a doc object"); - } catch (e) {} - -}); diff --git a/test/unit/offset.js b/test/unit/offset.js index ea1a4933..ae051884 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -20,7 +20,7 @@ testoffset("absolute"/* in iframe */, function($, iframe) { // this insures that the results will be wrong // if the offset method is using the scroll offset // of the parent window - var forceScroll = jQuery("
    ", { width: 2000, height: 2000 }).appendTo("body"); + var forceScroll = jQuery('
    ', { width: 2000, height: 2000 }).appendTo('body'); window.scrollTo(200, 200); if ( document.documentElement.scrollTop || document.body.scrollTop ) { @@ -31,7 +31,7 @@ testoffset("absolute"/* in iframe */, function($, iframe) { // get offset tests = [ - { id: "#absolute-1", top: 1, left: 1 } + { id: '#absolute-1', top: 1, left: 1 } ]; jQuery.each( tests, function() { equals( jQuery( this.id, doc ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); @@ -41,7 +41,7 @@ testoffset("absolute"/* in iframe */, function($, iframe) { // get position tests = [ - { id: "#absolute-1", top: 0, left: 0 } + { id: '#absolute-1', top: 0, left: 0 } ]; jQuery.each( tests, function() { equals( jQuery( this.id, doc ).position().top, this.top, "jQuery('" + this.id + "').position().top" ); @@ -56,10 +56,10 @@ testoffset("absolute", function( jQuery ) { // get offset tests var tests = [ - { id: "#absolute-1", top: 1, left: 1 }, - { id: "#absolute-1-1", top: 5, left: 5 }, - { id: "#absolute-1-1-1", top: 9, left: 9 }, - { id: "#absolute-2", top: 20, left: 20 } + { id: '#absolute-1', top: 1, left: 1 }, + { id: '#absolute-1-1', top: 5, left: 5 }, + { id: '#absolute-1-1-1', top: 9, left: 9 }, + { id: '#absolute-2', top: 20, left: 20 } ]; jQuery.each( tests, function() { equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); @@ -69,10 +69,10 @@ testoffset("absolute", function( jQuery ) { // get position tests = [ - { id: "#absolute-1", top: 0, left: 0 }, - { id: "#absolute-1-1", top: 1, left: 1 }, - { id: "#absolute-1-1-1", top: 1, left: 1 }, - { id: "#absolute-2", top: 19, left: 19 } + { id: '#absolute-1', top: 0, left: 0 }, + { id: '#absolute-1-1', top: 1, left: 1 }, + { id: '#absolute-1-1-1', top: 1, left: 1 }, + { id: '#absolute-2', top: 19, left: 19 } ]; jQuery.each( tests, function() { equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" ); @@ -80,29 +80,29 @@ testoffset("absolute", function( jQuery ) { }); // test #5781 - var offset = jQuery( "#positionTest" ).offset({ top: 10, left: 10 }).offset(); + var offset = jQuery( '#positionTest' ).offset({ top: 10, left: 10 }).offset(); equals( offset.top, 10, "Setting offset on element with position absolute but 'auto' values." ) equals( offset.left, 10, "Setting offset on element with position absolute but 'auto' values." ) // set offset tests = [ - { id: "#absolute-2", top: 30, left: 30 }, - { id: "#absolute-2", top: 10, left: 10 }, - { id: "#absolute-2", top: -1, left: -1 }, - { id: "#absolute-2", top: 19, left: 19 }, - { id: "#absolute-1-1-1", top: 15, left: 15 }, - { id: "#absolute-1-1-1", top: 5, left: 5 }, - { id: "#absolute-1-1-1", top: -1, left: -1 }, - { id: "#absolute-1-1-1", top: 9, left: 9 }, - { id: "#absolute-1-1", top: 10, left: 10 }, - { id: "#absolute-1-1", top: 0, left: 0 }, - { id: "#absolute-1-1", top: -1, left: -1 }, - { id: "#absolute-1-1", top: 5, left: 5 }, - { id: "#absolute-1", top: 2, left: 2 }, - { id: "#absolute-1", top: 0, left: 0 }, - { id: "#absolute-1", top: -1, left: -1 }, - { id: "#absolute-1", top: 1, left: 1 } + { id: '#absolute-2', top: 30, left: 30 }, + { id: '#absolute-2', top: 10, left: 10 }, + { id: '#absolute-2', top: -1, left: -1 }, + { id: '#absolute-2', top: 19, left: 19 }, + { id: '#absolute-1-1-1', top: 15, left: 15 }, + { id: '#absolute-1-1-1', top: 5, left: 5 }, + { id: '#absolute-1-1-1', top: -1, left: -1 }, + { id: '#absolute-1-1-1', top: 9, left: 9 }, + { id: '#absolute-1-1', top: 10, left: 10 }, + { id: '#absolute-1-1', top: 0, left: 0 }, + { id: '#absolute-1-1', top: -1, left: -1 }, + { id: '#absolute-1-1', top: 5, left: 5 }, + { id: '#absolute-1', top: 2, left: 2 }, + { id: '#absolute-1', top: 0, left: 0 }, + { id: '#absolute-1', top: -1, left: -1 }, + { id: '#absolute-1', top: 1, left: 1 } ]; jQuery.each( tests, function() { jQuery( this.id ).offset({ top: this.top, left: this.left }); @@ -144,9 +144,9 @@ testoffset("relative", function( jQuery ) { // get offset var tests = [ - { id: "#relative-1", top: ie ? 6 : 7, left: 7 }, - { id: "#relative-1-1", top: ie ? 13 : 15, left: 15 }, - { id: "#relative-2", top: ie ? 141 : 142, left: 27 } + { id: '#relative-1', top: ie ? 6 : 7, left: 7 }, + { id: '#relative-1-1', top: ie ? 13 : 15, left: 15 }, + { id: '#relative-2', top: ie ? 141 : 142, left: 27 } ]; jQuery.each( tests, function() { equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); @@ -156,9 +156,9 @@ testoffset("relative", function( jQuery ) { // get position tests = [ - { id: "#relative-1", top: ie ? 5 : 6, left: 6 }, - { id: "#relative-1-1", top: ie ? 4 : 5, left: 5 }, - { id: "#relative-2", top: ie ? 140 : 141, left: 26 } + { id: '#relative-1', top: ie ? 5 : 6, left: 6 }, + { id: '#relative-1-1', top: ie ? 4 : 5, left: 5 }, + { id: '#relative-2', top: ie ? 140 : 141, left: 26 } ]; jQuery.each( tests, function() { equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" ); @@ -168,18 +168,18 @@ testoffset("relative", function( jQuery ) { // set offset tests = [ - { id: "#relative-2", top: 200, left: 50 }, - { id: "#relative-2", top: 100, left: 10 }, - { id: "#relative-2", top: -5, left: -5 }, - { id: "#relative-2", top: 142, left: 27 }, - { id: "#relative-1-1", top: 100, left: 100 }, - { id: "#relative-1-1", top: 5, left: 5 }, - { id: "#relative-1-1", top: -1, left: -1 }, - { id: "#relative-1-1", top: 15, left: 15 }, - { id: "#relative-1", top: 100, left: 100 }, - { id: "#relative-1", top: 0, left: 0 }, - { id: "#relative-1", top: -1, left: -1 }, - { id: "#relative-1", top: 7, left: 7 } + { id: '#relative-2', top: 200, left: 50 }, + { id: '#relative-2', top: 100, left: 10 }, + { id: '#relative-2', top: -5, left: -5 }, + { id: '#relative-2', top: 142, left: 27 }, + { id: '#relative-1-1', top: 100, left: 100 }, + { id: '#relative-1-1', top: 5, left: 5 }, + { id: '#relative-1-1', top: -1, left: -1 }, + { id: '#relative-1-1', top: 15, left: 15 }, + { id: '#relative-1', top: 100, left: 100 }, + { id: '#relative-1', top: 0, left: 0 }, + { id: '#relative-1', top: -1, left: -1 }, + { id: '#relative-1', top: 7, left: 7 } ]; jQuery.each( tests, function() { jQuery( this.id ).offset({ top: this.top, left: this.left }); @@ -205,10 +205,10 @@ testoffset("static", function( jQuery ) { // get offset var tests = [ - { id: "#static-1", top: ie ? 6 : 7, left: 7 }, - { id: "#static-1-1", top: ie ? 13 : 15, left: 15 }, - { id: "#static-1-1-1", top: ie ? 20 : 23, left: 23 }, - { id: "#static-2", top: ie ? 121 : 122, left: 7 } + { id: '#static-1', top: ie ? 6 : 7, left: 7 }, + { id: '#static-1-1', top: ie ? 13 : 15, left: 15 }, + { id: '#static-1-1-1', top: ie ? 20 : 23, left: 23 }, + { id: '#static-2', top: ie ? 121 : 122, left: 7 } ]; jQuery.each( tests, function() { equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); @@ -218,10 +218,10 @@ testoffset("static", function( jQuery ) { // get position tests = [ - { id: "#static-1", top: ie ? 5 : 6, left: 6 }, - { id: "#static-1-1", top: ie ? 12 : 14, left: 14 }, - { id: "#static-1-1-1", top: ie ? 19 : 22, left: 22 }, - { id: "#static-2", top: ie ? 120 : 121, left: 6 } + { id: '#static-1', top: ie ? 5 : 6, left: 6 }, + { id: '#static-1-1', top: ie ? 12 : 14, left: 14 }, + { id: '#static-1-1-1', top: ie ? 19 : 22, left: 22 }, + { id: '#static-2', top: ie ? 120 : 121, left: 6 } ]; jQuery.each( tests, function() { equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.top + "').position().top" ); @@ -231,22 +231,22 @@ testoffset("static", function( jQuery ) { // set offset tests = [ - { id: "#static-2", top: 200, left: 200 }, - { id: "#static-2", top: 100, left: 100 }, - { id: "#static-2", top: -2, left: -2 }, - { id: "#static-2", top: 121, left: 6 }, - { id: "#static-1-1-1", top: 50, left: 50 }, - { id: "#static-1-1-1", top: 10, left: 10 }, - { id: "#static-1-1-1", top: -1, left: -1 }, - { id: "#static-1-1-1", top: 22, left: 22 }, - { id: "#static-1-1", top: 25, left: 25 }, - { id: "#static-1-1", top: 10, left: 10 }, - { id: "#static-1-1", top: -3, left: -3 }, - { id: "#static-1-1", top: 14, left: 14 }, - { id: "#static-1", top: 30, left: 30 }, - { id: "#static-1", top: 2, left: 2 }, - { id: "#static-1", top: -2, left: -2 }, - { id: "#static-1", top: 7, left: 7 } + { id: '#static-2', top: 200, left: 200 }, + { id: '#static-2', top: 100, left: 100 }, + { id: '#static-2', top: -2, left: -2 }, + { id: '#static-2', top: 121, left: 6 }, + { id: '#static-1-1-1', top: 50, left: 50 }, + { id: '#static-1-1-1', top: 10, left: 10 }, + { id: '#static-1-1-1', top: -1, left: -1 }, + { id: '#static-1-1-1', top: 22, left: 22 }, + { id: '#static-1-1', top: 25, left: 25 }, + { id: '#static-1-1', top: 10, left: 10 }, + { id: '#static-1-1', top: -3, left: -3 }, + { id: '#static-1-1', top: 14, left: 14 }, + { id: '#static-1', top: 30, left: 30 }, + { id: '#static-1', top: 2, left: 2 }, + { id: '#static-1', top: -2, left: -2 }, + { id: '#static-1', top: 7, left: 7 } ]; jQuery.each( tests, function() { jQuery( this.id ).offset({ top: this.top, left: this.left }); @@ -270,8 +270,8 @@ testoffset("fixed", function( jQuery ) { jQuery.offset.initialize(); var tests = [ - { id: "#fixed-1", top: 1001, left: 1001 }, - { id: "#fixed-2", top: 1021, left: 1021 } + { id: '#fixed-1', top: 1001, left: 1001 }, + { id: '#fixed-2', top: 1021, left: 1021 } ]; jQuery.each( tests, function() { @@ -284,18 +284,18 @@ testoffset("fixed", function( jQuery ) { equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" ); } else { // need to have same number of assertions - ok( true, "Fixed position is not supported" ); - ok( true, "Fixed position is not supported" ); + ok( true, 'Fixed position is not supported' ); + ok( true, 'Fixed position is not supported' ); } }); tests = [ - { id: "#fixed-1", top: 100, left: 100 }, - { id: "#fixed-1", top: 0, left: 0 }, - { id: "#fixed-1", top: -4, left: -4 }, - { id: "#fixed-2", top: 200, left: 200 }, - { id: "#fixed-2", top: 0, left: 0 }, - { id: "#fixed-2", top: -5, left: -5 } + { id: '#fixed-1', top: 100, left: 100 }, + { id: '#fixed-1', top: 0, left: 0 }, + { id: '#fixed-1', top: -4, left: -4 }, + { id: '#fixed-2', top: 200, left: 200 }, + { id: '#fixed-2', top: 0, left: 0 }, + { id: '#fixed-2', top: -5, left: -5 } ]; jQuery.each( tests, function() { @@ -314,58 +314,58 @@ testoffset("fixed", function( jQuery ) { equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" ); } else { // need to have same number of assertions - ok( true, "Fixed position is not supported" ); - ok( true, "Fixed position is not supported" ); - ok( true, "Fixed position is not supported" ); - ok( true, "Fixed position is not supported" ); + ok( true, 'Fixed position is not supported' ); + ok( true, 'Fixed position is not supported' ); + ok( true, 'Fixed position is not supported' ); + ok( true, 'Fixed position is not supported' ); } }); // Bug 8316 - var $noTopLeft = jQuery("#fixed-no-top-left"); + var $noTopLeft = jQuery('#fixed-no-top-left'); if ( jQuery.offset.supportsFixedPosition ) { equals( $noTopLeft.offset().top, 1007, "Check offset top for fixed element with no top set" ); equals( $noTopLeft.offset().left, 1007, "Check offset left for fixed element with no left set" ); } else { // need to have same number of assertions - ok( true, "Fixed position is not supported" ); - ok( true, "Fixed position is not supported" ); + ok( true, 'Fixed position is not supported' ); + ok( true, 'Fixed position is not supported' ); } }); testoffset("table", function( jQuery ) { expect(4); - equals( jQuery("#table-1").offset().top, 6, "jQuery('#table-1').offset().top" ); - equals( jQuery("#table-1").offset().left, 6, "jQuery('#table-1').offset().left" ); + equals( jQuery('#table-1').offset().top, 6, "jQuery('#table-1').offset().top" ); + equals( jQuery('#table-1').offset().left, 6, "jQuery('#table-1').offset().left" ); - equals( jQuery("#th-1").offset().top, 10, "jQuery('#th-1').offset().top" ); - equals( jQuery("#th-1").offset().left, 10, "jQuery('#th-1').offset().left" ); + equals( jQuery('#th-1').offset().top, 10, "jQuery('#th-1').offset().top" ); + equals( jQuery('#th-1').offset().left, 10, "jQuery('#th-1').offset().left" ); }); testoffset("scroll", function( jQuery, win ) { - expect(22); + expect(16); var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8; // IE is collapsing the top margin of 1px - equals( jQuery("#scroll-1").offset().top, ie ? 6 : 7, "jQuery('#scroll-1').offset().top" ); - equals( jQuery("#scroll-1").offset().left, 7, "jQuery('#scroll-1').offset().left" ); + equals( jQuery('#scroll-1').offset().top, ie ? 6 : 7, "jQuery('#scroll-1').offset().top" ); + equals( jQuery('#scroll-1').offset().left, 7, "jQuery('#scroll-1').offset().left" ); // IE is collapsing the top margin of 1px - equals( jQuery("#scroll-1-1").offset().top, ie ? 9 : 11, "jQuery('#scroll-1-1').offset().top" ); - equals( jQuery("#scroll-1-1").offset().left, 11, "jQuery('#scroll-1-1').offset().left" ); + equals( jQuery('#scroll-1-1').offset().top, ie ? 9 : 11, "jQuery('#scroll-1-1').offset().top" ); + equals( jQuery('#scroll-1-1').offset().left, 11, "jQuery('#scroll-1-1').offset().left" ); // scroll offset tests .scrollTop/Left - equals( jQuery("#scroll-1").scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" ); - equals( jQuery("#scroll-1").scrollLeft(), 5, "jQuery('#scroll-1').scrollLeft()" ); + equals( jQuery('#scroll-1').scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" ); + equals( jQuery('#scroll-1').scrollLeft(), 5, "jQuery('#scroll-1').scrollLeft()" ); - equals( jQuery("#scroll-1-1").scrollTop(), 0, "jQuery('#scroll-1-1').scrollTop()" ); - equals( jQuery("#scroll-1-1").scrollLeft(), 0, "jQuery('#scroll-1-1').scrollLeft()" ); + equals( jQuery('#scroll-1-1').scrollTop(), 0, "jQuery('#scroll-1-1').scrollTop()" ); + equals( jQuery('#scroll-1-1').scrollLeft(), 0, "jQuery('#scroll-1-1').scrollLeft()" ); - // equals( jQuery("body").scrollTop(), 0, "jQuery("body").scrollTop()" ); - // equals( jQuery("body").scrollLeft(), 0, "jQuery("body").scrollTop()" ); + // equals( jQuery('body').scrollTop(), 0, "jQuery('body').scrollTop()" ); + // equals( jQuery('body').scrollLeft(), 0, "jQuery('body').scrollTop()" ); win.name = "test"; @@ -390,21 +390,13 @@ testoffset("scroll", function( jQuery, win ) { equals( jQuery(window).scrollLeft(), 0, "jQuery(window).scrollLeft() other window" ); equals( jQuery(document).scrollTop(), 0, "jQuery(window).scrollTop() other document" ); equals( jQuery(document).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" ); - - // Tests scrollTop/Left with empty jquery objects - notEqual( jQuery().scrollTop(100), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); - notEqual( jQuery().scrollLeft(100), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); - notEqual( jQuery().scrollTop(null), null, "jQuery().scrollTop(null) testing setter on empty jquery object" ); - notEqual( jQuery().scrollLeft(null), null, "jQuery().scrollLeft(null) testing setter on empty jquery object" ); - strictEqual( jQuery().scrollTop(), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); - strictEqual( jQuery().scrollLeft(), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); }); testoffset("body", function( jQuery ) { expect(2); - equals( jQuery("body").offset().top, 1, "jQuery('#body').offset().top" ); - equals( jQuery("body").offset().left, 1, "jQuery('#body').offset().left" ); + equals( jQuery('body').offset().top, 1, "jQuery('#body').offset().top" ); + equals( jQuery('body').offset().left, 1, "jQuery('#body').offset().left" ); }); test("Chaining offset(coords) returns jQuery object", function() { @@ -441,33 +433,7 @@ test("offsetParent", function(){ equals( div[1], jQuery("#nothiddendiv")[0], "The div is the offsetParent." ); }); -test("fractions (see #7730 and #7885)", function() { - expect(2); - - jQuery('body').append('
    '); - - var expected = { top: 1000, left: 1000 }; - var div = jQuery('#fractions'); - - div.css({ - position: 'absolute', - left: '1000.7432222px', - top: '1000.532325px', - width: 100, - height: 100 - }); - - div.offset(expected); - - var result = div.offset(); - - equals( result.top, expected.top, "Check top" ); - equals( result.left, expected.left, "Check left" ); - - div.remove(); -}); - -function testoffset(name, fn) { +function testoffset( name, fn ) { test(name, function() { // pause execution for now @@ -490,10 +456,10 @@ function testoffset(name, fn) { }); function loadFixture() { - var src = "./data/offset/" + name + ".html?" + parseInt( Math.random()*1000, 10 ), - iframe = jQuery("