diff --git a/components/react/JSXTransformer.js b/components/react/JSXTransformer.js new file mode 100644 index 0000000000000..276810d7eebfe --- /dev/null +++ b/components/react/JSXTransformer.js @@ -0,0 +1,10139 @@ +/** + * JSXTransformer v0.3.0 + */ +(function(e){if("function"==typeof bootstrap)bootstrap("jsxtransformer",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeJSXTransformer=e}else"undefined"!=typeof window?window.JSXTransformer=e():global.JSXTransformer=e()})(function(){var define,ses,bootstrap,module,exports; +return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s orderedListOfVisitors. + */ +var transformVisitors = { + 'es6-classes': [ + classes.visitClassExpression, + classes.visitClassDeclaration, + classes.visitSuperCall, + classes.visitPrivateProperty + ] +}; + +transformVisitors.react = transformVisitors[ + "es6-classes" +].concat([ + react.visitReactTag, + reactDisplayName.visitReactDisplayName +]); + +/** + * Specifies the order in which each transform should run. + */ +var transformRunOrder = [ + 'es6-classes', + 'react' +]; + +/** + * Given a list of transform names, return the ordered list of visitors to be + * passed to the transform() function. + * + * @param {array?} excludes + * @return {array} + */ +function getVisitorsList(excludes) { + var ret = []; + for (var i = 0, il = transformRunOrder.length; i < il; i++) { + if (!excludes || excludes.indexOf(transformRunOrder[i]) === -1) { + ret = ret.concat(transformVisitors[transformRunOrder[i]]); + } + } + return ret; +} + +exports.getVisitorsList = getVisitorsList; +exports.transformVisitors = transformVisitors; + +})() +},{"./transforms/classes":5,"./transforms/react":6,"./transforms/reactDisplayName":7}],8:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ + +/** + * State represents the given parser state. It has a local and global parts. + * Global contains parser position, source, etc. Local contains scope based + * properties, like current class name. State should contain all the info + * required for transformation. It's the only mandatory object that is being + * passed to every function in transform chain. + * + * @param {String} source + * @param {Object} transformOptions + * @return {Object} + */ +function createState(source, transformOptions) { + return { + /** + * Name of the super class variable + * @type {String} + */ + superVar: '', + /** + * Name of the enclosing class scope + * @type {String} + */ + scopeName: '', + /** + * Global state (not affected by updateState) + * @type {Object} + */ + g: { + /** + * A set of general options that transformations can consider while doing + * a transformation: + * + * - minify + * Specifies that transformation steps should do their best to minify + * the output source when possible. This is useful for places where + * minification optimizations are possible with higher-level context + * info than what jsxmin can provide. + * + * For example, the ES6 class transform will minify munged private + * variables if this flag is set. + */ + opts: transformOptions, + /** + * Current position in the source code + * @type {Number} + */ + position: 0, + /** + * Buffer containing the result + * @type {String} + */ + buffer: '', + /** + * Indentation offset (only negative offset is supported now) + * @type {Number} + */ + indentBy: 0, + /** + * Source that is being transformed + * @type {String} + */ + source: source, + + /** + * Cached parsed docblock (see getDocblock) + * @type {object} + */ + docblock: null, + + /** + * Whether the thing was used + * @type {Boolean} + */ + tagNamespaceUsed: false, + + /** + * If using bolt xjs transformation + * @type {Boolean} + */ + isBolt: undefined, + + /** + * Whether to record source map (expensive) or not + * @type {SourceMapGenerator|null} + */ + sourceMap: null, + + /** + * Filename of the file being processed. Will be returned as a source + * attribute in the source map + */ + sourceMapFilename: 'source.js', + + /** + * Only when source map is used: last line in the source for which + * source map was generated + * @type {Number} + */ + sourceLine: 1, + + /** + * Only when source map is used: last line in the buffer for which + * source map was generated + * @type {Number} + */ + bufferLine: 1, + + /** + * The top-level Program AST for the original file. + */ + originalProgramAST: null, + + sourceColumn: 0, + bufferColumn: 0 + } + }; +} + +/** + * Updates a copy of a given state with "update" and returns an updated state. + * + * @param {Object} state + * @param {Object} update + * @return {Object} + */ +function updateState(state, update) { + return { + g: state.g, + superVar: update.superVar || state.superVar, + scopeName: update.scopeName || state.scopeName + }; +} + +/** + * Given a state fill the resulting buffer from the original source up to + * the end + * @param {Number} end + * @param {Object} state + * @param {Function?} contentTransformer Optional callback to transform newly + * added content. + */ +function catchup(end, state, contentTransformer) { + if (end < state.g.position) { + // cannot move backwards + return; + } + var source = state.g.source.substring(state.g.position, end); + var transformed = updateIndent(source, state); + if (state.g.sourceMap && transformed) { + // record where we are + state.g.sourceMap.addMapping({ + generated: { line: state.g.bufferLine, column: state.g.bufferColumn }, + original: { line: state.g.sourceLine, column: state.g.sourceColumn }, + source: state.g.sourceMapFilename + }); + + // record line breaks in transformed source + var sourceLines = source.split('\n'); + var transformedLines = transformed.split('\n'); + // Add line break mappings between last known mapping and the end of the + // added piece. So for the code piece + // (foo, bar); + // > var x = 2; + // > var b = 3; + // var c = + // only add lines marked with ">": 2, 3. + for (var i = 1; i < sourceLines.length - 1; i++) { + state.g.sourceMap.addMapping({ + generated: { line: state.g.bufferLine, column: 0 }, + original: { line: state.g.sourceLine, column: 0 }, + source: state.g.sourceMapFilename + }); + state.g.sourceLine++; + state.g.bufferLine++; + } + // offset for the last piece + if (sourceLines.length > 1) { + state.g.sourceLine++; + state.g.bufferLine++; + state.g.sourceColumn = 0; + state.g.bufferColumn = 0; + } + state.g.sourceColumn += sourceLines[sourceLines.length - 1].length; + state.g.bufferColumn += + transformedLines[transformedLines.length - 1].length; + } + state.g.buffer += + contentTransformer ? contentTransformer(transformed) : transformed; + state.g.position = end; +} + +/** + * Applies `catchup` but passing in a function that removes any non-whitespace + * characters. + */ +var re = /(\S)/g; +function stripNonWhite(value) { + return value.replace(re, function() { + return ''; + }); +} +/** + * Catches up as `catchup` but turns each non-white character into a space. + */ +function catchupWhiteSpace(end, state) { + catchup(end, state, stripNonWhite); +} + +/** + * Same as catchup but does not touch the buffer + * @param {Number} end + * @param {Object} state + */ +function move(end, state) { + // move the internal cursors + if (state.g.sourceMap) { + if (end < state.g.position) { + state.g.position = 0; + state.g.sourceLine = 1; + state.g.sourceColumn = 0; + } + + var source = state.g.source.substring(state.g.position, end); + var sourceLines = source.split('\n'); + if (sourceLines.length > 1) { + state.g.sourceLine += sourceLines.length - 1; + state.g.sourceColumn = 0; + } + state.g.sourceColumn += sourceLines[sourceLines.length - 1].length; + } + state.g.position = end; +} + +/** + * Appends a string of text to the buffer + * @param {String} string + * @param {Object} state + */ +function append(string, state) { + if (state.g.sourceMap && string) { + state.g.sourceMap.addMapping({ + generated: { line: state.g.bufferLine, column: state.g.bufferColumn }, + original: { line: state.g.sourceLine, column: state.g.sourceColumn }, + source: state.g.sourceMapFilename + }); + var transformedLines = string.split('\n'); + if (transformedLines.length > 1) { + state.g.bufferLine += transformedLines.length - 1; + state.g.bufferColumn = 0; + } + state.g.bufferColumn += + transformedLines[transformedLines.length - 1].length; + } + state.g.buffer += string; +} + +/** + * Update indent using state.indentBy property. Indent is measured in + * double spaces. Updates a single line only. + * + * @param {String} str + * @param {Object} state + * @return {String} + */ +function updateIndent(str, state) { + for (var i = 0; i < -state.g.indentBy; i++) { + str = str.replace(/(^|\n)( {2}|\t)/g, '$1'); + } + return str; +} + +/** + * Calculates indent from the beginning of the line until "start" or the first + * character before start. + * @example + * " foo.bar()" + * ^ + * start + * indent will be 2 + * + * @param {Number} start + * @param {Object} state + * @return {Number} + */ +function indentBefore(start, state) { + var end = start; + start = start - 1; + + while (start > 0 && state.g.source[start] != '\n') { + if (!state.g.source[start].match(/[ \t]/)) { + end = start; + } + start--; + } + return state.g.source.substring(start + 1, end); +} + +function getDocblock(state) { + if (!state.g.docblock) { + var docblock = require('./docblock'); + state.g.docblock = + docblock.parseAsObject(docblock.extract(state.g.source)); + } + return state.g.docblock; +} + +exports.catchup = catchup; +exports.catchupWhiteSpace = catchupWhiteSpace; +exports.append = append; +exports.move = move; +exports.updateIndent = updateIndent; +exports.indentBefore = indentBefore; +exports.updateState = updateState; +exports.createState = createState; +exports.getDocblock = getDocblock; + +})() +},{"./docblock":4}],2:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +/*jslint node: true*/ +"use strict"; + +/** + * Syntax transfomer for javascript. Takes the source in, spits the source + * out. Tries to maintain readability and preserve whitespace and line numbers + * where posssible. + * + * Support + * - ES6 class transformation + private property munging, see ./classes.js + * - React XHP style syntax transformations, see ./react.js + * - Bolt XHP style syntax transformations, see ./bolt.js + * + * The general flow is the following: + * - Parse the source with our customized esprima-parser + * https://github.com/voloko/esprima. We have to customize the parser to + * support non-standard XHP-style syntax. We parse the source range: true + * option that forces esprima to return positions in the source within + * resulting parse tree. + * + * - Traverse resulting syntax tree, trying to apply a set of visitors to each + * node. Each visitor should provide a .test() function that tests if the + * visitor can process a given node. + * + * - Visitor is responsible for code generation for a given syntax node. + * Generated code is stored in state.g.buffer that is passed to every + * visitor. It's up to the visitor to process the code the way it sees fit. + * All of the current visitors however use both the node and the original + * source to generate transformed code. They use nodes to generate new + * code and they copy the original source, preserving whitespace and comments, + * for the parts they don't care about. + */ +var esprima = require('esprima'); + +var createState = require('./utils').createState; +var catchup = require('./utils').catchup; + +/** + * @param {object} object + * @param {function} visitor + * @param {array} path + * @param {object} state + */ +function traverse(object, path, state) { + var key, child; + + if (walker(traverse, object, path, state) === false) { + return; + } + path.unshift(object); + for (key in object) { + // skip obviously wrong attributes + if (key === 'range' || key === 'loc') { + continue; + } + if (object.hasOwnProperty(key)) { + child = object[key]; + if (typeof child === 'object' && child !== null) { + child.range && catchup(child.range[0], state); + traverse(child, path, state); + child.range && catchup(child.range[1], state); + } + } + } + path.shift(); +} + +function walker(traverse, object, path, state) { + var visitors = state.g.visitors; + for (var i = 0; i < visitors.length; i++) { + if (visitors[i].test(object, path, state)) { + return visitors[i](traverse, object, path, state); + } + } +} + +function runPass(source, visitors, options) { + var ast = esprima.parse(source, { comment: true, loc: true, range: true }); + var state = createState(source, options); + state.g.originalProgramAST = ast; + state.g.visitors = visitors; + + if (options.sourceMap) { + var SourceMapGenerator = require('source-map').SourceMapGenerator; + state.g.sourceMap = new SourceMapGenerator({ file: 'transformed.js' }); + } + traverse(ast, [], state); + catchup(source.length, state); + return state; +} + +/** + * Applies all available transformations to the source + * @param {array} visitors + * @param {string} source + * @param {?object} options + * @return {object} + */ +function transform(visitors, source, options) { + options = options || {}; + + var state = runPass(source, visitors, options); + var sourceMap = state.g.sourceMap; + + if (sourceMap) { + return { + sourceMap: sourceMap, + sourceMapFilename: options.filename || 'source.js', + code: state.g.buffer + }; + } else { + return { + code: state.g.buffer + }; + } +} + + +exports.transform = transform; + +})() +},{"./utils":8,"source-map":9,"esprima":10}],11:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var move = require('../lib/utils').move; + +var knownTags = { + a: true, + abbr: true, + address: true, + applet: true, + area: true, + article: true, + aside: true, + audio: true, + b: true, + base: true, + bdi: true, + bdo: true, + blockquote: true, + body: true, + br: true, + button: true, + canvas: true, + circle: true, + ellipse: true, + caption: true, + cite: true, + code: true, + col: true, + colgroup: true, + command: true, + data: true, + datalist: true, + dd: true, + del: true, + details: true, + dfn: true, + dialog: true, + div: true, + dl: true, + dt: true, + em: true, + embed: true, + fieldset: true, + figcaption: true, + figure: true, + footer: true, + form: true, + g: true, + h1: true, + h2: true, + h3: true, + h4: true, + h5: true, + h6: true, + head: true, + header: true, + hgroup: true, + hr: true, + html: true, + i: true, + iframe: true, + img: true, + input: true, + ins: true, + kbd: true, + keygen: true, + label: true, + legend: true, + li: true, + line: true, + link: true, + map: true, + mark: true, + marquee: true, + menu: true, + meta: true, + meter: true, + nav: true, + noscript: true, + object: true, + ol: true, + optgroup: true, + option: true, + output: true, + p: true, + path: true, + param: true, + pre: true, + progress: true, + q: true, + rect: true, + rp: true, + rt: true, + ruby: true, + s: true, + samp: true, + script: true, + section: true, + select: true, + small: true, + source: true, + span: true, + strong: true, + style: true, + sub: true, + summary: true, + sup: true, + svg: true, + table: true, + tbody: true, + td: true, + text: true, + textarea: true, + tfoot: true, + th: true, + thead: true, + time: true, + title: true, + tr: true, + track: true, + u: true, + ul: true, + 'var': true, + video: true, + wbr: true +}; + +function safeTrim(string) { + return string.replace(/^[ \t]+/, '').replace(/[ \t]+$/, ''); +} + +// Replace all trailing whitespace characters with a single space character +function trimWithSingleSpace(string) { + return string.replace(/^[ \t\xA0]{2,}/, ' '). + replace(/[ \t\xA0]{2,}$/, ' ').replace(/^\s+$/, ''); +} + +/** + * Special handling for multiline string literals + * print lines: + * + * line + * line + * + * as: + * + * "line "+ + * "line" + */ +function renderXJSLiteral(object, isLast, state, start, end) { + /** Added blank check filtering and triming*/ + var trimmedChildValue = safeTrim(object.value); + + if (trimmedChildValue) { + // head whitespace + append(object.value.match(/^[\t ]*/)[0], state); + if (start) { + append(start, state); + } + + var trimmedChildValueWithSpace = trimWithSingleSpace(object.value); + + /** + */ + var initialLines = trimmedChildValue.split(/\r\n|\n|\r/); + + var lines = initialLines.filter(function(line) { + return safeTrim(line).length > 0; + }); + + var hasInitialNewLine = initialLines[0] !== lines[0]; + var hasFinalNewLine = + initialLines[initialLines.length - 1] !== lines[lines.length - 1]; + + var numLines = lines.length; + lines.forEach(function (line, ii) { + var lastLine = ii === numLines - 1; + var trimmedLine = safeTrim(line); + if (trimmedLine === '' && !lastLine) { + append(line, state); + } else { + var preString = ''; + var postString = ''; + var leading = ''; + + if (ii === 0) { + if (hasInitialNewLine) { + preString = ' '; + leading = '\n'; + } + if (trimmedChildValueWithSpace.substring(0, 1) === ' ') { + // If this is the first line, and the original content starts with + // whitespace, place a single space at the beginning. + preString = ' '; + } + } else { + leading = line.match(/^[ \t]*/)[0]; + } + if (!lastLine || trimmedChildValueWithSpace.substr( + trimmedChildValueWithSpace.length - 1, 1) === ' ' || + hasFinalNewLine + ) { + // If either not on the last line, or the original content ends with + // whitespace, place a single character at the end. + postString = ' '; + } + + append( + leading + + JSON.stringify( + preString + trimmedLine + postString + ) + + (lastLine ? '' : '+') + + line.match(/[ \t]*$/)[0], + state); + } + if (!lastLine) { + append('\n', state); + } + }); + } else { + if (start) { + append(start, state); + } + append('""', state); + } + if (end) { + append(end, state); + } + + // add comma before trailing whitespace + if (!isLast) { + append(',', state); + } + + // tail whitespace + append(object.value.match(/[ \t]*$/)[0], state); + move(object.range[1], state); +} + +function renderXJSExpression(traverse, object, isLast, path, state) { + // Plus 1 to skip `{`. + move(object.range[0] + 1, state); + traverse(object.value, path, state); + if (!isLast) { + // If we need to append a comma, make sure to do so after the expression. + catchup(object.value.range[1], state); + append(',', state); + } + // Minus 1 to skip `}`. + catchup(object.range[1] - 1, state); + move(object.range[1], state); + return false; +} + +function quoteAttrName(attr) { + // Quote invalid JS identifiers. + if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) { + return "'" + attr + "'"; + } + return attr; +} + +exports.knownTags = knownTags; +exports.renderXJSExpression = renderXJSExpression; +exports.renderXJSLiteral = renderXJSLiteral; +exports.quoteAttrName = quoteAttrName; + +})() +},{"../lib/utils":8}],10:[function(require,module,exports){ +(function(){/* + Copyright (C) 2013 Thaddee Tyl + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint bitwise:true plusplus:true */ +/*global esprima:true, define:true, exports:true, window: true, +throwError: true, generateStatement: true, peek: true, +parseAssignmentExpression: true, parseBlock: true, +parseClassExpression: true, parseClassDeclaration: true, parseExpression: true, +parseForStatement: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseImportSpecifier: true, +parseLeftHandSideExpression: true, parseParams: true, validateParam: true, +parseSpreadOrAssignmentExpression: true, +parseStatement: true, parseSourceElement: true, parseModuleBlock: true, parseConciseBody: true, +advanceXJSChild: true, isXJSIdentifierStart: true, isXJSIdentifierPart: true, +scanXJSStringLiteral: true, scanXJSIdentifier: true, +parseXJSAttributeValue: true, parseXJSChild: true, parseXJSElement: true, parseXJSExpression: true, +parseYieldExpression: true +*/ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + FnExprTokens, + Syntax, + PropertyKind, + Messages, + Regex, + SyntaxTreeDelegate, + XHTMLEntities, + ClassPropertyType, + source, + strict, + index, + lineNumber, + lineStart, + length, + delegate, + lookahead, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8, + RegularExpression: 9, + Template: 10, + XJSIdentifier: 11, + XJSText: 12 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.XJSIdentifier] = 'XJSIdentifier'; + TokenName[Token.XJSText] = 'XJSText'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + + // A function following one of those tokens is an expression. + FnExprTokens = ["(", "{", "[", "in", "typeof", "instanceof", "new", + "return", "case", "delete", "throw", "void", + // assignment operators + "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", + "&=", "|=", "^=", ",", + // binary/unary operators + "+", "-", "*", "/", "%", "++", "--", "<<", ">>", ">>>", "&", + "|", "^", "!", "~", "&&", "||", "?", ":", "===", "==", ">=", + "<=", "<", ">", "!=", "!=="]; + + Syntax = { + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + AssignmentExpression: 'AssignmentExpression', + BinaryExpression: 'BinaryExpression', + BlockStatement: 'BlockStatement', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ClassHeritage: 'ClassHeritage', + ComprehensionBlock: 'ComprehensionBlock', + ComprehensionExpression: 'ComprehensionExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExportDeclaration: 'ExportDeclaration', + ExportSpecifier: 'ExportSpecifier', + ExportSpecifierSet: 'ExportSpecifierSet', + ExpressionStatement: 'ExpressionStatement', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + ForStatement: 'ForStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Glob: 'Glob', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportSpecifier: 'ImportSpecifier', + LabeledStatement: 'LabeledStatement', + Literal: 'Literal', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MethodDefinition: 'MethodDefinition', + ModuleDeclaration: 'ModuleDeclaration', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Path: 'Path', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + SwitchCase: 'SwitchCase', + SwitchStatement: 'SwitchStatement', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + XJSIdentifier: 'XJSIdentifier', + XJSExpression: 'XJSExpression', + XJSElement: 'XJSElement', + XJSClosingElement: 'XJSClosingElement', + XJSOpeningElement: 'XJSOpeningElement', + XJSAttribute: 'XJSAttribute', + XJSText: 'XJSText', + YieldExpression: 'YieldExpression' + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + ClassPropertyType = { + static: 1, + prototype: 2 + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedTemplate: 'Unexpected quasi %0', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInFormalsList: 'Invalid left-hand side in formals list', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalDuplicateClassProperty: 'Illegal duplicate property in class definition', + IllegalReturn: 'Illegal return statement', + IllegalYield: 'Illegal yield expression', + IllegalSpread: 'Illegal spread element', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + ParameterAfterRestParameter: 'Rest parameter must be final parameter of an argument list', + ElementAfterSpreadElement: 'Spread must be the final element of an element list', + ObjectPatternAsRestParameter: 'Invalid rest parameter', + ObjectPatternAsSpread: 'Invalid spread argument', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode', + NoFromAfterImport: 'Missing from after import', + NoYieldInGenerator: 'Missing yield in generator', + NoUnintializedConst: 'Const must be initialized', + ComprehensionRequiresBlock: 'Comprehension must have at least one block', + ComprehensionError: 'Comprehension Error', + EachNotAllowed: 'Each is not supported', + InvalidXJSTagName: 'XJS tag name can not be empty', + InvalidXJSAttributeValue: 'XJS value should be either an expression or a quoted XJS text', + ExpectedXJSClosingTag: 'Expected corresponding XJS closing tag for %0' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\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\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\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-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\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-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\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-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\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]'), + NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\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\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\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\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function isDecimalDigit(ch) { + return (ch >= 48 && ch <= 57); // 0..9 + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === 32) || // space + (ch === 9) || // tab + (ch === 0xB) || + (ch === 0xC) || + (ch === 0xA0) || + (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) + (ch >= 65 && ch <= 90) || // A..Z + (ch >= 97 && ch <= 122) || // a..z + (ch === 92) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); + } + + function isIdentifierPart(ch) { + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) + (ch >= 65 && ch <= 90) || // A..Z + (ch >= 97 && ch <= 122) || // a..z + (ch >= 48 && ch <= 57) || // 0..9 + (ch === 92) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + case 'class': + case 'enum': + case 'export': + case 'extends': + case 'import': + case 'super': + return true; + default: + return false; + } + } + + function isStrictModeReservedWord(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + default: + return false; + } + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // Some others are from future reserved words. + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // 7.4 Comments + + function skipComment() { + var ch, blockComment, lineComment; + + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source.charCodeAt(index); + + if (lineComment) { + ++index; + if (isLineTerminator(ch)) { + lineComment = false; + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === 13 && source.charCodeAt(index + 1) === 10) { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source.charCodeAt(index++); + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + // Block comment ends with '*/' (char #42, char #47). + if (ch === 42) { + ch = source.charCodeAt(index); + if (ch === 47) { + ++index; + blockComment = false; + } + } + } + } else if (ch === 47) { + ch = source.charCodeAt(index + 1); + // Line comment starts with '//' (char #47, char #47). + if (ch === 47) { + index += 2; + lineComment = true; + } else if (ch === 42) { + // Block comment starts with '/*' (char #47, char #42). + index += 2; + blockComment = true; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function scanUnicodeCodePointEscape() { + var ch, code, cu1, cu2; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // UTF-16 Encoding + if (code <= 0xFFFF) { + return String.fromCharCode(code); + } + cu1 = ((code - 0x10000) >> 10) + 0xD800; + cu2 = ((code - 0x10000) & 1023) + 0xDC00; + return String.fromCharCode(cu1, cu2); + } + + function getEscapedIdentifier() { + var ch, id; + + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); + + // '\u' (char #92, char #117) denotes an escaped character. + if (ch === 92) { + if (source.charCodeAt(index) !== 117) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id = ch; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (!isIdentifierPart(ch)) { + break; + } + ++index; + id += String.fromCharCode(ch); + + // '\u' (char #92, char #117) denotes an escaped character. + if (ch === 92) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 117) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id += ch; + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 92) { + // Blackslash (char #92) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return source.slice(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + + // Backslash (char #92) starts an escaped character. + id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + code = source.charCodeAt(index), + code2, + ch1 = source[index], + ch2, + ch3, + ch4; + + switch (code) { + // Check for most common single-character punctuators. + case 40: // ( open bracket + case 41: // ) close bracket + case 59: // ; semicolon + case 44: // , comma + case 123: // { open curly brace + case 125: // } close curly brace + case 91: // [ + case 93: // ] + case 58: // : + case 63: // ? + case 126: // ~ + ++index; + if (extra.tokenize) { + if (code === 40) { + extra.openParenToken = extra.tokens.length; + } else if (code === 123) { + extra.openCurlyToken = extra.tokens.length; + } + } + return { + type: Token.Punctuator, + value: String.fromCharCode(code), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + default: + code2 = source.charCodeAt(index + 1); + + // '=' (char #61) marks an assignment or comparison operator. + if (code2 === 61) { + switch (code) { + case 37: // % + case 38: // & + case 42: // *: + case 43: // + + case 45: // - + case 47: // / + case 60: // < + case 62: // > + case 94: // ^ + case 124: // | + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + case 33: // ! + case 61: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 61) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + default: + break; + } + } + break; + } + + // Peek more characters. + + ch2 = source[index + 1]; + ch3 = source[index + 2]; + ch4 = source[index + 3]; + + // 4-character punctuator: >>>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + if (ch4 === '=') { + index += 4; + return { + type: Token.Punctuator, + value: '>>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // 3-character punctuators: === !== >>> <<= >>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + index += 3; + return { + type: Token.Punctuator, + value: '>>>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '<' && ch2 === '<' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '<<=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '.' && ch2 === '.' && ch3 === '.') { + index += 3; + return { + type: Token.Punctuator, + value: '...', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // Other 2-character punctuators: ++ -- << >> && || + + if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { + index += 2; + return { + type: Token.Punctuator, + value: ch1 + ch2, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '=' && ch2 === '>') { + index += 2; + return { + type: Token.Punctuator, + value: '=>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '.') { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // 7.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (!octal && number.length === 0) { + // only 0o or 0O + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanNumericLiteral() { + var number, start, ch, octal; + + ch = source[index]; + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + ++index; + return scanHexLiteral(start); + } + if (ch === 'b' || ch === 'B') { + ++index; + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (index < length) { + ch = source.charCodeAt(index); + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) { + return scanOctalLiteral(ch, start); + } + // decimal number starts with '0' such as '09' is illegal. + if (ch && isDecimalDigit(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === '.') { + number += source[index++]; + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + } else { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + } + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanTemplate() { + var cooked = '', ch, start, terminated, tail, restore, unescaped, code, octal; + + terminated = false; + tail = false; + start = index; + + ++index; + + while (index < length) { + ch = source[index++]; + if (ch === '`') { + tail = true; + terminated = true; + break; + } else if (ch === '$') { + if (source[index] === '{') { + ++index; + terminated = true; + break; + } + cooked += ch; + } else if (ch === '\\') { + ch = source[index++]; + if (!isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + cooked += '\n'; + break; + case 'r': + cooked += '\r'; + break; + case 't': + cooked += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + cooked += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + cooked += unescaped; + } else { + index = restore; + cooked += ch; + } + } + break; + case 'b': + cooked += '\b'; + break; + case 'f': + cooked += '\f'; + break; + case 'v': + cooked += '\v'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + cooked += String.fromCharCode(code); + } else { + cooked += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } else { + cooked += ch; + } + } + + if (!terminated) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.Template, + value: { + cooked: cooked, + raw: source.slice(start + 1, index - ((tail) ? 1 : 2)) + }, + tail: tail, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanTemplateElement(option) { + var startsWith, template; + + lookahead = null; + skipComment(); + + startsWith = (option.head) ? '`' : '}'; + + if (source[index] !== startsWith) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + template = scanTemplate(); + + peek(); + + return template; + } + + function scanRegExp() { + var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + + lookahead = null; + skipComment(); + + start = index; + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + while (index < length) { + ch = source[index++]; + str += ch; + if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + } + } + + if (!terminated) { + throwError({}, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + pattern = str.substr(1, str.length - 2); + + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch.charCodeAt(0))) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + } else { + str += '\\'; + } + } else { + flags += ch; + str += ch; + } + } + + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + + peek(); + + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + return { + literal: str, + value: value, + range: [start, index] + }; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return scanRegExp(); + } + if (prevToken.type === "Punctuator") { + if (prevToken.value === ")") { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === "Keyword" && + (checkToken.value === "if" || + checkToken.value === "while" || + checkToken.value === "for" || + checkToken.value === "with")) { + return scanRegExp(); + } + return scanPunctuator(); + } + if (prevToken.value === "}") { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === "Keyword") { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === "Keyword") { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return scanRegExp(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return scanRegExp(); + } + return scanRegExp(); + } + if (prevToken.type === "Keyword") { + return scanRegExp(); + } + return scanPunctuator(); + } + + function advance() { + var ch; + + if (state.inXJSChild) { + return advanceXJSChild(); + } + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + range: [index, index] + }; + } + + ch = source.charCodeAt(index); + + // Very common: ( and ) and ; + if (ch === 40 || ch === 41 || ch === 58) { + return scanPunctuator(); + } + + // String literal starts with single quote (#39) or double quote (#34). + if (ch === 39 || ch === 34) { + if (state.inXJSTag) { + return scanXJSStringLiteral(); + } + return scanStringLiteral(); + } + + if (state.inXJSTag && isXJSIdentifierStart(ch)) { + return scanXJSIdentifier(); + } + + if (ch === 96) { + return scanTemplate(); + } + if (isIdentifierStart(ch)) { + return scanIdentifier(); + } + + // Dot (.) char #46 can also start a floating-point number, hence the need + // to check the next character. + if (ch === 46) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + // Slash (/) char #47 can also start a regex. + if (extra.tokenize && ch === 47) { + return advanceSlash(); + } + + return scanPunctuator(); + } + + function lex() { + var token; + + token = lookahead; + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + lookahead = advance(); + + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; + } + + function peek() { + var pos, line, start; + + pos = index; + line = lineNumber; + start = lineStart; + lookahead = advance(); + index = pos; + lineNumber = line; + lineStart = start; + } + + function lookahead2() { + var adv, pos, line, start, result; + + // If we are collecting the tokens, don't grab the next one yet. + adv = (typeof extra.advance === 'function') ? extra.advance : advance; + + pos = index; + line = lineNumber; + start = lineStart; + + // Scan for the next immediate token. + if (lookahead === null) { + lookahead = adv(); + } + index = lookahead.range[1]; + lineNumber = lookahead.lineNumber; + lineStart = lookahead.lineStart; + + // Grab the token right after. + result = adv(); + index = pos; + lineNumber = line; + lineStart = start; + + return result; + } + + SyntaxTreeDelegate = { + + name: 'SyntaxTree', + + postProcess: function (node) { + return node; + }, + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : + Syntax.BinaryExpression; + return { + type: type, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createForOfStatement: function (left, right, body) { + return { + type: Syntax.ForOfStatement, + left: left, + right: right, + body: body, + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: generator, + expression: expression + }; + }, + + createFunctionExpression: function (id, params, defaults, body, rest, generator, expression) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: generator, + expression: expression + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name + }; + }, + + createXJSAttribute: function (name, value) { + return { + type: Syntax.XJSAttribute, + name: name, + value: value + }; + }, + + createXJSIdentifier: function (name, namespace) { + return { + type: Syntax.XJSIdentifier, + name: name, + namespace: namespace + }; + }, + + createXJSElement: function (openingElement, closingElement, children) { + return { + type: Syntax.XJSElement, + name: openingElement.name, + selfClosing: openingElement.selfClosing, + openingElement: openingElement, + closingElement: closingElement, + attributes: openingElement.attributes, + children: children + }; + }, + + createXJSExpression: function (expression) { + return { + type: Syntax.XJSExpression, + value: expression + }; + }, + + createXJSOpeningElement: function (name, attributes, selfClosing) { + return { + type: Syntax.XJSOpeningElement, + name: name, + selfClosing: selfClosing, + attributes: attributes + }; + }, + + createXJSClosingElement: function (name) { + return { + type: Syntax.XJSClosingElement, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: source.slice(token.range[0], token.range[1]) + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value, method, shorthand) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind, + method: method, + shorthand: shorthand + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + }, + + createTemplateElement: function (value, tail) { + return { + type: Syntax.TemplateElement, + value: value, + tail: tail + }; + }, + + createTemplateLiteral: function (quasis, expressions) { + return { + type: Syntax.TemplateLiteral, + quasis: quasis, + expressions: expressions + }; + }, + + createSpreadElement: function (argument) { + return { + type: Syntax.SpreadElement, + argument: argument + }; + }, + + createTaggedTemplateExpression: function (tag, quasi) { + return { + type: Syntax.TaggedTemplateExpression, + tag: tag, + quasi: quasi + }; + }, + + createArrowFunctionExpression: function (params, defaults, body, rest, expression) { + return { + type: Syntax.ArrowFunctionExpression, + id: null, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: false, + expression: expression + }; + }, + + createMethodDefinition: function (propertyType, kind, key, value) { + return { + type: Syntax.MethodDefinition, + key: key, + value: value, + kind: kind, + 'static': propertyType === ClassPropertyType.static + }; + }, + + createClassBody: function (body) { + return { + type: Syntax.ClassBody, + body: body + }; + }, + + createClassExpression: function (id, superClass, body) { + return { + type: Syntax.ClassExpression, + id: id, + superClass: superClass, + body: body + }; + }, + + createClassDeclaration: function (id, superClass, body) { + return { + type: Syntax.ClassDeclaration, + id: id, + superClass: superClass, + body: body + }; + }, + + createPath: function (body) { + return { + type: Syntax.Path, + body: body + }; + }, + + createGlob: function () { + return { + type: Syntax.Glob + }; + }, + + createExportSpecifier: function (id, from) { + return { + type: Syntax.ExportSpecifier, + id: id, + from: from + }; + }, + + createExportSpecifierSet: function (specifiers) { + return { + type: Syntax.ExportSpecifierSet, + specifiers: specifiers + }; + }, + + createExportDeclaration: function (declaration, specifiers) { + return { + type: Syntax.ExportDeclaration, + declaration: declaration, + specifiers: specifiers + }; + }, + + createImportSpecifier: function (id, from) { + return { + type: Syntax.ImportSpecifier, + id: id, + from: from + }; + }, + + createImportDeclaration: function (specifiers, from) { + return { + type: Syntax.ImportDeclaration, + specifiers: specifiers, + from: from + }; + }, + + createYieldExpression: function (argument, delegate) { + return { + type: Syntax.YieldExpression, + argument: argument, + delegate: delegate + }; + }, + + createModuleDeclaration: function (id, from, body) { + return { + type: Syntax.ModuleDeclaration, + id: id, + from: from, + body: body + }; + } + + + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception + + function throwError(token, messageFormat) { + var error, + args = Array.prototype.slice.call(arguments, 2), + msg = messageFormat.replace( + /%(\d)/g, + function (whole, index) { + assert(index < args.length, 'Message reference must be in range'); + return args[index]; + } + ); + + if (typeof token.lineNumber === 'number') { + error = new Error('Line ' + token.lineNumber + ': ' + msg); + error.index = token.range[0]; + error.lineNumber = token.lineNumber; + error.column = token.range[0] - lineStart + 1; + } else { + error = new Error('Line ' + lineNumber + ': ' + msg); + error.index = index; + error.lineNumber = lineNumber; + error.column = index - lineStart + 1; + } + + error.description = msg; + throw error; + } + + function throwErrorTolerant() { + try { + throwError.apply(null, arguments); + } catch (e) { + if (extra.errors) { + extra.errors.push(e); + } else { + throw e; + } + } + } + + + // Throw an exception because of the token. + + function throwUnexpected(token) { + if (token.type === Token.EOF) { + throwError(token, Messages.UnexpectedEOS); + } + + if (token.type === Token.NumericLiteral) { + throwError(token, Messages.UnexpectedNumber); + } + + if (token.type === Token.StringLiteral) { + throwError(token, Messages.UnexpectedString); + } + + if (token.type === Token.Identifier) { + throwError(token, Messages.UnexpectedIdentifier); + } + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + throwError(token, Messages.UnexpectedReserved); + } else if (strict && isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + return; + } + throwError(token, Messages.UnexpectedToken, token.value); + } + + if (token.type === Token.Template) { + throwError(token, Messages.UnexpectedTemplate, token.value.raw); + } + + // BooleanLiteral, NullLiteral, or Punctuator. + throwError(token, Messages.UnexpectedToken, token.value); + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpected(token); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpected(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + + // Return true if the next token matches the specified contextual keyword + + function matchContextualKeyword(keyword) { + return lookahead.type === Token.Identifier && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var line; + + // Catch the very common case first: immediately a semicolon (char #59). + if (source.charCodeAt(index) === 59) { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + return; + } + + if (match(';')) { + lex(); + return; + } + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + function isAssignableLeftHandSide(expr) { + return isLeftHandSide(expr) || expr.type === Syntax.ObjectPattern || expr.type === Syntax.ArrayPattern; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = [], blocks = [], filter = null, tmp, possiblecomprehension = true, body; + + expect('['); + while (!match(']')) { + if (lookahead.value === 'for' && + lookahead.type === Token.Keyword) { + if (!possiblecomprehension) { + throwError({}, Messages.ComprehensionError); + } + matchKeyword('for'); + tmp = parseForStatement({ignore_body: true}); + tmp.of = tmp.type === Syntax.ForOfStatement; + tmp.type = Syntax.ComprehensionBlock; + if (tmp.left.kind) { // can't be let or const + throwError({}, Messages.ComprehensionError); + } + blocks.push(tmp); + } else if (lookahead.value === 'if' && + lookahead.type === Token.Keyword) { + if (!possiblecomprehension) { + throwError({}, Messages.ComprehensionError); + } + expectKeyword('if'); + expect('('); + filter = parseExpression(); + expect(')'); + } else if (lookahead.value === ',' && + lookahead.type === Token.Punctuator) { + possiblecomprehension = false; // no longer allowed. + lex(); + elements.push(null); + } else { + tmp = parseSpreadOrAssignmentExpression(); + elements.push(tmp); + if (tmp && tmp.type === Syntax.SpreadElement) { + if (!match(']')) { + throwError({}, Messages.ElementAfterSpreadElement); + } + } else if (!(match(']') || matchKeyword('for') || matchKeyword('if'))) { + expect(','); // this lexes. + possiblecomprehension = false; + } + } + } + + expect(']'); + + if (filter && !blocks.length) { + throwError({}, Messages.ComprehensionRequiresBlock); + } + + if (blocks.length) { + if (elements.length !== 1) { + throwError({}, Messages.ComprehensionError); + } + return { + type: Syntax.ComprehensionExpression, + filter: filter, + blocks: blocks, + body: elements[0] + }; + } + return delegate.createArrayExpression(elements); + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(options) { + var previousStrict, previousYieldAllowed, params, body; + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = options.generator; + params = options.params || []; + + body = parseConciseBody(); + if (options.name && strict && isRestrictedWord(params[0].name)) { + throwErrorTolerant(options.name, Messages.StrictParamName); + } + if (state.yieldAllowed && !state.yieldFound) { + throwError({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionExpression(null, params, [], body, options.rest || null, options.generator, body.type !== Syntax.BlockStatement); + } + + + function parsePropertyMethodFunction(options) { + var previousStrict, tmp, method; + + previousStrict = strict; + strict = true; + + tmp = parseParams(); + + if (tmp.stricted) { + throwErrorTolerant(tmp.stricted, tmp.message); + } + + + method = parsePropertyFunction({ + params: tmp.params, + rest: tmp.rest, + generator: options.generator + }); + + strict = previousStrict; + + return method; + } + + + function parseObjectPropertyKey() { + var token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseObjectProperty() { + var token, key, id, value, param; + + token = lookahead; + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + return delegate.createProperty('get', key, parsePropertyFunction({ generator: false }), false, false); + } + if (token.value === 'set' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead; + param = [ parseVariableIdentifier() ]; + expect(')'); + return delegate.createProperty('set', key, parsePropertyFunction({ params: param, generator: false, name: token }), false, false); + } + if (match(':')) { + lex(); + return delegate.createProperty('init', id, parseAssignmentExpression(), false, false); + } + if (match('(')) { + return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: false }), true, false); + } + return delegate.createProperty('init', id, id, false, true); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { + if (!match('*')) { + throwUnexpected(token); + } + lex(); + + id = parseObjectPropertyKey(); + + if (!match('(')) { + throwUnexpected(lex()); + } + + return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: true }), true, false); + } + key = parseObjectPropertyKey(); + if (match(':')) { + lex(); + return delegate.createProperty('init', key, parseAssignmentExpression(), false, false); + } + if (match('(')) { + return delegate.createProperty('init', key, parsePropertyMethodFunction({ generator: false }), true, false); + } + throwUnexpected(lex()); + } + + function parseObjectInitialiser() { + var properties = [], property, name, key, kind, map = {}, toString = String; + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } else if (map[key] & kind) { + throwErrorTolerant({}, Messages.AccessorGetSet); + } + } + map[key] |= kind; + } else { + map[key] = kind; + } + + properties.push(property); + + if (!match('}')) { + expect(','); + } + } + + expect('}'); + + return delegate.createObjectExpression(properties); + } + + function parseTemplateElement(option) { + var token = scanTemplateElement(option); + if (strict && token.octal) { + throwError(token, Messages.StrictOctalLiteral); + } + return delegate.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail); + } + + function parseTemplateLiteral() { + var quasi, quasis, expressions; + + quasi = parseTemplateElement({ head: true }); + quasis = [ quasi ]; + expressions = []; + + while (!quasi.tail) { + expressions.push(parseExpression()); + quasi = parseTemplateElement({ head: false }); + quasis.push(quasi); + } + + return delegate.createTemplateLiteral(quasis, expressions); + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + ++state.parenthesizedCount; + + state.allowArrowFunction = !state.allowArrowFunction; + expr = parseExpression(); + state.allowArrowFunction = false; + + if (expr.type !== Syntax.ArrowFunctionExpression) { + expect(')'); + } + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var type, token; + + token = lookahead; + type = lookahead.type; + + if (type === Token.Identifier) { + lex(); + return delegate.createIdentifier(token.value); + } + + if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(lex()); + } + + if (type === Token.Keyword) { + if (matchKeyword('this')) { + lex(); + return delegate.createThisExpression(); + } + + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + + if (matchKeyword('class')) { + return parseClassExpression(); + } + + if (matchKeyword('super')) { + lex(); + return delegate.createIdentifier('super'); + } + } + + if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + return delegate.createLiteral(token); + } + + if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + return delegate.createLiteral(token); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('/') || match('/=')) { + return delegate.createLiteral(scanRegExp()); + } + + if (type === Token.Template) { + return parseTemplateLiteral(); + } + + if (match('<')) { + return parseXJSElement(); + } + + return throwUnexpected(lex()); + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = [], arg; + + expect('('); + + if (!match(')')) { + while (index < length) { + arg = parseSpreadOrAssignmentExpression(); + args.push(arg); + + if (match(')')) { + break; + } else if (arg.type === Syntax.SpreadElement) { + throwError({}, Messages.ElementAfterSpreadElement); + } + + expect(','); + } + } + + expect(')'); + + return args; + } + + function parseSpreadOrAssignmentExpression() { + if (match('...')) { + lex(); + return delegate.createSpreadElement(parseAssignmentExpression()); + } + return parseAssignmentExpression(); + } + + function parseNonComputedProperty() { + var token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var callee, args; + + expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; + + return delegate.createNewExpression(callee, args); + } + + function parseLeftHandSideExpressionAllowCall() { + var expr, args, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + } else if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + } + } + + return expr; + } + + + function parseLeftHandSideExpression() { + var expr, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || lookahead.type === Token.Template) { + if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + } + } + + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr = parseLeftHandSideExpressionAllowCall(), + token = lookahead; + + if (lookahead.type !== Token.Punctuator) { + return expr; + } + + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.createPostfixExpression(token.value, expr); + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + return parsePostfixExpression(); + } + + if (match('++') || match('--')) { + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + return delegate.createUnaryExpression(token.value, expr); + } + + if (match('+') || match('-') || match('~') || match('!')) { + token = lex(); + expr = parseUnaryExpression(); + return delegate.createUnaryExpression(token.value, expr); + } + + if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + throwErrorTolerant({}, Messages.StrictDelete); + } + return expr; + } + + return parsePostfixExpression(); + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators + // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators + + function parseBinaryExpression() { + var expr, token, prec, previousAllowIn, stack, right, operator, left, i; + + previousAllowIn = state.allowIn; + state.allowIn = true; + + expr = parseUnaryExpression(); + + token = lookahead; + prec = binaryPrecedence(token, previousAllowIn); + if (prec === 0) { + return expr; + } + token.prec = prec; + lex(); + + stack = [expr, token, parseUnaryExpression()]; + + while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) { + + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + stack.push(delegate.createBinaryExpression(operator, left, right)); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + stack.push(parseUnaryExpression()); + } + + state.allowIn = previousAllowIn; + + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + while (i > 1) { + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + } + return expr; + } + + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate; + + expr = parseBinaryExpression(); + + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + alternate = parseAssignmentExpression(); + + expr = delegate.createConditionalExpression(expr, consequent, alternate); + } + + return expr; + } + + // 11.13 Assignment Operators + + function reinterpretAsAssignmentBindingPattern(expr) { + var i, len, property, element; + + if (expr.type === Syntax.ObjectExpression) { + expr.type = Syntax.ObjectPattern; + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (property.kind !== 'init') { + throwError({}, Messages.InvalidLHSInAssignment); + } + reinterpretAsAssignmentBindingPattern(property.value); + } + } else if (expr.type === Syntax.ArrayExpression) { + expr.type = Syntax.ArrayPattern; + for (i = 0, len = expr.elements.length; i < len; i += 1) { + element = expr.elements[i]; + if (element) { + reinterpretAsAssignmentBindingPattern(element); + } + } + } else if (expr.type === Syntax.Identifier) { + if (isRestrictedWord(expr.name)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + } else if (expr.type === Syntax.SpreadElement) { + reinterpretAsAssignmentBindingPattern(expr.argument); + if (expr.argument.type === Syntax.ObjectPattern) { + throwError({}, Messages.ObjectPatternAsSpread); + } + } else { + if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) { + throwError({}, Messages.InvalidLHSInAssignment); + } + } + } + + + function reinterpretAsDestructuredParameter(options, expr) { + var i, len, property, element; + + if (expr.type === Syntax.ObjectExpression) { + expr.type = Syntax.ObjectPattern; + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (property.kind !== 'init') { + throwError({}, Messages.InvalidLHSInFormalsList); + } + reinterpretAsDestructuredParameter(options, property.value); + } + } else if (expr.type === Syntax.ArrayExpression) { + expr.type = Syntax.ArrayPattern; + for (i = 0, len = expr.elements.length; i < len; i += 1) { + element = expr.elements[i]; + if (element) { + reinterpretAsDestructuredParameter(options, element); + } + } + } else if (expr.type === Syntax.Identifier) { + validateParam(options, expr, expr.name); + } else { + if (expr.type !== Syntax.MemberExpression) { + throwError({}, Messages.InvalidLHSInFormalsList); + } + } + } + + function reinterpretAsCoverFormalsList(expressions) { + var i, len, param, params, options, rest; + + params = []; + rest = null; + options = { + paramSet: {} + }; + + for (i = 0, len = expressions.length; i < len; i += 1) { + param = expressions[i]; + if (param.type === Syntax.Identifier) { + params.push(param); + validateParam(options, param, param.name); + } else if (param.type === Syntax.ObjectExpression || param.type === Syntax.ArrayExpression) { + reinterpretAsDestructuredParameter(options, param); + params.push(param); + } else if (param.type === Syntax.SpreadElement) { + assert(i === len - 1, "It is guaranteed that SpreadElement is last element by parseExpression"); + reinterpretAsDestructuredParameter(options, param.argument); + rest = param.argument; + } else { + return null; + } + } + + if (options.firstRestricted) { + throwError(options.firstRestricted, options.message); + } + if (options.stricted) { + throwErrorTolerant(options.stricted, options.message); + } + + return { params: params, rest: rest }; + } + + function parseArrowFunctionExpression(options) { + var previousStrict, previousYieldAllowed, body; + + expect('=>'); + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + strict = true; + state.yieldAllowed = false; + body = parseConciseBody(); + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createArrowFunctionExpression(options.params, [], body, options.rest, body.type !== Syntax.BlockStatement); + } + + function parseAssignmentExpression() { + var expr, token, params, oldParenthesizedCount; + + if (matchKeyword('yield')) { + return parseYieldExpression(); + } + + oldParenthesizedCount = state.parenthesizedCount; + + if (match('(')) { + token = lookahead2(); + if ((token.type === Token.Punctuator && token.value === ')') || token.value === '...') { + params = parseParams(); + if (!match('=>')) { + throwUnexpected(lex()); + } + return parseArrowFunctionExpression(params); + } + } + + token = lookahead; + expr = parseConditionalExpression(); + + if (match('=>') && expr.type === Syntax.Identifier) { + if (state.parenthesizedCount === oldParenthesizedCount || state.parenthesizedCount === (oldParenthesizedCount + 1)) { + if (isRestrictedWord(expr.name)) { + throwError({}, Messages.StrictParamName); + } + return parseArrowFunctionExpression({ params: [ expr ], rest: null }); + } + } + + if (matchAssign()) { + // 11.13.1 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant(token, Messages.StrictLHSAssignment); + } + + // ES.next draf 11.13 Runtime Semantics step 1 + if (match('=') && (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression)) { + reinterpretAsAssignmentBindingPattern(expr); + } else if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + expr = delegate.createAssignmentExpression(lex().value, expr, parseAssignmentExpression()); + } + + return expr; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr, expressions, sequence, coverFormalsList, spreadFound, token; + + expr = parseAssignmentExpression(); + expressions = [ expr ]; + + if (match(',')) { + while (index < length) { + if (!match(',')) { + break; + } + + lex(); + expr = parseSpreadOrAssignmentExpression(); + expressions.push(expr); + + if (expr.type === Syntax.SpreadElement) { + spreadFound = true; + if (!match(')')) { + throwError({}, Messages.ElementAfterSpreadElement); + } + break; + } + } + + sequence = delegate.createSequenceExpression(expressions); + } + + if (state.allowArrowFunction && match(')')) { + token = lookahead2(); + if (token.value === '=>') { + lex(); + + state.allowArrowFunction = false; + expr = expressions; + coverFormalsList = reinterpretAsCoverFormalsList(expr); + if (coverFormalsList) { + return parseArrowFunctionExpression(coverFormalsList); + } + + throwUnexpected(token); + } + } + + if (spreadFound) { + throwError({}, Messages.IllegalSpread); + } + + return sequence || expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block; + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + // 12.2 Variable Statement + + function parseVariableIdentifier() { + var token = lex(); + + if (token.type !== Token.Identifier) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseVariableDeclaration(kind) { + var id, + init = null; + if (match('{')) { + id = parseObjectInitialiser(); + reinterpretAsAssignmentBindingPattern(id); + } else if (match('[')) { + id = parseArrayInitialiser(); + reinterpretAsAssignmentBindingPattern(id); + } else { + id = parseVariableIdentifier(); + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + throwErrorTolerant({}, Messages.StrictVarName); + } + } + + if (kind === 'const') { + if (!match('=')) { + throwError({}, Messages.NoUnintializedConst); + } + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return delegate.createVariableDeclarator(id, init); + } + + function parseVariableDeclarationList(kind) { + var list = []; + + do { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } while (index < length); + + return list; + } + + function parseVariableStatement() { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, 'var'); + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations; + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, kind); + } + + // http://wiki.ecmascript.org/doku.php?id=harmony:modules + + function parsePath() { + var body = []; + + while (true) { + body.push(parseVariableIdentifier()); + if (!match('.')) { + break; + } + lex(); + } + + return delegate.createPath(body); + } + + function parseGlob() { + expect('*'); + return delegate.createGlob(); + } + + function parseModuleDeclaration() { + var id, token, from = null; + + lex(); + + id = parseVariableIdentifier(); + + if (match('{')) { + return delegate.createModuleDeclaration(id, from, parseModuleBlock()); + } + + expect('='); + + token = lookahead; + if (token.type === Token.StringLiteral) { + from = parsePrimaryExpression(); + } else { + from = parsePath(); + } + + consumeSemicolon(); + + return delegate.createModuleDeclaration(id, from, null); + } + + function parseExportSpecifierSetProperty() { + var id, from = null; + + id = parseVariableIdentifier(); + + if (match(':')) { + lex(); + from = parsePath(); + } + + return delegate.createExportSpecifier(id, from); + } + + function parseExportSpecifier() { + var specifiers, id, from; + + if (match('{')) { + lex(); + specifiers = []; + + do { + specifiers.push(parseExportSpecifierSetProperty()); + } while (match(',') && lex()); + + expect('}'); + + return delegate.createExportSpecifierSet(specifiers); + } + + from = null; + + if (match('*')) { + id = parseGlob(); + if (matchContextualKeyword('from')) { + lex(); + from = parsePath(); + } + } else { + id = parseVariableIdentifier(); + } + return delegate.createExportSpecifier(id, from); + } + + function parseExportDeclaration() { + var token, specifiers; + + expectKeyword('export'); + + token = lookahead; + + if (token.type === Token.Keyword || (token.type === Token.Identifier && token.value === 'module')) { + switch (token.value) { + case 'function': + return delegate.createExportDeclaration(parseFunctionDeclaration(), null); + case 'module': + return delegate.createExportDeclaration(parseModuleDeclaration(), null); + case 'let': + case 'const': + return delegate.createExportDeclaration(parseConstLetDeclaration(token.value), null); + case 'var': + return delegate.createExportDeclaration(parseStatement(), null); + case 'class': + return delegate.createExportDeclaration(parseClassDeclaration(), null); + } + throwUnexpected(lex()); + } + + specifiers = [ parseExportSpecifier() ]; + if (match(',')) { + while (index < length) { + if (!match(',')) { + break; + } + lex(); + specifiers.push(parseExportSpecifier()); + } + } + + consumeSemicolon(); + + return delegate.createExportDeclaration(null, specifiers); + } + + function parseImportDeclaration() { + var specifiers, from; + + expectKeyword('import'); + + if (match('*')) { + specifiers = [parseGlob()]; + } else if (match('{')) { + lex(); + specifiers = []; + + do { + specifiers.push(parseImportSpecifier()); + } while (match(',') && lex()); + + expect('}'); + } else { + specifiers = [parseVariableIdentifier()]; + } + + if (!matchContextualKeyword('from')) { + throwError({}, Messages.NoFromAfterImport); + } + + lex(); + + if (lookahead.type === Token.StringLiteral) { + from = parsePrimaryExpression(); + } else { + from = parsePath(); + } + + consumeSemicolon(); + + return delegate.createImportDeclaration(specifiers, from); + } + + function parseImportSpecifier() { + var id, from; + + id = parseVariableIdentifier(); + from = null; + + if (match(':')) { + lex(); + from = parsePath(); + } + + return delegate.createImportSpecifier(id, from); + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + expect(';'); + return delegate.createEmptyStatement(); + } + + // 12.4 Expression Statement + + function parseExpressionStatement() { + var expr = parseExpression(); + consumeSemicolon(); + return delegate.createExpressionStatement(expr); + } + + // 12.5 If statement + + function parseIfStatement() { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return delegate.createIfStatement(test, consequent, alternate); + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement() { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return delegate.createDoWhileStatement(body, test); + } + + function parseWhileStatement() { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return delegate.createWhileStatement(test, body); + } + + function parseForVariableDeclaration() { + var token = lex(), + declarations = parseVariableDeclarationList(); + + return delegate.createVariableDeclaration(declarations, token.value); + } + + function parseForStatement(opts) { + var init, test, update, left, right, body, operator, oldInIteration; + init = test = update = null; + expectKeyword('for'); + + // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each + if (matchContextualKeyword("each")) { + throwError({}, Messages.EachNotAllowed); + } + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = true; + + if (init.declarations.length === 1) { + if (matchKeyword('in') || matchContextualKeyword('of')) { + operator = lookahead; + if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = true; + + if (matchContextualKeyword('of')) { + operator = lex(); + left = init; + right = parseExpression(); + init = null; + } else if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isAssignableLeftHandSide(init)) { + throwError({}, Messages.InvalidLHSInForIn); + } + operator = lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + if (!(opts !== undefined && opts.ignore_body)) { + body = parseStatement(); + } + + state.inIteration = oldInIteration; + + if (typeof left === 'undefined') { + return delegate.createForStatement(init, test, update, body); + } + + if (operator.value === 'in') { + return delegate.createForInStatement(left, right, body); + } + return delegate.createForOfStatement(left, right, body); + } + + // 12.7 The continue statement + + function parseContinueStatement() { + var label = null, key; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source.charCodeAt(index) === 59) { + lex(); + + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(label); + } + + // 12.8 The break statement + + function parseBreakStatement() { + var label = null, key; + + expectKeyword('break'); + + // Catch the very common case first: immediately a semicolon (char #59). + if (source.charCodeAt(index) === 59) { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(label); + } + + // 12.9 The return statement + + function parseReturnStatement() { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + throwErrorTolerant({}, Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source.charCodeAt(index) === 32) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { + argument = parseExpression(); + consumeSemicolon(); + return delegate.createReturnStatement(argument); + } + } + + if (peekLineTerminator()) { + return delegate.createReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return delegate.createReturnStatement(argument); + } + + // 12.10 The with statement + + function parseWithStatement() { + var object, body; + + if (strict) { + throwErrorTolerant({}, Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return delegate.createWithStatement(object, body); + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, + consequent = [], + sourceElement; + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + consequent.push(sourceElement); + } + + return delegate.createSwitchCase(test, consequent); + } + + function parseSwitchStatement() { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + if (match('}')) { + lex(); + return delegate.createSwitchStatement(discriminant); + } + + cases = []; + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError({}, Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return delegate.createSwitchStatement(discriminant, cases); + } + + // 12.13 The throw statement + + function parseThrowStatement() { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return delegate.createThrowStatement(argument); + } + + // 12.14 The try statement + + function parseCatchClause() { + var param, body; + + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpected(lookahead); + } + + param = parseExpression(); + // 12.14.1 + if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) { + throwErrorTolerant({}, Messages.StrictCatchVariable); + } + + expect(')'); + body = parseBlock(); + return delegate.createCatchClause(param, body); + } + + function parseTryStatement() { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError({}, Messages.NoCatchOrFinally); + } + + return delegate.createTryStatement(block, [], handlers, finalizer); + } + + // 12.15 The debugger statement + + function parseDebuggerStatement() { + expectKeyword('debugger'); + + consumeSemicolon(); + + return delegate.createDebuggerStatement(); + } + + // 12 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody, + key; + + if (type === Token.EOF) { + throwUnexpected(lookahead); + } + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return parseEmptyStatement(); + case '{': + return parseBlock(); + case '(': + return parseExpressionStatement(); + default: + break; + } + } + + if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return parseBreakStatement(); + case 'continue': + return parseContinueStatement(); + case 'debugger': + return parseDebuggerStatement(); + case 'do': + return parseDoWhileStatement(); + case 'for': + return parseForStatement(); + case 'function': + return parseFunctionDeclaration(); + case 'class': + return parseClassDeclaration(); + case 'if': + return parseIfStatement(); + case 'return': + return parseReturnStatement(); + case 'switch': + return parseSwitchStatement(); + case 'throw': + return parseThrowStatement(); + case 'try': + return parseTryStatement(); + case 'var': + return parseVariableStatement(); + case 'while': + return parseWhileStatement(); + case 'with': + return parseWithStatement(); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[key] = true; + labeledBody = parseStatement(); + delete state.labelSet[key]; + return delegate.createLabeledStatement(expr, labeledBody); + } + + consumeSemicolon(); + + return delegate.createExpressionStatement(expr); + } + + // 13 Function Definition + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return parseAssignmentExpression(); + } + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesizedCount; + + expect('{'); + + while (index < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + oldParenthesizedCount = state.parenthesizedCount; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + state.parenthesizedCount = 0; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + state.parenthesizedCount = oldParenthesizedCount; + + return delegate.createBlockStatement(sourceElements); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.firstRestricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, rest, param; + + token = lookahead; + if (token.value === '...') { + token = lex(); + rest = true; + } + + if (match('[')) { + param = parseArrayInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else if (match('{')) { + if (rest) { + throwError({}, Messages.ObjectPatternAsRestParameter); + } + param = parseObjectInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else { + param = parseVariableIdentifier(); + validateParam(options, token, token.value); + } + + if (rest) { + if (!match(')')) { + throwError({}, Messages.ParameterAfterRestParameter); + } + options.rest = param; + return false; + } + + options.params.push(param); + return !match(')'); + } + + function parseParams(firstRestricted) { + var options; + + options = { + params: [], + rest: null, + firstRestricted: firstRestricted + }; + + expect('('); + + if (!match(')')) { + options.paramSet = {}; + while (index < length) { + if (!parseParam(options)) { + break; + } + expect(','); + } + } + + expect(')'); + + return options; + } + + function parseFunctionDeclaration() { + var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator, expression; + + expectKeyword('function'); + + generator = false; + if (match('*')) { + lex(); + generator = true; + } + + token = lookahead; + + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = generator; + + // here we redo some work in order to set 'expression' + expression = !match('{'); + body = parseConciseBody(); + + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && tmp.stricted) { + throwErrorTolerant(tmp.stricted, message); + } + if (state.yieldAllowed && !state.yieldFound) { + throwError({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionDeclaration(id, tmp.params, [], body, tmp.rest, generator, expression); + } + + function parseFunctionExpression() { + var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator, expression; + + expectKeyword('function'); + + generator = false; + + if (match('*')) { + lex(); + generator = true; + } + + if (!match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = generator; + + // here we redo some work in order to set 'expression' + expression = !match('{'); + body = parseConciseBody(); + + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && tmp.stricted) { + throwErrorTolerant(tmp.stricted, message); + } + if (state.yieldAllowed && !state.yieldFound) { + throwError({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionExpression(id, tmp.params, [], body, tmp.rest, generator, expression); + } + + function parseYieldExpression() { + var delegateFlag, expr, previousYieldAllowed; + + expectKeyword('yield'); + + if (!state.yieldAllowed) { + throwErrorTolerant({}, Messages.IllegalYield); + } + + delegateFlag = false; + if (match('*')) { + lex(); + delegateFlag = true; + } + + // It is a Syntax Error if any AssignmentExpression Contains YieldExpression. + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + expr = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + state.yieldFound = true; + + return delegate.createYieldExpression(expr, delegateFlag); + } + + // 14 Classes + + function parseMethodDefinition(existingPropNames) { + var token, key, param, propType, isValidDuplicateProp = false; + + if (strict ? matchKeyword('static') : matchContextualKeyword('static')) { + propType = ClassPropertyType.static; + lex(); + } else { + propType = ClassPropertyType.prototype; + } + + if (match('*')) { + lex(); + return delegate.createMethodDefinition( + propType, + '', + parseObjectPropertyKey(), + parsePropertyMethodFunction({ generator: true }) + ); + } + + token = lookahead; + key = parseObjectPropertyKey(); + + if (token.value === 'get' && !match('(')) { + key = parseObjectPropertyKey(); + + // It is a syntax error if any other properties have a name + // duplicating this one unless they are a setter + if (existingPropNames[propType].hasOwnProperty(key.name)) { + isValidDuplicateProp = + // There isn't already a getter for this prop + existingPropNames[propType][key.name].get === undefined + // There isn't already a data prop by this name + && existingPropNames[propType][key.name].data === undefined + // The only existing prop by this name is a setter + && existingPropNames[propType][key.name].set !== undefined; + if (!isValidDuplicateProp) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].get = true; + + expect('('); + expect(')'); + return delegate.createMethodDefinition( + propType, + 'get', + key, + parsePropertyFunction({ generator: false }) + ); + } + if (token.value === 'set' && !match('(')) { + key = parseObjectPropertyKey(); + + // It is a syntax error if any other properties have a name + // duplicating this one unless they are a getter + if (existingPropNames[propType].hasOwnProperty(key.name)) { + isValidDuplicateProp = + // There isn't already a setter for this prop + existingPropNames[propType][key.name].set === undefined + // There isn't already a data prop by this name + && existingPropNames[propType][key.name].data === undefined + // The only existing prop by this name is a getter + && existingPropNames[propType][key.name].get !== undefined; + if (!isValidDuplicateProp) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].set = true; + + expect('('); + token = lookahead; + param = [ parseVariableIdentifier() ]; + expect(')'); + return delegate.createMethodDefinition( + propType, + 'set', + key, + parsePropertyFunction({ params: param, generator: false, name: token }) + ); + } + + // It is a syntax error if any other properties have the same name as a + // non-getter, non-setter method + if (existingPropNames[propType].hasOwnProperty(key.name)) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].data = true; + + return delegate.createMethodDefinition( + propType, + '', + key, + parsePropertyMethodFunction({ generator: false }) + ); + } + + function parseClassElement(existingProps) { + if (match(';')) { + lex(); + return; + } + return parseMethodDefinition(existingProps); + } + + function parseClassBody() { + var classElement, classElements = [], existingProps = {}; + + existingProps[ClassPropertyType.static] = {}; + existingProps[ClassPropertyType.prototype] = {}; + + expect('{'); + + while (index < length) { + if (match('}')) { + break; + } + classElement = parseClassElement(existingProps); + + if (typeof classElement !== 'undefined') { + classElements.push(classElement); + } + } + + expect('}'); + + return delegate.createClassBody(classElements); + } + + function parseClassExpression() { + var id, previousYieldAllowed, superClass = null; + + expectKeyword('class'); + + if (!matchKeyword('extends') && !match('{')) { + id = parseVariableIdentifier(); + } + + if (matchKeyword('extends')) { + expectKeyword('extends'); + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + superClass = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + } + + return delegate.createClassExpression(id, superClass, parseClassBody()); + } + + function parseClassDeclaration() { + var token, id, previousYieldAllowed, superClass = null; + + expectKeyword('class'); + + token = lookahead; + id = parseVariableIdentifier(); + + if (matchKeyword('extends')) { + expectKeyword('extends'); + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + superClass = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + } + + return delegate.createClassDeclaration(id, superClass, parseClassBody()); + } + + // 15 Program + + function parseSourceElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(lookahead.value); + case 'function': + return parseFunctionDeclaration(); + default: + return parseStatement(); + } + } + + if (lookahead.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseProgramElement() { + var lineNumber, token; + + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'export': + return parseExportDeclaration(); + case 'import': + return parseImportDeclaration(); + } + } + + if (lookahead.value === 'module' && lookahead.type === Token.Identifier) { + lineNumber = lookahead.lineNumber; + token = lookahead2(); + if (token.type === Token.Identifier && token.lineNumber === lineNumber) { + return parseModuleDeclaration(); + } + } + + return parseSourceElement(); + } + + function parseProgramElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseProgramElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseProgramElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseModuleElement() { + return parseProgramElement(); + } + + function parseModuleElements() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseModuleElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseModuleBlock() { + var block; + + expect('{'); + + block = parseModuleElements(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + function parseProgram() { + var body; + strict = false; + peek(); + body = parseProgramElements(); + return delegate.createProgram(body); + } + + // The following functions are needed only when the option to preserve + // the comments is active. + + function addComment(type, value, start, end, loc) { + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (extra.comments.length > 0) { + if (extra.comments[extra.comments.length - 1].range[1] > start) { + return; + } + } + + extra.comments.push({ + type: type, + value: value, + range: [start, end], + loc: loc + }); + } + + function scanComment() { + var comment, ch, loc, start, blockComment, lineComment; + + comment = ''; + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch.charCodeAt(0))) { + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + lineComment = false; + addComment('Line', comment, start, index - 1, loc); + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + comment = ''; + } else if (index >= length) { + lineComment = false; + comment += ch; + loc.end = { + line: lineNumber, + column: length - lineStart + }; + addComment('Line', comment, start, length, loc); + } else { + comment += ch; + } + } else if (blockComment) { + if (isLineTerminator(ch.charCodeAt(0))) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + comment += '\r\n'; + } else { + comment += ch; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + comment += ch; + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + comment = comment.substr(0, comment.length - 1); + blockComment = false; + ++index; + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + comment = ''; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + start = index; + index += 2; + lineComment = true; + if (index >= length) { + loc.end = { + line: lineNumber, + column: index - lineStart + }; + lineComment = false; + addComment('Line', comment, start, index, loc); + } + } else if (ch === '*') { + start = index; + index += 2; + blockComment = true; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch.charCodeAt(0))) { + ++index; + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function filterCommentLocation() { + var i, entry, comment, comments = []; + + for (i = 0; i < extra.comments.length; ++i) { + entry = extra.comments[i]; + comment = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + comment.range = entry.range; + } + if (extra.loc) { + comment.loc = entry.loc; + } + comments.push(comment); + } + + extra.comments = comments; + } + + // 16 XJS + + XHTMLEntities = { + quot: '\u0022', + amp: '&', + apos: "\u0027", + lt: "<", + gt: ">", + nbsp: "\u00A0", + iexcl: "\u00A1", + cent: "\u00A2", + pound: "\u00A3", + curren: "\u00A4", + yen: "\u00A5", + brvbar: "\u00A6", + sect: "\u00A7", + uml: "\u00A8", + copy: "\u00A9", + ordf: "\u00AA", + laquo: "\u00AB", + not: "\u00AC", + shy: "\u00AD", + reg: "\u00AE", + macr: "\u00AF", + deg: "\u00B0", + plusmn: "\u00B1", + sup2: "\u00B2", + sup3: "\u00B3", + acute: "\u00B4", + micro: "\u00B5", + para: "\u00B6", + middot: "\u00B7", + cedil: "\u00B8", + sup1: "\u00B9", + ordm: "\u00BA", + raquo: "\u00BB", + frac14: "\u00BC", + frac12: "\u00BD", + frac34: "\u00BE", + iquest: "\u00BF", + Agrave: "\u00C0", + Aacute: "\u00C1", + Acirc: "\u00C2", + Atilde: "\u00C3", + Auml: "\u00C4", + Aring: "\u00C5", + AElig: "\u00C6", + Ccedil: "\u00C7", + Egrave: "\u00C8", + Eacute: "\u00C9", + Ecirc: "\u00CA", + Euml: "\u00CB", + Igrave: "\u00CC", + Iacute: "\u00CD", + Icirc: "\u00CE", + Iuml: "\u00CF", + ETH: "\u00D0", + Ntilde: "\u00D1", + Ograve: "\u00D2", + Oacute: "\u00D3", + Ocirc: "\u00D4", + Otilde: "\u00D5", + Ouml: "\u00D6", + times: "\u00D7", + Oslash: "\u00D8", + Ugrave: "\u00D9", + Uacute: "\u00DA", + Ucirc: "\u00DB", + Uuml: "\u00DC", + Yacute: "\u00DD", + THORN: "\u00DE", + szlig: "\u00DF", + agrave: "\u00E0", + aacute: "\u00E1", + acirc: "\u00E2", + atilde: "\u00E3", + auml: "\u00E4", + aring: "\u00E5", + aelig: "\u00E6", + ccedil: "\u00E7", + egrave: "\u00E8", + eacute: "\u00E9", + ecirc: "\u00EA", + euml: "\u00EB", + igrave: "\u00EC", + iacute: "\u00ED", + icirc: "\u00EE", + iuml: "\u00EF", + eth: "\u00F0", + ntilde: "\u00F1", + ograve: "\u00F2", + oacute: "\u00F3", + ocirc: "\u00F4", + otilde: "\u00F5", + ouml: "\u00F6", + divide: "\u00F7", + oslash: "\u00F8", + ugrave: "\u00F9", + uacute: "\u00FA", + ucirc: "\u00FB", + uuml: "\u00FC", + yacute: "\u00FD", + thorn: "\u00FE", + yuml: "\u00FF", + OElig: "\u0152", + oelig: "\u0153", + Scaron: "\u0160", + scaron: "\u0161", + Yuml: "\u0178", + fnof: "\u0192", + circ: "\u02C6", + tilde: "\u02DC", + Alpha: "\u0391", + Beta: "\u0392", + Gamma: "\u0393", + Delta: "\u0394", + Epsilon: "\u0395", + Zeta: "\u0396", + Eta: "\u0397", + Theta: "\u0398", + Iota: "\u0399", + Kappa: "\u039A", + Lambda: "\u039B", + Mu: "\u039C", + Nu: "\u039D", + Xi: "\u039E", + Omicron: "\u039F", + Pi: "\u03A0", + Rho: "\u03A1", + Sigma: "\u03A3", + Tau: "\u03A4", + Upsilon: "\u03A5", + Phi: "\u03A6", + Chi: "\u03A7", + Psi: "\u03A8", + Omega: "\u03A9", + alpha: "\u03B1", + beta: "\u03B2", + gamma: "\u03B3", + delta: "\u03B4", + epsilon: "\u03B5", + zeta: "\u03B6", + eta: "\u03B7", + theta: "\u03B8", + iota: "\u03B9", + kappa: "\u03BA", + lambda: "\u03BB", + mu: "\u03BC", + nu: "\u03BD", + xi: "\u03BE", + omicron: "\u03BF", + pi: "\u03C0", + rho: "\u03C1", + sigmaf: "\u03C2", + sigma: "\u03C3", + tau: "\u03C4", + upsilon: "\u03C5", + phi: "\u03C6", + chi: "\u03C7", + psi: "\u03C8", + omega: "\u03C9", + thetasym: "\u03D1", + upsih: "\u03D2", + piv: "\u03D6", + ensp: "\u2002", + emsp: "\u2003", + thinsp: "\u2009", + zwnj: "\u200C", + zwj: "\u200D", + lrm: "\u200E", + rlm: "\u200F", + ndash: "\u2013", + mdash: "\u2014", + lsquo: "\u2018", + rsquo: "\u2019", + sbquo: "\u201A", + ldquo: "\u201C", + rdquo: "\u201D", + bdquo: "\u201E", + dagger: "\u2020", + Dagger: "\u2021", + bull: "\u2022", + hellip: "\u2026", + permil: "\u2030", + prime: "\u2032", + Prime: "\u2033", + lsaquo: "\u2039", + rsaquo: "\u203A", + oline: "\u203E", + frasl: "\u2044", + euro: "\u20AC", + image: "\u2111", + weierp: "\u2118", + real: "\u211C", + trade: "\u2122", + alefsym: "\u2135", + larr: "\u2190", + uarr: "\u2191", + rarr: "\u2192", + darr: "\u2193", + harr: "\u2194", + crarr: "\u21B5", + lArr: "\u21D0", + uArr: "\u21D1", + rArr: "\u21D2", + dArr: "\u21D3", + hArr: "\u21D4", + forall: "\u2200", + part: "\u2202", + exist: "\u2203", + empty: "\u2205", + nabla: "\u2207", + isin: "\u2208", + notin: "\u2209", + ni: "\u220B", + prod: "\u220F", + sum: "\u2211", + minus: "\u2212", + lowast: "\u2217", + radic: "\u221A", + prop: "\u221D", + infin: "\u221E", + ang: "\u2220", + and: "\u2227", + or: "\u2228", + cap: "\u2229", + cup: "\u222A", + "int": "\u222B", + there4: "\u2234", + sim: "\u223C", + cong: "\u2245", + asymp: "\u2248", + ne: "\u2260", + equiv: "\u2261", + le: "\u2264", + ge: "\u2265", + sub: "\u2282", + sup: "\u2283", + nsub: "\u2284", + sube: "\u2286", + supe: "\u2287", + oplus: "\u2295", + otimes: "\u2297", + perp: "\u22A5", + sdot: "\u22C5", + lceil: "\u2308", + rceil: "\u2309", + lfloor: "\u230A", + rfloor: "\u230B", + lang: "\u2329", + rang: "\u232A", + loz: "\u25CA", + spades: "\u2660", + clubs: "\u2663", + hearts: "\u2665", + diams: "\u2666" + }; + + function isXJSIdentifierStart(ch) { + // exclude backslash (\) + return (ch !== 92) && isIdentifierStart(ch); + } + + function isXJSIdentifierPart(ch) { + // exclude backslash (\) and add hyphen (-) + return (ch !== 92) && (ch === 45 || isIdentifierPart(ch)); + } + + function scanXJSIdentifier() { + var ch, start, id = '', namespace; + + start = index; + while (index < length) { + ch = source.charCodeAt(index); + if (!isXJSIdentifierPart(ch)) { + break; + } + id += source[index++]; + } + + if (ch === 58) { // : + ++index; + namespace = id; + id = ''; + + while (index < length) { + ch = source.charCodeAt(index); + if (!isXJSIdentifierPart(ch)) { + break; + } + id += source[index++]; + } + } + + if (!id) { + throwError({}, Messages.InvalidXJSTagName); + } + + return { + type: Token.XJSIdentifier, + value: id, + namespace: namespace, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanXJSEntity() { + var ch, str = '', count = 0, entity; + ch = source[index]; + assert(ch === '&', 'Entity must start with an ampersand'); + index++; + while (index < length && count++ < 10) { + ch = source[index++]; + if (ch === ';') { + break; + } + str += ch; + } + + if (str[0] === '#' && str[1] === 'x') { + entity = String.fromCharCode(parseInt(str.substr(2), 16)); + } else if (str[0] === '#') { + entity = String.fromCharCode(parseInt(str.substr(1), 10)); + } else { + entity = XHTMLEntities[str]; + } + return entity; + } + + function scanXJSText(stopChars) { + var ch, str = '', start; + start = index; + while (index < length) { + ch = source[index]; + if (stopChars.indexOf(ch) !== -1) { + break; + } + if (ch === '&') { + str += scanXJSEntity(); + } else { + ch = source[index++]; + if (isLineTerminator(ch.charCodeAt(0))) { + ++lineNumber; + } + str += ch; + } + } + return { + type: Token.XJSText, + value: str, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanXJSStringLiteral() { + var innerToken, quote, start; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + innerToken = scanXJSText([quote]); + + if (quote !== source[index]) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + ++index; + + innerToken.range = [start, index]; + + return innerToken; + } + + /** + * Between XJS opening and closing tags (e.g. HERE), anything that + * is not another XJS tag and is not an expression wrapped by {} is text. + */ + function advanceXJSChild() { + var ch = source.charCodeAt(index); + + // { (123) and < (60) + if (ch !== 123 && ch !== 60) { + return scanXJSText(['<', '{']); + } + + return scanPunctuator(); + } + + function parseXJSIdentifier() { + var token; + + if (lookahead.type !== Token.XJSIdentifier) { + throwError({}, Messages.InvalidXJSTagName); + } + + token = lex(); + return delegate.createXJSIdentifier(token.value, token.namespace); + } + + function parseXJSAttributeValue() { + var value; + if (lookahead.value === '{') { + value = parseXJSExpression(); + } else if (lookahead.type === Token.XJSText) { + value = delegate.createLiteral(lex()); + } else { + throwError({}, Messages.InvalidXJSAttributeValue); + } + return value; + } + + function parseXJSExpression() { + var value, origInXJSChild, origInXJSTag; + + origInXJSChild = state.inXJSChild; + origInXJSTag = state.inXJSTag; + state.inXJSChild = false; + state.inXJSTag = false; + + expect('{'); + + value = parseExpression(); + + state.inXJSChild = origInXJSChild; + state.inXJSTag = origInXJSTag; + + expect('}'); + + return delegate.createXJSExpression(value); + } + + function parseXJSAttribute() { + var token, name, value; + + name = parseXJSIdentifier(); + + // HTML empty attribute + if (match('=')) { + lex(); + return delegate.createXJSAttribute(name, parseXJSAttributeValue()); + } + + return delegate.createXJSAttribute(name); + } + + function parseXJSChild() { + var token; + if (lookahead.value === '{') { + token = parseXJSExpression(); + } else if (lookahead.type === Token.XJSText) { + token = delegate.createLiteral(lex()); + } else { + state.inXJSChild = false; + token = parseXJSElement(); + state.inXJSChild = true; + } + return token; + } + + function parseXJSClosingElement() { + var name, origInXJSTag; + origInXJSTag = state.inXJSTag; + state.inXJSTag = true; + state.inXJSChild = false; + expect('<'); + expect('/'); + name = parseXJSIdentifier(); + state.inXJSTag = origInXJSTag; + expect('>'); + return delegate.createXJSClosingElement(name); + } + + function parseXJSOpeningElement() { + var name, attribute, attributes = [], selfClosing = false, origInXJSTag; + + origInXJSTag = state.inXJSTag; + state.inXJSTag = true; + + expect('<'); + + name = parseXJSIdentifier(); + + while (index < length && + lookahead.value !== '/' && + lookahead.value !== '>') { + attributes.push(parseXJSAttribute()); + } + + state.inXJSTag = origInXJSTag; + + if (lookahead.value === '/') { + expect('/'); + expect('>'); + selfClosing = true; + } else { + state.inXJSChild = true; + expect('>'); + } + return delegate.createXJSOpeningElement(name, attributes, selfClosing); + } + + function parseXJSElement() { + var openingElement, closingElement, children = [], origInXJSChild; + + openingElement = parseXJSOpeningElement(); + + if (!openingElement.selfClosing) { + origInXJSChild = state.inXJSChild; + while (index < length) { + state.inXJSChild = false; // 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + } + + return regex; + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function createLocationMarker() { + var marker = {}; + + marker.range = [index, index]; + marker.loc = { + start: { + line: lineNumber, + column: index - lineStart + }, + end: { + line: lineNumber, + column: index - lineStart + } + }; + + marker.end = function () { + this.range[1] = index; + this.loc.end.line = lineNumber; + this.loc.end.column = index - lineStart; + }; + + marker.applyGroup = function (node) { + if (extra.range) { + node.groupRange = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.groupLoc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + node = delegate.postProcess(node); + } + }; + + marker.apply = function (node) { + if (extra.range) { + node.range = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.loc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + node = delegate.postProcess(node); + } + }; + + return marker; + } + + function trackGroupExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + expect('('); + + ++state.parenthesizedCount; + + state.allowArrowFunction = !state.allowArrowFunction; + expr = parseExpression(); + state.allowArrowFunction = false; + + if (expr.type === 'ArrowFunctionExpression') { + marker.end(); + marker.apply(expr); + } else { + expect(')'); + marker.end(); + marker.applyGroup(expr); + } + + return expr; + } + + function trackLeftHandSideExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || lookahead.type === Token.Template) { + if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + marker.end(); + marker.apply(expr); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + marker.end(); + marker.apply(expr); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function trackLeftHandSideExpressionAllowCall() { + var marker, expr, args; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + marker.end(); + marker.apply(expr); + } else if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + marker.end(); + marker.apply(expr); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + marker.end(); + marker.apply(expr); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function filterGroup(node) { + var n, i, entry; + + n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; + for (i in node) { + if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { + entry = node[i]; + if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { + n[i] = entry; + } else { + n[i] = filterGroup(entry); + } + } + } + return n; + } + + function wrapTrackingFunction(range, loc, preserveWhitespace) { + + return function (parseFunction) { + + function isBinary(node) { + return node.type === Syntax.LogicalExpression || + node.type === Syntax.BinaryExpression; + } + + function visit(node) { + var start, end; + + if (isBinary(node.left)) { + visit(node.left); + } + if (isBinary(node.right)) { + visit(node.right); + } + + if (range) { + if (node.left.groupRange || node.right.groupRange) { + start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; + end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; + node.range = [start, end]; + } else if (typeof node.range === 'undefined') { + start = node.left.range[0]; + end = node.right.range[1]; + node.range = [start, end]; + } + } + if (loc) { + if (node.left.groupLoc || node.right.groupLoc) { + start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; + end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; + node.loc = { + start: start, + end: end + }; + node = delegate.postProcess(node); + } else if (typeof node.loc === 'undefined') { + node.loc = { + start: node.left.loc.start, + end: node.right.loc.end + }; + node = delegate.postProcess(node); + } + } + } + + return function () { + var marker, node; + + if (!preserveWhitespace) { + skipComment(); + } + + marker = createLocationMarker(); + node = parseFunction.apply(null, arguments); + marker.end(); + + if (range && typeof node.range === 'undefined') { + marker.apply(node); + } + + if (loc && typeof node.loc === 'undefined') { + marker.apply(node); + } + + if (isBinary(node)) { + visit(node); + } + + return node; + }; + }; + } + + function patch() { + + var wrapTracking, wrapTrackingPreserveWhitespace; + + if (extra.comments) { + extra.skipComment = skipComment; + skipComment = scanComment; + } + + if (extra.range || extra.loc) { + + extra.parseGroupExpression = parseGroupExpression; + extra.parseLeftHandSideExpression = parseLeftHandSideExpression; + extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; + parseGroupExpression = trackGroupExpression; + parseLeftHandSideExpression = trackLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; + + wrapTracking = wrapTrackingFunction(extra.range, extra.loc); + wrapTrackingPreserveWhitespace = + wrapTrackingFunction(extra.range, extra.loc, true); + + extra.parseAssignmentExpression = parseAssignmentExpression; + extra.parseBinaryExpression = parseBinaryExpression; + extra.parseBlock = parseBlock; + extra.parseFunctionSourceElements = parseFunctionSourceElements; + extra.parseCatchClause = parseCatchClause; + extra.parseComputedMember = parseComputedMember; + extra.parseConditionalExpression = parseConditionalExpression; + extra.parseConstLetDeclaration = parseConstLetDeclaration; + extra.parseExportDeclaration = parseExportDeclaration; + extra.parseExportSpecifier = parseExportSpecifier; + extra.parseExportSpecifierSetProperty = parseExportSpecifierSetProperty; + extra.parseExpression = parseExpression; + extra.parseForVariableDeclaration = parseForVariableDeclaration; + extra.parseFunctionDeclaration = parseFunctionDeclaration; + extra.parseFunctionExpression = parseFunctionExpression; + extra.parseParams = parseParams; + extra.parseGlob = parseGlob; + extra.parseImportDeclaration = parseImportDeclaration; + extra.parseImportSpecifier = parseImportSpecifier; + extra.parseModuleDeclaration = parseModuleDeclaration; + extra.parseModuleBlock = parseModuleBlock; + extra.parseNewExpression = parseNewExpression; + extra.parseNonComputedProperty = parseNonComputedProperty; + extra.parseObjectProperty = parseObjectProperty; + extra.parseObjectPropertyKey = parseObjectPropertyKey; + extra.parsePath = parsePath; + extra.parsePostfixExpression = parsePostfixExpression; + extra.parsePrimaryExpression = parsePrimaryExpression; + extra.parseProgram = parseProgram; + extra.parsePropertyFunction = parsePropertyFunction; + extra.parseSpreadOrAssignmentExpression = parseSpreadOrAssignmentExpression; + extra.parseTemplateElement = parseTemplateElement; + extra.parseTemplateLiteral = parseTemplateLiteral; + extra.parseStatement = parseStatement; + extra.parseSwitchCase = parseSwitchCase; + extra.parseUnaryExpression = parseUnaryExpression; + extra.parseVariableDeclaration = parseVariableDeclaration; + extra.parseVariableIdentifier = parseVariableIdentifier; + extra.parseMethodDefinition = parseMethodDefinition; + extra.parseClassDeclaration = parseClassDeclaration; + extra.parseClassExpression = parseClassExpression; + extra.parseClassBody = parseClassBody; + extra.parseXJSIdentifier = parseXJSIdentifier; + extra.parseXJSChild = parseXJSChild; + extra.parseXJSAttribute = parseXJSAttribute; + extra.parseXJSAttributeValue = parseXJSAttributeValue; + extra.parseXJSExpression = parseXJSExpression; + extra.parseXJSElement = parseXJSElement; + extra.parseXJSClosingElement = parseXJSClosingElement; + extra.parseXJSOpeningElement = parseXJSOpeningElement; + + parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); + parseBinaryExpression = wrapTracking(extra.parseBinaryExpression); + parseBlock = wrapTracking(extra.parseBlock); + parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); + parseCatchClause = wrapTracking(extra.parseCatchClause); + parseComputedMember = wrapTracking(extra.parseComputedMember); + parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); + parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); + parseExportDeclaration = wrapTracking(parseExportDeclaration); + parseExportSpecifier = wrapTracking(parseExportSpecifier); + parseExportSpecifierSetProperty = wrapTracking(parseExportSpecifierSetProperty); + parseExpression = wrapTracking(extra.parseExpression); + parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); + parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); + parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); + parseParams = wrapTracking(extra.parseParams); + parseGlob = wrapTracking(extra.parseGlob); + parseImportDeclaration = wrapTracking(extra.parseImportDeclaration); + parseImportSpecifier = wrapTracking(extra.parseImportSpecifier); + parseModuleDeclaration = wrapTracking(extra.parseModuleDeclaration); + parseModuleBlock = wrapTracking(extra.parseModuleBlock); + parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); + parseNewExpression = wrapTracking(extra.parseNewExpression); + parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); + parseObjectProperty = wrapTracking(extra.parseObjectProperty); + parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); + parsePath = wrapTracking(extra.parsePath); + parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); + parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); + parseProgram = wrapTracking(extra.parseProgram); + parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); + parseTemplateElement = wrapTracking(extra.parseTemplateElement); + parseTemplateLiteral = wrapTracking(extra.parseTemplateLiteral); + parseSpreadOrAssignmentExpression = wrapTracking(extra.parseSpreadOrAssignmentExpression); + parseStatement = wrapTracking(extra.parseStatement); + parseSwitchCase = wrapTracking(extra.parseSwitchCase); + parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); + parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); + parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); + parseMethodDefinition = wrapTracking(extra.parseMethodDefinition); + parseClassDeclaration = wrapTracking(extra.parseClassDeclaration); + parseClassExpression = wrapTracking(extra.parseClassExpression); + parseClassBody = wrapTracking(extra.parseClassBody); + parseXJSIdentifier = wrapTracking(extra.parseXJSIdentifier); + parseXJSChild = wrapTrackingPreserveWhitespace(extra.parseXJSChild); + parseXJSAttribute = wrapTracking(extra.parseXJSAttribute); + parseXJSAttributeValue = wrapTracking(extra.parseXJSAttributeValue); + parseXJSExpression = wrapTracking(extra.parseXJSExpression); + parseXJSElement = wrapTracking(extra.parseXJSElement); + parseXJSClosingElement = wrapTracking(extra.parseXJSClosingElement); + parseXJSOpeningElement = wrapTracking(extra.parseXJSOpeningElement); + } + + if (typeof extra.tokens !== 'undefined') { + extra.advance = advance; + extra.scanRegExp = scanRegExp; + + advance = collectToken; + scanRegExp = collectRegex; + } + } + + function unpatch() { + if (typeof extra.skipComment === 'function') { + skipComment = extra.skipComment; + } + + if (extra.range || extra.loc) { + parseAssignmentExpression = extra.parseAssignmentExpression; + parseBinaryExpression = extra.parseBinaryExpression; + parseBlock = extra.parseBlock; + parseFunctionSourceElements = extra.parseFunctionSourceElements; + parseCatchClause = extra.parseCatchClause; + parseComputedMember = extra.parseComputedMember; + parseConditionalExpression = extra.parseConditionalExpression; + parseConstLetDeclaration = extra.parseConstLetDeclaration; + parseExportDeclaration = extra.parseExportDeclaration; + parseExportSpecifier = extra.parseExportSpecifier; + parseExportSpecifierSetProperty = extra.parseExportSpecifierSetProperty; + parseExpression = extra.parseExpression; + parseForVariableDeclaration = extra.parseForVariableDeclaration; + parseFunctionDeclaration = extra.parseFunctionDeclaration; + parseFunctionExpression = extra.parseFunctionExpression; + parseGlob = extra.parseGlob; + parseImportDeclaration = extra.parseImportDeclaration; + parseImportSpecifier = extra.parseImportSpecifier; + parseGroupExpression = extra.parseGroupExpression; + parseLeftHandSideExpression = extra.parseLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; + parseModuleDeclaration = extra.parseModuleDeclaration; + parseModuleBlock = extra.parseModuleBlock; + parseNewExpression = extra.parseNewExpression; + parseNonComputedProperty = extra.parseNonComputedProperty; + parseObjectProperty = extra.parseObjectProperty; + parseObjectPropertyKey = extra.parseObjectPropertyKey; + parsePath = extra.parsePath; + parsePostfixExpression = extra.parsePostfixExpression; + parsePrimaryExpression = extra.parsePrimaryExpression; + parseProgram = extra.parseProgram; + parsePropertyFunction = extra.parsePropertyFunction; + parseTemplateElement = extra.parseTemplateElement; + parseTemplateLiteral = extra.parseTemplateLiteral; + parseSpreadOrAssignmentExpression = extra.parseSpreadOrAssignmentExpression; + parseStatement = extra.parseStatement; + parseSwitchCase = extra.parseSwitchCase; + parseUnaryExpression = extra.parseUnaryExpression; + parseVariableDeclaration = extra.parseVariableDeclaration; + parseVariableIdentifier = extra.parseVariableIdentifier; + parseMethodDefinition = extra.parseMethodDefinition; + parseClassDeclaration = extra.parseClassDeclaration; + parseClassExpression = extra.parseClassExpression; + parseClassBody = extra.parseClassBody; + parseXJSIdentifier = extra.parseXJSIdentifier; + parseXJSChild = extra.parseXJSChild; + parseXJSAttribute = extra.parseXJSAttribute; + parseXJSAttributeValue = extra.parseXJSAttributeValue; + parseXJSExpression = extra.parseXJSExpression; + parseXJSElement = extra.parseXJSElement; + parseXJSClosingElement = extra.parseXJSClosingElement; + parseXJSOpeningElement = extra.parseXJSOpeningElement; + } + + if (typeof extra.scanRegExp === 'function') { + advance = extra.advance; + scanRegExp = extra.scanRegExp; + } + } + + // This is used to modify the delegate. + + function extend(object, properties) { + var entry, result = {}; + + for (entry in object) { + if (object.hasOwnProperty(entry)) { + result[entry] = object[entry]; + } + } + + for (entry in properties) { + if (properties.hasOwnProperty(entry)) { + result[entry] = properties[entry]; + } + } + + return result; + } + + function tokenize(code, options) { + var toString, + token, + tokens; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false + }; + + extra = {}; + + // Options matching. + options = options || {}; + + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; + + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + } + } + + patch(); + + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; + } + + token = lex(); + while (lookahead.type !== Token.EOF) { + try { + token = lex(); + } catch (lexError) { + token = lookahead; + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; + } + } + } + + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + return tokens; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + parenthesizedCount: 0, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + yieldAllowed: false, + yieldFound: false + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (extra.loc && options.source !== null && options.source !== undefined) { + delegate = extend(delegate, { + 'postProcess': function (node) { + node.loc.source = toString(options.source); + return node; + } + }); + } + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + } + } + + patch(); + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + if (extra.range || extra.loc) { + program.body = filterGroup(program.body); + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + + return program; + } + + // Sync with package.json and component.json. + exports.version = '1.1.0-dev-harmony'; + + exports.tokenize = tokenize; + + exports.parse = parse; + + // Deep copy. + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ + +})() +},{}],9:[function(require,module,exports){ +/* + * Copyright 2009-2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.txt or: + * http://opensource.org/licenses/BSD-3-Clause + */ +exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator; +exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer; +exports.SourceNode = require('./source-map/source-node').SourceNode; + +},{"./source-map/source-map-generator":12,"./source-map/source-map-consumer":13,"./source-map/source-node":14}],5:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; + +/** + * Desugarizer for ES6 minimal class proposal. See + * http://wiki.ecmascript.org/doku.php?id=harmony:proposals + * + * Does not require any runtime. Preserves whitespace and comments. + * Supports a class declaration with methods, super calls and inheritance. + * Currently does not support for getters and setters, since there's a very + * low probability we're going to use them anytime soon. + * + * Additional features: + * - Any member with private name (the name with prefix _, such _name) inside + * the class's scope will be munged. This would will to eliminate the case + * of sub-class accidentally overriding the super-class's provate properties + * also discouage people from accessing private members that they should not + * access. However, quoted property names don't get munged. + * + * class SkinnedMesh extends require('THREE').Mesh { + * + * update(camera) { + * camera.code = 'iphone' + * super.update(camera); + * } + * + * / + * * @constructor + * / + * constructor(geometry, materials) { + * super(geometry, materials); + * + * super.update(1); + * + * this.identityMatrix = new THREE.Matrix4(); + * this.bones = []; + * this.boneMatrices = []; + * this._name = 'foo'; + * } + * + * / + * * some other code + * / + * readMore() { + * + * } + * + * _doSomething() { + * + * } + * } + * + * should be converted to + * + * var SkinnedMesh = (function() { + * var __super = require('parent').Mesh; + * + * / + * * @constructor + * / + * function SkinnedMesh(geometry, materials) { + * __super.call(this, geometry, materials); + * + * __super.prototype.update.call(this, 1); + * + * this.identityMatrix = new THREE.Matrix4(); + * this.bones = []; + * this.boneMatrices = []; + * this.$SkinnedMesh_name = 'foo'; + * } + * SkinnedMesh.prototype = Object.create(__super.prototype); + * SkinnedMesh.prototype.constructor = SkinnedMesh; + * + * / + * * @param camera + * / + * SkinnedMesh.prototype.update = function(camera) { + * camera.code = 'iphone' + * __super.prototype.update.call(this, camera); + * }; + * + * SkinnedMesh.prototype.readMore = function() { + * + * }; + * + * SkinnedMesh.prototype.$SkinnedMesh_doSomething = function() { + * + * }; + * + * return SkinnedMesh; + * })(); + * + */ +var Syntax = require('esprima').Syntax; +var base62 = require('base62'); + +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var move = require('../lib/utils').move; +var indentBefore = require('../lib/utils').indentBefore; +var updateIndent = require('../lib/utils').updateIndent; +var updateState = require('../lib/utils').updateState; + +function findConstructorIndex(object) { + var classElements = object.body && object.body.body || []; + for (var i = 0; i < classElements.length; i++) { + if (classElements[i].type === Syntax.MethodDefinition && + classElements[i].key.name === 'constructor') { + return i; + } + } + return -1; +} + +var _mungedSymbolMaps = {}; +function getMungedName(scopeName, name, minify) { + if (minify) { + if (!_mungedSymbolMaps[scopeName]) { + _mungedSymbolMaps[scopeName] = { + symbolMap: {}, + identifierUUIDCounter: 0 + }; + } + + var symbolMap = _mungedSymbolMaps[scopeName].symbolMap; + if (!symbolMap[name]) { + symbolMap[name] = + base62.encode(_mungedSymbolMaps[scopeName].identifierUUIDCounter); + _mungedSymbolMaps[scopeName].identifierUUIDCounter++; + } + name = symbolMap[name]; + } + return '$' + scopeName + name; +} + +function shouldMungeName(scopeName, name, state) { + // only run when @preventMunge is not present in the docblock + if (state.g.preventMunge === undefined) { + var docblock = require('../lib/docblock'); + state.g.preventMunge = docblock.parseAsObject( + docblock.extract(state.g.source)).preventMunge !== undefined; + } + // Starts with only a single underscore (i.e. don't count double-underscores) + return !state.g.preventMunge && scopeName ? /^_(?!_)/.test(name) : false; +} + + +function getProtoOfPrototypeVariableName(superVar) { + return superVar + 'ProtoOfPrototype'; +} + +function getSuperKeyName(superVar) { + return superVar + 'Key'; +} + +function getSuperProtoOfPrototypeVariable(superVariableName, indent) { + var string = (indent + + 'var $proto = $superName && $superName.prototype ? ' + + '$superName.prototype : $superName;\n' + ).replace(/\$proto/g, getProtoOfPrototypeVariableName(superVariableName)) + .replace(/\$superName/g, superVariableName); + return string; +} + + +function getInheritanceSetup(superClassToken, className, indent, superName) { + var string = ''; + if (superClassToken) { + string += getStaticMethodsOnConstructorSetup(className, indent, superName); + string += getPrototypeOnConstructorSetup(className, indent, superName); + string += getConstructorPropertySetup(className, indent); + } + return string; +} + +function getStaticMethodsOnConstructorSetup(className, indent, superName) { + var string = ( indent + + 'for (var $keyName in $superName) {\n' + indent + + ' if ($superName.hasOwnProperty($keyName)) {\n' + indent + + ' $className[$keyName] = $superName[$keyName];\n' + indent + + ' }\n' + indent + + '}\n') + .replace(/\$className/g, className) + .replace(/\$keyName/g, getSuperKeyName(superName)) + .replace(/\$superName/g, superName); + return string; +} + +function getPrototypeOnConstructorSetup(className, indent, superName) { + var string = ( indent + + '$className.prototype = Object.create($protoPrototype);\n') + .replace(/\$protoPrototype/g, getProtoOfPrototypeVariableName(superName)) + .replace(/\$className/g, className); + return string; +} + +function getConstructorPropertySetup(className, indent) { + var string = ( indent + + '$className.prototype.constructor = $className;\n') + .replace(/\$className/g, className); + + return string; +} + +function getSuperConstructorSetup(superClassToken, indent, superName) { + if (!superClassToken) return ''; + var string = ( '\n' + indent + + ' if ($superName && $superName.prototype) {\n' + indent + + ' $superName.apply(this, arguments);\n' + indent + + ' }\n' + indent) + .replace(/\$superName/g, superName); + return string; +} + +function getMemberFunctionCall(superVar, propertyName, superArgs) { + var string = ( + '$superPrototype.$propertyName.call($superArguments)') + .replace(/\$superPrototype/g, getProtoOfPrototypeVariableName(superVar)) + .replace(/\$propertyName/g, propertyName) + .replace(/\$superArguments/g, superArgs); + return string; +} + +function getCallParams(classElement, state) { + var params = classElement.value.params; + if (!params.length) { + return ''; + } + return state.g.source.substring( + params[0].range[0], + params[params.length - 1].range[1]); +} + +function getSuperArguments(callExpression, state) { + var args = callExpression.arguments; + if (!args.length) { + return 'this'; + } + return 'this, ' + state.g.source.substring( + args[0].range[0], + args[args.length - 1].range[1]); +} + +// The seed is used to generate the name for an anonymous class, +// and this seed should be unique per browser's session. +// The value of the seed looks like this: 1229588505.2969012. +var classIDSeed = Date.now() % (60 * 60 * 1000) + Math.random(); + +/** + * Generates a name for an anonymous class. The generated value looks like + * this: "Classkc6pcn_mniza1yvi" + * @param {String} scopeName + * @return {string} the scope name for Anonymous Class + */ +function generateAnonymousClassName(scopeName) { + classIDSeed++; + return 'Class' + + (classIDSeed).toString(36).replace('.', '_') + + (scopeName || ''); +} + +function renderMethods(traverse, object, name, path, state) { + var classElements = object.body && object.body.body || []; + + move(object.body.range[0] + 1, state); + for (var i = 0; i < classElements.length; i++) { + if (classElements[i].key.name !== 'constructor') { + catchup(classElements[i].range[0], state); + + var memberName = classElements[i].key.name; + if (shouldMungeName(state.scopeName, memberName, state)) { + memberName = getMungedName( + state.scopeName, + memberName, + state.g.opts.minify + ); + } + + var prototypeOrStatic; + if (classElements[i]['static']) { + prototypeOrStatic = ''; + } else { + prototypeOrStatic = 'prototype.'; + } + + append(name + '.' + prototypeOrStatic + memberName + ' = ', state); + renderMethod(traverse, classElements[i], null, path, state); + append(';', state); + } + move(classElements[i].range[1], state); + } + if (classElements.length) { + append('\n', state); + } + move(object.range[1], state); +} + +function renderMethod(traverse, method, name, path, state) { + append(name ? 'function ' + name + '(' : 'function(', state); + append(getCallParams(method, state) + ') {', state); + move(method.value.body.range[0] + 1, state); + traverse(method.value.body, path, state); + catchup(method.value.body.range[1] - 1, state); + append('}', state); +} + +function renderSuperClass(traverse, superClass, path, state) { + append('var ' + state.superVar + ' = ', state); + move(superClass.range[0], state); + traverse(superClass, path, state); + catchup(superClass.range[1], state); + append(';\n', state); +} + +function renderConstructor(traverse, object, name, indent, path, state) { + var classElements = object.body && object.body.body || []; + var constructorIndex = findConstructorIndex(object); + var constructor = constructorIndex === -1 ? + null : + classElements[constructorIndex]; + if (constructor) { + move(constructorIndex === 0 ? + object.body.range[0] + 1 : + classElements[constructorIndex - 1].range[1], state); + catchup(constructor.range[0], state); + renderMethod(traverse, constructor, name, path, state); + append('\n', state); + } else { + if (object.superClass) { + append('\n' + indent, state); + } + append('function ', state); + if (object.id) { + move(object.id.range[0], state); + } + append(name, state); + if (object.id) { + move(object.id.range[1], state); + } + append('(){ ', state); + if (object.body) { + move(object.body.range[0], state); + } + append(getSuperConstructorSetup( + object.superClass, + indent, + state.superVar), state); + append('}\n', state); + } +} + +var superId = 0; +function renderClassBody(traverse, object, path, state) { + var name = object.id ? object.id.name : 'constructor'; + var superClass = object.superClass; + var indent = updateIndent( + indentBefore(object.range[0], state) + ' ', + state); + + state = updateState( + state, + { + scopeName: object.id ? object.id.name : + generateAnonymousClassName(state.scopeName), + superVar: superClass ? '__super' + superId++ : '' + }); + + // super class + if (superClass) { + append(indent, state); + renderSuperClass(traverse, superClass, path, state); + append(getSuperProtoOfPrototypeVariable(state.superVar, indent), state); + } + + renderConstructor(traverse, object, name, indent, path, state); + append(getInheritanceSetup(superClass, name, indent, state.superVar), state); + renderMethods(traverse, object, name, path, state); +} + + +/** + * @public + */ +function visitClassExpression(traverse, object, path, state) { + var indent = updateIndent( + indentBefore(object.range[0], state) + ' ', + state); + var name = object.id ? object.id.name : 'constructor'; + + append('(function() {\n', state); + renderClassBody(traverse, object, path, state); + append(indent + 'return ' + name + ';\n', state); + append(indent.substring(0, indent.length - 2) + '})()', state); + return false +} + +visitClassExpression.test = function(object, path, state) { + return object.type === Syntax.ClassExpression; +}; + +/** + * @public + */ +function visitClassDeclaration(traverse, object, path, state) { + state.g.indentBy--; + renderClassBody(traverse, object, path, state); + state.g.indentBy++; + return false; +} + +visitClassDeclaration.test = function(object, path, state) { + return object.type === Syntax.ClassDeclaration; +}; + + +/** + * @public + */ +function visitSuperCall(traverse, object, path, state) { + if (path[0].type === Syntax.CallExpression) { + append(state.superVar + + '.call(' + getSuperArguments(path[0], state) + ')', state); + move(path[0].range[1], state); + } else if (path[0].type === Syntax.MemberExpression) { + append(getMemberFunctionCall( + state.superVar, + path[0].property.name, + getSuperArguments(path[1], state)), state); + move(path[1].range[1], state); + } + return false; +} + +visitSuperCall.test = function(object, path, state) { + return state.superVar && object.type === Syntax.Identifier && + object.name === 'super'; +}; + +/** + * @public + */ +function visitPrivateProperty(traverse, object, path, state) { + var type = path[0] ? path[0].type : null; + if (type !== Syntax.Property) { + if (type === Syntax.MemberExpression) { + type = path[0].object ? path[0].object.type : null; + if (type === Syntax.Identifier && + path[0].object.range[0] === object.range[0]) { + // Identifier is a variable that appears "private". + return; + } + } else { + // Other syntax that are neither Property nor MemberExpression. + return; + } + } + + var oldName = object.name; + var newName = getMungedName( + state.scopeName, + oldName, + state.g.opts.minify + ); + append(newName, state); + move(object.range[1], state); +} + +visitPrivateProperty.test = function(object, path, state) { + return object.type === Syntax.Identifier && + shouldMungeName(state.scopeName, object.name, state); +}; + + +exports.visitClassDeclaration = visitClassDeclaration; +exports.visitClassExpression = visitClassExpression; +exports.visitSuperCall = visitSuperCall; +exports.visitPrivateProperty = visitPrivateProperty; + +})() +},{"../lib/utils":8,"../lib/docblock":4,"esprima":10,"base62":15}],6:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; + +var Syntax = require('esprima').Syntax; + +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var move = require('../lib/utils').move; +var getDocblock = require('../lib/utils').getDocblock; + +var FALLBACK_TAGS = require('./xjs').knownTags; +var renderXJSExpression = require('./xjs').renderXJSExpression; +var renderXJSLiteral = require('./xjs').renderXJSLiteral; +var quoteAttrName = require('./xjs').quoteAttrName; + +/** + * Customized desugar processor. + * + * Currently: (Somewhat tailored to React) + * => X(null, null) + * => X({prop: '1'}, null) + * => X({prop:'2'}, Y(null, null)) + * => X({prop:'2'}, [Y(null, null), Z(null, null)]) + * + * Exceptions to the simple rules above: + * if a property is named "class" it will be changed to "className" in the + * javascript since "class" is not a valid object key in javascript. + */ + +var JSX_ATTRIBUTE_RENAMES = { + 'class': 'className', + cxName: 'className' +}; + +var JSX_ATTRIBUTE_TRANSFORMS = { + cxName: function(attr) { + if (attr.value.type !== Syntax.Literal) { + throw new Error("cx only accepts a string literal"); + } else { + var classNames = attr.value.value.split(/\s+/g); + return 'cx(' + classNames.map(JSON.stringify).join(',') + ')'; + } + } +}; + +function visitReactTag(traverse, object, path, state) { + var jsxObjIdent = getDocblock(state).jsx; + + catchup(object.openingElement.range[0], state); + + if (object.name.namespace) { + throw new Error( + 'Namespace tags are not supported. ReactJSX is not XML.'); + } + + var isFallbackTag = FALLBACK_TAGS[object.name.name]; + append( + (isFallbackTag ? jsxObjIdent + '.' : '') + (object.name.name) + '(', + state + ); + + move(object.name.range[1], state); + + var childrenToRender = object.children.filter(function(child) { + return !(child.type === Syntax.Literal && !child.value.match(/\S/)); + }); + + // if we don't have any attributes, pass in null + if (object.attributes.length === 0) { + append('null', state); + } + + // write attributes + object.attributes.forEach(function(attr, index) { + catchup(attr.range[0], state); + if (attr.name.namespace) { + throw new Error( + 'Namespace attributes are not supported. ReactJSX is not XML.'); + } + var name = JSX_ATTRIBUTE_RENAMES[attr.name.name] || attr.name.name; + var isFirst = index === 0; + var isLast = index === object.attributes.length - 1; + + if (isFirst) { + append('{', state); + } + + append(quoteAttrName(name), state); + append(':', state); + + if (!attr.value) { + state.g.buffer += 'true'; + state.g.position = attr.name.range[1]; + if (!isLast) { + append(',', state); + } + } else if (JSX_ATTRIBUTE_TRANSFORMS[attr.name.name]) { + move(attr.value.range[0], state); + append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state); + move(attr.value.range[1], state); + if (!isLast) { + append(',', state); + } + } else if (attr.value.type === Syntax.Literal) { + move(attr.value.range[0], state); + renderXJSLiteral(attr.value, isLast, state); + } else { + move(attr.value.range[0], state); + renderXJSExpression(traverse, attr.value, isLast, path, state); + } + + if (isLast) { + append('}', state); + } + + catchup(attr.range[1], state); + }); + + if (!object.selfClosing) { + catchup(object.openingElement.range[1] - 1, state); + move(object.openingElement.range[1], state); + } + + // separate props and children arguments + append(', ', state); + + // filter out whitespace + if (childrenToRender.length > 0) { + if (childrenToRender.length > 1) { + append('[', state); + } + object.children.forEach(function(child) { + if (child.type === Syntax.Literal && !child.value.match(/\S/)) { + return; + } + catchup(child.range[0], state); + + var isLast = child === childrenToRender[childrenToRender.length - 1]; + + if (child.type === Syntax.Literal) { + renderXJSLiteral(child, isLast, state); + } else if (child.type === Syntax.XJSExpression) { + renderXJSExpression(traverse, child, isLast, path, state); + } else { + traverse(child, path, state); + if (!isLast) { + append(',', state); + state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1'); + } + } + + catchup(child.range[1], state); + }); + } else { + append('null', state); + } + + if (object.selfClosing) { + // everything up to /> + catchup(object.openingElement.range[1] - 2, state); + move(object.openingElement.range[1], state); + } else { + // everything up to + catchup(object.closingElement.range[0], state); + move(object.closingElement.range[1], state); + } + + if (childrenToRender.length > 0) { + if (childrenToRender.length > 1) { + append(']', state); + } + } + append(')', state); + return false; +} + +visitReactTag.test = function(object, path, state) { + // only run react when react @jsx namespace is specified in docblock + var jsx = getDocblock(state).jsx; + return object.type === Syntax.XJSElement && jsx && jsx.length; +}; + +exports.visitReactTag = visitReactTag; + +})() +},{"../lib/utils":8,"./xjs":11,"esprima":10}],7:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; + +var Syntax = require('esprima').Syntax; +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var getDocblock = require('../lib/utils').getDocblock; + +/** + * Transforms the following: + * + * var MyComponent = React.createClass({ + * render: ... + * }); + * + * into: + * + * var MyComponent = React.createClass({ + * displayName: 'MyComponent', + * render: ... + * }); + */ +function visitReactDisplayName(traverse, object, path, state) { + object.declarations.forEach(function(dec) { + if (dec.type === Syntax.VariableDeclarator && + dec.id.type === Syntax.Identifier && + dec.init && + dec.init.type === Syntax.CallExpression && + dec.init.callee.type === Syntax.MemberExpression && + dec.init.callee.object.type === Syntax.Identifier && + dec.init.callee.object.name === 'React' && + dec.init.callee.property.type === Syntax.Identifier && + dec.init.callee.property.name === 'createClass' && + dec.init['arguments'].length === 1 && + dec.init['arguments'][0].type === Syntax.ObjectExpression) { + + var displayName = dec.id.name; + catchup(dec.init['arguments'][0].range[0] + 1, state); + append("displayName: '" + displayName + "',", state); + } + }); +} + + +/** + * Will only run on @jsx files for now. + */ +visitReactDisplayName.test = function(object, path, state) { + return object.type === Syntax.VariableDeclaration && !!getDocblock(state).jsx; +}; + +exports.visitReactDisplayName = visitReactDisplayName; + +})() +},{"../lib/utils":8,"esprima":10}],15:[function(require,module,exports){ +var Base62 = (function (my) { + my.chars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] + + my.encode = function(i){ + if (i === 0) {return '0'} + var s = '' + while (i > 0) { + s = this.chars[i % 62] + s + i = Math.floor(i/62) + } + return s + }; + my.decode = function(a,b,c,d){ + for ( + b = c = ( + a === (/\W|_|^$/.test(a += "") || a) + ) - 1; + d = a.charCodeAt(c++); + ) + b = b * 62 + d - [, 48, 29, 87][d >> 5]; + return b + }; + + return my; +}({})); + +module.exports = Base62 +},{}],12:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generated: generated, + original: original, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.original) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.original.line, + column: mapping.original.column + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.original.line = original.line; + mapping.original.column = original.column; + if (original.name !== null && mapping.name !== null) { + // Only use the identifier name if it's an identifier + // in both SourceMaps + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping.'); + } + }; + + function cmpLocation(loc1, loc2) { + var cmp = (loc1 && loc1.line) - (loc2 && loc2.line); + return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column); + } + + function strcmp(str1, str2) { + str1 = str1 || ''; + str2 = str2 || ''; + return (str1 > str2) - (str1 < str2); + } + + function cmpMapping(mappingA, mappingB) { + return cmpLocation(mappingA.generated, mappingB.generated) || + cmpLocation(mappingA.original, mappingB.original) || + strcmp(mappingA.source, mappingB.source) || + strcmp(mappingA.name, mappingB.name); + } + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guarenteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(cmpMapping); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generated.line !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generated.line !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!cmpMapping(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generated.column + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generated.column; + + if (mapping.source && mapping.original) { + result += base64VLQ.encode(this._sources.indexOf(mapping.source) + - previousSource); + previousSource = this._sources.indexOf(mapping.source); + + // lines are stored 0-based in SourceMap spec version 3 + result += base64VLQ.encode(mapping.original.line - 1 + - previousOriginalLine); + previousOriginalLine = mapping.original.line - 1; + + result += base64VLQ.encode(mapping.original.column + - previousOriginalColumn); + previousOriginalColumn = mapping.original.column; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + return result; + }; + + /** + * Externalize the source map. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = map.sources.map(function (source) { + if (map.sourceRoot) { + source = util.relative(map.sourceRoot, source); + } + return Object.prototype.hasOwnProperty.call( + this._sourcesContents, util.toSetString(source)) + ? this._sourcesContents[util.toSetString(source)] + : null; + }, this); + } + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); + +},{"./base64-vlq":16,"./util":17,"./array-set":18,"amdefine":19}],13:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + var names = util.getArg(sourceMap, 'names'); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file'); + + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } + + this._names = ArraySet.fromArray(names); + this._sources = ArraySet.fromArray(sources); + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this.file = file; + + // `this._generatedMappings` and `this._originalMappings` hold the parsed + // mapping coordinates from the source map's "mappings" attribute. Each + // object in the array is of the form + // + // { + // generatedLine: The line number in the generated code, + // generatedColumn: The column number in the generated code, + // source: The path to the original source file that generated this + // chunk of code, + // originalLine: The line number in the original source that + // corresponds to this chunk of generated code, + // originalColumn: The column number in the original source that + // corresponds to this chunk of generated code, + // name: The name of the original symbol which generated this chunk of + // code. + // } + // + // All properties except for `generatedLine` and `generatedColumn` can be + // `null`. + // + // `this._generatedMappings` is ordered by the generated positions. + // + // `this._originalMappings` is ordered by the original positions. + this._generatedMappings = []; + this._originalMappings = []; + this._parseMappings(mappings, sourceRoot); + } + + /** + * The version of the source mapping spec that we are consuming. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + /** + * Parse the mappings in a string in to a data structure which we can easily + * query (an ordered list in this._generatedMappings). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this._generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this._originalMappings.push(mapping); + } + } + } + + this._originalMappings.sort(this._compareOriginalPositions); + }; + + /** + * Comparator between two mappings where the original positions are compared. + */ + SourceMapConsumer.prototype._compareOriginalPositions = + function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) { + if (mappingA.source > mappingB.source) { + return 1; + } + else if (mappingA.source < mappingB.source) { + return -1; + } + else { + var cmp = mappingA.originalLine - mappingB.originalLine; + return cmp === 0 + ? mappingA.originalColumn - mappingB.originalColumn + : cmp; + } + }; + + /** + * Comparator between two mappings where the generated positions are compared. + */ + SourceMapConsumer.prototype._compareGeneratedPositions = + function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { + var cmp = mappingA.generatedLine - mappingB.generatedLine; + return cmp === 0 + ? mappingA.generatedColumn - mappingB.generatedColumn + : cmp; + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + this._compareGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is + * the url of the original source file. Returns null if no + * original source content is availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + // Try to remove the sourceRoot + var relativeUrl = util.relative(this.sourceRoot, aSource); + if (this._sources.has(relativeUrl)) { + return this.sourcesContent[this._sources.indexOf(relativeUrl)]; + } + } + + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } + + throw new Error('"' + aSource + '" is not in the SourceMap.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + this._compareOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); + +},{"./util":17,"./binary-search":20,"./array-set":18,"./base64-vlq":16,"amdefine":19}],14:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + this.children.forEach(function (chunk) { + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + }, this); + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + this.children.forEach(function (chunk) { + if (chunk instanceof SourceNode) { + chunk.walkSourceContents(aFn); + } + }, this); + Object.keys(this.sourceContents).forEach(function (sourceFileKey) { + aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); + }, this); + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + this.walk(function (chunk, original) { + generated.code += chunk; + if (original.source !== null + && original.line !== null + && original.column !== null) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); + +},{"./source-map-generator":12,"./util":17,"amdefine":19}],21:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; + +process.nextTick = (function () { + var canSetImmediate = typeof window !== 'undefined' + && window.setImmediate; + var canPost = typeof window !== 'undefined' + && window.postMessage && window.addEventListener + ; + + if (canSetImmediate) { + return function (f) { return window.setImmediate(f) }; + } + + if (canPost) { + var queue = []; + window.addEventListener('message', function (ev) { + if (ev.source === window && ev.data === 'process-tick') { + ev.stopPropagation(); + if (queue.length > 0) { + var fn = queue.shift(); + fn(); + } + } + }, true); + + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; + } + + return function nextTick(fn) { + setTimeout(fn, 0); + }; +})(); + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +} + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; + +},{}],19:[function(require,module,exports){ +(function(process,__filename){/** vim: et:ts=4:sw=4:sts=4 + * @license amdefine 0.0.5 Copyright (c) 2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/amdefine for details + */ + +/*jslint node: true */ +/*global module, process */ +'use strict'; + +var path = require('path'); + +/** + * Creates a define for node. + * @param {Object} module the "module" object that is defined by Node for the + * current module. + * @param {Function} [require]. Node's require function for the current module. + * It only needs to be passed in Node versions before 0.5, when module.require + * did not exist. + * @returns {Function} a define function that is usable for the current node + * module. + */ +function amdefine(module, require) { + var defineCache = {}, + loaderCache = {}, + alreadyCalled = false, + makeRequire, stringRequire; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i+= 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + function normalize(name, baseName) { + var baseParts; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + baseParts = baseName.split('/'); + baseParts = baseParts.slice(0, baseParts.length - 1); + baseParts = baseParts.concat(name.split('/')); + trimDots(baseParts); + name = baseParts.join('/'); + } + } + + return name; + } + + /** + * Create the normalize() function passed to a loader plugin's + * normalize method. + */ + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } + + load.fromText = function (id, text) { + //This one is difficult because the text can/probably uses + //define, and any relative paths and requires should be relative + //to that id was it would be found on disk. But this would require + //bootstrapping a module/require fairly deeply from node core. + //Not sure how best to go about that yet. + throw new Error('amdefine does not implement load.fromText'); + }; + + return load; + } + + makeRequire = function (systemRequire, exports, module, relId) { + function amdRequire(deps, callback) { + if (typeof deps === 'string') { + //Synchronous, single module require('') + return stringRequire(systemRequire, exports, module, deps, relId); + } else { + //Array of dependencies with a callback. + + //Convert the dependencies to modules. + deps = deps.map(function (depName) { + return stringRequire(systemRequire, exports, module, depName, relId); + }); + + //Wait for next tick to call back the require call. + process.nextTick(function () { + callback.apply(null, deps); + }); + } + } + + amdRequire.toUrl = function (filePath) { + if (filePath.indexOf('.') === 0) { + return normalize(filePath, path.dirname(module.filename)); + } else { + return filePath; + } + }; + + return amdRequire; + }; + + //Favor explicit value, passed in if the module wants to support Node 0.4. + require = require || function req() { + return module.require.apply(module, arguments); + }; + + function runFactory(id, deps, factory) { + var r, e, m, result; + + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(require, e, m, id); + } else { + //Only support one define call per file + if (alreadyCalled) { + throw new Error('amdefine with no module ID cannot be called more than once per file.'); + } + alreadyCalled = true; + + //Use the real variables from node + //Use module.exports for exports, since + //the exports in here is amdefine exports. + e = module.exports; + m = module; + r = makeRequire(require, e, m, module.id); + } + + //If there are dependencies, they are strings, so need + //to convert them to dependency values. + if (deps) { + deps = deps.map(function (depName) { + return r(depName); + }); + } + + //Call the factory with the right dependencies. + if (typeof factory === 'function') { + result = factory.apply(module.exports, deps); + } else { + result = factory; + } + + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; + } + } + } + + stringRequire = function (systemRequire, exports, module, id, relId) { + //Split the ID by a ! so that + var index = id.indexOf('!'), + originalId = id, + prefix, plugin; + + if (index === -1) { + id = normalize(id, relId); + + //Straight module lookup. If it is one of the special dependencies, + //deal with it, otherwise, delegate to node. + if (id === 'require') { + return makeRequire(systemRequire, exports, module, relId); + } else if (id === 'exports') { + return exports; + } else if (id === 'module') { + return module; + } else if (loaderCache.hasOwnProperty(id)) { + return loaderCache[id]; + } else if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } else { + if(systemRequire) { + return systemRequire(originalId); + } else { + throw new Error('No module with ID: ' + id); + } + } + } else { + //There is a plugin in play. + prefix = id.substring(0, index); + id = id.substring(index + 1, id.length); + + plugin = stringRequire(systemRequire, exports, module, prefix, relId); + + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + //Normalize the ID normally. + id = normalize(id, relId); + } + + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); + + return loaderCache[id]; + } + } + }; + + //Create a define function specific to the module asking for amdefine. + function define(id, deps, factory) { + if (Array.isArray(id)) { + factory = deps; + deps = id; + id = undefined; + } else if (typeof id !== 'string') { + factory = id; + id = deps = undefined; + } + + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } + + if (!deps) { + deps = ['require', 'exports', 'module']; + } + + //Set up properties for this module. If an ID, then use + //internal cache. If no ID, then use the external variables + //for this node module. + if (id) { + //Put the module in deep freeze until there is a + //require call for it. + defineCache[id] = [id, deps, factory]; + } else { + runFactory(id, deps, factory); + } + } + + //define.require, which has access to all the values in the + //cache. Useful for AMD modules that all have IDs in the file, + //but need to finally export a value to node based on one of those + //IDs. + define.require = function (id) { + if (loaderCache[id]) { + return loaderCache[id]; + } + + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } + }; + + define.amd = {}; + + return define; +} + +module.exports = amdefine; + +})(require("__browserify_process"),"/../node_modules/source-map/node_modules/amdefine/amdefine.js") +},{"path":22,"__browserify_process":21}],16:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); + +},{"./base64":23,"amdefine":19}],17:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + + function join(aRoot, aPath) { + var url; + + if (aPath.match(urlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + return aRoot.replace(url.path, '') + aPath; + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + +}); + +},{"amdefine":19}],18:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i]); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr) { + if (this.has(aStr)) { + // Already a member; nothing to do. + return; + } + var idx = this._array.length; + this._array.push(aStr); + this._set[util.toSetString(aStr)] = idx; + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); + +},{"./util":17,"amdefine":19}],20:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid]); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); + +},{"amdefine":19}],22:[function(require,module,exports){ +(function(process){function filter (xs, fn) { + var res = []; + for (var i = 0; i < xs.length; i++) { + if (fn(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length; i >= 0; i--) { + var last = parts[i]; + if (last == '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Regex to split a filename into [*, dir, basename, ext] +// posix version +var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { +var resolvedPath = '', + resolvedAbsolute = false; + +for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) + ? arguments[i] + : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string' || !path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; +} + +// At this point the path should be resolved to a full absolute path, but +// handle relative paths to be safe (might happen when process.cwd() fails) + +// Normalize the path +resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { +var isAbsolute = path.charAt(0) === '/', + trailingSlash = path.slice(-1) === '/'; + +// Normalize the path +path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + return p && typeof p === 'string'; + }).join('/')); +}; + + +exports.dirname = function(path) { + var dir = splitPathRe.exec(path)[1] || ''; + var isWindows = false; + if (!dir) { + // No dirname + return '.'; + } else if (dir.length === 1 || + (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) { + // It is just a slash or a drive letter with a slash + return dir; + } else { + // It is a full dirname, strip trailing slash + return dir.substring(0, dir.length - 1); + } +}; + + +exports.basename = function(path, ext) { + var f = splitPathRe.exec(path)[2] || ''; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPathRe.exec(path)[3] || ''; +}; + +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +})(require("__browserify_process")) +},{"__browserify_process":21}],23:[function(require,module,exports){ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); + +},{"amdefine":19}]},{},[1])(1) +}); +; \ No newline at end of file diff --git a/components/react/bower.json b/components/react/bower.json new file mode 100644 index 0000000000000..7eaef58e9989d --- /dev/null +++ b/components/react/bower.json @@ -0,0 +1,5 @@ +{ + "name": "react", + "version": "0.3.0", + "main": "react.js" +} \ No newline at end of file diff --git a/components/react/component.json b/components/react/component.json new file mode 100644 index 0000000000000..ed4ecf1b61f8f --- /dev/null +++ b/components/react/component.json @@ -0,0 +1,6 @@ +{ + "repository": { + "type": "git", + "url": "git://github.com/facebook/react-bower.git" + } +} \ No newline at end of file diff --git a/components/react/react.js b/components/react/react.js new file mode 100644 index 0000000000000..7186e3732d3d2 --- /dev/null +++ b/components/react/react.js @@ -0,0 +1,8453 @@ +/** + * React v0.3.0 + */ +(function(e){if("function"==typeof bootstrap)bootstrap("react",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeReact=e}else"undefined"!=typeof window?window.React=e():global.React=e()})(function(){var define,ses,bootstrap,module,exports; +return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;sHello World; + * } + * }); + * + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will available on the prototype. + * + * @interface ReactCompositeComponentInterface + * @internal + */ +var ReactCompositeComponentInterface = { + + /** + * An array of Mixin objects to include when defining your component. + * + * @type {array} + * @optional + */ + mixins: SpecPolicy.DEFINE_MANY, + + /** + * Definition of props for this component. + * + * @type {array} + * @optional + */ + props: SpecPolicy.DEFINE_ONCE, + + + + // ==== Definition methods ==== + + /** + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. + * + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional + */ + getInitialState: SpecPolicy.DEFINE_ONCE, + + /** + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. + * + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @nosideeffects + * @required + */ + render: SpecPolicy.DEFINE_ONCE, + + + + // ==== Delegate methods ==== + + /** + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. + * + * @optional + */ + componentWillMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. + * + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked before the component receives new props. + * + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional + */ + componentWillReceiveProps: SpecPolicy.DEFINE_MANY, + + /** + * Invoked while deciding if the component should be updated as a result of + * receiving new props and state. + * + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props and state will not require a component update. + * + * shouldComponentUpdate: function(nextProps, nextState) { + * return !equal(nextProps, this.props) || !equal(nextState, this.state); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @return {boolean} True if the component should update. + * @optional + */ + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, + + /** + * Invoked when the component is about to update due to a transition from + * `this.props` and `this.state` to `nextProps` and `nextState`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {ReactReconcileTransaction} transaction + * @optional + */ + componentWillUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: SpecPolicy.DEFINE_MANY, + + + + // ==== Advanced methods ==== + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: SpecPolicy.OVERRIDE_BASE + +}; + +/** + * Mapping from class specification keys to special processing functions. + * + * Although these are declared in the specification when defining classes + * using `React.createClass`, they will not be on the component's prototype. + */ +var RESERVED_SPEC_KEYS = { + displayName: function(Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function(Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + props: function(Constructor, props) { + Constructor.propDeclarations = props; + } +}; + +/** + * Custom version of `mixInto` which handles policy validation and reserved + * specification keys when building `ReactCompositeComponent` classses. + */ +function mixSpecIntoComponent(Constructor, spec) { + var proto = Constructor.prototype; + for (var name in spec) { + if (!spec.hasOwnProperty(name)) { + continue; + } + var property = spec[name]; + var specPolicy = ReactCompositeComponentInterface[name]; + + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactCompositeComponentMixin.hasOwnProperty(name)) { + invariant( + specPolicy === SpecPolicy.OVERRIDE_BASE, + 'ReactCompositeComponentInterface: You are attempting to override ' + + '`%s` from your class specification. Ensure that your method names ' + + 'do not overlap with React methods.', + name + ); + } + + // Disallow using `React.autoBind` on internal methods. + if (specPolicy != null) { + invariant( + !property || !property.__reactAutoBind, + 'ReactCompositeComponentInterface: You are attempting to use ' + + '`React.autoBind` on `%s`, a method that is internal to React.' + + 'Internal methods are called with the component as the context.', + name + ); + } + + // Disallow defining methods more than once unless explicitly allowed. + if (proto.hasOwnProperty(name)) { + invariant( + specPolicy === SpecPolicy.DEFINE_MANY, + 'ReactCompositeComponentInterface: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be due ' + + 'to a mixin.', + name + ); + } + + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else if (property && property.__reactAutoBind) { + if (!proto.__reactAutoBindMap) { + proto.__reactAutoBindMap = {}; + } + proto.__reactAutoBindMap[name] = property.__reactAutoBind; + } else if (proto.hasOwnProperty(name)) { + // For methods which are defined more than once, call the existing methods + // before calling the new property. + proto[name] = createChainedFunction(proto[name], property); + } else { + proto[name] = property; + } + } +} + +/** + * Creates a function that invokes two functions and ignores their return vales. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ +function createChainedFunction(one, two) { + return function chainedFunction(a, b, c, d, e, tooMany) { + invariant( + typeof tooMany === 'undefined', + 'Chained function can only take a maximum of 5 arguments.' + ); + one.call(this, a, b, c, d, e); + two.call(this, a, b, c, d, e); + }; +} + +/** + * `ReactCompositeComponent` maintains an auxiliary life cycle state in + * `this._compositeLifeCycleState` (which can be null). + * + * This is different from the life cycle state maintained by `ReactComponent` in + * `this._lifeCycleState`. + */ +var CompositeLifeCycle = keyMirror({ + /** + * Components in the process of being mounted respond to state changes + * differently. + */ + MOUNTING: null, + /** + * Components in the process of being unmounted are guarded against state + * changes. + */ + UNMOUNTING: null, + /** + * Components that are mounted and receiving new props respond to state + * changes differently. + */ + RECEIVING_PROPS: null, + /** + * Components that are mounted and receiving new state are guarded against + * additional state changes. + */ + RECEIVING_STATE: null +}); + +/** + * @lends {ReactCompositeComponent.prototype} + */ +var ReactCompositeComponentMixin = { + + /** + * Base constructor for all composite component. + * + * @param {?object} initialProps + * @param {*} children + * @final + * @internal + */ + construct: function(initialProps, children) { + ReactComponent.Mixin.construct.call(this, initialProps, children); + this.state = null; + this._pendingState = null; + this._compositeLifeCycleState = null; + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function(rootID, transaction) { + ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); + + // Unset `this._lifeCycleState` until after this method is finished. + this._lifeCycleState = ReactComponent.LifeCycle.UNMOUNTED; + this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; + + if (this.constructor.propDeclarations) { + this._assertValidProps(this.props); + } + + if (this.__reactAutoBindMap) { + this._bindAutoBindMethods(); + } + + this.state = this.getInitialState ? this.getInitialState() : null; + this._pendingState = null; + + if (this.componentWillMount) { + this.componentWillMount(); + // When mounting, calls to `setState` by `componentWillMount` will set + // `this._pendingState` without triggering a re-render. + if (this._pendingState) { + this.state = this._pendingState; + this._pendingState = null; + } + } + + if (this.componentDidMount) { + transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); + } + + this._renderedComponent = this._renderValidatedComponent(); + + // Done with mounting, `setState` will now trigger UI changes. + this._compositeLifeCycleState = null; + this._lifeCycleState = ReactComponent.LifeCycle.MOUNTED; + + return this._renderedComponent.mountComponent(rootID, transaction); + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function() { + this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; + if (this.componentWillUnmount) { + this.componentWillUnmount(); + } + this._compositeLifeCycleState = null; + + ReactComponent.Mixin.unmountComponent.call(this); + this._renderedComponent.unmountComponent(); + this._renderedComponent = null; + + if (this.refs) { + this.refs = null; + } + + // Some existing components rely on this.props even after they've been + // destroyed (in event handlers). + // TODO: this.props = null; + // TODO: this.state = null; + }, + + /** + * Updates the rendered DOM nodes given a new set of props. + * + * @param {object} nextProps Next set of properties. + * @param {ReactReconcileTransaction} transaction + * @final + * @internal + */ + receiveProps: function(nextProps, transaction) { + if (this.constructor.propDeclarations) { + this._assertValidProps(nextProps); + } + ReactComponent.Mixin.receiveProps.call(this, nextProps, transaction); + + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; + if (this.componentWillReceiveProps) { + this.componentWillReceiveProps(nextProps, transaction); + } + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; + // When receiving props, calls to `setState` by `componentWillReceiveProps` + // will set `this._pendingState` without triggering a re-render. + var nextState = this._pendingState || this.state; + this._pendingState = null; + this._receivePropsAndState(nextProps, nextState, transaction); + this._compositeLifeCycleState = null; + }, + + /** + * Sets a subset of the state. Always use this or `replaceState` to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {object} partialState Next partial state to be merged with state. + * @final + * @protected + */ + setState: function(partialState) { + // Merge with `_pendingState` if it exists, otherwise with existing state. + this.replaceState(merge(this._pendingState || this.state, partialState)); + }, + + /** + * Replaces all of the state. Always use this or `setState` to mutate state. + * You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {object} completeState Next state. + * @final + * @protected + */ + replaceState: function(completeState) { + var compositeLifeCycleState = this._compositeLifeCycleState; + invariant( + this._lifeCycleState === ReactComponent.LifeCycle.MOUNTED || + compositeLifeCycleState === CompositeLifeCycle.MOUNTING, + 'replaceState(...): Can only update a mounted (or mounting) component.' + ); + invariant( + compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && + compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, + 'replaceState(...): Cannot update while unmounting component or during ' + + 'an existing state transition (such as within `render`).' + ); + + this._pendingState = completeState; + + // Do not trigger a state transition if we are in the middle of mounting or + // receiving props because both of those will already be doing this. + if (compositeLifeCycleState !== CompositeLifeCycle.MOUNTING && + compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_PROPS) { + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; + + var nextState = this._pendingState; + this._pendingState = null; + + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform( + this._receivePropsAndState, + this, + this.props, + nextState, + transaction + ); + ReactComponent.ReactReconcileTransaction.release(transaction); + + this._compositeLifeCycleState = null; + } + }, + + /** + * Receives next props and next state, and negotiates whether or not the + * component should update as a result. + * + * @param {object} nextProps Next object to set as props. + * @param {?object} nextState Next object to set as state. + * @param {ReactReconcileTransaction} transaction + * @private + */ + _receivePropsAndState: function(nextProps, nextState, transaction) { + if (!this.shouldComponentUpdate || + this.shouldComponentUpdate(nextProps, nextState)) { + // Will set `this.props` and `this.state`. + this._performComponentUpdate(nextProps, nextState, transaction); + } else { + // If it's determined that a component should not update, we still want + // to set props and state. + this.props = nextProps; + this.state = nextState; + } + }, + + /** + * Merges new props and state, notifies delegate methods of update and + * performs update. + * + * @param {object} nextProps Next object to set as properties. + * @param {?object} nextState Next object to set as state. + * @param {ReactReconcileTransaction} transaction + * @private + */ + _performComponentUpdate: function(nextProps, nextState, transaction) { + var prevProps = this.props; + var prevState = this.state; + + if (this.componentWillUpdate) { + this.componentWillUpdate(nextProps, nextState, transaction); + } + + this.props = nextProps; + this.state = nextState; + + this.updateComponent(transaction); + + if (this.componentDidUpdate) { + transaction.getReactOnDOMReady().enqueue( + this, + this.componentDidUpdate.bind(this, prevProps, prevState) + ); + } + }, + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: function(transaction) { + var currentComponent = this._renderedComponent; + var nextComponent = this._renderValidatedComponent(); + if (currentComponent.constructor === nextComponent.constructor) { + if (!nextComponent.props.isStatic) { + currentComponent.receiveProps(nextComponent.props, transaction); + } + } else { + // These two IDs are actually the same! But nothing should rely on that. + var thisID = this._rootNodeID; + var currentComponentID = currentComponent._rootNodeID; + currentComponent.unmountComponent(); + var nextMarkup = nextComponent.mountComponent(thisID, transaction); + ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( + currentComponentID, + nextMarkup + ); + this._renderedComponent = nextComponent; + } + }, + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldUpdateComponent`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @final + * @protected + */ + forceUpdate: function() { + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform( + this._performComponentUpdate, + this, + this.props, + this.state, + transaction + ); + ReactComponent.ReactReconcileTransaction.release(transaction); + }, + + /** + * @private + */ + _renderValidatedComponent: function() { + ReactCurrentOwner.current = this; + var renderedComponent = this.render(); + ReactCurrentOwner.current = null; + invariant( + ReactComponent.isValidComponent(renderedComponent), + '%s.render(): A valid ReactComponent must be returned.', + this.constructor.displayName || 'ReactCompositeComponent' + ); + return renderedComponent; + }, + + /** + * @param {object} props + * @private + */ + _assertValidProps: function(props) { + var propDeclarations = this.constructor.propDeclarations; + var componentName = this.constructor.displayName; + for (var propName in propDeclarations) { + var checkProp = propDeclarations[propName]; + if (checkProp) { + checkProp(props, propName, componentName); + } + } + }, + + /** + * @private + */ + _bindAutoBindMethods: function() { + for (var autoBindKey in this.__reactAutoBindMap) { + if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { + continue; + } + var method = this.__reactAutoBindMap[autoBindKey]; + this[autoBindKey] = this._bindAutoBindMethod(method); + } + }, + + /** + * Binds a method to the component. + * + * @param {function} method Method to be bound. + * @private + */ + _bindAutoBindMethod: function(method) { + var component = this; + var hasWarned = false; + function autoBound(a, b, c, d, e, tooMany) { + invariant( + typeof tooMany === 'undefined', + 'React.autoBind(...): Methods can only take a maximum of 5 arguments.' + ); + if (component._lifeCycleState === ReactComponent.LifeCycle.MOUNTED) { + return method.call(component, a, b, c, d, e); + } else if (!hasWarned) { + hasWarned = true; + if (true) { + console.warn( + 'React.autoBind(...): Attempted to invoke an auto-bound method ' + + 'on an unmounted instance of `%s`. You either have a memory leak ' + + 'or an event handler that is being run after unmounting.', + component.constructor.displayName || 'ReactCompositeComponent' + ); + } + } + } + return autoBound; + } + +}; + +var ReactCompositeComponentBase = function() {}; +mixInto(ReactCompositeComponentBase, ReactComponent.Mixin); +mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); +mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); +mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); + +/** + * Module for creating composite components. + * + * @class ReactCompositeComponent + * @extends ReactComponent + * @extends ReactOwner + * @extends ReactPropTransferer + */ +var ReactCompositeComponent = { + + LifeCycle: CompositeLifeCycle, + + Base: ReactCompositeComponentBase, + + /** + * Creates a composite component class given a class specification. + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + createClass: function(spec) { + var Constructor = function(initialProps, children) { + this.construct(initialProps, children); + }; + Constructor.prototype = new ReactCompositeComponentBase(); + Constructor.prototype.constructor = Constructor; + mixSpecIntoComponent(Constructor, spec); + invariant( + Constructor.prototype.render, + 'createClass(...): Class specification must implement a `render` method.' + ); + + var ConvenienceConstructor = function(props, children) { + return new Constructor(props, children); + }; + ConvenienceConstructor.componentConstructor = Constructor; + ConvenienceConstructor.originalSpec = spec; + return ConvenienceConstructor; + }, + + /** + * Marks the provided method to be automatically bound to the component. + * This means the method's context will always be the component. + * + * React.createClass({ + * handleClick: React.autoBind(function() { + * this.setState({jumping: true}); + * }), + * render: function() { + * return Jump; + * } + * }); + * + * @param {function} method Method to be bound. + * @public + */ + autoBind: function(method) { + function unbound() { + invariant( + false, + 'React.autoBind(...): Attempted to invoke an auto-bound method that ' + + 'was not correctly defined on the class specification.' + ); + } + unbound.__reactAutoBind = method; + return unbound; + } + +}; + +module.exports = ReactCompositeComponent; + +})() +},{"./ReactComponent":3,"./ReactCurrentOwner":7,"./ReactOwner":8,"./ReactPropTransferer":9,"./invariant":10,"./keyMirror":11,"./merge":12,"./mixInto":13}],3:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactComponent + */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactDOMIDOperations = require("./ReactDOMIDOperations"); +var ReactMount = require("./ReactMount"); +var ReactOwner = require("./ReactOwner"); +var ReactReconcileTransaction = require("./ReactReconcileTransaction"); + +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); + +/** + * Prop key that references a component's owner. + * @private + */ +var OWNER = '{owner}'; + +/** + * Every React component is in one of these life cycles. + */ +var ComponentLifeCycle = keyMirror({ + /** + * Mounted components have a DOM node representation and are capable of + * receiving new props. + */ + MOUNTED: null, + /** + * Unmounted components are inactive and cannot receive new props. + */ + UNMOUNTED: null +}); + +/** + * Components are the basic units of composition in React. + * + * Every component accepts a set of keyed input parameters known as "props" that + * are initialized by the constructor. Once a component is mounted, the props + * can be mutated using `setProps` or `replaceProps`. + * + * Every component is capable of the following operations: + * + * `mountComponent` + * Initializes the component, renders markup, and registers event listeners. + * + * `receiveProps` + * Updates the rendered DOM nodes given a new set of props. + * + * `unmountComponent` + * Releases any resources allocated by this component. + * + * Components can also be "owned" by other components. Being owned by another + * component means being constructed by that component. This is different from + * being the child of a component, which means having a DOM representation that + * is a child of the DOM representation of that component. + * + * @class ReactComponent + */ +var ReactComponent = { + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid component. + * @final + */ + isValidComponent: function(object) { + return !!( + object && + typeof object.mountComponentIntoNode === 'function' && + typeof object.receiveProps === 'function' + ); + }, + + /** + * @internal + */ + LifeCycle: ComponentLifeCycle, + + /** + * React references `ReactDOMIDOperations` using this property in order to + * allow dependency injection. + * + * @internal + */ + DOMIDOperations: ReactDOMIDOperations, + + /** + * React references `ReactReconcileTransaction` using this property in order + * to allow dependency injection. + * + * @internal + */ + ReactReconcileTransaction: ReactReconcileTransaction, + + /** + * @param {object} DOMIDOperations + * @final + */ + setDOMOperations: function(DOMIDOperations) { + ReactComponent.DOMIDOperations = DOMIDOperations; + }, + + /** + * @param {Transaction} ReactReconcileTransaction + * @final + */ + setReactReconcileTransaction: function(ReactReconcileTransaction) { + ReactComponent.ReactReconcileTransaction = ReactReconcileTransaction; + }, + + /** + * Base functionality for every ReactComponent constructor. + * + * @lends {ReactComponent.prototype} + */ + Mixin: { + + /** + * Returns the DOM node rendered by this component. + * + * @return {?DOMElement} The root node of this component. + * @final + * @protected + */ + getDOMNode: function() { + invariant( + ExecutionEnvironment.canUseDOM, + 'getDOMNode(): The DOM is not supported in the current environment.' + ); + invariant( + this._lifeCycleState === ComponentLifeCycle.MOUNTED, + 'getDOMNode(): A component must be mounted to have a DOM node.' + ); + var rootNode = this._rootNode; + if (!rootNode) { + rootNode = document.getElementById(this._rootNodeID); + if (!rootNode) { + // TODO: Log the frequency that we reach this path. + rootNode = ReactMount.findReactRenderedDOMNodeSlow(this._rootNodeID); + } + this._rootNode = rootNode; + } + return rootNode; + }, + + /** + * Sets a subset of the props. + * + * @param {object} partialProps Subset of the next props. + * @final + * @public + */ + setProps: function(partialProps) { + this.replaceProps(merge(this.props, partialProps)); + }, + + /** + * Replaces all of the props. + * + * @param {object} props New props. + * @final + * @public + */ + replaceProps: function(props) { + invariant( + !this.props[OWNER], + 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + + 'component with an owner. This is an anti-pattern since props will ' + + 'get reactively updated when rendered. Instead, change the owner\'s ' + + '`render` method to pass the correct value as props to the component ' + + 'where it is created.' + ); + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform(this.receiveProps, this, props, transaction); + ReactComponent.ReactReconcileTransaction.release(transaction); + }, + + /** + * Base constructor for all React component. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.construct.call(this, ...)`. + * + * @param {?object} initialProps + * @param {*} children + * @internal + */ + construct: function(initialProps, children) { + this.props = initialProps || {}; + if (typeof children !== 'undefined') { + this.props.children = children; + } + // Record the component responsible for creating this component. + this.props[OWNER] = ReactCurrentOwner.current; + // All components start unmounted. + this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * NOTE: This does not insert any nodes into the DOM. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.mountComponent.call(this, ...)`. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @internal + */ + mountComponent: function(rootID, transaction) { + invariant( + this._lifeCycleState === ComponentLifeCycle.UNMOUNTED, + 'mountComponent(%s, ...): Can only mount an unmounted component.', + rootID + ); + var props = this.props; + if (props.ref != null) { + ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]); + } + this._rootNodeID = rootID; + this._lifeCycleState = ComponentLifeCycle.MOUNTED; + // Effectively: return ''; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * NOTE: This does not remove any nodes from the DOM. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.unmountComponent.call(this)`. + * + * @internal + */ + unmountComponent: function() { + invariant( + this._lifeCycleState === ComponentLifeCycle.MOUNTED, + 'unmountComponent(): Can only unmount a mounted component.' + ); + var props = this.props; + if (props.ref != null) { + ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); + } + this._rootNode = null; + this._rootNodeID = null; + this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; + }, + + /** + * Updates the rendered DOM nodes given a new set of props. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.receiveProps.call(this, ...)`. + * + * @param {object} nextProps Next set of properties. + * @param {ReactReconcileTransaction} transaction + * @internal + */ + receiveProps: function(nextProps, transaction) { + invariant( + this._lifeCycleState === ComponentLifeCycle.MOUNTED, + 'receiveProps(...): Can only update a mounted component.' + ); + var props = this.props; + // If either the owner or a `ref` has changed, make sure the newest owner + // has stored a reference to `this`, and the previous owner (if different) + // has forgotten the reference to `this`. + if (nextProps[OWNER] !== props[OWNER] || nextProps.ref !== props.ref) { + if (props.ref != null) { + ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); + } + // Correct, even if the owner is the same, and only the ref has changed. + if (nextProps.ref != null) { + ReactOwner.addComponentAsRefTo(this, nextProps.ref, nextProps[OWNER]); + } + } + }, + + /** + * Mounts this component and inserts it into the DOM. + * + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @final + * @internal + * @see {ReactMount.renderComponent} + */ + mountComponentIntoNode: function(rootID, container) { + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform( + this._mountComponentIntoNode, + this, + rootID, + container, + transaction + ); + ReactComponent.ReactReconcileTransaction.release(transaction); + }, + + /** + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {ReactReconcileTransaction} transaction + * @final + * @private + */ + _mountComponentIntoNode: function(rootID, container, transaction) { + var renderStart = Date.now(); + var markup = this.mountComponent(rootID, transaction); + ReactMount.totalInstantiationTime += (Date.now() - renderStart); + + var injectionStart = Date.now(); + // Asynchronously inject markup by ensuring that the container is not in + // the document when settings its `innerHTML`. + var parent = container.parentNode; + if (parent) { + var next = container.nextSibling; + parent.removeChild(container); + container.innerHTML = markup; + if (next) { + parent.insertBefore(container, next); + } else { + parent.appendChild(container); + } + } else { + container.innerHTML = markup; + } + ReactMount.totalInjectionTime += (Date.now() - injectionStart); + }, + + /** + * Unmounts this component and removes it from the DOM. + * + * @param {DOMElement} container DOM element to unmount from. + * @final + * @internal + * @see {ReactMount.unmountAndReleaseReactRootNode} + */ + unmountComponentFromNode: function(container) { + this.unmountComponent(); + // http://jsperf.com/emptying-a-node + while (container.lastChild) { + container.removeChild(container.lastChild); + } + }, + + /** + * Checks if this component is owned by the supplied `owner` component. + * + * @param {ReactComponent} owner Component to check. + * @return {boolean} True if `owners` owns this component. + * @final + * @internal + */ + isOwnedBy: function(owner) { + return this.props[OWNER] === owner; + } + + } + +}; + +function logDeprecated(msg) { + if (true) { + throw new Error(msg); + } +} + +/** + * @deprecated + */ +ReactComponent.Mixin.update = function(props) { + logDeprecated('this.update() is deprecated. Use this.setProps()'); + this.setProps(props); +}; +ReactComponent.Mixin.updateAll = function(props) { + logDeprecated('this.updateAll() is deprecated. Use this.replaceProps()'); + this.replaceProps(props); +}; + +module.exports = ReactComponent; + +},{"./ExecutionEnvironment":14,"./ReactCurrentOwner":7,"./ReactDOMIDOperations":15,"./ReactMount":5,"./ReactOwner":8,"./ReactReconcileTransaction":16,"./invariant":10,"./keyMirror":11,"./merge":12}],4:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOM + * @typechecks + */ + +"use strict"; + +var ReactNativeComponent = require("./ReactNativeComponent"); + +var mergeInto = require("./mergeInto"); +var objMapKeyVal = require("./objMapKeyVal"); + +/** + * Creates a new React class that is idempotent and capable of containing other + * React components. It accepts event listeners and DOM properties that are + * valid according to `DOMProperty`. + * + * - Event listeners: `onClick`, `onMouseDown`, etc. + * - DOM properties: `className`, `name`, `title`, etc. + * + * The `style` property functions differently from the DOM API. It accepts an + * object mapping of style properties to values. + * + * @param {string} tag Tag name (e.g. `div`). + * @param {boolean} omitClose True if the close tag should be omitted. + * @private + */ +function createDOMComponentClass(tag, omitClose) { + var Constructor = function(initialProps, children) { + this.construct(initialProps, children); + }; + + Constructor.prototype = new ReactNativeComponent(tag, omitClose); + Constructor.prototype.constructor = Constructor; + + return function(props, children) { + return new Constructor(props, children); + }; +} + +/** + * Creates a mapping from supported HTML tags to `ReactNativeComponent` classes. + * This is also accessible via `React.DOM`. + * + * @public + */ +var ReactDOM = objMapKeyVal({ + a: false, + abbr: false, + address: false, + audio: false, + b: false, + body: false, + br: true, + button: false, + code: false, + col: true, + colgroup: false, + dd: false, + div: false, + section: false, + dl: false, + dt: false, + em: false, + embed: true, + fieldset: false, + footer: false, + // Danger: this gets monkeypatched! See ReactDOMForm for more info. + form: false, + h1: false, + h2: false, + h3: false, + h4: false, + h5: false, + h6: false, + header: false, + hr: true, + i: false, + iframe: false, + img: true, + input: true, + label: false, + legend: false, + li: false, + line: false, + nav: false, + object: false, + ol: false, + optgroup: false, + option: false, + p: false, + param: true, + pre: false, + select: false, + small: false, + source: false, + span: false, + sub: false, + sup: false, + strong: false, + table: false, + tbody: false, + td: false, + textarea: false, + tfoot: false, + th: false, + thead: false, + time: false, + title: false, + tr: false, + u: false, + ul: false, + video: false, + wbr: false, + + // SVG + circle: false, + g: false, + path: false, + polyline: false, + rect: false, + svg: false, + text: false +}, createDOMComponentClass); + +var injection = { + injectComponentClasses: function(componentClasses) { + mergeInto(ReactDOM, componentClasses); + } +}; + +ReactDOM.injection = injection; + +module.exports = ReactDOM; + +},{"./ReactNativeComponent":17,"./mergeInto":18,"./objMapKeyVal":19}],5:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactMount + */ + +"use strict"; + +var ReactEvent = require("./ReactEvent"); +var ReactInstanceHandles = require("./ReactInstanceHandles"); +var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback"); + +var $ = require("./$"); + +var globalMountPointCounter = 0; + +/** Mapping from reactRoot DOM ID to React component instance. */ +var instanceByReactRootID = {}; + +/** Mapping from reactRoot DOM ID to `container` nodes. */ +var containersByReactRootID = {}; + +/** + * @param {DOMElement} container DOM element that may contain a React component. + * @return {?string} A "reactRoot" ID, if a React component is rendered. + */ +function getReactRootID(container) { + return container.firstChild && container.firstChild.id; +} + +/** + * Mounting is the process of initializing a React component by creatings its + * representative DOM elements and inserting them into a supplied `container`. + * Any prior content inside `container` is destroyed in the process. + * + * ReactMount.renderComponent(component, $('container')); + * + *
<-- Supplied `container`. + *
<-- Rendered reactRoot of React component. + * // ... + *
+ *
+ * + * Inside of `container`, the first element rendered is the "reactRoot". + */ +var ReactMount = { + + /** Time spent generating markup. */ + totalInstantiationTime: 0, + + /** Time spent inserting markup into the DOM. */ + totalInjectionTime: 0, + + /** Whether support for touch events should be initialized. */ + useTouchEvents: false, + + /** + * This is a hook provided to support rendering React components while + * ensuring that the apparent scroll position of its `container` does not + * change. + * + * @param {DOMElement} container The `container` being rendered into. + * @param {function} renderCallback This must be called once to do the render. + */ + scrollMonitor: function(container, renderCallback) { + renderCallback(); + }, + + /** + * Ensures tht the top-level event delegation listener is set up. This will be + * invoked some time before the first time any React component is rendered. + * + * @param {object} TopLevelCallbackCreator + * @private + */ + prepareTopLevelEvents: function(TopLevelCallbackCreator) { + ReactEvent.ensureListening( + ReactMount.useTouchEvents, + TopLevelCallbackCreator + ); + }, + + /** + * Renders a React component into the DOM in the supplied `container`. + * + * If the React component was previously rendered into `container`, this will + * perform an update on it and only mutate the DOM as necessary to reflect the + * latest React component. + * + * @param {ReactComponent} nextComponent Component instance to render. + * @param {DOMElement} container DOM element to render into. + * @return {ReactComponent} Component instance rendered in `container`. + */ + renderComponent: function(nextComponent, container) { + var prevComponent = instanceByReactRootID[getReactRootID(container)]; + if (prevComponent) { + var nextProps = nextComponent.props; + ReactMount.scrollMonitor(container, function() { + prevComponent.replaceProps(nextProps); + }); + return prevComponent; + } + + ReactMount.prepareTopLevelEvents(ReactEventTopLevelCallback); + + var reactRootID = ReactMount.registerContainer(container); + instanceByReactRootID[reactRootID] = nextComponent; + nextComponent.mountComponentIntoNode(reactRootID, container); + return nextComponent; + }, + + /** + * Creates a function that accepts a `container` and renders the supplied + * React component instance into it. + * + * var renderInto = ReactMount.createComponentRenderer(component); + * // ... + * var component = renderInto($('container')); + * + * @param {ReactComponent} component Component instance to render. + * @return {function(DOMElement): ReactComponent} + */ + createComponentRenderer: function(component) { + return function(container) { + return ReactMount.renderComponent(component, container); + }; + }, + + /** + * Constructs a component instance of `constructor` with `initialProps` and + * renders it into the supplied `container`. + * + * @param {function} constructor React component constructor. + * @param {?object} props Initial props of the component instance. + * @param {DOMElement} container DOM element to render into. + * @return {ReactComponent} Component instance rendered in `container`. + */ + constructAndRenderComponent: function(constructor, props, container) { + return ReactMount.renderComponent(constructor(props), container); + }, + + /** + * Constructs a component instance of `constructor` with `initialProps` and + * renders it into a container node identified by supplied `id`. + * + * @param {function} componentConstructor React component constructor + * @param {?object} props Initial props of the component instance. + * @param {string} id ID of the DOM element to render into. + * @return {ReactComponent} Component instance rendered in the container node. + */ + constructAndRenderComponentByID: function(constructor, props, id) { + return ReactMount.constructAndRenderComponent(constructor, props, $(id)); + }, + + /** + * Registers a container node into which React components will be rendered. + * This also creates the "reatRoot" ID that will be assigned to the element + * rendered within. + * + * @param {DOMElement} container DOM element to register as a container. + * @return {string} The "reactRoot" ID of elements rendered within. + */ + registerContainer: function(container) { + var reactRootID = getReactRootID(container); + if (reactRootID) { + // If one exists, make sure it is a valid "reactRoot" ID. + reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID); + } + if (!reactRootID) { + // No valid "reactRoot" ID found, create one. + reactRootID = ReactInstanceHandles.getReactRootID( + globalMountPointCounter++ + ); + } + containersByReactRootID[reactRootID] = container; + return reactRootID; + }, + + /** + * Unmounts and destroys the React component rendered in the `container`. + * + * @param {DOMElement} container DOM element containing a React component. + */ + unmountAndReleaseReactRootNode: function(container) { + var reactRootID = getReactRootID(container); + var component = instanceByReactRootID[reactRootID]; + // TODO: Consider throwing if no `component` was found. + component.unmountComponentFromNode(container); + delete instanceByReactRootID[reactRootID]; + delete containersByReactRootID[reactRootID]; + }, + + /** + * Finds the container DOM element that contains React component to which the + * supplied DOM `id` belongs. + * + * @param {string} id The ID of an element rendered by a React component. + * @return {?DOMElement} DOM element that contains the `id`. + */ + findReactContainerForID: function(id) { + var reatRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); + // TODO: Consider throwing if `id` is not a valid React element ID. + return containersByReactRootID[reatRootID]; + }, + + /** + * Given the ID of a DOM node rendered by a React component, finds the root + * DOM node of the React component. + * + * @param {string} id ID of a DOM node in the React component. + * @return {?DOMElement} Root DOM node of the React component. + */ + findReactRenderedDOMNodeSlow: function(id) { + var reactRoot = ReactMount.findReactContainerForID(id); + return ReactInstanceHandles.findComponentRoot(reactRoot, id); + } + +}; + +module.exports = ReactMount; + +})() +},{"./ReactEvent":20,"./ReactInstanceHandles":21,"./ReactEventTopLevelCallback":22,"./$":23}],6:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDefaultInjection + */ + +"use strict"; + +var ReactDOM = require("./ReactDOM"); +var ReactDOMForm = require("./ReactDOMForm"); + +var DefaultEventPluginOrder = require("./DefaultEventPluginOrder"); +var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin"); +var EventPluginHub = require("./EventPluginHub"); +var ReactInstanceHandles = require("./ReactInstanceHandles"); +var SimpleEventPlugin = require("./SimpleEventPlugin"); + +function inject() { + /** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ + EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder); + EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles); + + /** + * Two important event plugins included by default (without having to require + * them). + */ + EventPluginHub.injection.injectEventPluginsByName({ + 'SimpleEventPlugin': SimpleEventPlugin, + 'EnterLeaveEventPlugin': EnterLeaveEventPlugin + }); + + /* + * This is a bit of a hack. We need to override the
element + * to be a composite component because IE8 does not bubble or capture + * submit to the top level. In order to make this work with our + * dependency graph we need to inject it here. + */ + ReactDOM.injection.injectComponentClasses({ + form: ReactDOMForm + }); +} + +module.exports = { + inject: inject +}; + +},{"./ReactDOM":4,"./ReactDOMForm":24,"./DefaultEventPluginOrder":25,"./EnterLeaveEventPlugin":26,"./EventPluginHub":27,"./ReactInstanceHandles":21,"./SimpleEventPlugin":28}],7:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactCurrentOwner + */ + +"use strict"; + +/** + * Keeps track of the current owner. + * + * The current owner is the component who should own any components that are + * currently being constructed. + */ +var ReactCurrentOwner = { + + /** + * @internal + * @type {ReactComponent} + */ + current: null + +}; + +module.exports = ReactCurrentOwner; + +},{}],10:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule invariant + */ + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf style format and arguments to provide information about + * what broke and what you were expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +function invariant(condition) { + if (!condition) { + throw new Error('Invariant Violation'); + } +} + +module.exports = invariant; + +if (true) { + var invariantDev = function(condition, format, a, b, c, d, e, f) { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); + } + + if (!condition) { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + throw new Error( + 'Invariant Violation: ' + + format.replace(/%s/g, function() { return args[argIndex++]; }) + ); + } + }; + + module.exports = invariantDev; +} + +},{}],13:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule mixInto + */ + +"use strict"; + +/** + * Simply copies properties to the prototype. + */ +var mixInto = function(constructor, methodBag) { + var methodName; + for (methodName in methodBag) { + if (!methodBag.hasOwnProperty(methodName)) { + continue; + } + constructor.prototype[methodName] = methodBag[methodName]; + } +}; + +module.exports = mixInto; + +},{}],14:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ExecutionEnvironment + */ + +/*jslint evil: true */ + +"use strict"; + +var canUseDOM = typeof window !== 'undefined'; + +/** + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. + */ +var ExecutionEnvironment = { + + canUseDOM: canUseDOM, + + canUseWorkers: typeof Worker !== 'undefined', + + isInWorker: !canUseDOM, // For now, this is true - might change in the future. + + global: new Function('return this;')() + +}; + +module.exports = ExecutionEnvironment; + +})() +},{}],19:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule objMapKeyVal + */ + +"use strict"; + +/** + * Behaves the same as `objMap` but invokes func with the key first, and value + * second. Use `objMap` unless you need this special case. + * Invokes func as: + * + * func(key, value, iteration) + * + * @param {?object} obj Object to map keys over + * @param {!function} func Invoked for each key/val pair. + * @param {?*} context + * @return {?object} Result of mapping or null if obj is falsey + */ +function objMapKeyVal(obj, func, context) { + if (!obj) { + return null; + } + var i = 0; + var ret = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + ret[key] = func.call(context, key, obj[key], i++); + } + } + return ret; +} + +module.exports = objMapKeyVal; + +},{}],8:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactOwner + */ + +"use strict"; + +var invariant = require("./invariant"); + +/** + * ReactOwners are capable of storing references to owned components. + * + * All components are capable of //being// referenced by owner components, but + * only ReactOwner components are capable of //referencing// owned components. + * The named reference is known as a "ref". + * + * Refs are available when mounted and updated during reconciliation. + * + * var MyComponent = React.createClass({ + * render: function() { + * return ( + *
+ * + *
+ * ); + * }, + * handleClick: React.autoBind(function() { + * this.refs.custom.handleClick(); + * }), + * componentDidMount: function() { + * this.refs.custom.initialize(); + * } + * }); + * + * Refs should rarely be used. When refs are used, they should only be done to + * control data that is not handled by React's data flow. + * + * @class ReactOwner + */ +var ReactOwner = { + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid owner. + * @final + */ + isValidOwner: function(object) { + return !!( + object && + typeof object.attachRef === 'function' && + typeof object.detachRef === 'function' + ); + }, + + /** + * Adds a component by ref to an owner component. + * + * @param {ReactComponent} component Component to reference. + * @param {string} ref Name by which to refer to the component. + * @param {ReactOwner} owner Component on which to record the ref. + * @final + * @internal + */ + addComponentAsRefTo: function(component, ref, owner) { + invariant( + ReactOwner.isValidOwner(owner), + 'addComponentAsRefTo(...): Only a ReactOwner can have refs.' + ); + owner.attachRef(ref, component); + }, + + /** + * Removes a component by ref from an owner component. + * + * @param {ReactComponent} component Component to dereference. + * @param {string} ref Name of the ref to remove. + * @param {ReactOwner} owner Component on which the ref is recorded. + * @final + * @internal + */ + removeComponentAsRefFrom: function(component, ref, owner) { + invariant( + ReactOwner.isValidOwner(owner), + 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs.' + ); + // Check that `component` is still the current ref because we do not want to + // detach the ref if another component stole it. + if (owner.refs[ref] === component) { + owner.detachRef(ref); + } + }, + + /** + * A ReactComponent must mix this in to have refs. + * + * @lends {ReactOwner.prototype} + */ + Mixin: { + + /** + * Lazily allocates the refs object and stores `component` as `ref`. + * + * @param {string} ref Reference name. + * @param {component} component Component to store as `ref`. + * @final + * @private + */ + attachRef: function(ref, component) { + invariant( + component.isOwnedBy(this), + 'attachRef(%s, ...): Only a component\'s owner can store a ref to it.', + ref + ); + var refs = this.refs || (this.refs = {}); + refs[ref] = component; + }, + + /** + * Detaches a reference name. + * + * @param {string} ref Name to dereference. + * @final + * @private + */ + detachRef: function(ref) { + delete this.refs[ref]; + } + + } + +}; + +module.exports = ReactOwner; + +},{"./invariant":10}],9:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactPropTransferer + */ + +"use strict"; + +var emptyFunction = require("./emptyFunction"); +var joinClasses = require("./joinClasses"); +var merge = require("./merge"); + +/** + * Creates a transfer strategy that will merge prop values using the supplied + * `mergeStrategy`. If a prop was previously unset, this just sets it. + * + * @param {function} mergeStrategy + * @return {function} + */ +function createTransferStrategy(mergeStrategy) { + return function(props, key, value) { + if (!props.hasOwnProperty(key)) { + props[key] = value; + } else { + props[key] = mergeStrategy(props[key], value); + } + }; +} + +/** + * Transfer strategies dictate how props are transferred by `transferPropsTo`. + */ +var TransferStrategies = { + /** + * Never transfer the `ref` prop. + */ + ref: emptyFunction, + /** + * Transfer the `className` prop by merging them. + */ + className: createTransferStrategy(joinClasses), + /** + * Transfer the `style` prop (which is an object) by merging them. + */ + style: createTransferStrategy(merge) +}; + +/** + * ReactPropTransferer are capable of transferring props to another component + * using a `transferPropsTo` method. + * + * @class ReactPropTransferer + */ +var ReactPropTransferer = { + + TransferStrategies: TransferStrategies, + + /** + * @lends {ReactPropTransferer.prototype} + */ + Mixin: { + + /** + * Transfer props from this component to a target component. + * + * Props that do not have an explicit transfer strategy will be transferred + * only if the target component does not already have the prop set. + * + * This is usually used to pass down props to a returned root component. + * + * @param {ReactComponent} component Component receiving the properties. + * @return {ReactComponent} The supplied `component`. + * @final + * @protected + */ + transferPropsTo: function(component) { + var props = {}; + for (var thatKey in component.props) { + if (component.props.hasOwnProperty(thatKey)) { + props[thatKey] = component.props[thatKey]; + } + } + for (var thisKey in this.props) { + if (!this.props.hasOwnProperty(thisKey)) { + continue; + } + var transferStrategy = TransferStrategies[thisKey]; + if (transferStrategy) { + transferStrategy(props, thisKey, this.props[thisKey]); + } else if (!props.hasOwnProperty(thisKey)) { + props[thisKey] = this.props[thisKey]; + } + } + component.props = props; + return component; + } + + } + +}; + +module.exports = ReactPropTransferer; + +},{"./emptyFunction":29,"./joinClasses":30,"./merge":12}],11:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule keyMirror + */ + +"use strict"; + +var throwIf = require("./throwIf"); + +var NOT_OBJECT_ERROR = 'NOT_OBJECT_ERROR'; +if (true) { + NOT_OBJECT_ERROR = 'keyMirror only works on objects'; +} + +/** + * Utility for constructing enums with keys being equal to the associated + * values, even when using advanced key crushing. This is useful for debugging, + * but also for using the values themselves as lookups into the enum. + * Example: + * var COLORS = keyMirror({blue: null, red: null}); + * var myColor = COLORS.blue; + * var isColorValid = !!COLORS[myColor] + * The last line could not be performed if the values of the generated enum were + * not equal to their keys. + * Input: {key1: val1, key2: val2} + * Output: {key1: key1, key2: key2} + */ +var keyMirror = function(obj) { + var ret = {}; + var key; + + throwIf(!(obj instanceof Object) || Array.isArray(obj), NOT_OBJECT_ERROR); + + for (key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + ret[key] = key; + } + return ret; +}; + +module.exports = keyMirror; + +},{"./throwIf":31}],12:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule merge + */ + +"use strict"; + +var mergeInto = require("./mergeInto"); + +/** + * Shallow merges two structures into a return value, without mutating either. + * + * @param {?object} one Optional object with properties to merge from. + * @param {?object} two Optional object with properties to merge from. + * @return {object} The shallow extension of one by two. + */ +var merge = function(one, two) { + var result = {}; + mergeInto(result, one); + mergeInto(result, two); + return result; +}; + +module.exports = merge; + +},{"./mergeInto":18}],15:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMIDOperations + * @typechecks + */ + +/*jslint evil: true */ + +"use strict"; + +var CSSPropertyOperations = require("./CSSPropertyOperations"); +var DOMChildrenOperations = require("./DOMChildrenOperations"); +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var ReactDOMNodeCache = require("./ReactDOMNodeCache"); + +var getTextContentAccessor = require("./getTextContentAccessor"); +var invariant = require("./invariant"); + +/** + * Errors for properties that should not be updated with `updatePropertyById()`. + * + * @type {object} + * @private + */ +var INVALID_PROPERTY_ERRORS = { + content: '`content` must be set using `updateTextContentByID()`.', + dangerouslySetInnerHTML: + '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', + style: '`style` must be set using `updateStylesByID()`.' +}; + +/** + * The DOM property to use when setting text content. + * + * @type {string} + * @private + */ +var textContentAccessor = getTextContentAccessor() || 'NA'; + +/** + * Operations used to process updates to DOM nodes. This is made injectable via + * `ReactComponent.DOMIDOperations`. + */ +var ReactDOMIDOperations = { + + /** + * Updates a DOM node with new property values. This should only be used to + * update DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A valid property name, see `DOMProperty`. + * @param {*} value New value of the property. + * @internal + */ + updatePropertyByID: function(id, name, value) { + var node = ReactDOMNodeCache.getCachedNodeByID(id); + invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ); + DOMPropertyOperations.setValueForProperty(node, name, value); + }, + + /** + * This should almost never be used instead of `updatePropertyByID()` due to + * the extra object allocation required by the API. That said, this is useful + * for batching up several operations across worker thread boundaries. + * + * @param {string} id ID of the node to update. + * @param {object} properties A mapping of valid property names. + * @internal + * @see {ReactDOMIDOperations.updatePropertyByID} + */ + updatePropertiesByID: function(id, properties) { + for (var name in properties) { + if (!properties.hasOwnProperty(name)) { + continue; + } + ReactDOMIDOperations.updatePropertiesByID(id, name, properties[name]); + } + }, + + /** + * Updates a DOM node with new style values. + * + * @param {string} id ID of the node to update. + * @param {object} styles Mapping from styles to values. + * @internal + */ + updateStylesByID: function(id, styles) { + var node = ReactDOMNodeCache.getCachedNodeByID(id); + CSSPropertyOperations.setValueForStyles(node, styles); + }, + + /** + * Updates a DOM node's innerHTML set by `props.dangerouslySetInnerHTML`. + * + * @param {string} id ID of the node to update. + * @param {object} html An HTML object with the `__html` property. + * @internal + */ + updateInnerHTMLByID: function(id, html) { + var node = ReactDOMNodeCache.getCachedNodeByID(id); + // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces. + // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html + node.innerHTML = (html && html.__html || '').replace(/^ /g, ' '); + }, + + /** + * Updates a DOM node's text content set by `props.content`. + * + * @param {string} id ID of the node to update. + * @param {string} content Text content. + * @internal + */ + updateTextContentByID: function(id, content) { + var node = ReactDOMNodeCache.getCachedNodeByID(id); + node[textContentAccessor] = content; + }, + + /** + * Replaces a DOM node that exists in the document with markup. + * + * @param {string} id ID of child to be replaced. + * @param {string} markup Dangerous markup to inject in place of child. + * @internal + * @see {Danger.dangerouslyReplaceNodeWithMarkup} + */ + dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { + var node = ReactDOMNodeCache.getCachedNodeByID(id); + DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); + ReactDOMNodeCache.purgeEntireCache(); + }, + + /** + * TODO: We only actually *need* to purge the cache when we remove elements. + * Detect if any elements were removed instead of blindly purging. + */ + manageChildrenByParentID: function(parentID, domOperations) { + var parent = ReactDOMNodeCache.getCachedNodeByID(parentID); + DOMChildrenOperations.manageChildren(parent, domOperations); + ReactDOMNodeCache.purgeEntireCache(); + }, + + setTextNodeValueAtIndexByParentID: function(parentID, index, value) { + var parent = ReactDOMNodeCache.getCachedNodeByID(parentID); + DOMChildrenOperations.setTextNodeValueAtIndex(parent, index, value); + } + +}; + +module.exports = ReactDOMIDOperations; + +})() +},{"./CSSPropertyOperations":32,"./DOMChildrenOperations":33,"./DOMPropertyOperations":34,"./ReactDOMNodeCache":35,"./getTextContentAccessor":36,"./invariant":10}],16:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactReconcileTransaction + * @typechecks + */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var PooledClass = require("./PooledClass"); +var ReactEvent = require("./ReactEvent"); +var ReactInputSelection = require("./ReactInputSelection"); +var ReactOnDOMReady = require("./ReactOnDOMReady"); +var Transaction = require("./Transaction"); + +var mixInto = require("./mixInto"); + +/** + * Ensures that, when possible, the selection range (currently selected text + * input) is not disturbed by performing the transaction. + */ +var SELECTION_RESTORATION = { + /** + * @return {Selection} Selection information. + */ + initialize: ReactInputSelection.getSelectionInformation, + /** + * @param {Selection} sel Selection information returned from `initialize`. + */ + close: ReactInputSelection.restoreSelection +}; + +/** + * Suppresses events (blur/focus) that could be inadvertently dispatched due to + * high level DOM manipulations (like temporarily removing a text input from the + * DOM). + */ +var EVENT_SUPPRESSION = { + /** + * @return {boolean} The enabled status of `ReactEvent` before the + * reconciliation. + */ + initialize: function() { + var currentlyEnabled = ReactEvent.isEnabled(); + ReactEvent.setEnabled(false); + return currentlyEnabled; + }, + + /** + * @param {boolean} previouslyEnabled The enabled status of `ReactEvent` + * before the reconciliation occured. `close` restores the previous value. + */ + close: function(previouslyEnabled) { + ReactEvent.setEnabled(previouslyEnabled); + } +}; + +/** + * Provides a `ReactOnDOMReady` queue for collecting `onDOMReady` callbacks + * during the performing of the transaction. + */ +var ON_DOM_READY_QUEUEING = { + /** + * Initializes the internal `onDOMReady` queue. + */ + initialize: function() { + this.reactOnDOMReady.reset(); + }, + + /** + * After DOM is flushed, invoke all registered `onDOMReady` callbacks. + */ + close: function() { + this.reactOnDOMReady.notifyAll(); + } +}; + +/** + * Executed within the scope of the `Transaction` instance. Consider these as + * being member methods, but with an implied ordering while being isolated from + * each other. + */ +var TRANSACTION_WRAPPERS = [ + SELECTION_RESTORATION, + EVENT_SUPPRESSION, + ON_DOM_READY_QUEUEING +]; + +/** + * Currently: + * - The order that these are listed in the transaction is critical: + * - Suppresses events. + * - Restores selection range. + * + * Future: + * - Restore document/overflow scroll positions that were unintentionally + * modified via DOM insertions above the top viewport boundary. + * - Implement/integrate with customized constraint based layout system and keep + * track of which dimensions must be remeasured. + * + * @class ReactReconcileTransaction + */ +function ReactReconcileTransaction() { + this.reinitializeTransaction(); + this.reactOnDOMReady = ReactOnDOMReady.getPooled(null); +} + +var Mixin = { + /** + * @see Transaction + * @abstract + * @final + * @return {array} List of operation wrap proceedures. + * TODO: convert to array + */ + getTransactionWrappers: function() { + if (ExecutionEnvironment.canUseDOM) { + return TRANSACTION_WRAPPERS; + } else { + return []; + } + }, + + /** + * @return {object} The queue to collect `onDOMReady` callbacks with. + * TODO: convert to ReactOnDOMReady + */ + getReactOnDOMReady: function() { + return this.reactOnDOMReady; + }, + + /** + * `PooledClass` looks for this, and will invoke this before allowing this + * instance to be resused. + */ + destructor: function() { + ReactOnDOMReady.release(this.reactOnDOMReady); + this.reactOnDOMReady = null; + } +}; + + +mixInto(ReactReconcileTransaction, Transaction.Mixin); +mixInto(ReactReconcileTransaction, Mixin); + +PooledClass.addPoolingTo(ReactReconcileTransaction); + +module.exports = ReactReconcileTransaction; + +},{"./ExecutionEnvironment":14,"./PooledClass":37,"./ReactEvent":20,"./ReactInputSelection":38,"./ReactOnDOMReady":39,"./Transaction":40,"./mixInto":13}],17:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactNativeComponent + * @typechecks + */ + +"use strict"; + +var CSSPropertyOperations = require("./CSSPropertyOperations"); +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var ReactComponent = require("./ReactComponent"); +var ReactEvent = require("./ReactEvent"); +var ReactMultiChild = require("./ReactMultiChild"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var flattenChildren = require("./flattenChildren"); +var invariant = require("./invariant"); +var keyOf = require("./keyOf"); +var merge = require("./merge"); +var mixInto = require("./mixInto"); + +var putListener = ReactEvent.putListener; +var registrationNames = ReactEvent.registrationNames; + +// For quickly matching children type, to test if can be treated as content. +var CONTENT_TYPES = {'string': true, 'number': true}; + +var CONTENT = keyOf({content: null}); +var DANGEROUSLY_SET_INNER_HTML = keyOf({dangerouslySetInnerHTML: null}); +var STYLE = keyOf({style: null}); + +/** + * @param {?object} props + */ +function assertValidProps(props) { + if (!props) { + return; + } + // Note the use of `!=` which checks for null or undefined. + var hasChildren = props.children != null ? 1 : 0; + var hasContent = props.content != null ? 1 : 0; + var hasInnerHTML = props.dangerouslySetInnerHTML != null ? 1 : 0; + invariant( + hasChildren + hasContent + hasInnerHTML <= 1, + 'Can only set one of `children`, `props.content`, or ' + + '`props.dangerouslySetInnerHTML`.' + ); + invariant( + props.style == null || typeof props.style === 'object', + 'The `style` prop expects a mapping from style properties to values, ' + + 'not a string.' + ); +} + +/** + * @constructor ReactNativeComponent + * @extends ReactComponent + * @extends ReactMultiChild + */ +function ReactNativeComponent(tag, omitClose) { + this._tagOpen = '<' + tag + ' '; + this._tagClose = omitClose ? '' : ''; + this.tagName = tag.toUpperCase(); +} + +ReactNativeComponent.Mixin = { + + /** + * Generates root tag markup then recurses. This method has side effects and + * is not idempotent. + * + * @internal + * @param {string} rootID The root DOM ID for this node. + * @param {ReactReconcileTransaction} transaction + * @return {string} The computed markup. + */ + mountComponent: function(rootID, transaction) { + ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); + assertValidProps(this.props); + return ( + this._createOpenTagMarkup() + + this._createContentMarkup(transaction) + + this._tagClose + ); + }, + + /** + * Creates markup for the open tag and all attributes. + * + * This method has side effects because events get registered. + * + * Iterating over object properties is faster than iterating over arrays. + * @see http://jsperf.com/obj-vs-arr-iteration + * + * @private + * @return {string} Markup of opening tag. + */ + _createOpenTagMarkup: function() { + var props = this.props; + var ret = this._tagOpen; + + for (var propKey in props) { + if (!props.hasOwnProperty(propKey)) { + continue; + } + var propValue = props[propKey]; + if (propValue == null) { + continue; + } + if (registrationNames[propKey]) { + putListener(this._rootNodeID, propKey, propValue); + } else { + if (propKey === STYLE) { + if (propValue) { + propValue = props.style = merge(props.style); + } + propValue = CSSPropertyOperations.createMarkupForStyles(propValue); + } + var markup = + DOMPropertyOperations.createMarkupForProperty(propKey, propValue); + if (markup) { + ret += ' ' + markup; + } + } + } + + return ret + ' id="' + this._rootNodeID + '">'; + }, + + /** + * Creates markup for the content between the tags. + * + * @private + * @param {ReactReconcileTransaction} transaction + * @return {string} Content markup. + */ + _createContentMarkup: function(transaction) { + // Intentional use of != to avoid catching zero/false. + var innerHTML = this.props.dangerouslySetInnerHTML; + if (innerHTML != null) { + if (innerHTML.__html != null) { + return innerHTML.__html; + } + } else { + var contentToUse = this.props.content != null ? this.props.content : + CONTENT_TYPES[typeof this.props.children] ? this.props.children : null; + var childrenToUse = contentToUse != null ? null : this.props.children; + if (contentToUse != null) { + return escapeTextForBrowser(contentToUse); + } else if (childrenToUse != null) { + return this.mountMultiChild( + flattenChildren(childrenToUse), + transaction + ); + } + } + return ''; + }, + + /** + * Controls a native DOM component after it has already been allocated and + * attached to the DOM. Reconciles the root DOM node, then recurses. + * + * @internal + * @param {object} nextProps + * @param {ReactReconcileTransaction} transaction + */ + receiveProps: function(nextProps, transaction) { + invariant( + this._rootNodeID, + 'Trying to control a native dom element without a backing id' + ); + assertValidProps(nextProps); + ReactComponent.Mixin.receiveProps.call(this, nextProps, transaction); + this._updateDOMProperties(nextProps); + this._updateDOMChildren(nextProps, transaction); + this.props = nextProps; + }, + + /** + * Reconciles the properties by detecting differences in property values and + * updating the DOM as necessary. This function is probably the single most + * critical path for performance optimization. + * + * TODO: Benchmark whether checking for changed values in memory actually + * improves performance (especially statically positioned elements). + * TODO: Benchmark the effects of putting this at the top since 99% of props + * do not change for a given reconciliation. + * TODO: Benchmark areas that can be improved with caching. + * + * @private + * @param {object} nextProps + */ + _updateDOMProperties: function(nextProps) { + var lastProps = this.props; + for (var propKey in nextProps) { + var nextProp = nextProps[propKey]; + var lastProp = lastProps[propKey]; + if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) { + continue; + } + if (propKey === STYLE) { + if (nextProp) { + nextProp = nextProps.style = merge(nextProp); + } + var styleUpdates; + for (var styleName in nextProp) { + if (!nextProp.hasOwnProperty(styleName)) { + continue; + } + if (!lastProp || lastProp[styleName] !== nextProp[styleName]) { + if (!styleUpdates) { + styleUpdates = {}; + } + styleUpdates[styleName] = nextProp[styleName]; + } + } + if (styleUpdates) { + ReactComponent.DOMIDOperations.updateStylesByID( + this._rootNodeID, + styleUpdates + ); + } + } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { + var lastHtml = lastProp && lastProp.__html; + var nextHtml = nextProp && nextProp.__html; + if (lastHtml !== nextHtml) { + ReactComponent.DOMIDOperations.updateInnerHTMLByID( + this._rootNodeID, + nextProp + ); + } + } else if (propKey === CONTENT) { + ReactComponent.DOMIDOperations.updateTextContentByID( + this._rootNodeID, + '' + nextProp + ); + } else if (registrationNames[propKey]) { + putListener(this._rootNodeID, propKey, nextProp); + } else { + ReactComponent.DOMIDOperations.updatePropertyByID( + this._rootNodeID, + propKey, + nextProp + ); + } + } + }, + + /** + * Reconciles the children with the various properties that affect the + * children content. + * + * @param {object} nextProps + * @param {ReactReconcileTransaction} transaction + */ + _updateDOMChildren: function(nextProps, transaction) { + var thisPropsContentType = typeof this.props.content; + var thisPropsContentEmpty = + this.props.content == null || thisPropsContentType === 'boolean'; + var nextPropsContentType = typeof nextProps.content; + var nextPropsContentEmpty = + nextProps.content == null || nextPropsContentType === 'boolean'; + + var lastUsedContent = !thisPropsContentEmpty ? this.props.content : + CONTENT_TYPES[typeof this.props.children] ? this.props.children : null; + + var contentToUse = !nextPropsContentEmpty ? nextProps.content : + CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null; + + // Note the use of `!=` which checks for null or undefined. + + var lastUsedChildren = + lastUsedContent != null ? null : this.props.children; + var childrenToUse = contentToUse != null ? null : nextProps.children; + + if (contentToUse != null) { + var childrenRemoved = lastUsedChildren != null && childrenToUse == null; + if (childrenRemoved) { + this.updateMultiChild(null, transaction); + } + if (lastUsedContent !== contentToUse) { + ReactComponent.DOMIDOperations.updateTextContentByID( + this._rootNodeID, + '' + contentToUse + ); + } + } else { + var contentRemoved = lastUsedContent != null && contentToUse == null; + if (contentRemoved) { + ReactComponent.DOMIDOperations.updateTextContentByID( + this._rootNodeID, + '' + ); + } + this.updateMultiChild(flattenChildren(nextProps.children), transaction); + } + }, + + /** + * Destroys all event registrations for this instance. Does not remove from + * the DOM. That must be done by the parent. + * + * @internal + */ + unmountComponent: function() { + ReactComponent.Mixin.unmountComponent.call(this); + this.unmountMultiChild(); + ReactEvent.deleteAllListeners(this._rootNodeID); + } + +}; + +mixInto(ReactNativeComponent, ReactComponent.Mixin); +mixInto(ReactNativeComponent, ReactNativeComponent.Mixin); +mixInto(ReactNativeComponent, ReactMultiChild.Mixin); + +module.exports = ReactNativeComponent; + +},{"./DOMPropertyOperations":34,"./CSSPropertyOperations":32,"./ReactComponent":3,"./ReactEvent":20,"./ReactMultiChild":41,"./escapeTextForBrowser":42,"./flattenChildren":43,"./invariant":10,"./merge":12,"./keyOf":44,"./mixInto":13}],18:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule mergeInto + * @typechecks + */ + +"use strict"; + +var mergeHelpers = require("./mergeHelpers"); + +var checkMergeObjectArg = mergeHelpers.checkMergeObjectArg; + +/** + * Shallow merges two structures by mutating the first parameter. + * + * @param {object} one Object to be merged into. + * @param {?object} two Optional object with properties to merge from. + */ +function mergeInto(one, two) { + checkMergeObjectArg(one); + if (two != null) { + checkMergeObjectArg(two); + for (var key in two) { + if (!two.hasOwnProperty(key)) { + continue; + } + one[key] = two[key]; + } + } +} + +module.exports = mergeInto; + +},{"./mergeHelpers":45}],20:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactEvent + */ + +"use strict"; + +var BrowserEnv = require("./BrowserEnv"); +var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var NormalizedEventListener = require("./NormalizedEventListener"); + +var invariant = require("./invariant"); +var isEventSupported = require("./isEventSupported"); + +var registrationNames = EventPluginHub.registrationNames; +var topLevelTypes = EventConstants.topLevelTypes; +var listen = NormalizedEventListener.listen; +var capture = NormalizedEventListener.capture; + +/** + * `ReactEvent` is used to attach top-level event listeners. For example: + * + * ReactEvent.putListener('myID', 'onClick', myFunction); + * + * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'. + */ + +/** + * Overview of React and the event system: + * + * . + * +-------------+ . + * | DOM | . + * +-------------+ . +-----------+ + * + . +--------+|SimpleEvent| + * | . | |Plugin | + * +-----|-------+ . v +-----------+ + * | | | . +--------------+ +------------+ + * | +------------.---->|EventPluginHub| | Event | + * | | . | | +-----------+ | Propagators| + * | ReactEvent | . | | |TapEvent | |------------| + * | | . | |<---+|Plugin | |other plugin| + * | +------------.---------+ | +-----------+ | utilities | + * | | | . | | | +------------+ + * | | | . +---|----------+ + * | | | . | ^ +-----------+ + * | | | . | | |Enter/Leave| + * +-----| ------+ . | +-------+|Plugin | + * | . v +-----------+ + * + . +--------+ + * +-------------+ . |callback| + * | application | . |registry| + * |-------------| . +--------+ + * | | . + * | | . + * | | . + * | | . + * +-------------+ . + * . + * React Core . General Purpose Event Plugin System + */ + +/** + * We listen for bubbled touch events on the document object. + * + * Firefox v8.01 (and possibly others) exhibited strange behavior when mounting + * `onmousemove` events at some node that was not the document element. The + * symptoms were that if your mouse is not moving over something contained + * within that mount point (for example on the background) the top-level + * listeners for `onmousemove` won't be called. However, if you register the + * `mousemove` on the document object, then it will of course catch all + * `mousemove`s. This along with iOS quirks, justifies restricting top-level + * listeners to the document object only, at least for these movement types of + * events and possibly all events. + * + * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html + * + * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but + * they bubble to document. + * + * @see http://www.quirksmode.org/dom/events/keys.html. + */ + +var _isListening = false; + +var EVENT_LISTEN_MISUSE; +var WORKER_DISABLE; + +if (true) { + EVENT_LISTEN_MISUSE = + 'You must register listeners at the top of the document, only once - ' + + 'and only in the main UI thread of a browser - if you are attempting ' + + 'listen in a worker, the framework is probably doing something wrong ' + + 'and you should report this immediately.'; + WORKER_DISABLE = + 'Cannot disable event listening in Worker thread. This is likely a ' + + 'bug in the framework. Please report immediately.'; +} + + +/** + * Traps top-level events that bubble. Delegates to the main dispatcher + * `handleTopLevel` after performing some basic normalization via + * `TopLevelCallbackCreator.createTopLevelCallback`. + */ +function trapBubbledEvent(topLevelType, handlerBaseName, onWhat) { + listen( + onWhat, + handlerBaseName, + ReactEvent.TopLevelCallbackCreator.createTopLevelCallback(topLevelType) + ); +} + +/** + * Traps a top-level event by using event capturing. + */ +function trapCapturedEvent(topLevelType, handlerBaseName, onWhat) { + capture( + onWhat, + handlerBaseName, + ReactEvent.TopLevelCallbackCreator.createTopLevelCallback(topLevelType) + ); +} + +/** + * Listens to document scroll and window resize events that may change the + * document scroll values. We store those results so as to discourage + * application code from asking the DOM itself which could trigger additional + * reflows. + */ +function registerDocumentScrollListener() { + listen(window, 'scroll', function(nativeEvent) { + if (nativeEvent.target === window) { + BrowserEnv.refreshAuthoritativeScrollValues(); + } + }); +} + +function registerDocumentResizeListener() { + listen(window, 'resize', function(nativeEvent) { + if (nativeEvent.target === window) { + BrowserEnv.refreshAuthoritativeScrollValues(); + } + }); +} + +/** + * Summary of `ReactEvent` event handling: + * + * - We trap low level 'top-level' events. + * + * - We dedupe cross-browser event names into these 'top-level types' so that + * `DOMMouseScroll` or `mouseWheel` both become `topMouseWheel`. + * + * - At this point we have native browser events with the top-level type that + * was used to catch it at the top-level. + * + * - We continuously stream these native events (and their respective top-level + * types) to the event plugin system `EventPluginHub` and ask the plugin + * system if it was able to extract `AbstractEvent` objects. `AbstractEvent` + * objects are the events that applications actually deal with - they are not + * native browser events but cross-browser wrappers. + * + * - When returning the `AbstractEvent` objects, `EventPluginHub` will make + * sure each abstract event is annotated with "dispatches", which are the + * sequence of listeners (and IDs) that care about the event. + * + * - These `AbstractEvent` objects are fed back into the event plugin system, + * which in turn executes these dispatches. + * + * @private + */ +function listenAtTopLevel(touchNotMouse) { + invariant( + !_isListening, + 'listenAtTopLevel(...): Cannot setup top-level listener more than once.' + ); + var mountAt = document; + + registerDocumentScrollListener(); + registerDocumentResizeListener(); + trapBubbledEvent(topLevelTypes.topMouseOver, 'mouseover', mountAt); + trapBubbledEvent(topLevelTypes.topMouseDown, 'mousedown', mountAt); + trapBubbledEvent(topLevelTypes.topMouseUp, 'mouseup', mountAt); + trapBubbledEvent(topLevelTypes.topMouseMove, 'mousemove', mountAt); + trapBubbledEvent(topLevelTypes.topMouseOut, 'mouseout', mountAt); + trapBubbledEvent(topLevelTypes.topClick, 'click', mountAt); + trapBubbledEvent(topLevelTypes.topDoubleClick, 'dblclick', mountAt); + trapBubbledEvent(topLevelTypes.topMouseWheel, 'mousewheel', mountAt); + if (touchNotMouse) { + trapBubbledEvent(topLevelTypes.topTouchStart, 'touchstart', mountAt); + trapBubbledEvent(topLevelTypes.topTouchEnd, 'touchend', mountAt); + trapBubbledEvent(topLevelTypes.topTouchMove, 'touchmove', mountAt); + trapBubbledEvent(topLevelTypes.topTouchCancel, 'touchcancel', mountAt); + } + trapBubbledEvent(topLevelTypes.topKeyUp, 'keyup', mountAt); + trapBubbledEvent(topLevelTypes.topKeyPress, 'keypress', mountAt); + trapBubbledEvent(topLevelTypes.topKeyDown, 'keydown', mountAt); + trapBubbledEvent(topLevelTypes.topChange, 'change', mountAt); + trapBubbledEvent( + topLevelTypes.topDOMCharacterDataModified, + 'DOMCharacterDataModified', + mountAt + ); + + // Firefox needs to capture a different mouse scroll event. + // @see http://www.quirksmode.org/dom/events/tests/scroll.html + trapBubbledEvent(topLevelTypes.topMouseWheel, 'DOMMouseScroll', mountAt); + // IE < 9 doesn't support capturing so just trap the bubbled event there. + if (isEventSupported('scroll', true)) { + trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt); + } else { + trapBubbledEvent(topLevelTypes.topScroll, 'scroll', window); + } + + if (isEventSupported('focus', true)) { + trapCapturedEvent(topLevelTypes.topFocus, 'focus', mountAt); + trapCapturedEvent(topLevelTypes.topBlur, 'blur', mountAt); + } else if (isEventSupported('focusin')) { + // IE has `focusin` and `focusout` events which bubble. + // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html + trapBubbledEvent(topLevelTypes.topFocus, 'focusin', mountAt); + trapBubbledEvent(topLevelTypes.topBlur, 'focusout', mountAt); + } +} + +/** + * This is the heart of `ReactEvent`. It simply streams the top-level native + * events to `EventPluginHub`. + * + * @param {object} topLevelType Record from `EventConstants`. + * @param {Event} nativeEvent A Standard Event with fixed `target` property. + * @param {DOMElement} renderedTarget Element of interest to the framework. + * @param {string} renderedTargetID string ID of `renderedTarget`. + * @internal + */ +function handleTopLevel( + topLevelType, + nativeEvent, + renderedTargetID, + renderedTarget) { + var abstractEvents = EventPluginHub.extractAbstractEvents( + topLevelType, + nativeEvent, + renderedTargetID, + renderedTarget + ); + + // The event queue being processed in the same cycle allows preventDefault. + EventPluginHub.enqueueAbstractEvents(abstractEvents); + EventPluginHub.processAbstractEventQueue(); +} + +function setEnabled(enabled) { + invariant( + ExecutionEnvironment.canUseDOM, + 'setEnabled(...): Cannot toggle event listening in a Worker thread. This ' + + 'is likely a bug in the framework. Please report immediately.' + ); + ReactEvent.TopLevelCallbackCreator.setEnabled(enabled); +} + +function isEnabled() { + return ReactEvent.TopLevelCallbackCreator.isEnabled(); +} + +/** + * Ensures that top-level event delegation listeners are listening at `mountAt`. + * There are issues with listening to both touch events and mouse events on the + * top-level, so we make the caller choose which one to listen to. (If there's a + * touch top-level listeners, anchors don't receive clicks for some reason, and + * only in some cases). + * + * @param {boolean} touchNotMouse Listen to touch events instead of mouse. + * @param {object} TopLevelCallbackCreator Module that can create top-level + * callback handlers. + * @internal + */ +function ensureListening(touchNotMouse, TopLevelCallbackCreator) { + invariant( + ExecutionEnvironment.canUseDOM, + 'ensureListening(...): Cannot toggle event listening in a Worker thread. ' + + 'This is likely a bug in the framework. Please report immediately.' + ); + if (!_isListening) { + ReactEvent.TopLevelCallbackCreator = TopLevelCallbackCreator; + listenAtTopLevel(touchNotMouse); + _isListening = true; + } +} + +var ReactEvent = { + TopLevelCallbackCreator: null, // Injectable callback creator. + handleTopLevel: handleTopLevel, + setEnabled: setEnabled, + isEnabled: isEnabled, + ensureListening: ensureListening, + registrationNames: registrationNames, + putListener: EventPluginHub.putListener, + getListener: EventPluginHub.getListener, + deleteAllListeners: EventPluginHub.deleteAllListeners, + trapBubbledEvent: trapBubbledEvent, + trapCapturedEvent: trapCapturedEvent +}; + +module.exports = ReactEvent; + +},{"./BrowserEnv":46,"./EventConstants":47,"./EventPluginHub":27,"./ExecutionEnvironment":14,"./invariant":10,"./NormalizedEventListener":48,"./isEventSupported":49}],21:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactInstanceHandles + */ + +"use strict"; + +var getDOMNodeID = require("./getDOMNodeID"); +var invariant = require("./invariant"); + +var SEPARATOR = '.'; +var SEPARATOR_LENGTH = SEPARATOR.length; + +/** + * Maximum depth of traversals before we consider the possibility of a bad ID. + */ +var MAX_TREE_DEPTH = 100; + +/** + * Checks if a character in the supplied ID is a separator or the end. + * + * @param {string} id A React DOM ID. + * @param {number} index Index of the character to check. + * @return {boolean} True if the character is a separator or end of the ID. + * @private + */ +function isMarker(id, index) { + return id.charAt(index) === SEPARATOR || index === id.length; +} + +/** + * Checks if the supplied string is a valid React DOM ID. + * + * @param {string} id A React DOM ID, maybe. + * @return {boolean} True if the string is a valid React DOM ID. + * @private + */ +function isValidID(id) { + return id === '' || ( + id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR + ); +} + +/** + * True if the supplied `node` is rendered by React. + * + * @param {DOMElement} node DOM Element to check. + * @return {boolean} True if the DOM Element appears to be rendered by React. + * @private + */ +function isRenderedByReact(node) { + var id = getDOMNodeID(node); + return id && id.charAt(0) === SEPARATOR; +} + +/** + * Gets the parent ID of the supplied React DOM ID, `id`. + * + * @param {string} id ID of a component. + * @return {string} ID of the parent, or an empty string. + * @private + */ +function parentID(id) { + return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : ''; +} + +/** + * Traverses the parent path between two IDs (either up or down). The IDs must + * not be the same, and there must exist a parent path between them. + * + * @param {?string} start ID at which to start traversal. + * @param {?string} stop ID at which to end traversal. + * @param {function} cb Callback to invoke each ID with. + * @param {?boolean} skipFirst Whether or not to skip the first node. + * @param {?boolean} skipLast Whether or not to skip the last node. + * @private + */ +function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) { + start = start || ''; + stop = stop || ''; + invariant( + start !== stop, + 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.', + start + ); + var ancestorID = ReactInstanceHandles.getFirstCommonAncestorID(start, stop); + var traverseUp = ancestorID === stop; + invariant( + traverseUp || ancestorID === start, + 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' + + 'not have a parent path.', + start, + stop + ); + // Traverse from `start` to `stop` one depth at a time. + var depth = 0; + var traverse = traverseUp ? parentID : ReactInstanceHandles.nextDescendantID; + for (var id = start; /* until break */; id = traverse(id, stop)) { + if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) { + cb(id, traverseUp, arg); + } + if (id === stop) { + // Only break //after// visiting `stop`. + break; + } + invariant( + depth++ < MAX_TREE_DEPTH, + 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' + + 'traversing the React DOM ID tree. This may be due to malformed IDs: %s', + start, stop + ); + } +} + +/** + * Manages the IDs assigned to DOM representations of React components. This + * uses a specific scheme in order to traverse the DOM efficiently (e.g. in + * order to simulate events). + * + * @internal + */ +var ReactInstanceHandles = { + + separator: SEPARATOR, + + /** + * Traverses up the ancestors of the supplied node to find a node that is a + * DOM representation of a React component. + * + * @param {DOMElement} node + * @return {?DOMElement} + * @internal + */ + getFirstReactDOM: function(node) { + var current = node; + while (current && current.parentNode !== current) { + if (isRenderedByReact(current)) { + return current; + } + current = current.parentNode; + } + return null; + }, + + /** + * Finds a node with the supplied `id` inside of the supplied `ancestorNode`. + * Exploits the ID naming scheme to perform the search quickly. + * + * @param {DOMElement} ancestorNode Search from this root. + * @pararm {string} id ID of the DOM representation of the component. + * @return {?DOMElement} DOM element with the supplied `id`, if one exists. + * @internal + */ + findComponentRoot: function(ancestorNode, id) { + var child = ancestorNode.firstChild; + while (child) { + if (id === child.id) { + return child; + } else if (id.indexOf(child.id) === 0) { + return ReactInstanceHandles.findComponentRoot(child, id); + } + child = child.nextSibling; + } + // Effectively: return null; + }, + + /** + * Gets the nearest common ancestor ID of two IDs. + * + * Using this ID scheme, the nearest common ancestor ID is the longest common + * prefix of the two IDs that immediately preceded a "marker" in both strings. + * + * @param {string} oneID + * @param {string} twoID + * @return {string} Nearest common ancestor ID, or the empty string if none. + * @internal + */ + getFirstCommonAncestorID: function(oneID, twoID) { + var minLength = Math.min(oneID.length, twoID.length); + if (minLength === 0) { + return ''; + } + var lastCommonMarkerIndex = 0; + // Use `<=` to traverse until the "EOL" of the shorter string. + for (var i = 0; i <= minLength; i++) { + if (isMarker(oneID, i) && isMarker(twoID, i)) { + lastCommonMarkerIndex = i; + } else if (oneID.charAt(i) !== twoID.charAt(i)) { + break; + } + } + var longestCommonID = oneID.substr(0, lastCommonMarkerIndex); + invariant( + isValidID(longestCommonID), + 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s', + oneID, + twoID, + longestCommonID + ); + return longestCommonID; + }, + /** + * Creates a DOM ID to use when mounting React components. + * + * @param {number} mountPointCount The count of React renders so far. + * @return {string} React root ID. + * @internal + */ + getReactRootID: function(mountPointCount) { + return '.reactRoot[' + mountPointCount + ']'; + }, + + /** + * Gets the DOM ID of the React component that is the root of the tree that + * contains the React component with the supplied DOM ID. + * + * @param {string} id DOM ID of a React component. + * @return {string} DOM ID of the React component that is the root. + * @internal + */ + getReactRootIDFromNodeID: function(id) { + var regexResult = /\.reactRoot\[[^\]]+\]/.exec(id); + return regexResult && regexResult[0]; + }, + + /** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * NOTE: Does not invoke the callback on the nearest common ancestor because + * nothing "entered" or "left" that element. + * + * @param {string} leaveID ID being left. + * @param {string} enterID ID being entered. + * @param {function} cb Callback to invoke on each entered/left ID. + * @param {*} upArg Argument to invoke the callback with on left IDs. + * @param {*} downArg Argument to invoke the callback with on entered IDs. + * @internal + */ + traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) { + var longestCommonID = ReactInstanceHandles.getFirstCommonAncestorID( + leaveID, + enterID + ); + if (longestCommonID !== leaveID) { + traverseParentPath(leaveID, longestCommonID, cb, upArg, false, true); + } + if (longestCommonID !== enterID) { + traverseParentPath(longestCommonID, enterID, cb, downArg, true, false); + } + }, + + /** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + * + * NOTE: This traversal happens on IDs without touching the DOM. + * + * @param {string} targetID ID of the target node. + * @param {function} cb Callback to invoke. + * @param {*} arg Argument to invoke the callback with. + * @internal + */ + traverseTwoPhase: function(targetID, cb, arg) { + if (targetID) { + traverseParentPath('', targetID, cb, arg, true, false); + traverseParentPath(targetID, '', cb, arg, false, true); + } + }, + + /** + * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the + * supplied `destinationID`. If they are equal, the ID is returned. + * + * @param {string} ancestorID ID of an ancestor node of `destinationID`. + * @param {string} destinationID ID of the destination node. + * @return {string} Next ID on the path from `ancestorID` to `destinationID`. + * @internal + */ + nextDescendantID: function(ancestorID, destinationID) { + invariant( + isValidID(ancestorID) && isValidID(destinationID), + 'nextDescendantID(%s, %s): Received an invalid React DOM ID.', + ancestorID, + destinationID + ); + var longestCommonID = ReactInstanceHandles.getFirstCommonAncestorID( + ancestorID, + destinationID + ); + invariant( + longestCommonID === ancestorID, + 'nextDescendantID(...): React has made an invalid assumption about the ' + + 'DOM hierarchy. Expected `%s` to be an ancestor of `%s`.', + ancestorID, + destinationID + ); + if (ancestorID === destinationID) { + return ancestorID; + } + // Skip over the ancestor and the immediate separator. Traverse until we hit + // another separator or we reach the end of `destinationID`. + var start = ancestorID.length + SEPARATOR_LENGTH; + for (var i = start; i < destinationID.length; i++) { + if (isMarker(destinationID, i)) { + break; + } + } + return destinationID.substr(0, i); + } + +}; + +module.exports = ReactInstanceHandles; + +},{"./invariant":10,"./getDOMNodeID":50}],22:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactEventTopLevelCallback + */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var ReactEvent = require("./ReactEvent"); +var ReactInstanceHandles = require("./ReactInstanceHandles"); + +var getDOMNodeID = require("./getDOMNodeID"); + +var _topLevelListenersEnabled = true; + +var ReactEventTopLevelCallback = { + + /** + * @param {boolean} enabled Whether or not all callbacks that have ever been + * created with this module should be enabled. + */ + setEnabled: function(enabled) { + _topLevelListenersEnabled = !!enabled; + }, + + isEnabled: function() { + return _topLevelListenersEnabled; + }, + + /** + * For a given `topLevelType`, creates a callback that could be added as a + * listener to the document. That top level callback will simply fix the + * native events before invoking `handleTopLevel`. + * + * - Raw native events cannot be trusted to describe their targets correctly + * so we expect that the argument to the nested function has already been + * fixed. But the `target` property may not be something of interest to + * React, so we find the most suitable target. But even at that point, DOM + * Elements (the target ) can't be trusted to describe their IDs correctly + * so we obtain the ID in a reliable manner and pass it to + * `handleTopLevel`. The target/id that we found to be relevant to our + * framework are called `renderedTarget`/`renderedTargetID` respectively. + */ + createTopLevelCallback: function(topLevelType) { + return function(fixedNativeEvent) { + if (!_topLevelListenersEnabled) { + return; + } + var renderedTarget = ReactInstanceHandles.getFirstReactDOM( + fixedNativeEvent.target + ) || ExecutionEnvironment.global; + var renderedTargetID = getDOMNodeID(renderedTarget); + var event = fixedNativeEvent; + var target = renderedTarget; + ReactEvent.handleTopLevel(topLevelType, event, renderedTargetID, target); + }; + } + +}; + +module.exports = ReactEventTopLevelCallback; + +})() +},{"./ExecutionEnvironment":14,"./ReactEvent":20,"./ReactInstanceHandles":21,"./getDOMNodeID":50}],23:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule $ + */ + +var ge = require("./ge"); + +/** + * Find a node by ID. + * + * If your application code depends on the existence of the element, use $, + * which will throw if the element doesn't exist. + * + * If you're not sure whether or not the element exists, use ge instead, and + * manually check for the element's existence in your application code. + */ +function $(arg) { + var element = ge(arg); + if (!element) { + if (typeof arg == 'undefined') { + arg = 'undefined'; + } else if (arg === null) { + arg = 'null'; + } + throw new Error( + 'Tried to get element "' + arg.toString() + '" but it is not present ' + + 'on the page.' + ); + } + return element; +} + +module.exports = $; + +},{"./ge":51}],24:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMForm + */ + +"use strict"; + +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); +var ReactEvent = require("./ReactEvent"); +var EventConstants = require("./EventConstants"); + +// Store a reference to the `ReactNativeComponent`. +var form = ReactDOM.form; + +/** + * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need + * to capture it on the element itself. There are lots of hacks we could + * do to accomplish this, but the most reliable is to make a + * composite component and use `componentDidMount` to attach the event handlers. + */ +var ReactDOMForm = ReactCompositeComponent.createClass({ + render: function() { + // TODO: Instead of using `ReactDOM` directly, we should use JSX. However, + // `jshint` fails to parse JSX so in order for linting to work in the open + // source repo, we need to just use `ReactDOM.form`. + return this.transferPropsTo(form(null, this.props.children)); + }, + + componentDidMount: function(node) { + ReactEvent.trapBubbledEvent( + EventConstants.topLevelTypes.topSubmit, + 'submit', + node + ); + } +}); + +module.exports = ReactDOMForm; + +},{"./ReactCompositeComponent":2,"./ReactDOM":4,"./ReactEvent":20,"./EventConstants":47}],25:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DefaultEventPluginOrder + */ + +"use strict"; + + var keyOf = require("./keyOf"); + +/** + * Module that is injectable into `EventPluginHub`, that specifies a + * deterministic ordering of `EventPlugin`s. A convenient way to reason about + * plugins, without having to package every one of them. This is better than + * having plugins be ordered in the same order that they are injected because + * that ordering would be influenced by the packaging order. + * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that + * preventing default on events is convenient in `SimpleEventPlugin` handlers. + */ +var DefaultEventPluginOrder = [ + keyOf({ResponderEventPlugin: null}), + keyOf({SimpleEventPlugin: null}), + keyOf({TapEventPlugin: null}), + keyOf({EnterLeaveEventPlugin: null}), + keyOf({AnalyticsEventPlugin: null}) +]; + +module.exports = DefaultEventPluginOrder; + +},{"./keyOf":44}],26:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EnterLeaveEventPlugin + */ + +"use strict"; + +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var AbstractEvent = require("./AbstractEvent"); +var EventConstants = require("./EventConstants"); +var ReactInstanceHandles = require("./ReactInstanceHandles"); + +var getDOMNodeID = require("./getDOMNodeID"); +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; +var getFirstReactDOM = ReactInstanceHandles.getFirstReactDOM; + +var abstractEventTypes = { + mouseEnter: {registrationName: keyOf({onMouseEnter: null})}, + mouseLeave: {registrationName: keyOf({onMouseLeave: null})} +}; + +/** + * For almost every interaction we care about, there will be a top level + * `mouseOver` and `mouseOut` event that occur so we can usually only pay + * attention to one of the two (we'll pay attention to the `mouseOut` event) to + * avoid extracting a duplicate event. However, there's one interaction where + * there will be no `mouseOut` event to rely on - mousing from outside the + * browser *into* the chrome. We detect this scenario and only in that case, we + * use the `mouseOver` event. + * + * @see EventPluginHub.extractAbstractEvents + */ +var extractAbstractEvents = function( + topLevelType, + nativeEvent, + renderedTargetID, + renderedTarget) { + + if (topLevelType === topLevelTypes.topMouseOver && + (nativeEvent.relatedTarget || nativeEvent.fromElement)) { + return; + } + if (topLevelType !== topLevelTypes.topMouseOut && + topLevelType !== topLevelTypes.topMouseOver){ + return null; // Must not be a mouse in or mouse out - ignoring. + } + + var to, from; + if (topLevelType === topLevelTypes.topMouseOut) { + to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || + ExecutionEnvironment.global; + from = renderedTarget; + } else { + to = renderedTarget; + from = ExecutionEnvironment.global; + } + + // Nothing pertains to our managed components. + if (from === to ) { + return; + } + + var fromID = from ? getDOMNodeID(from) : ''; + var toID = to ? getDOMNodeID(to) : ''; + var leave = AbstractEvent.getPooled( + abstractEventTypes.mouseLeave, + fromID, + topLevelType, + nativeEvent + ); + var enter = AbstractEvent.getPooled( + abstractEventTypes.mouseEnter, + toID, + topLevelType, + nativeEvent + ); + EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); + return [leave, enter]; +}; + +var EnterLeaveEventPlugin = { + abstractEventTypes: abstractEventTypes, + extractAbstractEvents: extractAbstractEvents +}; + +module.exports = EnterLeaveEventPlugin; + +})() +},{"./EventPropagators":52,"./ExecutionEnvironment":14,"./AbstractEvent":53,"./EventConstants":47,"./ReactInstanceHandles":21,"./getDOMNodeID":50,"./keyOf":44}],27:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPluginHub + */ + +"use strict"; + +var AbstractEvent = require("./AbstractEvent"); +var CallbackRegistry = require("./CallbackRegistry"); +var EventPluginUtils = require("./EventPluginUtils"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); +var throwIf = require("./throwIf"); + +var deleteListener = CallbackRegistry.deleteListener; + +var ERRORS = keyMirror({ + DOUBLE_REGISTER: null, + DOUBLE_ENQUEUE: null, + DEPENDENCY_ERROR: null +}); + +if (true) { + ERRORS.DOUBLE_REGISTER = + 'You\'ve included an event plugin that extracts an ' + + 'event type with the exact same or identity as an event that ' + + 'had previously been injected - or, one of the registration names ' + + 'used by an plugin has already been used.'; + ERRORS.DOUBLE_ENQUEUE = + 'During the processing of events, more events were enqueued. This ' + + 'is strange and should not happen. Please report immediately. '; + ERRORS.DEPENDENCY_ERROR = + 'You have either attempted to load an event plugin that has no ' + + 'entry in EventPluginOrder, or have attempted to extract events ' + + 'when some critical dependencies have not yet been injected.'; +} + + +/** + * EventPluginHub: To see a diagram and explanation of the overall architecture + * of the plugin hub system, @see ReactEvents.js + */ + +/** + * Injected Dependencies: + */ +var injection = { + /** + * [required] Dependency of `EventPropagators`. + */ + injectInstanceHandle: function(InjectedInstanceHandle) { + EventPropagators.injection.injectInstanceHandle(InjectedInstanceHandle); + }, + + /** + * `EventPluginOrder`: [optional] Provides deterministic ordering of + * `EventPlugin`s. Ordering decoupled from the injection of actual + * plugins so that there is always a deterministic and permanent ordering + * regardless of the plugins that happen to become packaged, or applications + * that happen to inject on-the-fly event plugins. + */ + EventPluginOrder: null, + injectEventPluginOrder: function(InjectedEventPluginOrder) { + injection.EventPluginOrder = InjectedEventPluginOrder; + injection._recomputePluginsList(); + }, + + /** + * `EventPlugins`: [optional][lazy-loadable] Plugins that must be listed in + * the `EventPluginOrder` injected dependency. The list of plugins may grow as + * custom plugins are injected into the system at page as part of the + * initialization process, or even after the initialization process (on-the- + * fly). Plugins injected into the hub have an opportunity to infer abstract + * events when top level events are streamed through the `EventPluginHub`. + */ + plugins: [], + injectEventPluginsByName: function(pluginsByName) { + injection.pluginsByName = merge(injection.pluginsByName, pluginsByName); + injection._recomputePluginsList(); + }, + + /** + * A reference of all injected plugins by their name. Both plugins and + * `EventPluginOrder` can be injected on-the-fly. Any time either dependency + * is (re)injected, the resulting list of plugins in correct order is + * recomputed. + */ + pluginsByName: {}, + _recomputePluginsList: function() { + var injectPluginByName = function(name, PluginModule) { + var pluginIndex = injection.EventPluginOrder.indexOf(name); + throwIf(pluginIndex === -1, ERRORS.DEPENDENCY_ERROR + name); + if (!injection.plugins[pluginIndex]) { + injection.plugins[pluginIndex] = PluginModule; + for (var eventName in PluginModule.abstractEventTypes) { + var eventType = PluginModule.abstractEventTypes[eventName]; + recordAllRegistrationNames(eventType, PluginModule); + } + } + }; + if (injection.EventPluginOrder) { // Else, do when plugin order injected + var injectedPluginsByName = injection.pluginsByName; + for (var name in injectedPluginsByName) { + injectPluginByName(name, injectedPluginsByName[name]); + } + } + } +}; + + +/** + * `renderedTarget`: We'll refer to the concept of a "rendered target". Any + * framework code that uses the `EventPluginHub` will stream events to the + * `EventPluginHub`. In order for registered plugins to make sense of the native + * events, it helps to allow plugins to not only have access to the native + * `Event` object but also the notion of a "rendered target", which is the + * conceptual target `Element` of the `Event` that the framework (user of + * `EventPluginHub`) deems as being the "important" target. + */ +/** + * Keeps track of all valid "registration names" (`onClick` etc). We expose + * these structures to other modules, who will always see updates that we apply + * to these structures. They should never have a desire to mutate these. + */ +var registrationNames = {}; + +/** + * This prevents the need for clients to call `Object.keys(registrationNames)` + * every time they want to loop through the possible registration names. + */ +var registrationNamesArr = []; + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var abstractEventQueue = []; + +/** + * Records all the registration names that the event plugin makes available + * to the general event system. These are things like + * `onClick`/`onClickCapture`. + */ +function recordAllRegistrationNames(eventType, PluginModule) { + var phaseName; + var phasedRegistrationNames = eventType.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (phaseName in phasedRegistrationNames) { + if (!phasedRegistrationNames.hasOwnProperty(phaseName)) { + continue; + } + if (true) { + throwIf( + registrationNames[phasedRegistrationNames[phaseName]], + ERRORS.DOUBLE_REGISTER + ); + } + registrationNames[phasedRegistrationNames[phaseName]] = PluginModule; + registrationNamesArr.push(phasedRegistrationNames[phaseName]); + } + } else if (eventType.registrationName) { + if (true) { + throwIf( + registrationNames[eventType.registrationName], + ERRORS.DOUBLE_REGISTER + ); + } + registrationNames[eventType.registrationName] = PluginModule; + registrationNamesArr.push(eventType.registrationName); + } +} + +/** + * A hacky way to reverse engineer which event plugin module created an + * AbstractEvent. + * @param {AbstractEvent} abstractEvent to look at + */ +function getPluginModuleForAbstractEvent(abstractEvent) { + if (abstractEvent.type.registrationName) { + return registrationNames[abstractEvent.type.registrationName]; + } else { + for (var phase in abstractEvent.type.phasedRegistrationNames) { + if (!abstractEvent.type.phasedRegistrationNames.hasOwnProperty(phase)) { + continue; + } + var PluginModule = registrationNames[ + abstractEvent.type.phasedRegistrationNames[phase] + ]; + if (PluginModule) { + return PluginModule; + } + } + } + return null; +} + +var deleteAllListeners = function(domID) { + var ii; + for (ii = 0; ii < registrationNamesArr.length; ii++) { + deleteListener(domID, registrationNamesArr[ii]); + } +}; + +/** + * Accepts the stream of top level native events, and gives every registered + * plugin an opportunity to extract `AbstractEvent`s with annotated dispatches. + * + * @param {Enum} topLevelType Record from `EventConstants`. + * @param {Event} nativeEvent A Standard Event with fixed `target` property. + * @param {Element} renderedTarget Element of interest to the framework, usually + * the same as `nativeEvent.target` but occasionally an element immediately + * above `nativeEvent.target` (the first DOM node recognized as one "rendered" + * by the framework at hand.) + * @param {string} renderedTargetID string ID of `renderedTarget`. + */ +var extractAbstractEvents = + function(topLevelType, nativeEvent, renderedTargetID, renderedTarget) { + var abstractEvents; + var plugins = injection.plugins; + var len = plugins.length; + for (var i = 0; i < len; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + var extractedAbstractEvents = + possiblePlugin && + possiblePlugin.extractAbstractEvents( + topLevelType, + nativeEvent, + renderedTargetID, + renderedTarget + ); + if (extractedAbstractEvents) { + abstractEvents = accumulate(abstractEvents, extractedAbstractEvents); + } + } + return abstractEvents; + }; + +var enqueueAbstractEvents = function(abstractEvents) { + if (abstractEvents) { + abstractEventQueue = accumulate(abstractEventQueue, abstractEvents); + } +}; + +/** + * Executes a single abstract event dispatch. Returns a value, but this return + * value doesn't make much sense when executing dispatches for a list of a + * events. However, if a plugin executes a single dispatch, mostly bypassing + * `EventPluginHub`, it can execute dispatches directly and assign special + * meaning to the return value. So this will return the result of executing the + * dispatch, though for most use cases, it gets dropped. + */ +var executeDispatchesAndRelease = function(abstractEvent) { + if (abstractEvent) { + var PluginModule = getPluginModuleForAbstractEvent(abstractEvent); + var pluginExecuteDispatch = PluginModule && PluginModule.executeDispatch; + EventPluginUtils.executeDispatchesInOrder( + abstractEvent, + pluginExecuteDispatch || EventPluginUtils.executeDispatch + ); + AbstractEvent.release(abstractEvent); + } +}; + +/** + * Sets `abstractEventQueue` to null before processing it, so that we can tell + * if in the process of processing events, more were enqueued. We throw if we + * find that any were enqueued though this use case could be supported in the + * future. For now, throwing an error as it's something we don't expect to + * occur. + */ +var processAbstractEventQueue = function() { + var processingAbstractEventQueue = abstractEventQueue; + abstractEventQueue = null; + forEachAccumulated(processingAbstractEventQueue, executeDispatchesAndRelease); + if (true) { + throwIf(abstractEventQueue, ERRORS.DOUBLE_ENQUEUE); + } +}; + +/** + * Provides a unified interface for an arbitrary and dynamic set of event + * plugins. Loosely, a hub, where several "event plugins" may act as a single + * event plugin behind the facade of `EventPluginHub`. Each event plugin injects + * themselves into the HUB, and will immediately become operable upon injection. + * + * @constructor EventPluginHub + */ +var EventPluginHub = { + registrationNames: registrationNames, + registrationNamesArr: registrationNamesArr, + putListener: CallbackRegistry.putListener, + getListener: CallbackRegistry.getListener, + deleteAllListeners: deleteAllListeners, + extractAbstractEvents: extractAbstractEvents, + enqueueAbstractEvents: enqueueAbstractEvents, + processAbstractEventQueue: processAbstractEventQueue, + injection: injection +}; + + +if (ExecutionEnvironment.canUseDOM) { + window.EventPluginHub = EventPluginHub; +} + +module.exports = EventPluginHub; + +})() +},{"./AbstractEvent":53,"./CallbackRegistry":54,"./EventPluginUtils":55,"./EventPropagators":52,"./ExecutionEnvironment":14,"./accumulate":56,"./forEachAccumulated":57,"./keyMirror":11,"./throwIf":31,"./merge":12}],28:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule SimpleEventPlugin + */ + +"use strict"; + +var AbstractEvent = require("./AbstractEvent"); +var EventConstants = require("./EventConstants"); +var EventPropagators = require("./EventPropagators"); + +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; + +var SimpleEventPlugin = { + abstractEventTypes: { + // Note: We do not allow listening to mouseOver events. Instead, use the + // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`. + mouseDown: { + phasedRegistrationNames: { + bubbled: keyOf({onMouseDown: true}), + captured: keyOf({onMouseDownCapture: true}) + } + }, + mouseUp: { + phasedRegistrationNames: { + bubbled: keyOf({onMouseUp: true}), + captured: keyOf({onMouseUpCapture: true}) + } + }, + mouseMove: { + phasedRegistrationNames: { + bubbled: keyOf({onMouseMove: true}), + captured: keyOf({onMouseMoveCapture: true}) + } + }, + doubleClick: { + phasedRegistrationNames: { + bubbled: keyOf({onDoubleClick: true}), + captured: keyOf({onDoubleClickCapture: true}) + } + }, + click: { + phasedRegistrationNames: { + bubbled: keyOf({onClick: true}), + captured: keyOf({onClickCapture: true}) + } + }, + mouseWheel: { + phasedRegistrationNames: { + bubbled: keyOf({onMouseWheel: true}), + captured: keyOf({onMouseWheelCapture: true}) + } + }, + touchStart: { + phasedRegistrationNames: { + bubbled: keyOf({onTouchStart: true}), + captured: keyOf({onTouchStartCapture: true}) + } + }, + touchEnd: { + phasedRegistrationNames: { + bubbled: keyOf({onTouchEnd: true}), + captured: keyOf({onTouchEndCapture: true}) + } + }, + touchCancel: { + phasedRegistrationNames: { + bubbled: keyOf({onTouchCancel: true}), + captured: keyOf({onTouchCancelCapture: true}) + } + }, + touchMove: { + phasedRegistrationNames: { + bubbled: keyOf({onTouchMove: true}), + captured: keyOf({onTouchMoveCapture: true}) + } + }, + keyUp: { + phasedRegistrationNames: { + bubbled: keyOf({onKeyUp: true}), + captured: keyOf({onKeyUpCapture: true}) + } + }, + keyPress: { + phasedRegistrationNames: { + bubbled: keyOf({onKeyPress: true}), + captured: keyOf({onKeyPressCapture: true}) + } + }, + keyDown: { + phasedRegistrationNames: { + bubbled: keyOf({onKeyDown: true}), + captured: keyOf({onKeyDownCapture: true}) + } + }, + focus: { + phasedRegistrationNames: { + bubbled: keyOf({onFocus: true}), + captured: keyOf({onFocusCapture: true}) + } + }, + blur: { + phasedRegistrationNames: { + bubbled: keyOf({onBlur: true}), + captured: keyOf({onBlurCapture: true}) + } + }, + scroll: { + phasedRegistrationNames: { + bubbled: keyOf({onScroll: true}), + captured: keyOf({onScrollCapture: true}) + } + }, + change: { + phasedRegistrationNames: { + bubbled: keyOf({onChange: true}), + captured: keyOf({onChangeCapture: true}) + } + }, + submit: { + phasedRegistrationNames: { + bubbled: keyOf({onSubmit: true}), + captured: keyOf({onSubmitCapture: true}) + } + }, + DOMCharacterDataModified: { + phasedRegistrationNames: { + bubbled: keyOf({onDOMCharacterDataModified: true}), + captured: keyOf({onDOMCharacterDataModifiedCapture: true}) + } + } + }, + + /** + * Same as the default implementation, except cancels the event when return + * value is false. + * @param {AbstractEvent} AbstractEvent to handle + * @param {function} Application-level callback + * @param {string} domID DOM id to pass to the callback. + */ + executeDispatch: function(abstractEvent, listener, domID) { + var returnValue = listener(abstractEvent, domID); + if (returnValue === false) { + abstractEvent.stopPropagation(); + abstractEvent.preventDefault(); + } + }, + + /** + * @see EventPluginHub.extractAbstractEvents + */ + extractAbstractEvents: + function(topLevelType, nativeEvent, renderedTargetID, renderedTarget) { + var data; + var abstractEventType = + SimpleEventPlugin.topLevelTypesToAbstract[topLevelType]; + if (!abstractEventType) { + return null; + } + switch(topLevelType) { + case topLevelTypes.topMouseWheel: + data = AbstractEvent.normalizeMouseWheelData(nativeEvent); + break; + case topLevelTypes.topScroll: + data = AbstractEvent.normalizeScrollDataFromTarget(renderedTarget); + break; + case topLevelTypes.topClick: + case topLevelTypes.topDoubleClick: + case topLevelTypes.topChange: + case topLevelTypes.topDOMCharacterDataModified: + case topLevelTypes.topMouseDown: + case topLevelTypes.topMouseUp: + case topLevelTypes.topMouseMove: + case topLevelTypes.topTouchMove: + case topLevelTypes.topTouchStart: + case topLevelTypes.topTouchEnd: + data = AbstractEvent.normalizePointerData(nativeEvent); + break; + default: + data = null; + } + var abstractEvent = AbstractEvent.getPooled( + abstractEventType, + renderedTargetID, + topLevelType, + nativeEvent, + data + ); + EventPropagators.accumulateTwoPhaseDispatches(abstractEvent); + return abstractEvent; + } +}; + +SimpleEventPlugin.topLevelTypesToAbstract = { + topMouseDown: SimpleEventPlugin.abstractEventTypes.mouseDown, + topMouseUp: SimpleEventPlugin.abstractEventTypes.mouseUp, + topMouseMove: SimpleEventPlugin.abstractEventTypes.mouseMove, + topClick: SimpleEventPlugin.abstractEventTypes.click, + topDoubleClick: SimpleEventPlugin.abstractEventTypes.doubleClick, + topMouseWheel: SimpleEventPlugin.abstractEventTypes.mouseWheel, + topTouchStart: SimpleEventPlugin.abstractEventTypes.touchStart, + topTouchEnd: SimpleEventPlugin.abstractEventTypes.touchEnd, + topTouchMove: SimpleEventPlugin.abstractEventTypes.touchMove, + topTouchCancel: SimpleEventPlugin.abstractEventTypes.touchCancel, + topKeyUp: SimpleEventPlugin.abstractEventTypes.keyUp, + topKeyPress: SimpleEventPlugin.abstractEventTypes.keyPress, + topKeyDown: SimpleEventPlugin.abstractEventTypes.keyDown, + topFocus: SimpleEventPlugin.abstractEventTypes.focus, + topBlur: SimpleEventPlugin.abstractEventTypes.blur, + topScroll: SimpleEventPlugin.abstractEventTypes.scroll, + topChange: SimpleEventPlugin.abstractEventTypes.change, + topSubmit: SimpleEventPlugin.abstractEventTypes.submit, + topDOMCharacterDataModified: + SimpleEventPlugin.abstractEventTypes.DOMCharacterDataModified +}; + +module.exports = SimpleEventPlugin; + +},{"./AbstractEvent":53,"./EventConstants":47,"./EventPropagators":52,"./keyOf":44}],30:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule joinClasses + * @typechecks + */ + +"use strict"; + +/** + * Combines multiple className strings into one. + * http://jsperf.com/joinclasses-args-vs-array + * + * @param {...?string} classes + * @return {string} + */ +function joinClasses(className/*, ... */) { + if (!className) { + className = ''; + } + var nextClass; + var argLength = arguments.length; + if (argLength > 1) { + for (var ii = 1; ii < argLength; ii++) { + nextClass = arguments[ii]; + nextClass && (className += ' ' + nextClass); + } + } + return className; +} + +module.exports = joinClasses; + +},{}],31:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule throwIf + */ + +"use strict"; + +var throwIf = function(condition, err) { + if (condition) { + throw new Error(err); + } +}; + +module.exports = throwIf; + +},{}],37:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule PooledClass + */ + +"use strict"; + +/** + * Static poolers. Several custom versions for each potential number of + * arguments. A completely generic pooler is easy to implement, but would + * require accessing the `arguments` object. In each of these, `this` refers to + * the Class itself, not an instance. If any others are needed, simply add them + * here, or in their own files. + */ +var oneArgumentPooler = function(copyFieldsFrom) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, copyFieldsFrom); + return instance; + } else { + return new Klass(copyFieldsFrom); + } +}; + +var twoArgumentPooler = function(a1, a2) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2); + return instance; + } else { + return new Klass(a1, a2); + } +}; + +var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4, a5); + return instance; + } else { + return new Klass(a1, a2, a3, a4, a5); + } +}; + +var standardReleaser = function(instance) { + var Klass = this; + if (instance.destructor) { + instance.destructor(); + } + if (Klass.instancePool.length < Klass.poolSize) { + Klass.instancePool.push(instance); + } +}; + +var DEFAULT_POOL_SIZE = 10; +var DEFAULT_POOLER = oneArgumentPooler; + +/** + * Augments `CopyConstructor` to be a poolable class, augmenting only the class + * itself (statically) not adding any prototypical fields. Any CopyConstructor + * you give this may have a `poolSize` property, and will look for a + * prototypical `destructor` on instances (optional). + * + * @param {Function} CopyConstructor Constructor that can be used to reset. + * @param {Function} pooler Customizable pooler. + */ +var addPoolingTo = function(CopyConstructor, pooler) { + var NewKlass = CopyConstructor; + NewKlass.instancePool = []; + NewKlass.getPooled = pooler || DEFAULT_POOLER; + if (!NewKlass.poolSize) { + NewKlass.poolSize = DEFAULT_POOL_SIZE; + } + NewKlass.release = standardReleaser; + return NewKlass; +}; + +var PooledClass = { + addPoolingTo: addPoolingTo, + oneArgumentPooler: oneArgumentPooler, + twoArgumentPooler: twoArgumentPooler, + fiveArgumentPooler: fiveArgumentPooler +}; + +module.exports = PooledClass; + +},{}],38:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactInputSelection + */ + +"use strict"; + +// It is not safe to read the document.activeElement property in IE if there's +// nothing focused. +function getActiveElement() { + try { + return document.activeElement; + } catch (e) { + } +} + +/** + * @ReactInputSelection: React input selection module. Based on Selection.js, + * but modified to be suitable for react and has a couple of bug fixes (doesn't + * assume buttons have range selections allowed). + * Input selection module for React. + */ +var ReactInputSelection = { + + hasSelectionCapabilities: function(elem) { + return elem && ( + (elem.nodeName === 'INPUT' && elem.type === 'text') || + elem.nodeName === 'TEXTAREA' || + elem.contentEditable === 'true' + ); + }, + + getSelectionInformation: function() { + var focusedElem = getActiveElement(); + return { + focusedElem: focusedElem, + selectionRange: + ReactInputSelection.hasSelectionCapabilities(focusedElem) ? + ReactInputSelection.getSelection(focusedElem) : + null + }; + }, + + /** + * @restoreSelection: If any selection information was potentially lost, + * restore it. This is useful when performing operations that could remove dom + * nodes and place them back in, resulting in focus being lost. + */ + restoreSelection: function(priorSelectionInformation) { + var curFocusedElem = getActiveElement(); + var priorFocusedElem = priorSelectionInformation.focusedElem; + var priorSelectionRange = priorSelectionInformation.selectionRange; + if (curFocusedElem !== priorFocusedElem && + document.getElementById(priorFocusedElem.id)) { + if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) { + ReactInputSelection.setSelection( + priorFocusedElem, + priorSelectionRange + ); + } + priorFocusedElem.focus(); + } + }, + + /** + * @getSelection: Gets the selection bounds of a textarea or input. + * -@input: Look up selection bounds of this input or textarea + * -@return {start: selectionStart, end: selectionEnd} + */ + getSelection: function(input) { + var range; + if (input.contentEditable === 'true' && window.getSelection) { + range = window.getSelection().getRangeAt(0); + var commonAncestor = range.commonAncestorContainer; + if (commonAncestor && commonAncestor.nodeType === 3) { + commonAncestor = commonAncestor.parentNode; + } + if (commonAncestor !== input) { + return {start: 0, end: 0}; + } else { + return {start: range.startOffset, end: range.endOffset}; + } + } + + if (!document.selection) { + // Mozilla, Safari, etc. + return {start: input.selectionStart, end: input.selectionEnd}; + } + + range = document.selection.createRange(); + if (range.parentElement() !== input) { + // There can only be one selection per document in IE, so if the + // containing element of the document's selection isn't our text field, + // our text field must have no selection. + return {start: 0, end: 0}; + } + + var length = input.value.length; + + if (input.nodeName === 'INPUT') { + return { + start: -range.moveStart('character', -length), + end: -range.moveEnd('character', -length) + }; + } else { + var range2 = range.duplicate(); + range2.moveToElementText(input); + range2.setEndPoint('StartToEnd', range); + var end = length - range2.text.length; + range2.setEndPoint('StartToStart', range); + return { + start: length - range2.text.length, + end: end + }; + } + }, + + /** + * @setSelection: Sets the selection bounds of a textarea or input and focuses + * the input. + * -@input Set selection bounds of this input or textarea + * -@rangeObj Object of same form that is returned from get* + */ + setSelection: function(input, rangeObj) { + var range; + var start = rangeObj.start; + var end = rangeObj.end; + if (typeof end === 'undefined') { + end = start; + } + if (document.selection) { + // IE is inconsistent about character offsets when it comes to carriage + // returns, so we need to manually take them into account + if (input.tagName === 'TEXTAREA') { + var cr_before = + (input.value.slice(0, start).match(/\r/g) || []).length; + var cr_inside = + (input.value.slice(start, end).match(/\r/g) || []).length; + start -= cr_before; + end -= cr_before + cr_inside; + } + range = input.createTextRange(); + range.collapse(true); + range.moveStart('character', start); + range.moveEnd('character', end - start); + range.select(); + } else { + if (input.contentEditable === 'true') { + if (input.childNodes.length === 1) { + range = document.createRange(); + range.setStart(input.childNodes[0], start); + range.setEnd(input.childNodes[0], end); + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } + } else { + input.selectionStart = start; + input.selectionEnd = Math.min(end, input.value.length); + input.focus(); + } + } + } + +}; + +module.exports = ReactInputSelection; + +},{}],44:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule keyOf + */ + +/** + * Allows extraction of a minified key. Let's the build system minify keys + * without loosing the ability to dynamically use key strings as values + * themselves. Pass in an object with a single key/val pair and it will return + * you the string key of that single record. Suppose you want to grab the + * value for a key 'className' inside of an object. Key/val minification may + * have aliased that key to be 'xa12'. keyOf({className: null}) will return + * 'xa12' in that case. Resolve keys you want to use once at startup time, then + * reuse those resolutions. + */ +var keyOf = function(oneKeyObj) { + var key; + for (key in oneKeyObj) { + if (!oneKeyObj.hasOwnProperty(key)) { + continue; + } + return key; + } + return null; +}; + + +module.exports = keyOf; + +},{}],46:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule BrowserEnv + */ + +"use strict"; + +/** + * A place to share/cache browser/chrome level computations. + */ +var BrowserEnv = { + currentScrollLeft: 0, + currentScrollTop: 0, + browserInfo: null, + refreshAuthoritativeScrollValues: function() { + BrowserEnv.currentScrollLeft = + document.body.scrollLeft + document.documentElement.scrollLeft; + BrowserEnv.currentScrollTop = + document.body.scrollTop + document.documentElement.scrollTop; + } +}; + +module.exports = BrowserEnv; + +},{}],50:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule getDOMNodeID + */ + +"use strict"; + +/** + * Accessing "id" or calling getAttribute('id') on a form element can return its + * control whose name or ID is "id". However, not all DOM nodes support + * `getAttributeNode` (document - which is not a form) so that is checked first. + * + * @param {Element} domNode DOM node element to return ID of. + * @returns {string} The ID of `domNode`. + */ +function getDOMNodeID(domNode) { + if (domNode.getAttributeNode) { + var attributeNode = domNode.getAttributeNode('id'); + return attributeNode && attributeNode.value || ''; + } else { + return domNode.id || ''; + } +} + +module.exports = getDOMNodeID; + +},{}],51:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ge + */ + +/** + * Find a node by ID. Optionally search a sub-tree outside of the document + * + * Use ge if you're not sure whether or not the element exists. You can test + * for existence yourself in your application code. + * + * If your application code depends on the existence of the element, use $ + * instead, which will throw in DEV if the element doesn't exist. + */ +function ge(arg, root, tag) { + return typeof arg != 'string' ? arg : + !root ? document.getElementById(arg) : + _geFromSubtree(arg, root, tag); +} + +function _geFromSubtree(id, root, tag) { + var elem, children, ii; + + if (_getNodeID(root) == id) { + return root; + } else if (root.getElementsByTagName) { + // All Elements implement this, which does an iterative DFS, which is + // faster than recursion and doesn't run into stack depth issues. + children = root.getElementsByTagName(tag || '*'); + for (ii = 0; ii < children.length; ii++) { + if (_getNodeID(children[ii]) == id) { + return children[ii]; + } + } + } else { + // DocumentFragment does not implement getElementsByTagName, so + // recurse over its children. Its children must be Elements, so + // each child will use the getElementsByTagName case instead. + children = root.childNodes; + for (ii = 0; ii < children.length; ii++) { + elem = _geFromSubtree(id, children[ii]); + if (elem) { + return elem; + } + } + } + + return null; +} + +/** + * Return the ID value for a given node. This allows us to avoid issues + * with forms that contain inputs with name="id". + * + * @return string (null if attribute not set) + */ +function _getNodeID(node) { + // #document and #document-fragment do not have getAttributeNode. + var id = node.getAttributeNode && node.getAttributeNode('id'); + return id ? id.value : null; +} + +module.exports = ge; + +},{}],54:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CallbackRegistry + */ + +"use strict"; + +var listenerBank = {}; + +/** + * Stores "listeners" by `registrationName`/`id`. There should be at most one + * "listener" per `registrationName/id` in the `listenerBank`. + * Access listeners via `listenerBank[registrationName][id]` + * + * @constructor CallbackRegistry + */ +var CallbackRegistry = { + + /** + * Stores `listener` at `listenerBank[registrationName][id]. Is idempotent. + * @param {string} domID The id of the DOM node. + * @param {string} registrationName The name of listener (`onClick` etc). + * @param {Function} listener The callback to to store. + */ + putListener: function(id, registrationName, listener) { + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, + + /** + * @param {string} id. + * @param {string} registrationName Name of registration (`onClick` etc). + * @return {Function?} The Listener + */ + getListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + return bankForRegistrationName && bankForRegistrationName[id]; + }, + + /** + * Deletes the listener from the registration bank. + * @param {string} id + * @param {string} registrationName (`onClick` etc). + */ + deleteListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + if (bankForRegistrationName) { + delete bankForRegistrationName[id]; + } + }, + + // This is needed for tests only. Do not use in real life + __purge: function() { + listenerBank = {}; + } +}; + +module.exports = CallbackRegistry; + +},{}],57:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule forEachAccumulated + */ + +"use strict"; + +/** + * @param {array} an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + */ +var forEachAccumulated = function(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +}; + +module.exports = forEachAccumulated; + +},{}],29:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule emptyFunction + */ + +var copyProperties = require("./copyProperties"); + +function makeEmptyFunction(arg) { + return function() { + return arg; + }; +} + +/** + * This function accepts and discards inputs; it has no side effects. This is + * primarily useful idiomatically for overridable function endpoints which + * always need to be callable, since JS lacks a null-call idiom ala Cocoa. + */ +function emptyFunction() {} + +copyProperties(emptyFunction, { + thatReturns: makeEmptyFunction, + thatReturnsFalse: makeEmptyFunction(false), + thatReturnsTrue: makeEmptyFunction(true), + thatReturnsNull: makeEmptyFunction(null), + thatReturnsThis: function() { return this; }, + thatReturnsArgument: function(arg) { return arg; }, + mustImplement: function(module, property) { + return function() { + if (true) { + throw new Error(module + '.' + property + ' must be implemented!'); + } + }; + } +}); + +module.exports = emptyFunction; + +},{"./copyProperties":58}],32:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CSSPropertyOperations + * @typechecks + */ + +"use strict"; + +var dangerousStyleValue = require("./dangerousStyleValue"); +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var hyphenate = require("./hyphenate"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +var processStyleName = memoizeStringOnly(function(styleName) { + return escapeTextForBrowser(hyphenate(styleName)); +}); + +/** + * Operations for dealing with CSS properties. + */ +var CSSPropertyOperations = { + + /** + * Serializes a mapping of style properties for use as inline styles: + * + * > createMarkupForStyles({width: '200px', height: 0}) + * "width:200px;height:0;" + * + * Undefined values are ignored so that declarative programming is easier. + * + * @param {object} styles + * @return {string} + */ + createMarkupForStyles: function(styles) { + var serialized = ''; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + if (typeof styleValue !== 'undefined') { + serialized += processStyleName(styleName) + ':'; + serialized += dangerousStyleValue(styleName, styleValue) + ';'; + } + } + return serialized; + }, + + /** + * Sets the value for multiple styles on a node. + * + * @param {DOMElement} node + * @param {object} styles + */ + setValueForStyles: function(node, styles) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + style[styleName] = dangerousStyleValue(styleName, styleValue); + } + } + +}; + +module.exports = CSSPropertyOperations; + +},{"./dangerousStyleValue":59,"./escapeTextForBrowser":42,"./hyphenate":60,"./memoizeStringOnly":61}],33:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMChildrenOperations + */ + +"use strict"; + +var Danger = require("./Danger"); + +var insertNodeAt = require("./insertNodeAt"); +var keyOf = require("./keyOf"); +var throwIf = require("./throwIf"); + +var NON_INCREASING_OPERATIONS; +if (true) { + NON_INCREASING_OPERATIONS = + 'DOM child management operations must be provided in order ' + + 'of increasing destination index. This is likely an issue with ' + + 'the core framework.'; +} + +var MOVE_NODE_AT_ORIG_INDEX = keyOf({moveFrom: null}); +var INSERT_MARKUP = keyOf({insertMarkup: null}); +var REMOVE_AT = keyOf({removeAt: null}); + +/** + * In order to carry out movement of DOM nodes without knowing their IDs, we + * have to first store knowledge about nodes' original indices before beginning + * to carry out the sequence of operations. Once we begin the sequence, the DOM + * indices in future instructions are no longer valid. + * + * @param {Element} parent Parent DOM node. + * @param {Object} childOperations Description of child operations. + * @returns {Array?} Sparse array containing elements by their current index in + * the DOM. + */ +var _getNodesByOriginalIndex = function(parent, childOperations) { + var nodesByOriginalIndex; // Sparse array. + var childOperation; + var origIndex; + for (var i = 0; i < childOperations.length; i++) { + childOperation = childOperations[i]; + if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { + nodesByOriginalIndex = nodesByOriginalIndex || []; + origIndex = childOperation.moveFrom; + nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; + } else if (REMOVE_AT in childOperation) { + nodesByOriginalIndex = nodesByOriginalIndex || []; + origIndex = childOperation.removeAt; + nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; + } + } + return nodesByOriginalIndex; +}; + +/** + * Removes DOM elements from their parent, or moved. + * @param {Element} parent Parent DOM node. + * @param {Array} nodesByOriginalIndex Child nodes by their original index + * (potentially sparse.) + */ +var _removeChildrenByOriginalIndex = function(parent, nodesByOriginalIndex) { + for (var j = 0; j < nodesByOriginalIndex.length; j++) { + var nodeToRemove = nodesByOriginalIndex[j]; + if (nodeToRemove) { // We used a sparse array. + parent.removeChild(nodesByOriginalIndex[j]); + } + } +}; + +/** + * Once all nodes that will be removed or moved - are removed from the parent + * node, we can begin the process of placing nodes into their final locations. + * We must perform all operations in the order of the final DOM index - + * otherwise, we couldn't count on the fact that an insertion at index X, will + * remain at index X. This will iterate through the child operations, adding + * content where needed, skip over removals (they've already been removed) and + * insert "moved" Elements that were previously removed. The "moved" elements + * are only temporarily removed from the parent, so that index calculations can + * be manageable and perform well in the cases that matter. + */ +var _placeNodesAtDestination = + function(parent, childOperations, nodesByOriginalIndex) { + var origNode; + var finalIndex; + var lastFinalIndex = -1; + var childOperation; + for (var k = 0; k < childOperations.length; k++) { + childOperation = childOperations[k]; + if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { + origNode = nodesByOriginalIndex[childOperation.moveFrom]; + finalIndex = childOperation.finalIndex; + insertNodeAt(parent, origNode, finalIndex); + if (true) { + throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); + lastFinalIndex = finalIndex; + } + } else if (REMOVE_AT in childOperation) { + } else if (INSERT_MARKUP in childOperation) { + finalIndex = childOperation.finalIndex; + var markup = childOperation.insertMarkup; + Danger.dangerouslyInsertMarkupAt(parent, markup, finalIndex); + if (true) { + throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); + lastFinalIndex = finalIndex; + } + } + } + }; + +var manageChildren = function(parent, childOperations) { + var nodesByOriginalIndex = _getNodesByOriginalIndex(parent, childOperations); + if (nodesByOriginalIndex) { + _removeChildrenByOriginalIndex(parent, nodesByOriginalIndex); + } + _placeNodesAtDestination(parent, childOperations, nodesByOriginalIndex); +}; + +var setTextNodeValueAtIndex = function(parent, index, val) { + parent.childNodes[index].nodeValue = val; +}; + +/** + * Also reexport all of the dangerous functions. It helps to have all dangerous + * functions located in a single module `Danger`. + */ +var DOMChildrenOperations = { + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + manageChildren: manageChildren, + setTextNodeValueAtIndex: setTextNodeValueAtIndex +}; + +module.exports = DOMChildrenOperations; + +})() +},{"./Danger":62,"./insertNodeAt":63,"./keyOf":44,"./throwIf":31}],34:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMPropertyOperations + * @typechecks + */ + +"use strict"; + +var DOMProperty = require("./DOMProperty"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { + return escapeTextForBrowser(name) + '="'; +}); + +/** + * Operations for dealing with DOM properties. + */ +var DOMPropertyOperations = { + + /** + * Creates markup for a property. + * + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. + */ + createMarkupForProperty: function(name, value) { + if (DOMProperty.isStandardName[name]) { + if (value == null || DOMProperty.hasBooleanValue[name] && !value) { + return ''; + } + var attributeName = DOMProperty.getAttributeName[name]; + return processAttributeNameAndPrefix(attributeName) + + escapeTextForBrowser(value) + '"'; + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + return ''; + } + return processAttributeNameAndPrefix(name) + + escapeTextForBrowser(value) + '"'; + } else { + return null; + } + }, + + /** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ + setValueForProperty: function(node, name, value) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, value); + } else if (DOMProperty.mustUseAttribute[name]) { + if (DOMProperty.hasBooleanValue[name] && !value) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + node.setAttribute(DOMProperty.getAttributeName[name], value); + } + } else { + var propName = DOMProperty.getPropertyName[name]; + if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) { + node[propName] = value; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.setAttribute(name, value); + } + } + +}; + +module.exports = DOMPropertyOperations; + +},{"./DOMProperty":64,"./escapeTextForBrowser":42,"./memoizeStringOnly":61}],35:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMNodeCache + */ + +"use strict"; + +var ReactMount = require("./ReactMount"); + +var nodeCache = {}; + +/** + * DOM node cache only intended for use by React. Placed into a shared module so + * that both read and write utilities may benefit from a shared cache. + */ +var ReactDOMNodeCache = { + /** + * Releases fast id lookups (node/style cache). This implementation is + * aggressive with purging because the bookkeeping associated with doing fine + * grained deleted from the cache may outweight the benefits of the cache. The + * heuristic that should be used to purge is 'any time anything is deleted'. + * Typically this means that a large amount of content is being replaced and + * several elements would need purging regardless. It's also a time when an + * application is likely not in the middle of a "smooth operation" (such as + * animating/scrolling). + */ + purgeEntireCache: function() { + nodeCache = {}; + return nodeCache; + }, + getCachedNodeByID: function(id) { + return nodeCache[id] || + (nodeCache[id] = + document.getElementById(id) || + ReactMount.findReactRenderedDOMNodeSlow(id)); + } +}; + +module.exports = ReactDOMNodeCache; + +},{"./ReactMount":5}],36:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule getTextContentAccessor + */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var contentKey = null; + +/** + * Gets the key used to access text content on a DOM node. + * + * @return {?string} Key used to access text content. + * @internal + */ +function getTextContentAccessor() { + if (!contentKey && ExecutionEnvironment.canUseDOM) { + contentKey = 'innerText' in document.createElement('div') ? + 'innerText' : + 'textContent'; + } + return contentKey; +} + +module.exports = getTextContentAccessor; + +},{"./ExecutionEnvironment":14}],39:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactOnDOMReady + */ + +"use strict"; + +var PooledClass = require("./PooledClass"); + +var mixInto = require("./mixInto"); + +/** + * A specialized pseudo-event module to help keep track of components waiting to + * be notified when their DOM representations are available for use. + * + * This implements `PooledClass`, so you should never need to instantiate this. + * Instead, use `ReactOnDOMReady.getPooled()`. + * + * @param {?array} initialCollection + * @class ReactOnDOMReady + * @implements PooledClass + * @internal + */ +function ReactOnDOMReady(initialCollection) { + this._queue = initialCollection || null; +} + +mixInto(ReactOnDOMReady, { + + /** + * Enqueues a callback to be invoked when `notifyAll` is invoked. This is used + * to enqueue calls to `componentDidMount` and `componentDidUpdate`. + * + * @param {ReactComponent} component Component being rendered. + * @param {function(DOMElement)} callback Invoked when `notifyAll` is invoked. + * @internal + */ + enqueue: function(component, callback) { + this._queue = this._queue || []; + this._queue.push({component: component, callback: callback}); + }, + + /** + * Invokes all enqueued callbacks and clears the queue. This is invoked after + * the DOM representation of a component has been created or updated. + * + * @internal + */ + notifyAll: function() { + var queue = this._queue; + if (queue) { + this._queue = null; + for (var i = 0, l = queue.length; i < l; i++) { + var component = queue[i].component; + var callback = queue[i].callback; + callback.call(component, component.getDOMNode()); + } + queue.length = 0; + } + }, + + /** + * Resets the internal queue. + * + * @internal + */ + reset: function() { + this._queue = null; + }, + + /** + * `PooledClass` looks for this. + */ + destructor: function() { + this.reset(); + } + +}); + +PooledClass.addPoolingTo(ReactOnDOMReady); + +module.exports = ReactOnDOMReady; + +},{"./PooledClass":37,"./mixInto":13}],40:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule Transaction + */ + +"use strict"; + +var throwIf = require("./throwIf"); + +var DUAL_TRANSACTION = 'DUAL_TRANSACTION'; +var MISSING_TRANSACTION = 'MISSING_TRANSACTION'; +if (true) { + DUAL_TRANSACTION = + 'Cannot initialize transaction when there is already an outstanding ' + + 'transaction. Common causes of this are trying to render a component ' + + 'when you are already rendering a component or attempting a state ' + + 'transition while in a render function. Another possibility is that ' + + 'you are rendering new content (or state transitioning) in a ' + + 'componentDidRender callback. If this is not the case, please report the ' + + 'issue immediately.'; + + MISSING_TRANSACTION = + 'Cannot close transaction when there is none open.'; +} + +/** + * `Transaction` creates a black box that is able to wrap any method such that + * certain invariants are maintained before and after the method is invoked + * (Even if an exception is thrown while invoking the wrapped method). Whoever + * instantiates a transaction can provide enforcers of the invariants at + * creation time. The `Transaction` class itself will supply one additional + * automatic invariant for you - the invariant that any transaction instance + * should not be ran while it is already being ran. You would typically create a + * single instance of a `Transaction` for reuse multiple times, that potentially + * is used to wrap several different methods. Wrappers are extremely simple - + * they only require implementing two methods. + * + *
+ *                       wrappers (injected at creation time)
+ *                                      +        +
+ *                                      |        |
+ *                    +-----------------|--------|--------------+
+ *                    |                 v        |              |
+ *                    |      +---------------+   |              |
+ *                    |   +--|    wrapper1   |---|----+         |
+ *                    |   |  +---------------+   v    |         |
+ *                    |   |          +-------------+  |         |
+ *                    |   |     +----|   wrapper2  |--------+   |
+ *                    |   |     |    +-------------+  |     |   |
+ *                    |   |     |                     |     |   |
+ *                    |   v     v                     v     v   | wrapper
+ *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
+ * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
+ * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | +---+ +---+   +---------+   +---+ +---+ |
+ *                    |  initialize                    close    |
+ *                    +-----------------------------------------+
+ * 
+ * + * Bonus: + * - Reports timing metrics by method name and wrapper index. + * + * Use cases: + * - Preserving the input selection ranges before/after reconciliation. + * Restoring selection even in the event of an unexpected error. + * - Deactivating events while rearranging the DOM, preventing blurs/focuses, + * while guaranteeing that afterwards, the event system is reactivated. + * - Flushing a queue of collected DOM mutations to the main UI thread after a + * reconciliation takes place in a worker thread. + * - Invoking any collected `componentDidRender` callbacks after rendering new + * content. + * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue + * to preserve the `scrollTop` (an automatic scroll aware DOM). + * - (Future use case): Layout calculations before and after DOM upates. + * + * Transactional plugin API: + * - A module that has an `initialize` method that returns any precomputation. + * - and a `close` method that accepts the precomputation. `close` is invoked + * when the wrapped process is completed, or has failed. + * + * @param {Array} transactionWrapper Wrapper modules + * that implement `initialize` and `close`. + * @return {Transaction} Single transaction for reuse in thread. + * + * @class Transaction + */ +var Mixin = { + /** + * Sets up this instance so that it is prepared for collecting metrics. Does + * so such that this setup method may be used on an instance that is already + * initialized, in a way that does not consume additional memory upon reuse. + * That can be useful if you decide to make your subclass of this mixin a + * "PooledClass". + */ + reinitializeTransaction: function() { + this.transactionWrappers = this.getTransactionWrappers(); + if (!this.wrapperInitData) { + this.wrapperInitData = []; + } else { + this.wrapperInitData.length = 0; + } + if (!this.timingMetrics) { + this.timingMetrics = {}; + } + this.timingMetrics.methodInvocationTime = 0; + if (!this.timingMetrics.wrapperInitTimes) { + this.timingMetrics.wrapperInitTimes = []; + } else { + this.timingMetrics.wrapperInitTimes.length = 0; + } + if (!this.timingMetrics.wrapperCloseTimes) { + this.timingMetrics.wrapperCloseTimes = []; + } else { + this.timingMetrics.wrapperCloseTimes.length = 0; + } + this._isInTransaction = false; + }, + + _isInTransaction: false, + + /** + * @abstract + * @return {Array} Array of transaction wrappers. + */ + getTransactionWrappers: null, + + isInTransaction: function() { + return !!this._isInTransaction; + }, + + /** + * Executes the function within a safety window. Use this for the top level + * methods that result in large amounts of computation/mutations that would + * need to be safety checked. + * + * @param {function} method Member of scope to call. + * @param {Object} scope Scope to invoke from. + * @param {Object?=} args... Arguments to pass to the method (optional). + * Helps prevent need to bind in many cases. + * @returns Return value from `method`. + */ + perform: function(method, scope, a, b, c, d, e, f) { + throwIf(this.isInTransaction(), DUAL_TRANSACTION); + var memberStart = Date.now(); + var err = null; + var ret; + try { + this.initializeAll(); + ret = method.call(scope, a, b, c, d, e, f); + } catch (ie_requires_catch) { + err = ie_requires_catch; + } finally { + var memberEnd = Date.now(); + this.methodInvocationTime += (memberEnd - memberStart); + try { + this.closeAll(); + } catch (closeAllErr) { + err = err || closeAllErr; + } + } + if (err) { + throw err; + } + return ret; + }, + + initializeAll: function() { + this._isInTransaction = true; + var transactionWrappers = this.transactionWrappers; + var wrapperInitTimes = this.timingMetrics.wrapperInitTimes; + var err = null; + for (var i = 0; i < transactionWrappers.length; i++) { + var initStart = Date.now(); + var wrapper = transactionWrappers[i]; + try { + this.wrapperInitData[i] = + wrapper.initialize ? wrapper.initialize.call(this) : null; + } catch (initErr) { + err = err || initErr; // Remember the first error. + this.wrapperInitData[i] = Transaction.OBSERVED_ERROR; + } finally { + var curInitTime = wrapperInitTimes[i]; + var initEnd = Date.now(); + wrapperInitTimes[i] = (curInitTime || 0) + (initEnd - initStart); + } + } + if (err) { + throw err; + } + }, + + /** + * Invokes each of `this.transactionWrappers.close[i]` functions, passing into + * them the respective return values of `this.transactionWrappers.init[i]` + * (`close`rs that correspond to initializers that failed will not be + * invoked). + */ + closeAll: function() { + throwIf(!this.isInTransaction(), MISSING_TRANSACTION); + var transactionWrappers = this.transactionWrappers; + var wrapperCloseTimes = this.timingMetrics.wrapperCloseTimes; + var err = null; + for (var i = 0; i < transactionWrappers.length; i++) { + var wrapper = transactionWrappers[i]; + var closeStart = Date.now(); + var initData = this.wrapperInitData[i]; + try { + if (initData !== Transaction.OBSERVED_ERROR) { + wrapper.close && wrapper.close.call(this, initData); + } + } catch (closeErr) { + err = err || closeErr; // Remember the first error. + } finally { + var closeEnd = Date.now(); + var curCloseTime = wrapperCloseTimes[i]; + wrapperCloseTimes[i] = (curCloseTime || 0) + (closeEnd - closeStart); + } + } + this.wrapperInitData.length = 0; + this._isInTransaction = false; + if (err) { + throw err; + } + } +}; + +var Transaction = { + Mixin: Mixin, + /** + * Token to look for to determine if an error occured. + */ + OBSERVED_ERROR: {} + +}; + +module.exports = Transaction; + +})() +},{"./throwIf":31}],42:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule escapeTextForBrowser + */ + +"use strict"; + +var throwIf = require("./throwIf"); + +var ESCAPE_TYPE_ERR; + +if (true) { + ESCAPE_TYPE_ERR = + 'The React core has attempted to escape content that is of a ' + + 'mysterious type (object etc) Escaping only works on numbers and strings'; +} + +var ESCAPE_LOOKUP = { + "&": "&", + ">": ">", + "<": "<", + "\"": """, + "'": "'", + "/": "/" +}; + +function escaper(match) { + return ESCAPE_LOOKUP[match]; +} + +var escapeTextForBrowser = function (text) { + var type = typeof text; + var invalid = type === 'object'; + if (true) { + throwIf(invalid, ESCAPE_TYPE_ERR); + } + if (text === '' || invalid) { + return ''; + } else { + if (type === 'string') { + return text.replace(/[&><"'\/]/g, escaper); + } else { + return (''+text).replace(/[&><"'\/]/g, escaper); + } + } +}; + +module.exports = escapeTextForBrowser; + +},{"./throwIf":31}],41:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactMultiChild + */ + +"use strict"; + +var ReactComponent = require("./ReactComponent"); + +/** + * Given a `curChild` and `newChild`, determines if `curChild` should be managed + * as it exists, as opposed to being destroyed and/or replaced. + * @param {?ReactComponent} curChild + * @param {?ReactComponent} newChild + * @return {!boolean} Whether or not `curChild` should be updated with + * `newChild`'s props + */ +function shouldManageExisting(curChild, newChild) { + return curChild && newChild && curChild.constructor === newChild.constructor; +} + +/** + * `ReactMultiChild` provides common functionality for components that have + * multiple children. Standard `ReactCompositeComponent`s do not currently have + * multiple children. `ReactNativeComponent`s do, however. Other specially + * reconciled components will also have multiple children. Contains three + * internally used properties that are used to keep track of state throughout + * the `updateMultiChild` process. + * + * @class ReactMultiChild + */ + +/** + * @lends `ReactMultiChildMixin`. + */ +var ReactMultiChildMixin = { + + enqueueMarkupAt: function(markup, insertAt) { + this.domOperations = this.domOperations || []; + this.domOperations.push({insertMarkup: markup, finalIndex: insertAt}); + }, + + enqueueMove: function(originalIndex, finalIndex) { + this.domOperations = this.domOperations || []; + this.domOperations.push({moveFrom: originalIndex, finalIndex: finalIndex}); + }, + + enqueueUnmountChildByName: function(name, removeChild) { + if (ReactComponent.isValidComponent(removeChild)) { + this.domOperations = this.domOperations || []; + this.domOperations.push({removeAt: removeChild._domIndex}); + removeChild.unmountComponent && removeChild.unmountComponent(); + delete this._renderedChildren[name]; + } + }, + + /** + * Process any pending DOM operations that have been accumulated when updating + * the UI. By default, we execute the injected `DOMIDOperations` module's + * `manageChildrenByParentID` which does executes the DOM operations without + * any animation. It can be used as a reference implementation for special + * animation based implementations. + * + * @abstract + */ + processChildDOMOperationsQueue: function() { + if (this.domOperations) { + ReactComponent.DOMIDOperations + .manageChildrenByParentID(this._rootNodeID, this.domOperations); + this.domOperations = null; + } + }, + + unmountMultiChild: function() { + var renderedChildren = this._renderedChildren; + for (var name in renderedChildren) { + if (renderedChildren.hasOwnProperty(name) && renderedChildren[name]) { + var renderedChild = renderedChildren[name]; + renderedChild.unmountComponent && renderedChild.unmountComponent(); + } + } + this._renderedChildren = null; + }, + + /** + * Generates markup for a component that holds multiple children. #todo: Allow + * all `ReactMultiChildMixin`s to support having arrays of children without a + * container node. This current implementation may assume that children exist + * at domIndices [0, parentNode.length]. + * + * Has side effects of (likely) causing events to be registered. Also, every + * component instance may only be rendered once. + * + * @param {?Object} children Flattened children object. + * @return {!String} The rendered markup. + */ + mountMultiChild: function(children, transaction) { + var accum = ''; + var index = 0; + for (var name in children) { + var child = children[name]; + if (children.hasOwnProperty(name) && child) { + accum += child.mountComponent( + this._rootNodeID + '.' + name, + transaction + ); + child._domIndex = index; + index++; + } + } + this._renderedChildren = children; // children are in just the right form! + this.domOperations = null; + return accum; + }, + + /** + * Reconciles new children with old children in three phases. + * + * - Adds new content while updating existing children that should remain. + * - Remove children that are no longer present in the next children. + * - As a very last step, moves existing dom structures around. + * - (Comment 1) `curChildrenDOMIndex` is the largest index of the current + * rendered children that appears in the next children and did not need to + * be "moved". + * - (Comment 2) This is the key insight. If any non-removed child's previous + * index is less than `curChildrenDOMIndex` it must be moved. + * + * @param {?Object} children Flattened children object. + */ + updateMultiChild: function(nextChildren, transaction) { + if (!nextChildren && !this._renderedChildren) { + return; + } else if (nextChildren && !this._renderedChildren) { + this._renderedChildren = {}; // lazily allocate backing store with nothing + } else if (!nextChildren && this._renderedChildren) { + nextChildren = {}; + } + var rootDomIdDot = this._rootNodeID + '.'; + var markupBuffer = null; // Accumulate adjacent new children markup. + var numPendingInsert = 0; // How many root nodes are waiting in markupBuffer + var loopDomIndex = 0; // Index of loop through new children. + var curChildrenDOMIndex = 0; // See (Comment 1) + for (var name in nextChildren) { + if (!nextChildren.hasOwnProperty(name)) {continue;} + var curChild = this._renderedChildren[name]; + var nextChild = nextChildren[name]; + if (shouldManageExisting(curChild, nextChild)) { + if (markupBuffer) { + this.enqueueMarkupAt(markupBuffer, loopDomIndex - numPendingInsert); + markupBuffer = null; + } + numPendingInsert = 0; + if (curChild._domIndex < curChildrenDOMIndex) { // (Comment 2) + this.enqueueMove(curChild._domIndex, loopDomIndex); + } + curChildrenDOMIndex = Math.max(curChild._domIndex, curChildrenDOMIndex); + !nextChild.props.isStatic && + curChild.receiveProps(nextChild.props, transaction); + curChild._domIndex = loopDomIndex; + } else { + if (curChild) { // !shouldUpdate && curChild => delete + this.enqueueUnmountChildByName(name, curChild); + curChildrenDOMIndex = + Math.max(curChild._domIndex, curChildrenDOMIndex); + } + if (nextChild) { // !shouldUpdate && nextChild => insert + this._renderedChildren[name] = nextChild; + var nextMarkup = + nextChild.mountComponent(rootDomIdDot + name, transaction); + markupBuffer = markupBuffer ? markupBuffer + nextMarkup : nextMarkup; + numPendingInsert++; + nextChild._domIndex = loopDomIndex; + } + } + loopDomIndex = nextChild ? loopDomIndex + 1 : loopDomIndex; + } + if (markupBuffer) { + this.enqueueMarkupAt(markupBuffer, loopDomIndex - numPendingInsert); + } + for (var childName in this._renderedChildren) { // from other direction + if (!this._renderedChildren.hasOwnProperty(childName)) { continue; } + var child = this._renderedChildren[childName]; + if (child && !nextChildren[childName]) { + this.enqueueUnmountChildByName(childName, child); + } + } + this.processChildDOMOperationsQueue(); + } +}; + +var ReactMultiChild = { + Mixin: ReactMultiChildMixin +}; + +module.exports = ReactMultiChild; + +})() +},{"./ReactComponent":3}],43:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule flattenChildren + */ + +"use strict"; + +var ReactTextComponent = require("./ReactTextComponent"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); + +var throwIf = require("./throwIf"); + +/** + * @polyFill Array.isArray + */ + + +var INVALID_CHILD = 'INVALID_CHILD'; +if (true) { + INVALID_CHILD = + 'You may not pass a child of that type to a React component. It ' + + 'is a common mistake to try to pass a standard browser DOM element ' + + 'as a child of a React component.'; +} + +/** + * If there is only a single child, it still needs a name. + */ +var ONLY_CHILD_NAME = '0'; + +var flattenChildrenImpl = function(res, children, nameSoFar) { + if (Array.isArray(children)) { + for (var i = 0; i < children.length; i++) { + flattenChildrenImpl(res, children[i], nameSoFar + '[' + i + ']'); + } + } else { + var type = typeof children; + var isOnlyChild = nameSoFar === ''; + var storageName = isOnlyChild ? ONLY_CHILD_NAME : nameSoFar; + if (children === null || children === undefined || type === 'boolean') { + res[storageName] = null; + } else if (children.mountComponentIntoNode) { + /* We found a component instance */ + res[storageName] = children; + } else { + if (type === 'object') { + throwIf(children && children.nodeType === 1, INVALID_CHILD); + for (var key in children) { + if (children.hasOwnProperty(key)) { + flattenChildrenImpl( + res, + children[key], + nameSoFar + '{' + escapeTextForBrowser(key) + '}' + ); + } + } + } else if (type === 'string') { + res[storageName] = new ReactTextComponent(children); + } else if (type === 'number') { + res[storageName] = new ReactTextComponent('' + children); + } + } + } +}; + +/** + * Flattens children that are typically specified as `props.children`. + * @return {!Object} flattened children keyed by name. + */ +function flattenChildren(children) { + if (children === null || children === undefined) { + return children; + } + var result = {}; + flattenChildrenImpl(result, children, ''); + return result; +} + +module.exports = flattenChildren; + +},{"./ReactTextComponent":65,"./escapeTextForBrowser":42,"./throwIf":31}],45:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule mergeHelpers + * + * requiresPolyfills: Array.isArray + */ + +"use strict"; + +var keyMirror = require("./keyMirror"); +var throwIf = require("./throwIf"); + +/* + * Maximum number of levels to traverse. Will catch circular structures. + * @const + */ +var MAX_MERGE_DEPTH = 36; + +var ERRORS = keyMirror({ + MERGE_ARRAY_FAIL: null, + MERGE_CORE_FAILURE: null, + MERGE_TYPE_USAGE_FAILURE: null, + MERGE_DEEP_MAX_LEVELS: null, + MERGE_DEEP_NO_ARR_STRATEGY: null +}); + +if (true) { + ERRORS = { + MERGE_ARRAY_FAIL: + 'Unsupported type passed to a merge function. You may have passed a ' + + 'structure that contains an array and the merge function does not know ' + + 'how to merge arrays. ', + + MERGE_CORE_FAILURE: + 'Critical assumptions about the merge functions have been violated. ' + + 'This is the fault of the merge functions themselves, not necessarily ' + + 'the callers.', + + MERGE_TYPE_USAGE_FAILURE: + 'Calling merge function with invalid types. You may call merge ' + + 'functions (non-array non-terminal) OR (null/undefined) arguments. ' + + 'mergeInto functions have the same requirements but with an added ' + + 'restriction that the first parameter must not be null/undefined.', + + MERGE_DEEP_MAX_LEVELS: + 'Maximum deep merge depth exceeded. You may attempting to merge ' + + 'circular structures in an unsupported way.', + MERGE_DEEP_NO_ARR_STRATEGY: + 'You must provide an array strategy to deep merge functions to ' + + 'instruct the deep merge how to resolve merging two arrays.' + }; +} + +/** + * We won't worry about edge cases like new String('x') or new Boolean(true). + * Functions are considered terminals, and arrays are not. + * @param {*} o The item/object/value to test. + * @return {boolean} true iff the argument is a terminal. + */ +var isTerminal = function(o) { + return typeof o !== 'object' || o === null; +}; + +var mergeHelpers = { + + MAX_MERGE_DEPTH: MAX_MERGE_DEPTH, + + isTerminal: isTerminal, + + /** + * Converts null/undefined values into empty object. + * + * @param {?Object=} arg Argument to be normalized (nullable optional) + * @return {!Object} + */ + normalizeMergeArg: function(arg) { + return arg === undefined || arg === null ? {} : arg; + }, + + /** + * If merging Arrays, a merge strategy *must* be supplied. If not, it is + * likely the caller's fault. If this function is ever called with anything + * but `one` and `two` being `Array`s, it is the fault of the merge utilities. + * + * @param {*} one Array to merge into. + * @param {*} two Array to merge from. + */ + checkMergeArrayArgs: function(one, two) { + throwIf( + !Array.isArray(one) || !Array.isArray(two), + ERRORS.MERGE_CORE_FAILURE + ); + }, + + /** + * @param {*} one Object to merge into. + * @param {*} two Object to merge from. + */ + checkMergeObjectArgs: function(one, two) { + mergeHelpers.checkMergeObjectArg(one); + mergeHelpers.checkMergeObjectArg(two); + }, + + /** + * @param {*} arg + */ + checkMergeObjectArg: function(arg) { + throwIf(isTerminal(arg) || Array.isArray(arg), ERRORS.MERGE_CORE_FAILURE); + }, + + /** + * Checks that a merge was not given a circular object or an object that had + * too great of depth. + * + * @param {number} Level of recursion to validate against maximum. + */ + checkMergeLevel: function(level) { + throwIf(level >= MAX_MERGE_DEPTH, ERRORS.MERGE_DEEP_MAX_LEVELS); + }, + + /** + * Checks that a merge was not given a circular object or an object that had + * too great of depth. + * + * @param {number} Level of recursion to validate against maximum. + */ + checkArrayStrategy: function(strategy) { + throwIf( + strategy !== undefined && !(strategy in mergeHelpers.ArrayStrategies), + ERRORS.MERGE_DEEP_NO_ARR_STRATEGY + ); + }, + + /** + * Set of possible behaviors of merge algorithms when encountering two Arrays + * that must be merged together. + * - `clobber`: The left `Array` is ignored. + * - `indexByIndex`: The result is achieved by recursively deep merging at + * each index. (not yet supported.) + */ + ArrayStrategies: keyMirror({ + Clobber: true, + IndexByIndex: true + }), + + ERRORS: ERRORS +}; + +module.exports = mergeHelpers; + +},{"./keyMirror":11,"./throwIf":31}],47:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventConstants + */ + +"use strict"; + +var keyMirror = require("./keyMirror"); + +var PropagationPhases = keyMirror({bubbled: null, captured: null}); + +/** + * Types of raw signals from the browser caught at the top level. + */ +var topLevelTypes = keyMirror({ + topBlur: null, + topChange: null, + topClick: null, + topDOMCharacterDataModified: null, + topDoubleClick: null, + topFocus: null, + topKeyDown: null, + topKeyPress: null, + topKeyUp: null, + topMouseDown: null, + topMouseMove: null, + topMouseOut: null, + topMouseOver: null, + topMouseUp: null, + topMouseWheel: null, + topScroll: null, + topSubmit: null, + topTouchCancel: null, + topTouchEnd: null, + topTouchMove: null, + topTouchStart: null +}); + +var EventConstants = { + topLevelTypes: topLevelTypes, + PropagationPhases: PropagationPhases +}; + +module.exports = EventConstants; + +},{"./keyMirror":11}],48:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule NormalizedEventListener + */ + +"use strict"; + +var EventListener = require("./EventListener"); + +/** + * @param {?Event} eventParam Event parameter from an attached listener. + * @return {Event} Normalized event object. + * @private + */ +function normalizeEvent(eventParam) { + var normalized = eventParam || window.event; + // In some browsers (OLD FF), setting the target throws an error. A good way + // to tell if setting the target will throw an error, is to check if the event + // has a `target` property. Safari events have a `target` but it's not always + // normalized. Even if a `target` property exists, it's good to only set the + // target property if we realize that a change will actually take place. + var hasTargetProperty = 'target' in normalized; + var eventTarget = normalized.target || normalized.srcElement || window; + // Safari may fire events on text nodes (Node.TEXT_NODE is 3) + // @see http://www.quirksmode.org/js/events_properties.html + var textNodeNormalizedTarget = + (eventTarget.nodeType === 3) ? eventTarget.parentNode : eventTarget; + if (!hasTargetProperty || normalized.target !== textNodeNormalizedTarget) { + // Create an object that inherits from the native event so that we can set + // `target` on it. (It is read-only and setting it throws in strict mode). + normalized = Object.create(normalized); + normalized.target = textNodeNormalizedTarget; + } + return normalized; +} + +function createNormalizedCallback(cb) { + return function(unfixedNativeEvent) { + cb(normalizeEvent(unfixedNativeEvent)); + }; +} + +var NormalizedEventListener = { + + /** + * Listens to bubbled events on a DOM node. + * + * NOTE: The listener will be invoked with a normalized event object. + * + * @param {DOMElement} el DOM element to register listener on. + * @param {string} handlerBaseName Event name, e.g. "click". + * @param {function} cb Callback function. + * @public + */ + listen: function(el, handlerBaseName, cb) { + EventListener.listen(el, handlerBaseName, createNormalizedCallback(cb)); + }, + + /** + * Listens to captured events on a DOM node. + * + * NOTE: The listener will be invoked with a normalized event object. + * + * @param {DOMElement} el DOM element to register listener on. + * @param {string} handlerBaseName Event name, e.g. "click". + * @param {function} cb Callback function. + * @public + */ + capture: function(el, handlerBaseName, cb) { + EventListener.capture(el, handlerBaseName, createNormalizedCallback(cb)); + } + +}; + +module.exports = NormalizedEventListener; + +},{"./EventListener":66}],49:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule isEventSupported + */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var testNode; +if (ExecutionEnvironment.canUseDOM) { + testNode = document.createElement('div'); +} + +/** + * Checks if an event is supported in the current execution environment. + * + * NOTE: This will not work correctly for non-generic events such as `change`, + * `reset`, `load`, `error`, and `select`. + * + * Borrows from Modernizr. + * + * @param {string} eventNameSuffix Event name, e.g. "click". + * @param {?boolean} capture Check if the capture phase is supported. + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ +function isEventSupported(eventNameSuffix, capture) { + if (!testNode || (capture && !testNode.addEventListener)) { + return false; + } + var element = document.createElement('div'); + var eventName = 'on' + eventNameSuffix; + var isSupported = eventName in element; + + if (!isSupported) { + element.setAttribute(eventName, ''); + isSupported = typeof element[eventName] === 'function'; + if (typeof element[eventName] !== 'undefined') { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + element = null; + return isSupported; +} + +module.exports = isEventSupported; + +},{"./ExecutionEnvironment":14}],52:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPropagators + */ + +"use strict"; + +var CallbackRegistry = require("./CallbackRegistry"); +var EventConstants = require("./EventConstants"); + +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var getListener = CallbackRegistry.getListener; +var PropagationPhases = EventConstants.PropagationPhases; + +/** + * Injected dependencies: + */ + +/** + * - `InstanceHandle`: [required] Module that performs logical traversals of DOM + * hierarchy given ids of the logical DOM elements involved. + */ +var injection = { + InstanceHandle: null, + injectInstanceHandle: function(InjectedInstanceHandle) { + injection.InstanceHandle = InjectedInstanceHandle; + if (true) { + injection.validate(); + } + }, + validate: function() { + var invalid = !injection.InstanceHandle|| + !injection.InstanceHandle.traverseTwoPhase || + !injection.InstanceHandle.traverseEnterLeave; + if (invalid) { + throw new Error('InstanceHandle not injected before use!'); + } + } +}; + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(id, abstractEvent, propagationPhase) { + var registrationName = + abstractEvent.type.phasedRegistrationNames[propagationPhase]; + return getListener(id, registrationName); +} + +/** + * Tags an `AbstractEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(domID, upwards, abstractEvent) { + if (true) { + if (!domID) { + throw new Error('Dispatching id must not be null'); + } + injection.validate(); + } + var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; + var listener = listenerAtPhase(domID, abstractEvent, phase); + if (listener) { + abstractEvent._dispatchListeners = + accumulate(abstractEvent._dispatchListeners, listener); + abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, domID); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We can not perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(abstractEvent) { + if (abstractEvent && abstractEvent.type.phasedRegistrationNames) { + injection.InstanceHandle.traverseTwoPhase( + abstractEvent.abstractTargetID, + accumulateDirectionalDispatches, + abstractEvent + ); + } +} + + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `abstractTargetID` be the same as the dispatched ID. + */ +function accumulateDispatches(id, ignoredDirection, abstractEvent) { + if (abstractEvent && abstractEvent.type.registrationName) { + var listener = getListener(id, abstractEvent.type.registrationName); + if (listener) { + abstractEvent._dispatchListeners = + accumulate(abstractEvent._dispatchListeners, listener); + abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, id); + } + } +} + +/** + * Accumulates dispatches on an `AbstractEvent`, but only for the + * `abstractTargetID`. + * @param {AbstractEvent} abstractEvent + */ +function accumulateDirectDispatchesSingle(abstractEvent) { + if (abstractEvent && abstractEvent.type.registrationName) { + accumulateDispatches(abstractEvent.abstractTargetID, null, abstractEvent); + } +} + +function accumulateTwoPhaseDispatches(abstractEvents) { + if (true) { + injection.validate(); + } + forEachAccumulated(abstractEvents, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { + if (true) { + injection.validate(); + } + injection.InstanceHandle.traverseEnterLeave( + fromID, + toID, + accumulateDispatches, + leave, + enter + ); +} + + +function accumulateDirectDispatches(abstractEvents) { + if (true) { + injection.validate(); + } + forEachAccumulated(abstractEvents, accumulateDirectDispatchesSingle); +} + + + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing event a + * single one. + * + * @constructor EventPropagators + */ +var EventPropagators = { + accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, + accumulateDirectDispatches: accumulateDirectDispatches, + accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, + injection: injection +}; + +module.exports = EventPropagators; + +},{"./CallbackRegistry":54,"./EventConstants":47,"./accumulate":56,"./forEachAccumulated":57}],55:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPluginUtils + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var AbstractEvent = require("./AbstractEvent"); + +var invariant = require("./invariant"); + +var topLevelTypes = EventConstants.topLevelTypes; + +function isEndish(topLevelType) { + return topLevelType === topLevelTypes.topMouseUp || + topLevelType === topLevelTypes.topTouchEnd || + topLevelType === topLevelTypes.topTouchCancel; +} + +function isMoveish(topLevelType) { + return topLevelType === topLevelTypes.topMouseMove || + topLevelType === topLevelTypes.topTouchMove; +} +function isStartish(topLevelType) { + return topLevelType === topLevelTypes.topMouseDown || + topLevelType === topLevelTypes.topTouchStart; +} + +function storePageCoordsIn(obj, nativeEvent) { + var pageX = AbstractEvent.eventPageX(nativeEvent); + var pageY = AbstractEvent.eventPageY(nativeEvent); + obj.pageX = pageX; + obj.pageY = pageY; +} + +function eventDistance(coords, nativeEvent) { + var pageX = AbstractEvent.eventPageX(nativeEvent); + var pageY = AbstractEvent.eventPageY(nativeEvent); + return Math.pow( + Math.pow(pageX - coords.pageX, 2) + Math.pow(pageY - coords.pageY, 2), + 0.5 + ); +} + +var validateEventDispatches; +if (true) { + validateEventDispatches = function(abstractEvent) { + var dispatchListeners = abstractEvent._dispatchListeners; + var dispatchIDs = abstractEvent._dispatchIDs; + + var listenersIsArr = Array.isArray(dispatchListeners); + var idsIsArr = Array.isArray(dispatchIDs); + var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; + var listenersLen = listenersIsArr ? + dispatchListeners.length : + dispatchListeners ? 1 : 0; + + invariant( + idsIsArr === listenersIsArr && IDsLen === listenersLen, + 'EventPluginUtils: Invalid `abstractEvent`.' + ); + }; +} + +/** + * Invokes `cb(abstractEvent, listener, id)`. Avoids using call if no scope is + * provided. The `(listener,id)` pair effectively forms the "dispatch" but are + * kept separate to conserve memory. + */ +function forEachEventDispatch(abstractEvent, cb) { + var dispatchListeners = abstractEvent._dispatchListeners; + var dispatchIDs = abstractEvent._dispatchIDs; + if (true) { + validateEventDispatches(abstractEvent); + } + if (Array.isArray(dispatchListeners)) { + var i; + for ( + i = 0; + i < dispatchListeners.length && !abstractEvent.isPropagationStopped; + i++) { + // Listeners and IDs are two parallel arrays that are always in sync. + cb(abstractEvent, dispatchListeners[i], dispatchIDs[i]); + } + } else if (dispatchListeners) { + cb(abstractEvent, dispatchListeners, dispatchIDs); + } +} + +/** + * Default implementation of PluginModule.executeDispatch(). + * @param {AbstractEvent} AbstractEvent to handle + * @param {function} Application-level callback + * @param {string} domID DOM id to pass to the callback. + */ +function executeDispatch(abstractEvent, listener, domID) { + listener(abstractEvent, domID); +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(abstractEvent, executeDispatch) { + forEachEventDispatch(abstractEvent, executeDispatch); + abstractEvent._dispatchListeners = null; + abstractEvent._dispatchIDs = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @returns id of the first dispatch execution who's listener returns true, or + * null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrue(abstractEvent) { + var dispatchListeners = abstractEvent._dispatchListeners; + var dispatchIDs = abstractEvent._dispatchIDs; + if (true) { + validateEventDispatches(abstractEvent); + } + if (Array.isArray(dispatchListeners)) { + var i; + for ( + i = 0; + i < dispatchListeners.length && !abstractEvent.isPropagationStopped; + i++) { + // Listeners and IDs are two parallel arrays that are always in sync. + if (dispatchListeners[i](abstractEvent, dispatchIDs[i])) { + return dispatchIDs[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(abstractEvent, dispatchIDs)) { + return dispatchIDs; + } + } + return null; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @returns The return value of executing the single dispatch. + */ +function executeDirectDispatch(abstractEvent) { + if (true) { + validateEventDispatches(abstractEvent); + } + var dispatchListener = abstractEvent._dispatchListeners; + var dispatchID = abstractEvent._dispatchIDs; + invariant( + !Array.isArray(dispatchListener), + 'executeDirectDispatch(...): Invalid `abstractEvent`.' + ); + var res = dispatchListener ? + dispatchListener(abstractEvent, dispatchID) : + null; + abstractEvent._dispatchListeners = null; + abstractEvent._dispatchIDs = null; + return res; +} + +/** + * @param {AbstractEvent} abstractEvent + * @returns {bool} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(abstractEvent) { + return !!abstractEvent._dispatchListeners; +} + +/** + * General utilities that are useful in creating custom Event Plugins. + */ +var EventPluginUtils = { + isEndish: isEndish, + isMoveish: isMoveish, + isStartish: isStartish, + storePageCoordsIn: storePageCoordsIn, + eventDistance: eventDistance, + executeDispatchesInOrder: executeDispatchesInOrder, + executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, + executeDirectDispatch: executeDirectDispatch, + hasDispatches: hasDispatches, + executeDispatch: executeDispatch +}; + +module.exports = EventPluginUtils; + +},{"./EventConstants":47,"./AbstractEvent":53,"./invariant":10}],56:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule accumulate + */ + +"use strict"; + +var throwIf = require("./throwIf"); + +var INVALID_ARGS = 'INVALID_ACCUM_ARGS'; + +if (true) { + INVALID_ARGS = + 'accumulate requires non empty (non-null, defined) next ' + + 'values. All arrays accumulated must not contain any empty items.'; +} + +/** + * Accumulates items that must never be empty, into a result in a manner that + * conserves memory - avoiding allocation of arrays until they are needed. The + * accumulation may start and/or end up being a single element or an array + * depending on the total count (if greater than one, an array is allocated). + * Handles most common case first (starting with an empty current value and + * acquiring one). + * @returns {Accumulation} An accumulation which is either a single item or an + * Array of items. + */ +function accumulate(cur, next) { + var curValIsEmpty = cur == null; // Will test for emptiness (null/undef) + var nextValIsEmpty = next === null; + if (true) { + throwIf(nextValIsEmpty, INVALID_ARGS); + } + if (nextValIsEmpty) { + return cur; + } else { + if (curValIsEmpty) { + return next; + } else { + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + var curIsArray = Array.isArray(cur); + var nextIsArray = Array.isArray(next); + if (curIsArray) { + return cur.concat(next); + } else { + if (nextIsArray) { + return [cur].concat(next); + } else { + return [cur, next]; + } + } + } + } +} + +module.exports = accumulate; + +},{"./throwIf":31}],53:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule AbstractEvent + */ + +"use strict"; + +var BrowserEnv = require("./BrowserEnv"); +var PooledClass = require("./PooledClass"); +var TouchEventUtils = require("./TouchEventUtils"); + +var throwIf = require("./throwIf"); + + +// Only accessed in __DEV__ +var CLONE_TYPE_ERR; +if (true) { + CLONE_TYPE_ERR = + 'You may only clone instances of AbstractEvent for ' + + 'persistent references. Check yourself.'; +} +var MAX_POOL_SIZE = 20; + +/** + * AbstractEvent copy constructor. @see `PooledClass`. Provides a single place + * to define all cross browser normalization of DOM events. Does not attempt to + * extend a native event, rather creates a completely new object that has a + * reference to the nativeEvent through .nativeEvent member. The property .data + * should hold all data that is extracted from the event in a cross browser + * manner. Application code should use the data field when possible, not the + * unreliable native event. + */ +function AbstractEvent( + abstractEventType, + abstractTargetID, // Allows the abstract target to differ from native. + originatingTopLevelEventType, + nativeEvent, + data) { + this.type = abstractEventType; + this.abstractTargetID = abstractTargetID || ''; + this.originatingTopLevelEventType = originatingTopLevelEventType; + this.nativeEvent = nativeEvent; + this.data = data; + // TODO: Deprecate storing target - doesn't always make sense for some types + this.target = nativeEvent && nativeEvent.target; + + /** + * As a performance optimization, we tag the existing event with the listeners + * (or listener [singular] if only one). This avoids having to package up an + * abstract event along with the set of listeners into a wrapping "dispatch" + * object. No one should ever read this property except event system and + * plugin/dispatcher code. We also tag the abstract event with a parallel + * ID array. _dispatchListeners[i] is being dispatched to a DOM node at ID + * _dispatchIDs[i]. The lengths should never, ever, ever be different. + */ + this._dispatchListeners = null; + this._dispatchIDs = null; + + this.isPropagationStopped = false; +} + +/** `PooledClass` looks for this. */ +AbstractEvent.poolSize = MAX_POOL_SIZE; + +/** + * `PooledClass` looks for `destructor` on each instance it releases. We need to + * ensure that we remove all references to listeners which could trap large + * amounts of memory in their closures. + */ +AbstractEvent.prototype.destructor = function() { + this.target = null; + this._dispatchListeners = null; + this._dispatchIDs = null; +}; + +/** + * Enhance the `AbstractEvent` class to have pooling abilities. We instruct + * `PooledClass` that our copy constructor accepts five arguments (this is just + * a performance optimization). These objects are instantiated frequently. + */ +PooledClass.addPoolingTo(AbstractEvent, PooledClass.fiveArgumentPooler); + +AbstractEvent.prototype.stopPropagation = function() { + this.isPropagationStopped = true; + if (this.nativeEvent.stopPropagation) { + this.nativeEvent.stopPropagation(); + } + // IE8 only understands cancelBubble, not stopPropagation(). + this.nativeEvent.cancelBubble = true; +}; + +AbstractEvent.prototype.preventDefault = function() { + AbstractEvent.preventDefaultOnNativeEvent(this.nativeEvent); +}; + +/** + * Utility function for preventing default in cross browser manner. + */ +AbstractEvent.preventDefaultOnNativeEvent = function(nativeEvent) { + if (nativeEvent.preventDefault) { + nativeEvent.preventDefault(); + } else { + nativeEvent.returnValue = false; + } +}; + +/** + * @param {Element} target The target element. + */ +AbstractEvent.normalizeScrollDataFromTarget = function(target) { + return { + scrollTop: target.scrollTop, + scrollLeft: target.scrollLeft, + clientWidth: target.clientWidth, + clientHeight: target.clientHeight, + scrollHeight: target.scrollHeight, + scrollWidth: target.scrollWidth + }; +}; + +/* + * There are some normalizations that need to happen for various browsers. In + * addition to replacing the general event fixing with a framework such as + * jquery, we need to normalize mouse events here. Code below is mostly borrowed + * from: jScrollPane/script/jquery.mousewheel.js + */ +AbstractEvent.normalizeMouseWheelData = function(nativeEvent) { + var delta = 0; + var deltaX = 0; + var deltaY = 0; + + /* traditional scroll wheel data */ + if ( nativeEvent.wheelDelta ) { delta = nativeEvent.wheelDelta/120; } + if ( nativeEvent.detail ) { delta = -nativeEvent.detail/3; } + + /* Multidimensional scroll (touchpads) with deltas */ + deltaY = delta; + + /* Gecko based browsers */ + if (nativeEvent.axis !== undefined && + nativeEvent.axis === nativeEvent.HORIZONTAL_AXIS ) { + deltaY = 0; + deltaX = -delta; + } + + /* Webkit based browsers */ + if (nativeEvent.wheelDeltaY !== undefined ) { + deltaY = nativeEvent.wheelDeltaY/120; + } + if (nativeEvent.wheelDeltaX !== undefined ) { + deltaX = -nativeEvent.wheelDeltaX/120; + } + + return { delta: delta, deltaX: deltaX, deltaY: deltaY }; +}; + +/** + * I <3 Quirksmode.org: + * http://www.quirksmode.org/js/events_properties.html + */ +AbstractEvent.isNativeClickEventRightClick = function(nativeEvent) { + return nativeEvent.which ? nativeEvent.which === 3 : + nativeEvent.button ? nativeEvent.button === 2 : + false; +}; + +AbstractEvent.normalizePointerData = function(nativeEvent) { + return { + globalX: AbstractEvent.eventPageX(nativeEvent), + globalY: AbstractEvent.eventPageY(nativeEvent), + rightMouseButton: + AbstractEvent.isNativeClickEventRightClick(nativeEvent) + }; +}; + +AbstractEvent.normalizeDragEventData = + function(nativeEvent, globalX, globalY, startX, startY) { + return { + globalX: globalX, + globalY: globalY, + startX: startX, + startY: startY + }; + }; + +/** + * Warning: It is possible to move your finger on a touch surface, yet not + * effect the `eventPageX/Y` because the touch had caused a scroll that + * compensated for your movement. To track movements across the page, prevent + * default to avoid scrolling, and control scrolling in javascript. + */ + +/** + * Gets the exact position of a touch/mouse event on the page with respect to + * the document body. The only reason why this method is needed instead of using + * `TouchEventUtils.extractSingleTouch` is to support IE8-. Mouse events in all + * browsers except IE8- contain a pageY. IE8 and below require clientY + * computation: + * + * @param {Event} nativeEvent Native event, possibly touch or mouse. + * @return {number} Coordinate with respect to document body. + */ +AbstractEvent.eventPageY = function(nativeEvent) { + var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent); + if (singleTouch) { + return singleTouch.pageY; + } else if (typeof nativeEvent.pageY !== 'undefined') { + return nativeEvent.pageY; + } else { + return nativeEvent.clientY + BrowserEnv.currentPageScrollTop; + } +}; + +/** + * @see `AbstractEvent.eventPageY`. + * + * @param {Event} nativeEvent Native event, possibly touch or mouse. + * @return {number} Coordinate with respect to document body. + */ +AbstractEvent.eventPageX = function(nativeEvent) { + var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent); + if (singleTouch) { + return singleTouch.pageX; + } else if (typeof nativeEvent.pageX !== 'undefined') { + return nativeEvent.pageX; + } else { + return nativeEvent.clientX + BrowserEnv.currentPageScrollLeft; + } +}; + +/** + * A semantic API around cloning an event for use in another event loop. We + * clear out all dispatched `AbstractEvent`s after each event loop, adding them + * back into the pool. This allows a way to hold onto a reference that won't be + * added back into the pool. Please note that `AbstractEvent.nativeEvent` is + * *not* cloned and you will run into problems in IE if you assume that it will + * be! The moral of that story is to always normalize any data you need into the + * `.data` field. The data field is not cloned either, but there won't be any + * issues related to use of `.data` in a future event cycle so long as no part + * of your application mutates it. We don't clone the private fields because + * your application should never be accessing them. + * + * - TODO: In __DEV__ when "releasing" events, don't put them back into the + * pool. Instead add ES5 getters on all their fields that throw errors so you + * can detect any application that's hanging onto events and reusing them. + * In prod - we can put them back into the pool for reuse. + */ +AbstractEvent.persistentCloneOf = function(abstractEvent) { + if (true) { + throwIf(!(abstractEvent instanceof AbstractEvent), CLONE_TYPE_ERR); + } + return new AbstractEvent( + abstractEvent.type, + abstractEvent.abstractTargetID, + abstractEvent.originatingTopLevelEventType, + abstractEvent.nativeEvent, + abstractEvent.data, + abstractEvent.target + ); +}; + +module.exports = AbstractEvent; + + +},{"./BrowserEnv":46,"./TouchEventUtils":67,"./throwIf":31,"./PooledClass":37}],58:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule copyProperties + */ + +/** + * Copy properties from one or more objects (up to 5) into the first object. + * This is a shallow copy. It mutates the first object and also returns it. + * + * NOTE: `arguments` has a very significant performance penalty, which is why + * we don't support unlimited arguments. + */ +function copyProperties(obj, a, b, c, d, e, f) { + obj = obj || {}; + + if (true) { + if (f) { + throw new Error('Too many arguments passed to copyProperties'); + } + } + + var args = [a, b, c, d, e]; + var ii = 0, v; + while (args[ii]) { + v = args[ii++]; + for (var k in v) { + obj[k] = v[k]; + } + + // IE ignores toString in object iteration.. See: + // webreflection.blogspot.com/2007/07/quick-fix-internet-explorer-and.html + if (v.hasOwnProperty && v.hasOwnProperty('toString') && + (typeof v.toString != 'undefined') && (obj.toString !== v.toString)) { + obj.toString = v.toString; + } + } + + return obj; +} + +module.exports = copyProperties; + +},{}],60:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule hyphenate + * @typechecks + */ + +var _uppercasePattern = /([A-Z])/g; + +/** + * Hyphenates a camelcased string, for example: + * + * > hyphenate('backgroundColor') + * < "background-color" + * + * @param {string} string + * @return {string} + */ +function hyphenate(string) { + return string.replace(_uppercasePattern, '-$1').toLowerCase(); +} + +module.exports = hyphenate; + +},{}],61:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule memoizeStringOnly + * @typechecks + */ + +"use strict"; + +/** + * Memoizes the return value of a function that accepts one string argument. + * + * @param {function} callback + * @return {function} + */ +function memoizeStringOnly(callback) { + var cache = {}; + return function(string) { + if (cache.hasOwnProperty(string)) { + return cache[string]; + } else { + return cache[string] = callback.call(this, string); + } + }; +} + +module.exports = memoizeStringOnly; + +},{}],63:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule insertNodeAt + */ + +"use strict"; + +/** + * Inserts `node` at a particular child index. Other nodes move to make room. + * @param {!Element} root The parent root node to insert into. + * @param {!node} node The node to insert. + * @param {!number} atIndex The index in `root` that `node` should exist at. + */ +function insertNodeAt(root, node, atIndex) { + var childNodes = root.childNodes; + // Remove from parent so that if node is already child of root, + // `childNodes[atIndex]` already takes into account the removal. + var curAtIndex = root.childNodes[atIndex]; + if (curAtIndex === node) { + return node; + } + if (node.parentNode) { + node.parentNode.removeChild(node); + } + if (atIndex >= childNodes.length) { + root.appendChild(node); + } else { + root.insertBefore(node, childNodes[atIndex]); + } + return node; +} + +module.exports = insertNodeAt; + +},{}],66:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventListener + */ + +/** + * Upstream version of event listener. Does not take into account specific + * nature of platform. + */ +var EventListener = { + /** + * Listens to bubbled events on a DOM node. + * + * @param {Element} el DOM element to register listener on. + * @param {string} handlerBaseName 'click'/'mouseover' + * @param {Function!} cb Callback function + */ + listen: function(el, handlerBaseName, cb) { + if (el.addEventListener) { + el.addEventListener(handlerBaseName, cb, false); + } else if (el.attachEvent) { + el.attachEvent('on' + handlerBaseName, cb); + } + }, + + /** + * Listens to captured events on a DOM node. + * + * @see `EventListener.listen` for params. + * @throws Exception if addEventListener is not supported. + */ + capture: function(el, handlerBaseName, cb) { + if (!el.addEventListener) { + console.error( + 'You are attempting to use addEventlistener ' + + 'in a browser that does not support it support it.' + + 'This likely means that you will not receive events that ' + + 'your application relies on (such as scroll).'); + return; + } else { + el.addEventListener(handlerBaseName, cb, true); + } + } +}; + +module.exports = EventListener; + +},{}],67:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule TouchEventUtils + */ + +var TouchEventUtils = { + /** + * Utility function for common case of extracting out the primary touch from a + * touch event. + * - `touchEnd` events usually do not have the `touches` property. + * http://stackoverflow.com/questions/3666929/ + * mobile-sarai-touchend-event-not-firing-when-last-touch-is-removed + * + * @param {Event} nativeEvent Native event that may or may not be a touch. + * @return {TouchesObject?} an object with pageX and pageY or null. + */ + extractSingleTouch: function(nativeEvent) { + var touches = nativeEvent.touches; + var changedTouches = nativeEvent.changedTouches; + var hasTouches = touches && touches.length > 0; + var hasChangedTouches = changedTouches && changedTouches.length > 0; + + return !hasTouches && hasChangedTouches ? changedTouches[0] : + hasTouches ? touches[0] : + nativeEvent; + } +}; + +module.exports = TouchEventUtils; + +},{}],59:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule dangerousStyleValue + * @typechecks + */ + +"use strict"; + +var CSSProperty = require("./CSSProperty"); + +/** + * Convert a value into the proper css writable value. The `styleName` name + * name should be logical (no hyphens), as specified in `CSSProperty.isNumber`. + * + * @param {string} styleName CSS property name such as `topMargin`. + * @param {*} value CSS property value such as `10px`. + * @return {string} Normalized style value with dimensions applied. + */ +function dangerousStyleValue(styleName, value) { + // Note that we've removed escapeTextForBrowser() calls here since the + // whole string will be escaped when the attribute is injected into + // the markup. If you provide unsafe user data here they can inject + // arbitrary CSS which may be problematic (I couldn't repro this): + // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ + // This is not an XSS hole but instead a potential CSS injection issue + // which has lead to a greater discussion about how we're going to + // trust URLs moving forward. See #2115901 + if (value === null || value === false || value === true || value === '') { + return ''; + } + if (isNaN(value)) { + return !value ? '' : '' + value; + } + return CSSProperty.isNumber[styleName] ? '' + value : (value + 'px'); +} + +module.exports = dangerousStyleValue; + +},{"./CSSProperty":68}],62:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule Danger + */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var throwIf = require("./throwIf"); + +var DOM_UNSUPPORTED; +var NO_MARKUP_PARENT; +var NO_MULTI_MARKUP; +if (true) { + DOM_UNSUPPORTED = + 'You may not insert markup into the document while you are in a worker ' + + 'thread. It\'s not you, it\'s me. This is likely the fault of the ' + + 'framework. Please report this immediately.'; + NO_MARKUP_PARENT = + 'You have attempted to inject markup without a suitable parent. This is ' + + 'likely the fault of the framework - please report immediately.'; + NO_MULTI_MARKUP = + 'The framework has attempted to either insert zero or multiple markup ' + + 'roots into a single location when it should not. This is a serious ' + + 'error - a fault of the framework - please report immediately.'; +} + +var validateMarkupParams; +if (true) { + validateMarkupParams = function(parentNode, markup) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + throwIf(!parentNode || !parentNode.tagName, NO_MARKUP_PARENT); + throwIf(!markup, NO_MULTI_MARKUP); + }; +} + +var dummies = {}; + +function getParentDummy(parent) { + var parentTag = parent.tagName; + return dummies[parentTag] || + (dummies[parentTag] = document.createElement(parentTag)); +} + +/** + * Inserts node after 'after'. If 'after' is null, inserts it after nothing, + * which is inserting it at the beginning. + * + * @param {Element} elem Parent element. + * @param {Element} insert Element to insert. + * @param {Element} after Element to insert after. + * @returns {Element} Element that was inserted. + */ +function insertNodeAfterNode(elem, insert, after) { + if (true) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + } + if (after) { + if (after.nextSibling) { + return elem.insertBefore(insert, after.nextSibling); + } else { + return elem.appendChild(insert); + } + } else { + return elem.insertBefore(insert, elem.firstChild); + } +} + +/** + * Slow: Should only be used when it is known there are a few (or one) element + * in the node list. + * @param {Element} parentRootDomNode Parent element. + * @param {HTMLCollection} htmlCollection HTMLCollection to insert. + * @param {Element} after Element to insert the node list after. + */ +function inefficientlyInsertHTMLCollectionAfter( + parentRootDomNode, + htmlCollection, + after) { + + if (true) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + } + var ret; + var originalLength = htmlCollection.length; + // Access htmlCollection[0] because htmlCollection shrinks as we remove items. + // `insertNodeAfterNode` will remove items from the htmlCollection. + for (var i = 0; i < originalLength; i++) { + ret = + insertNodeAfterNode(parentRootDomNode, htmlCollection[0], ret || after); + } +} + +/** + * Super-dangerously inserts markup into existing DOM structure. Seriously, you + * don't want to use this module unless you are building a framework. This + * requires that the markup that you are inserting represents the root of a + * tree. We do not support the case where there `markup` represents several + * roots. + * + * @param {Element} parentNode Parent DOM element. + * @param {string} markup Markup to dangerously insert. + * @param {number} index Position to insert markup at. + */ +function dangerouslyInsertMarkupAt(parentNode, markup, index) { + if (true) { + validateMarkupParams(parentNode, markup); + } + var parentDummy = getParentDummy(parentNode); + parentDummy.innerHTML = markup; + var htmlCollection = parentDummy.childNodes; + var afterNode = index ? parentNode.childNodes[index - 1] : null; + inefficientlyInsertHTMLCollectionAfter(parentNode, htmlCollection, afterNode); +} + +/** + * Replaces a node with a string of markup at its current position within its + * parent. `childNode` must be in the document (or at least within a parent + * node). The string of markup must represent a tree of markup with a single + * root. + * + * @param {Element} childNode Child node to replace. + * @param {string} markup Markup to dangerously replace child with. + */ +function dangerouslyReplaceNodeWithMarkup(childNode, markup) { + var parentNode = childNode.parentNode; + if (true) { + validateMarkupParams(parentNode, markup); + } + var parentDummy = getParentDummy(parentNode); + parentDummy.innerHTML = markup; + var htmlCollection = parentDummy.childNodes; + if (true) { + throwIf(htmlCollection.length !== 1, NO_MULTI_MARKUP); + } + parentNode.replaceChild(htmlCollection[0], childNode); +} + +var Danger = { + dangerouslyInsertMarkupAt: dangerouslyInsertMarkupAt, + dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup +}; + +module.exports = Danger; + +},{"./ExecutionEnvironment":14,"./throwIf":31}],64:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMProperty + * @typechecks + */ + +/*jslint bitwise: true */ + +"use strict"; + +var invariant = require("./invariant"); + +/** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ +var DOMProperty = { + + /** + * Checks whether a property name is a standard property. + * @type {Object} + */ + isStandardName: {}, + + /** + * Mapping from normalized names to attribute names that differ. Attribute + * names are used when rendering markup or with `*Attribute()`. + * @type {Object} + */ + getAttributeName: {}, + + /** + * Mapping from normalized names to properties on DOM node instances. + * (This includes properties that mutate due to external factors.) + * @type {Object} + */ + getPropertyName: {}, + + /** + * Mapping from normalized names to mutation methods. This will only exist if + * mutation cannot be set simply by the property or `setAttribute()`. + * @type {Object} + */ + getMutationMethod: {}, + + /** + * Whether the property must be accessed and mutated as an object property. + * @type {Object} + */ + mustUseAttribute: {}, + + /** + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * @type {Object} + */ + mustUseProperty: {}, + + /** + * Whether the property should be removed when set to a falsey value. + * @type {Object} + */ + hasBooleanValue: {}, + + /** + * Whether or not setting a value causes side effects such as triggering + * resources to be loaded or text selection changes. We must ensure that + * the value is only set if it has changed. + * @type {Object} + */ + hasSideEffects: {}, + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: RegExp.prototype.test.bind( + /^(data|aria)-[a-z_][a-z\d_.\-]*$/ + ) +}; + +/** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ +var MustUseAttribute = 0x1; +var MustUseProperty = 0x2; +var HasBooleanValue = 0x4; +var HasSideEffects = 0x8; + +var Properties = { + /** + * Standard Properties + */ + accept: null, + action: null, + ajaxify: MustUseAttribute, + allowFullScreen: MustUseAttribute | HasBooleanValue, + alt: null, + autoComplete: null, + autoplay: HasBooleanValue, + cellPadding: null, + cellSpacing: null, + checked: MustUseProperty | HasBooleanValue, + className: MustUseProperty, + colSpan: null, + contentEditable: null, + controls: MustUseProperty | HasBooleanValue, + data: null, // For `` acts as `src`. + dir: null, + disabled: MustUseProperty | HasBooleanValue, + enctype: null, + height: null, + href: null, + htmlFor: null, + method: null, + multiple: MustUseProperty | HasBooleanValue, + name: null, + poster: null, + preload: null, + placeholder: null, + rel: null, + required: HasBooleanValue, + role: MustUseAttribute, + scrollLeft: MustUseProperty, + scrollTop: MustUseProperty, + selected: MustUseProperty | HasBooleanValue, + spellCheck: null, + src: null, + style: null, + tabIndex: null, + target: null, + title: null, + type: null, + value: MustUseProperty | HasSideEffects, + width: null, + wmode: MustUseAttribute, + /** + * SVG Properties + */ + cx: MustUseProperty, + cy: MustUseProperty, + d: MustUseProperty, + fill: MustUseProperty, + fx: MustUseProperty, + fy: MustUseProperty, + points: MustUseProperty, + r: MustUseProperty, + stroke: MustUseProperty, + strokeLinecap: MustUseProperty, + strokeWidth: MustUseProperty, + transform: MustUseProperty, + x: MustUseProperty, + x1: MustUseProperty, + x2: MustUseProperty, + version: MustUseProperty, + viewBox: MustUseProperty, + y: MustUseProperty, + y1: MustUseProperty, + y2: MustUseProperty, + spreadMethod: MustUseProperty, + offset: MustUseProperty, + stopColor: MustUseProperty, + stopOpacity: MustUseProperty, + gradientUnits: MustUseProperty, + gradientTransform: MustUseProperty +}; + +/** + * Attribute names not specified use the **lowercase** normalized name. + */ +var DOMAttributeNames = { + className: 'class', + htmlFor: 'for', + strokeLinecap: 'stroke-linecap', + strokeWidth: 'stroke-width', + stopColor: 'stop-color', + stopOpacity: 'stop-opacity' +}; + +/** + * Property names not specified use the normalized name. + */ +var DOMPropertyNames = { + autoComplete: 'autocomplete', + spellCheck: 'spellcheck' +}; + +/** + * Properties that require special mutation methods. + */ +var DOMMutationMethods = { + /** + * Setting `className` to null may cause it to be set to the string "null". + * + * @param {DOMElement} node + * @param {*} value + */ + className: function(node, value) { + node.className = value || ''; + } +}; + +for (var propName in Properties) { + DOMProperty.isStandardName[propName] = true; + + DOMProperty.getAttributeName[propName] = + DOMAttributeNames[propName] || propName.toLowerCase(); + + DOMProperty.getPropertyName[propName] = + DOMPropertyNames[propName] || propName; + + var mutationMethod = DOMMutationMethods[propName]; + if (mutationMethod) { + DOMProperty.getMutationMethod[propName] = mutationMethod; + } + + var propConfig = Properties[propName]; + DOMProperty.mustUseAttribute[propName] = propConfig & MustUseAttribute; + DOMProperty.mustUseProperty[propName] = propConfig & MustUseProperty; + DOMProperty.hasBooleanValue[propName] = propConfig & HasBooleanValue; + DOMProperty.hasSideEffects[propName] = propConfig & HasSideEffects; + + invariant( + !DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName], + 'DOMProperty: Cannot use require using both attribute and property: %s', + propName + ); + invariant( + DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName], + 'DOMProperty: Properties that have side effects must use property: %s', + propName + ); +} + +module.exports = DOMProperty; + +},{"./invariant":10}],65:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactTextComponent + * @typechecks + */ + +"use strict"; + +var ReactComponent = require("./ReactComponent"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var mixInto = require("./mixInto"); + +/** + * Text nodes violate a couple assumptions that React makes about components: + * + * - When mounting text into the DOM, adjacent text nodes are merged. + * - Text nodes cannot be assigned a React root ID. + * + * This component is used to wrap strings in elements so that they can undergo + * the same reconciliation that is applied to elements. + * + * TODO: Investigate representing React components in the DOM with text nodes. + * + * @class ReactTextComponent + * @extends ReactComponent + * @internal + */ +var ReactTextComponent = function(initialText) { + this.construct({text: initialText}); +}; + +mixInto(ReactTextComponent, ReactComponent.Mixin); +mixInto(ReactTextComponent, { + + /** + * Creates the markup for this text node. This node is not intended to have + * any features besides containing text content. + * + * @param {string} rootID DOM ID of the root node. + * @return {string} Markup for this text node. + * @internal + */ + mountComponent: function(rootID) { + ReactComponent.Mixin.mountComponent.call(this, rootID); + return ( + '' + + escapeTextForBrowser(this.props.text) + + '' + ); + }, + + /** + * Updates this component by updating the text content. + * + * @param {object} nextProps Contains the next text content. + * @param {ReactReconcileTransaction} transaction + * @internal + */ + receiveProps: function(nextProps, transaction) { + if (nextProps.text !== this.props.text) { + this.props.text = nextProps.text; + ReactComponent.DOMIDOperations.updateTextContentByID( + this._rootNodeID, + nextProps.text + ); + } + } + +}); + +module.exports = ReactTextComponent; + +},{"./ReactComponent":3,"./escapeTextForBrowser":42,"./mixInto":13}],68:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CSSProperty + */ + +"use strict"; + +/** + * CSS properties for which we do not append "px". + */ +var isNumber = { + fillOpacity: true, + fontWeight: true, + opacity: true, + orphans: true, + textDecoration: true, + zIndex: true, + zoom: true +}; + +var CSSProperty = { + isNumber: isNumber +}; + +module.exports = CSSProperty; + +},{}]},{},[1])(1) +}); +; \ No newline at end of file diff --git a/components/react/react.min.js b/components/react/react.min.js new file mode 100644 index 0000000000000..152b175f2b91c --- /dev/null +++ b/components/react/react.min.js @@ -0,0 +1,19 @@ +/** + * React v0.3.0 + * + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +!function(e){if("function"==typeof bootstrap)bootstrap("react",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeReact=e}else"undefined"!=typeof window?window.React=e():global.React=e()}(function(){return function(e,t,n){function o(n,i){if(!t[n]){if(!e[n]){var a="function"==typeof require&&require;if(!i&&a)return a(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var s=t[n]={exports:{}};e[n][0].call(s.exports,function(t){var r=e[n][1][t];return o(r?r:t)},s,s.exports)}return t[n].exports}for(var r="function"==typeof require&&require,i=0;i=t+n+o,"Can only set one of `children`, `props.content`, or `props.dangerouslySetInnerHTML`."),p(null==e.style||"object"==typeof e.style,"The `style` prop expects a mapping from style properties to values, not a string.")}}function o(e,t){this._tagOpen="<"+e+" ",this._tagClose=t?"":"",this.tagName=e.toUpperCase()}var r=e("./CSSPropertyOperations"),i=e("./DOMPropertyOperations"),a=e("./ReactComponent"),s=e("./ReactEvent"),u=e("./ReactMultiChild"),c=e("./escapeTextForBrowser"),l=e("./flattenChildren"),p=e("./invariant"),d=e("./keyOf"),h=e("./merge"),f=e("./mixInto"),m=s.putListener,v=s.registrationNames,g={string:!0,number:!0},y=d({content:null}),E=d({dangerouslySetInnerHTML:null}),C=d({style:null});o.Mixin={mountComponent:function(e,t){return a.Mixin.mountComponent.call(this,e,t),n(this.props),this._createOpenTagMarkup()+this._createContentMarkup(t)+this._tagClose},_createOpenTagMarkup:function(){var e=this.props,t=this._tagOpen;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];if(null!=o)if(v[n])m(this._rootNodeID,n,o);else{n===C&&(o&&(o=e.style=h(e.style)),o=r.createMarkupForStyles(o));var a=i.createMarkupForProperty(n,o);a&&(t+=" "+a)}}return t+' id="'+this._rootNodeID+'">'},_createContentMarkup:function(e){var t=this.props.dangerouslySetInnerHTML;if(null!=t){if(null!=t.__html)return t.__html}else{var n=null!=this.props.content?this.props.content:g[typeof this.props.children]?this.props.children:null,o=null!=n?null:this.props.children;if(null!=n)return c(n);if(null!=o)return this.mountMultiChild(l(o),e)}return""},receiveProps:function(e,t){p(this._rootNodeID,"Trying to control a native dom element without a backing id"),n(e),a.Mixin.receiveProps.call(this,e,t),this._updateDOMProperties(e),this._updateDOMChildren(e,t),this.props=e},_updateDOMProperties:function(e){var t=this.props;for(var n in e){var o=e[n],r=t[n];if(e.hasOwnProperty(n)&&o!==r)if(n===C){o&&(o=e.style=h(o));var i;for(var s in o)o.hasOwnProperty(s)&&(r&&r[s]===o[s]||(i||(i={}),i[s]=o[s]));i&&a.DOMIDOperations.updateStylesByID(this._rootNodeID,i)}else if(n===E){var u=r&&r.__html,c=o&&o.__html;u!==c&&a.DOMIDOperations.updateInnerHTMLByID(this._rootNodeID,o)}else n===y?a.DOMIDOperations.updateTextContentByID(this._rootNodeID,""+o):v[n]?m(this._rootNodeID,n,o):a.DOMIDOperations.updatePropertyByID(this._rootNodeID,n,o)}},_updateDOMChildren:function(e,t){var n=typeof this.props.content,o=null==this.props.content||"boolean"===n,r=typeof e.content,i=null==e.content||"boolean"===r,s=o?g[typeof this.props.children]?this.props.children:null:this.props.content,u=i?g[typeof e.children]?e.children:null:e.content,c=null!=s?null:this.props.children,p=null!=u?null:e.children;if(null!=u){var d=null!=c&&null==p;d&&this.updateMultiChild(null,t),s!==u&&a.DOMIDOperations.updateTextContentByID(this._rootNodeID,""+u)}else{var h=null!=s&&null==u;h&&a.DOMIDOperations.updateTextContentByID(this._rootNodeID,""),this.updateMultiChild(l(e.children),t)}},unmountComponent:function(){a.Mixin.unmountComponent.call(this),this.unmountMultiChild(),s.deleteAllListeners(this._rootNodeID)}},f(o,a.Mixin),f(o,o.Mixin),f(o,u.Mixin),t.exports=o},{"./CSSPropertyOperations":32,"./DOMPropertyOperations":34,"./ReactComponent":3,"./ReactEvent":20,"./ReactMultiChild":41,"./escapeTextForBrowser":42,"./flattenChildren":43,"./invariant":10,"./keyOf":44,"./merge":12,"./mixInto":13}],18:[function(e,t){"use strict";function n(e,t){if(r(e),null!=t){r(t);for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])}}var o=e("./mergeHelpers"),r=o.checkMergeObjectArg;t.exports=n},{"./mergeHelpers":45}],20:[function(e,t){"use strict";function n(e,t,n){C(n,t,R.TopLevelCallbackCreator.createTopLevelCallback(e))}function o(e,t,n){D(n,t,R.TopLevelCallbackCreator.createTopLevelCallback(e))}function r(){C(window,"scroll",function(e){e.target===window&&p.refreshAuthoritativeScrollValues()})}function i(){C(window,"resize",function(e){e.target===window&&p.refreshAuthoritativeScrollValues()})}function a(e){v(!M,"listenAtTopLevel(...): Cannot setup top-level listener more than once.");var t=document;r(),i(),n(E.topMouseOver,"mouseover",t),n(E.topMouseDown,"mousedown",t),n(E.topMouseUp,"mouseup",t),n(E.topMouseMove,"mousemove",t),n(E.topMouseOut,"mouseout",t),n(E.topClick,"click",t),n(E.topDoubleClick,"dblclick",t),n(E.topMouseWheel,"mousewheel",t),e&&(n(E.topTouchStart,"touchstart",t),n(E.topTouchEnd,"touchend",t),n(E.topTouchMove,"touchmove",t),n(E.topTouchCancel,"touchcancel",t)),n(E.topKeyUp,"keyup",t),n(E.topKeyPress,"keypress",t),n(E.topKeyDown,"keydown",t),n(E.topChange,"change",t),n(E.topDOMCharacterDataModified,"DOMCharacterDataModified",t),n(E.topMouseWheel,"DOMMouseScroll",t),g("scroll",!0)?o(E.topScroll,"scroll",t):n(E.topScroll,"scroll",window),g("focus",!0)?(o(E.topFocus,"focus",t),o(E.topBlur,"blur",t)):g("focusin")&&(n(E.topFocus,"focusin",t),n(E.topBlur,"focusout",t))}function s(e,t,n,o){var r=h.extractAbstractEvents(e,t,n,o);h.enqueueAbstractEvents(r),h.processAbstractEventQueue()}function u(e){v(f.canUseDOM,"setEnabled(...): Cannot toggle event listening in a Worker thread. This is likely a bug in the framework. Please report immediately."),R.TopLevelCallbackCreator.setEnabled(e)}function c(){return R.TopLevelCallbackCreator.isEnabled()}function l(e,t){v(f.canUseDOM,"ensureListening(...): Cannot toggle event listening in a Worker thread. This is likely a bug in the framework. Please report immediately."),M||(R.TopLevelCallbackCreator=t,a(e),M=!0)}var p=e("./BrowserEnv"),d=e("./EventConstants"),h=e("./EventPluginHub"),f=e("./ExecutionEnvironment"),m=e("./NormalizedEventListener"),v=e("./invariant"),g=e("./isEventSupported"),y=h.registrationNames,E=d.topLevelTypes,C=m.listen,D=m.capture,M=!1,R={TopLevelCallbackCreator:null,handleTopLevel:s,setEnabled:u,isEnabled:c,ensureListening:l,registrationNames:y,putListener:h.putListener,getListener:h.getListener,deleteAllListeners:h.deleteAllListeners,trapBubbledEvent:n,trapCapturedEvent:o};t.exports=R},{"./BrowserEnv":46,"./EventConstants":47,"./EventPluginHub":27,"./ExecutionEnvironment":14,"./NormalizedEventListener":48,"./invariant":10,"./isEventSupported":49}],21:[function(e,t){"use strict";function n(e,t){return e.charAt(t)===c||t===e.length}function o(e){return""===e||e.charAt(0)===c&&e.charAt(e.length-1)!==c}function r(e){var t=s(e);return t&&t.charAt(0)===c}function i(e){return e?e.substr(0,e.lastIndexOf(c)):""}function a(e,t,n,o,r,a){e=e||"",t=t||"",u(e!==t,"traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.",e);var s=d.getFirstCommonAncestorID(e,t),c=s===t;u(c||s===e,"traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do not have a parent path.",e,t);for(var l=0,h=c?i:d.nextDescendantID,f=e;r&&f===e||a&&f===t||n(f,c,o),f!==t;f=h(f,t))u(l++=a;a++)if(n(e,a)&&n(t,a))i=a;else if(e.charAt(a)!==t.charAt(a))break;var s=e.substr(0,i);return u(o(s),"getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s",e,t,s),s},getReactRootID:function(e){return".reactRoot["+e+"]"},getReactRootIDFromNodeID:function(e){var t=/\.reactRoot\[[^\]]+\]/.exec(e);return t&&t[0]},traverseEnterLeave:function(e,t,n,o,r){var i=d.getFirstCommonAncestorID(e,t);i!==e&&a(e,i,n,o,!1,!0),i!==t&&a(i,t,n,r,!0,!1)},traverseTwoPhase:function(e,t,n){e&&(a("",e,t,n,!0,!1),a(e,"",t,n,!1,!0))},nextDescendantID:function(e,t){u(o(e)&&o(t),"nextDescendantID(%s, %s): Received an invalid React DOM ID.",e,t);var r=d.getFirstCommonAncestorID(e,t);if(u(r===e,"nextDescendantID(...): React has made an invalid assumption about the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.",e,t),e===t)return e;for(var i=e.length+l,a=i;as;s++){var u=i[s],l=u&&u.extractAbstractEvents(e,t,n,o); +l&&(r=c(r,l))}return r},M=function(e){e&&(E=c(E,e))},R=function(e){if(e){var t=o(e),n=t&&t.executeDispatch;a.executeDispatchesInOrder(e,n||a.executeDispatch),r.release(e)}},I=function(){var e=E;E=null,l(e,R)},O={registrationNames:g,registrationNamesArr:y,putListener:i.putListener,getListener:i.getListener,deleteAllListeners:C,extractAbstractEvents:D,enqueueAbstractEvents:M,processAbstractEventQueue:I,injection:v};u.canUseDOM&&(window.EventPluginHub=O),t.exports=O}()},{"./AbstractEvent":53,"./CallbackRegistry":54,"./EventPluginUtils":55,"./EventPropagators":52,"./ExecutionEnvironment":14,"./accumulate":56,"./forEachAccumulated":57,"./keyMirror":11,"./merge":12,"./throwIf":31}],28:[function(e,t){"use strict";var n=e("./AbstractEvent"),o=e("./EventConstants"),r=e("./EventPropagators"),i=e("./keyOf"),a=o.topLevelTypes,s={abstractEventTypes:{mouseDown:{phasedRegistrationNames:{bubbled:i({onMouseDown:!0}),captured:i({onMouseDownCapture:!0})}},mouseUp:{phasedRegistrationNames:{bubbled:i({onMouseUp:!0}),captured:i({onMouseUpCapture:!0})}},mouseMove:{phasedRegistrationNames:{bubbled:i({onMouseMove:!0}),captured:i({onMouseMoveCapture:!0})}},doubleClick:{phasedRegistrationNames:{bubbled:i({onDoubleClick:!0}),captured:i({onDoubleClickCapture:!0})}},click:{phasedRegistrationNames:{bubbled:i({onClick:!0}),captured:i({onClickCapture:!0})}},mouseWheel:{phasedRegistrationNames:{bubbled:i({onMouseWheel:!0}),captured:i({onMouseWheelCapture:!0})}},touchStart:{phasedRegistrationNames:{bubbled:i({onTouchStart:!0}),captured:i({onTouchStartCapture:!0})}},touchEnd:{phasedRegistrationNames:{bubbled:i({onTouchEnd:!0}),captured:i({onTouchEndCapture:!0})}},touchCancel:{phasedRegistrationNames:{bubbled:i({onTouchCancel:!0}),captured:i({onTouchCancelCapture:!0})}},touchMove:{phasedRegistrationNames:{bubbled:i({onTouchMove:!0}),captured:i({onTouchMoveCapture:!0})}},keyUp:{phasedRegistrationNames:{bubbled:i({onKeyUp:!0}),captured:i({onKeyUpCapture:!0})}},keyPress:{phasedRegistrationNames:{bubbled:i({onKeyPress:!0}),captured:i({onKeyPressCapture:!0})}},keyDown:{phasedRegistrationNames:{bubbled:i({onKeyDown:!0}),captured:i({onKeyDownCapture:!0})}},focus:{phasedRegistrationNames:{bubbled:i({onFocus:!0}),captured:i({onFocusCapture:!0})}},blur:{phasedRegistrationNames:{bubbled:i({onBlur:!0}),captured:i({onBlurCapture:!0})}},scroll:{phasedRegistrationNames:{bubbled:i({onScroll:!0}),captured:i({onScrollCapture:!0})}},change:{phasedRegistrationNames:{bubbled:i({onChange:!0}),captured:i({onChangeCapture:!0})}},submit:{phasedRegistrationNames:{bubbled:i({onSubmit:!0}),captured:i({onSubmitCapture:!0})}},DOMCharacterDataModified:{phasedRegistrationNames:{bubbled:i({onDOMCharacterDataModified:!0}),captured:i({onDOMCharacterDataModifiedCapture:!0})}}},executeDispatch:function(e,t,n){var o=t(e,n);o===!1&&(e.stopPropagation(),e.preventDefault())},extractAbstractEvents:function(e,t,o,i){var u,c=s.topLevelTypesToAbstract[e];if(!c)return null;switch(e){case a.topMouseWheel:u=n.normalizeMouseWheelData(t);break;case a.topScroll:u=n.normalizeScrollDataFromTarget(i);break;case a.topClick:case a.topDoubleClick:case a.topChange:case a.topDOMCharacterDataModified:case a.topMouseDown:case a.topMouseUp:case a.topMouseMove:case a.topTouchMove:case a.topTouchStart:case a.topTouchEnd:u=n.normalizePointerData(t);break;default:u=null}var l=n.getPooled(c,o,e,t,u);return r.accumulateTwoPhaseDispatches(l),l}};s.topLevelTypesToAbstract={topMouseDown:s.abstractEventTypes.mouseDown,topMouseUp:s.abstractEventTypes.mouseUp,topMouseMove:s.abstractEventTypes.mouseMove,topClick:s.abstractEventTypes.click,topDoubleClick:s.abstractEventTypes.doubleClick,topMouseWheel:s.abstractEventTypes.mouseWheel,topTouchStart:s.abstractEventTypes.touchStart,topTouchEnd:s.abstractEventTypes.touchEnd,topTouchMove:s.abstractEventTypes.touchMove,topTouchCancel:s.abstractEventTypes.touchCancel,topKeyUp:s.abstractEventTypes.keyUp,topKeyPress:s.abstractEventTypes.keyPress,topKeyDown:s.abstractEventTypes.keyDown,topFocus:s.abstractEventTypes.focus,topBlur:s.abstractEventTypes.blur,topScroll:s.abstractEventTypes.scroll,topChange:s.abstractEventTypes.change,topSubmit:s.abstractEventTypes.submit,topDOMCharacterDataModified:s.abstractEventTypes.DOMCharacterDataModified},t.exports=s},{"./AbstractEvent":53,"./EventConstants":47,"./EventPropagators":52,"./keyOf":44}],30:[function(e,t){"use strict";function n(e){e||(e="");var t,n=arguments.length;if(n>1)for(var o=1;n>o;o++)t=arguments[o],t&&(e+=" "+t);return e}t.exports=n},{}],31:[function(e,t){"use strict";var n=function(e,t){if(e)throw new Error(t)};t.exports=n},{}],37:[function(e,t){"use strict";var n=function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)},o=function(e,t){var n=this;if(n.instancePool.length){var o=n.instancePool.pop();return n.call(o,e,t),o}return new n(e,t)},r=function(e,t,n,o,r){var i=this;if(i.instancePool.length){var a=i.instancePool.pop();return i.call(a,e,t,n,o,r),a}return new i(e,t,n,o,r)},i=function(e){var t=this;e.destructor&&e.destructor(),t.instancePool.lengtht;t++){var o=e[t].component,r=e[t].callback;r.call(o,o.getDOMNode())}e.length=0}},reset:function(){this._queue=null},destructor:function(){this.reset()}}),o.addPoolingTo(n),t.exports=n},{"./PooledClass":37,"./mixInto":13}],40:[function(e,t){!function(){"use strict";var n=e("./throwIf"),o="DUAL_TRANSACTION",r="MISSING_TRANSACTION",i={reinitializeTransaction:function(){this.transactionWrappers=this.getTransactionWrappers(),this.wrapperInitData?this.wrapperInitData.length=0:this.wrapperInitData=[],this.timingMetrics||(this.timingMetrics={}),this.timingMetrics.methodInvocationTime=0,this.timingMetrics.wrapperInitTimes?this.timingMetrics.wrapperInitTimes.length=0:this.timingMetrics.wrapperInitTimes=[],this.timingMetrics.wrapperCloseTimes?this.timingMetrics.wrapperCloseTimes.length=0:this.timingMetrics.wrapperCloseTimes=[],this._isInTransaction=!1},_isInTransaction:!1,getTransactionWrappers:null,isInTransaction:function(){return!!this._isInTransaction},perform:function(e,t,r,i,a,s,u,c){n(this.isInTransaction(),o);var l,p=Date.now(),d=null;try{this.initializeAll(),l=e.call(t,r,i,a,s,u,c)}catch(h){d=h}finally{var f=Date.now();this.methodInvocationTime+=f-p;try{this.closeAll()}catch(m){d=d||m}}if(d)throw d;return l},initializeAll:function(){this._isInTransaction=!0;for(var e=this.transactionWrappers,t=this.timingMetrics.wrapperInitTimes,n=null,o=0;o":">","<":"<",'"':""","'":"'","/":"/"},r=function(e){var t=typeof e,o="object"===t;return""===e||o?"":"string"===t?e.replace(/[&><"'\/]/g,n):(""+e).replace(/[&><"'\/]/g,n)};t.exports=r},{"./throwIf":31}],43:[function(e,t){"use strict";function n(e){if(null===e||void 0===e)return e;var t={};return u(t,e,""),t}var o=e("./ReactTextComponent"),r=e("./escapeTextForBrowser"),i=e("./throwIf"),a="INVALID_CHILD",s="0",u=function(e,t,n){if(Array.isArray(t))for(var c=0;c=r,i.MERGE_DEEP_MAX_LEVELS)},checkArrayStrategy:function(e){o(void 0!==e&&!(e in s.ArrayStrategies),i.MERGE_DEEP_NO_ARR_STRATEGY)},ArrayStrategies:n({Clobber:!0,IndexByIndex:!0}),ERRORS:i};t.exports=s},{"./keyMirror":11,"./throwIf":31}],47:[function(e,t){"use strict";var n=e("./keyMirror"),o=n({bubbled:null,captured:null}),r=n({topBlur:null,topChange:null,topClick:null,topDOMCharacterDataModified:null,topDoubleClick:null,topFocus:null,topKeyDown:null,topKeyPress:null,topKeyUp:null,topMouseDown:null,topMouseMove:null,topMouseOut:null,topMouseOver:null,topMouseUp:null,topMouseWheel:null,topScroll:null,topSubmit:null,topTouchCancel:null,topTouchEnd:null,topTouchMove:null,topTouchStart:null}),i={topLevelTypes:r,PropagationPhases:o};t.exports=i},{"./keyMirror":11}],48:[function(e,t){"use strict";function n(e){var t=e||window.event,n="target"in t,o=t.target||t.srcElement||window,r=3===o.nodeType?o.parentNode:o;return n&&t.target===r||(t=Object.create(t),t.target=r),t}function o(e){return function(t){e(n(t))}}var r=e("./EventListener"),i={listen:function(e,t,n){r.listen(e,t,o(n))},capture:function(e,t,n){r.capture(e,t,o(n))}};t.exports=i},{"./EventListener":66}],49:[function(e,t){"use strict";function n(e,t){if(!o||t&&!o.addEventListener)return!1;var n=document.createElement("div"),r="on"+e,i=r in n;return i||(n.setAttribute(r,""),i="function"==typeof n[r],"undefined"!=typeof n[r]&&(n[r]=void 0),n.removeAttribute(r)),n=null,i}var o,r=e("./ExecutionEnvironment");r.canUseDOM&&(o=document.createElement("div")),t.exports=n},{"./ExecutionEnvironment":14}],52:[function(e,t){"use strict";function n(e,t,n){var o=t.type.phasedRegistrationNames[n];return f(e,o)}function o(e,t,o){var r=t?m.bubbled:m.captured,i=n(e,o,r);i&&(o._dispatchListeners=d(o._dispatchListeners,i),o._dispatchIDs=d(o._dispatchIDs,e))}function r(e){e&&e.type.phasedRegistrationNames&&v.InstanceHandle.traverseTwoPhase(e.abstractTargetID,o,e)}function i(e,t,n){if(n&&n.type.registrationName){var o=f(e,n.type.registrationName);o&&(n._dispatchListeners=d(n._dispatchListeners,o),n._dispatchIDs=d(n._dispatchIDs,e))}}function a(e){e&&e.type.registrationName&&i(e.abstractTargetID,null,e)}function s(e){h(e,r)}function u(e,t,n,o){v.InstanceHandle.traverseEnterLeave(n,o,i,e,t)}function c(e){h(e,a)}var l=e("./CallbackRegistry"),p=e("./EventConstants"),d=e("./accumulate"),h=e("./forEachAccumulated"),f=l.getListener,m=p.PropagationPhases,v={InstanceHandle:null,injectInstanceHandle:function(e){v.InstanceHandle=e},validate:function(){var e=!v.InstanceHandle||!v.InstanceHandle.traverseTwoPhase||!v.InstanceHandle.traverseEnterLeave;if(e)throw new Error("InstanceHandle not injected before use!")}},g={accumulateTwoPhaseDispatches:s,accumulateDirectDispatches:c,accumulateEnterLeaveDispatches:u,injection:v};t.exports=g},{"./CallbackRegistry":54,"./EventConstants":47,"./accumulate":56,"./forEachAccumulated":57}],53:[function(e,t){"use strict";function n(e,t,n,o,r){this.type=e,this.abstractTargetID=t||"",this.originatingTopLevelEventType=n,this.nativeEvent=o,this.data=r,this.target=o&&o.target,this._dispatchListeners=null,this._dispatchIDs=null,this.isPropagationStopped=!1}var o=e("./BrowserEnv"),r=e("./PooledClass"),i=e("./TouchEventUtils");e("./throwIf");var a=20;n.poolSize=a,n.prototype.destructor=function(){this.target=null,this._dispatchListeners=null,this._dispatchIDs=null},r.addPoolingTo(n,r.fiveArgumentPooler),n.prototype.stopPropagation=function(){this.isPropagationStopped=!0,this.nativeEvent.stopPropagation&&this.nativeEvent.stopPropagation(),this.nativeEvent.cancelBubble=!0},n.prototype.preventDefault=function(){n.preventDefaultOnNativeEvent(this.nativeEvent)},n.preventDefaultOnNativeEvent=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},n.normalizeScrollDataFromTarget=function(e){return{scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,clientWidth:e.clientWidth,clientHeight:e.clientHeight,scrollHeight:e.scrollHeight,scrollWidth:e.scrollWidth}},n.normalizeMouseWheelData=function(e){var t=0,n=0,o=0;return e.wheelDelta&&(t=e.wheelDelta/120),e.detail&&(t=-e.detail/3),o=t,void 0!==e.axis&&e.axis===e.HORIZONTAL_AXIS&&(o=0,n=-t),void 0!==e.wheelDeltaY&&(o=e.wheelDeltaY/120),void 0!==e.wheelDeltaX&&(n=-e.wheelDeltaX/120),{delta:t,deltaX:n,deltaY:o}},n.isNativeClickEventRightClick=function(e){return e.which?3===e.which:e.button?2===e.button:!1},n.normalizePointerData=function(e){return{globalX:n.eventPageX(e),globalY:n.eventPageY(e),rightMouseButton:n.isNativeClickEventRightClick(e)}},n.normalizeDragEventData=function(e,t,n,o,r){return{globalX:t,globalY:n,startX:o,startY:r}},n.eventPageY=function(e){var t=i.extractSingleTouch(e);return t?t.pageY:"undefined"!=typeof e.pageY?e.pageY:e.clientY+o.currentPageScrollTop},n.eventPageX=function(e){var t=i.extractSingleTouch(e);return t?t.pageX:"undefined"!=typeof e.pageX?e.pageX:e.clientX+o.currentPageScrollLeft},n.persistentCloneOf=function(e){return new n(e.type,e.abstractTargetID,e.originatingTopLevelEventType,e.nativeEvent,e.data,e.target)},t.exports=n},{"./BrowserEnv":46,"./PooledClass":37,"./TouchEventUtils":67,"./throwIf":31}],55:[function(e,t){"use strict";function n(e){return e===v.topMouseUp||e===v.topTouchEnd||e===v.topTouchCancel}function o(e){return e===v.topMouseMove||e===v.topTouchMove}function r(e){return e===v.topMouseDown||e===v.topTouchStart}function i(e,t){var n=f.eventPageX(t),o=f.eventPageY(t);e.pageX=n,e.pageY=o}function a(e,t){var n=f.eventPageX(t),o=f.eventPageY(t);return Math.pow(Math.pow(n-e.pageX,2)+Math.pow(o-e.pageY,2),.5)}function s(e,t){var n=e._dispatchListeners,o=e._dispatchIDs;if(Array.isArray(n)){var r;for(r=0;r=o.length?e.appendChild(t):e.insertBefore(t,o[n]),t)}t.exports=n},{}],66:[function(e,t){var n={listen:function(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n)},capture:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!0),void 0):(console.error("You are attempting to use addEventlistener in a browser that does not support it support it.This likely means that you will not receive events that your application relies on (such as scroll)."),void 0)}};t.exports=n},{}],67:[function(e,t){var n={extractSingleTouch:function(e){var t=e.touches,n=e.changedTouches,o=t&&t.length>0,r=n&&n.length>0;return!o&&r?n[0]:o?t[0]:e}};t.exports=n},{}],59:[function(e,t){"use strict";function n(e,t){return null===t||t===!1||t===!0||""===t?"":isNaN(t)?t?""+t:"":o.isNumber[e]?""+t:t+"px"}var o=e("./CSSProperty");t.exports=n},{"./CSSProperty":68}],62:[function(e,t){"use strict";function n(e){var t=e.tagName;return s[t]||(s[t]=document.createElement(t))}function o(e,t,n){return n?n.nextSibling?e.insertBefore(t,n.nextSibling):e.appendChild(t):e.insertBefore(t,e.firstChild)}function r(e,t,n){for(var r,i=t.length,a=0;i>a;a++)r=o(e,t[0],r||n)}function i(e,t,o){var i=n(e);i.innerHTML=t;var a=i.childNodes,s=o?e.childNodes[o-1]:null;r(e,a,s)}function a(e,t){var o=e.parentNode,r=n(o);r.innerHTML=t;var i=r.childNodes;o.replaceChild(i[0],e)}e("./ExecutionEnvironment"),e("./throwIf");var s={},u={dangerouslyInsertMarkupAt:i,dangerouslyReplaceNodeWithMarkup:a};t.exports=u},{"./ExecutionEnvironment":14,"./throwIf":31}],64:[function(e,t){"use strict";var n=e("./invariant"),o={isStandardName:{},getAttributeName:{},getPropertyName:{},getMutationMethod:{},mustUseAttribute:{},mustUseProperty:{},hasBooleanValue:{},hasSideEffects:{},isCustomAttribute:RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/)},r=1,i=2,a=4,s=8,u={accept:null,action:null,ajaxify:r,allowFullScreen:r|a,alt:null,autoComplete:null,autoplay:a,cellPadding:null,cellSpacing:null,checked:i|a,className:i,colSpan:null,contentEditable:null,controls:i|a,data:null,dir:null,disabled:i|a,enctype:null,height:null,href:null,htmlFor:null,method:null,multiple:i|a,name:null,poster:null,preload:null,placeholder:null,rel:null,required:a,role:r,scrollLeft:i,scrollTop:i,selected:i|a,spellCheck:null,src:null,style:null,tabIndex:null,target:null,title:null,type:null,value:i|s,width:null,wmode:r,cx:i,cy:i,d:i,fill:i,fx:i,fy:i,points:i,r:i,stroke:i,strokeLinecap:i,strokeWidth:i,transform:i,x:i,x1:i,x2:i,version:i,viewBox:i,y:i,y1:i,y2:i,spreadMethod:i,offset:i,stopColor:i,stopOpacity:i,gradientUnits:i,gradientTransform:i},c={className:"class",htmlFor:"for",strokeLinecap:"stroke-linecap",strokeWidth:"stroke-width",stopColor:"stop-color",stopOpacity:"stop-opacity"},l={autoComplete:"autocomplete",spellCheck:"spellcheck"},p={className:function(e,t){e.className=t||""}};for(var d in u){o.isStandardName[d]=!0,o.getAttributeName[d]=c[d]||d.toLowerCase(),o.getPropertyName[d]=l[d]||d;var h=p[d];h&&(o.getMutationMethod[d]=h);var f=u[d];o.mustUseAttribute[d]=f&r,o.mustUseProperty[d]=f&i,o.hasBooleanValue[d]=f&a,o.hasSideEffects[d]=f&s,n(!o.mustUseAttribute[d]||!o.mustUseProperty[d],"DOMProperty: Cannot use require using both attribute and property: %s",d),n(o.mustUseProperty[d]||!o.hasSideEffects[d],"DOMProperty: Properties that have side effects must use property: %s",d)}t.exports=o},{"./invariant":10}],65:[function(e,t){"use strict";var n=e("./ReactComponent"),o=e("./escapeTextForBrowser"),r=e("./mixInto"),i=function(e){this.construct({text:e})};r(i,n.Mixin),r(i,{mountComponent:function(e){return n.Mixin.mountComponent.call(this,e),''+o(this.props.text)+""},receiveProps:function(e){e.text!==this.props.text&&(this.props.text=e.text,n.DOMIDOperations.updateTextContentByID(this._rootNodeID,e.text))}}),t.exports=i},{"./ReactComponent":3,"./escapeTextForBrowser":42,"./mixInto":13}],68:[function(e,t){"use strict";var n={fillOpacity:!0,fontWeight:!0,opacity:!0,orphans:!0,textDecoration:!0,zIndex:!0,zoom:!0},o={isNumber:n};t.exports=o},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml index 2bd9d9494c3e1..e3c8c4c366004 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -11,4 +11,4 @@ exclude: - Gemfile.lock - README.md - Rakefile -baseurl: /react +baseurl: /react \ No newline at end of file diff --git a/docs/_css/react.scss b/docs/_css/react.scss index 72577c495d8b1..235465d08a6ef 100644 --- a/docs/_css/react.scss +++ b/docs/_css/react.scss @@ -12,8 +12,8 @@ $skinnyContentWidth: 650px; $contentWidth: 920px; $contentPadding: 20px; -$columnWidth: 280px; -$columnGutter: 40px; +$columnWidth: (280px / $contentWidth) * 100%; +$columnGutter: (40px / $contentWidth) * 100%; $twoColumnWidth: 2 * $columnWidth + $columnGutter; @@ -41,13 +41,9 @@ html { } -.container { - padding-top: 50px; - min-width: $contentWidth + (2 * $contentPadding); -} - .wrap { - width: $contentWidth + (2 * $contentPadding); + width: 90%; + max-width: $contentWidth + (2 * $contentPadding); margin-left: auto; margin-right: auto; padding-left: 20px; @@ -79,17 +75,35 @@ li { @include clearfix; background: $darkestColor; color: $lightTextColor; - position: fixed; - top: 0; height: 50px; box-shadow: 0 0 5px rgba(0, 0, 0, .5); width: 100%; z-index: 100; + clear: none; a { color: $lightColor; text-decoration: none; } + + .nav-toggle { + display: none; + float: right; + margin-top: 10px; + margin-bottom: 12px; + cursor: pointer; + .icon-bar { + display: block; + background-color: #f5f5f5; + width: 18px; + height: 2px; + border-radius: 1px; + box-shadow: 0 1px 0 rgba(0, 0, 0, .25); + } + .icon-bar + .icon-bar { + margin-top: 3px; + } + } .nav-site { float: right; @@ -124,6 +138,7 @@ li { color: #00d8ff; font-size: 24px; line-height: 50px; + float: left; } .nav-logo { @@ -143,10 +158,10 @@ li { // Hero! .hero { - height: 300px; // background: $darkColor url(../img/header.png) no-repeat center; background: $darkColor; padding-top: 50px; + padding-bottom: 50px; color: $lightColor; font-weight: 300; @@ -184,6 +199,18 @@ li { background: darken($primary, 5%); } } + + @media (max-width: 600px) { + .button { + width: auto; + display: block; + margin-left: auto; + margin-right: auto; + } + .button + .button { + margin-top: 10px; + } + } } // Downloads @@ -254,7 +281,7 @@ li { .home-divider { border-top-color: #bbb; margin: 0 auto; - width: 400px; + max-width: 400px; } .marketing-row { @@ -264,7 +291,7 @@ li { .marketing-col { float: left; - margin-right: 40px; + margin-right: $columnGutter; width: $columnWidth; h3 { @@ -276,6 +303,12 @@ li { p { font-size: 16px; } + + @media (max-width: 768px) { + float: none; + margin-right: 0; + width: auto; + } } .marketing-col:last-child { @@ -293,6 +326,9 @@ li { p { margin: 0 0 25px 0; max-width: $twoColumnWidth; + @media (max-width: 768px) { + max-width: none; + } } .example { @@ -350,6 +386,14 @@ footer { margin-top: 36px; margin-bottom: 18px; overflow: auto; + + @media (max-width: 580px) { + .left, + .right { + text-align: center; + float: none; + } + } } section.black content { @@ -366,6 +410,42 @@ section.black content { .subHeader { font-size: 24px; } + + .inner-content { + width: $twoColumnWidth; + max-width: none; + } + + .nav-docs { + width: $columnWidth; + max-width: none; + } + + @media (max-width: 600px) { + .inner-content, + .nav-docs { + float: none; + width: auto; + } + .nav-docs { + margin-bottom: 20px; + h3 { + line-height: 20px; + margin: 5px 0; + } + ul { + overflow: auto; + } + li { + width: 50%; + float: left; + } + @media (max-width: 320px) { + width: 100%; + float: none; + } + } + } // H2s form documentation topic dividers. Extra space helps. h2 { @@ -497,7 +577,7 @@ p { .inner-content { float: right; - width: $skinnyContentWidth; + max-width: $skinnyContentWidth; } .nosidebar .inner-content { @@ -567,6 +647,17 @@ p code { width: $columnWidth; } +@media (max-width: 768px) { + .playgroundCode, + .playgroundPreview { + width: auto; + float: none; + } + .playgroundCode + .playgroundPreview { + margin-top: 20px; + } +} + .MarkdownEditor textarea { width: 100%; height: 100px @@ -644,11 +735,47 @@ p code { text-decoration: none !important; } -@media screen and (max-width: 960px) { +// responsive menu +@media (max-width: 768px) { .nav-main { - position: static; - } - .container { - padding-top: 0; + min-height: 50px; + height: auto; + + .nav-toggle { + display: block; + float: right; + } + + .nav-site { + max-height: 0; + overflow: hidden; + clear: both; + float: none; + @include transition(all 0.3s ease); + + ul { + padding-bottom: 8px; + box-shadow: inner 0 0 30px rgba(0, 0, 0, .75); + } + a { + line-height: 32px; + display: block; + height: auto; + + &.active { + border-bottom: none; + border-radius: 5px; + } + } + } + .nav-site.open { + max-height: 999px; + } + + ul, + li { + display: block; + margin: 0; + } } -} +} \ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index d12322c3a477f..4845ea6ddd8ca 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -26,6 +26,7 @@ + @@ -37,13 +38,20 @@ React - + + diff --git a/docs/js/javascript.js b/docs/js/javascript.js index c734555047f45..0dd487b9a4cf6 100644 --- a/docs/js/javascript.js +++ b/docs/js/javascript.js @@ -422,4 +422,4 @@ CodeMirror.defineMIME("application/javascript", "javascript"); CodeMirror.defineMIME("application/ecmascript", "javascript"); CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); -CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); +CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); \ No newline at end of file diff --git a/docs/js/menu.js b/docs/js/menu.js new file mode 100644 index 0000000000000..a015de4b52a05 --- /dev/null +++ b/docs/js/menu.js @@ -0,0 +1,23 @@ +/** + * Responsive menu. + * + * @author Martin Bean + */ + +window.onload = function() { + var navSite = document.getElementsByClassName('nav-site'); + var navToggle = document.getElementsByClassName('nav-toggle'); + + function classToggle(element, tclass) { + var classes = element.className; + var pattern = new RegExp(tclass); + var hasClass = pattern.test(classes); + + classes = hasClass ? classes.replace(pattern, '') : classes + ' ' + tclass; + element.className = classes.trim(); + }; + + navToggle[0].onclick = function() { + classToggle(navSite[0], 'open'); + }; +}; \ No newline at end of file