diff --git a/Makefile b/Makefile index 4920c02..ba883f6 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ veryclean: clean rm -rf bower_components bower_components: - bower install react#v0.8.0 + bower install react#v0.9.0 vendor/reagent/react.min.js: bower_components/react/react.min.js Makefile cp $< $@ diff --git a/bower_components/react/.bower.json b/bower_components/react/.bower.json index 3eb6009..9545767 100644 --- a/bower_components/react/.bower.json +++ b/bower_components/react/.bower.json @@ -1,16 +1,16 @@ { "name": "react", - "version": "0.8.0", + "version": "0.9.0", "main": "react.js", "homepage": "https://github.com/facebook/react-bower", - "_release": "0.8.0", + "_release": "0.9.0", "_resolution": { "type": "version", - "tag": "v0.8.0", - "commit": "ac2915c7b1e78bd6068b042066759127ecfff69b" + "tag": "v0.9.0", + "commit": "81855fdf1b8454ee0ea8dd0e05a896cf5cf03010" }, "_source": "git://github.com/facebook/react-bower.git", - "_target": "v0.8.0", + "_target": "v0.9.0", "_originalSource": "react", "_direct": true } \ No newline at end of file diff --git a/bower_components/react/JSXTransformer.js b/bower_components/react/JSXTransformer.js index 07cc91f..1234541 100644 --- a/bower_components/react/JSXTransformer.js +++ b/bower_components/react/JSXTransformer.js @@ -1,225 +1,1329 @@ /** - * JSXTransformer v0.8.0 + * JSXTransformer v0.9.0 */ -!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSXTransformer=e():"undefined"!=typeof global?global.JSXTransformer=e():"undefined"!=typeof self&&(self.JSXTransformer=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o i; ++i) { - if (array.hasOwnProperty(i)) { - if (isValueSet) { - value = callback(value, array[i], i, array); - } - else { - value = array[i]; - isValueSet = true; - } + if (canSetImmediate) { + return function (f) { return window.setImmediate(f) }; } - } - return value; -}; + if (canPost) { + var queue = []; + window.addEventListener('message', function (ev) { + var source = ev.source; + if ((source === window || source === null) && ev.data === 'process-tick') { + ev.stopPropagation(); + if (queue.length > 0) { + var fn = queue.shift(); + fn(); + } + } + }, true); -// String.prototype.substr - negative index don't work in IE8 -if ('ab'.substr(-1) !== 'b') { - exports.substr = function (str, start, length) { - // did we get a negative start, calculate how much it is from the beginning of the string - if (start < 0) start = str.length + start; - - // call the original function - return str.substr(start, length); - }; -} else { - exports.substr = function (str, start, length) { - return str.substr(start, length); - }; -} - -// String.prototype.trim is supported in IE9 -exports.trim = function (str) { - if (str.trim) return str.trim(); - return str.replace(/^\s+|\s+$/g, ''); -}; - -// Function.prototype.bind is supported in IE9 -exports.bind = function () { - var args = Array.prototype.slice.call(arguments); - var fn = args.shift(); - if (fn.bind) return fn.bind.apply(fn, args); - var self = args.shift(); - return function () { - fn.apply(self, args.concat([Array.prototype.slice.call(arguments)])); - }; -}; - -// Object.create is supported in IE9 -function create(prototype, properties) { - var object; - if (prototype === null) { - object = { '__proto__' : null }; - } - else { - if (typeof prototype !== 'object') { - throw new TypeError( - 'typeof prototype[' + (typeof prototype) + '] != \'object\'' - ); + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; } - var Type = function () {}; - Type.prototype = prototype; - object = new Type(); - object.__proto__ = prototype; - } - if (typeof properties !== 'undefined' && Object.defineProperties) { - Object.defineProperties(object, properties); - } - return object; -} -exports.create = typeof Object.create === 'function' ? Object.create : create; -// Object.keys and Object.getOwnPropertyNames is supported in IE9 however -// they do show a description and number property on Error objects -function notObject(object) { - return ((typeof object != "object" && typeof object != "function") || object === null); -} - -function keysShim(object) { - if (notObject(object)) { - throw new TypeError("Object.keys called on a non-object"); - } - - var result = []; - for (var name in object) { - if (hasOwnProperty.call(object, name)) { - result.push(name); - } - } - return result; -} - -// getOwnPropertyNames is almost the same as Object.keys one key feature -// is that it returns hidden properties, since that can't be implemented, -// this feature gets reduced so it just shows the length property on arrays -function propertyShim(object) { - if (notObject(object)) { - throw new TypeError("Object.getOwnPropertyNames called on a non-object"); - } - - var result = keysShim(object); - if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) { - result.push('length'); - } - return result; -} - -var keys = typeof Object.keys === 'function' ? Object.keys : keysShim; -var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ? - Object.getOwnPropertyNames : propertyShim; - -if (new Error().hasOwnProperty('description')) { - var ERROR_PROPERTY_FILTER = function (obj, array) { - if (toString.call(obj) === '[object Error]') { - array = exports.filter(array, function (name) { - return name !== 'description' && name !== 'number' && name !== 'message'; - }); - } - return array; - }; - - exports.keys = function (object) { - return ERROR_PROPERTY_FILTER(object, keys(object)); - }; - exports.getOwnPropertyNames = function (object) { - return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object)); - }; -} else { - exports.keys = keys; - exports.getOwnPropertyNames = getOwnPropertyNames; -} - -// Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements -function valueObject(value, key) { - return { value: value[key] }; -} - -if (typeof Object.getOwnPropertyDescriptor === 'function') { - try { - Object.getOwnPropertyDescriptor({'a': 1}, 'a'); - exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; - } catch (e) { - // IE8 dom element issue - use a try catch and default to valueObject - exports.getOwnPropertyDescriptor = function (value, key) { - try { - return Object.getOwnPropertyDescriptor(value, key); - } catch (e) { - return valueObject(value, key); - } + return function nextTick(fn) { + setTimeout(fn, 0); }; - } -} else { - exports.getOwnPropertyDescriptor = valueObject; +})(); + +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'); +}; + },{}],2:[function(require,module,exports){ +var base64 = require('base64-js') +var ieee754 = require('ieee754') + +exports.Buffer = Buffer +exports.SlowBuffer = Buffer +exports.INSPECT_MAX_BYTES = 50 +Buffer.poolSize = 8192 + +/** + * If `Buffer._useTypedArrays`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (compatible down to IE6) + */ +Buffer._useTypedArrays = (function () { + // Detect if browser supports Typed Arrays. Supported browsers are IE 10+, + // Firefox 4+, Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+. + if (typeof Uint8Array === 'undefined' || typeof ArrayBuffer === 'undefined') + return false + + // Does the browser support adding properties to `Uint8Array` instances? If + // not, then that's the same as no `Uint8Array` support. We need to be able to + // add all the node Buffer API methods. + // Relevant Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=695438 + try { + var arr = new Uint8Array(0) + arr.foo = function () { return 42 } + return 42 === arr.foo() && + typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray` + } catch (e) { + return false + } +})() + +/** + * Class: Buffer + * ============= + * + * The Buffer constructor returns instances of `Uint8Array` that are augmented + * with function properties for all the node `Buffer` API functions. We use + * `Uint8Array` so that square bracket notation works as expected -- it returns + * a single octet. + * + * By augmenting the instances, we can avoid modifying the `Uint8Array` + * prototype. + */ +function Buffer (subject, encoding, noZero) { + if (!(this instanceof Buffer)) + return new Buffer(subject, encoding, noZero) + + var type = typeof subject + + // Workaround: node's base64 implementation allows for non-padded strings + // while base64-js does not. + if (encoding === 'base64' && type === 'string') { + subject = stringtrim(subject) + while (subject.length % 4 !== 0) { + subject = subject + '=' + } + } + + // Find the length + var length + if (type === 'number') + length = coerce(subject) + else if (type === 'string') + length = Buffer.byteLength(subject, encoding) + else if (type === 'object') + length = coerce(subject.length) // Assume object is an array + else + throw new Error('First argument needs to be a number, array or string.') + + var buf + if (Buffer._useTypedArrays) { + // Preferred: Return an augmented `Uint8Array` instance for best performance + buf = augment(new Uint8Array(length)) + } else { + // Fallback: Return THIS instance of Buffer (created by `new`) + buf = this + buf.length = length + buf._isBuffer = true + } + + var i + if (Buffer._useTypedArrays && typeof Uint8Array === 'function' && + subject instanceof Uint8Array) { + // Speed optimization -- use set if we're copying from a Uint8Array + buf._set(subject) + } else if (isArrayish(subject)) { + // Treat array-ish objects as a byte array + for (i = 0; i < length; i++) { + if (Buffer.isBuffer(subject)) + buf[i] = subject.readUInt8(i) + else + buf[i] = subject[i] + } + } else if (type === 'string') { + buf.write(subject, 0, encoding) + } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) { + for (i = 0; i < length; i++) { + buf[i] = 0 + } + } + + return buf +} + +// STATIC METHODS +// ============== + +Buffer.isEncoding = function (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'binary': + case 'base64': + case 'raw': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.isBuffer = function (b) { + return !!(b !== null && b !== undefined && b._isBuffer) +} + +Buffer.byteLength = function (str, encoding) { + var ret + str = str + '' + switch (encoding || 'utf8') { + case 'hex': + ret = str.length / 2 + break + case 'utf8': + case 'utf-8': + ret = utf8ToBytes(str).length + break + case 'ascii': + case 'binary': + case 'raw': + ret = str.length + break + case 'base64': + ret = base64ToBytes(str).length + break + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + ret = str.length * 2 + break + default: + throw new Error('Unknown encoding') + } + return ret +} + +Buffer.concat = function (list, totalLength) { + assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' + + 'list should be an Array.') + + if (list.length === 0) { + return new Buffer(0) + } else if (list.length === 1) { + return list[0] + } + + var i + if (typeof totalLength !== 'number') { + totalLength = 0 + for (i = 0; i < list.length; i++) { + totalLength += list[i].length + } + } + + var buf = new Buffer(totalLength) + var pos = 0 + for (i = 0; i < list.length; i++) { + var item = list[i] + item.copy(buf, pos) + pos += item.length + } + return buf +} + +// BUFFER INSTANCE METHODS +// ======================= + +function _hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + // must be an even number of digits + var strLen = string.length + assert(strLen % 2 === 0, 'Invalid hex string') + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; i++) { + var byte = parseInt(string.substr(i * 2, 2), 16) + assert(!isNaN(byte), 'Invalid hex string') + buf[offset + i] = byte + } + Buffer._charsWritten = i * 2 + return i +} + +function _utf8Write (buf, string, offset, length) { + var charsWritten = Buffer._charsWritten = + blitBuffer(utf8ToBytes(string), buf, offset, length) + return charsWritten +} + +function _asciiWrite (buf, string, offset, length) { + var charsWritten = Buffer._charsWritten = + blitBuffer(asciiToBytes(string), buf, offset, length) + return charsWritten +} + +function _binaryWrite (buf, string, offset, length) { + return _asciiWrite(buf, string, offset, length) +} + +function _base64Write (buf, string, offset, length) { + var charsWritten = Buffer._charsWritten = + blitBuffer(base64ToBytes(string), buf, offset, length) + return charsWritten +} + +Buffer.prototype.write = function (string, offset, length, encoding) { + // Support both (string, offset, length, encoding) + // and the legacy (string, encoding, offset, length) + if (isFinite(offset)) { + if (!isFinite(length)) { + encoding = length + length = undefined + } + } else { // legacy + var swap = encoding + encoding = offset + offset = length + length = swap + } + + offset = Number(offset) || 0 + var remaining = this.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + encoding = String(encoding || 'utf8').toLowerCase() + + switch (encoding) { + case 'hex': + return _hexWrite(this, string, offset, length) + case 'utf8': + case 'utf-8': + case 'ucs2': // TODO: No support for ucs2 or utf16le encodings yet + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return _utf8Write(this, string, offset, length) + case 'ascii': + return _asciiWrite(this, string, offset, length) + case 'binary': + return _binaryWrite(this, string, offset, length) + case 'base64': + return _base64Write(this, string, offset, length) + default: + throw new Error('Unknown encoding') + } +} + +Buffer.prototype.toString = function (encoding, start, end) { + var self = this + + encoding = String(encoding || 'utf8').toLowerCase() + start = Number(start) || 0 + end = (end !== undefined) + ? Number(end) + : end = self.length + + // Fastpath empty strings + if (end === start) + return '' + + switch (encoding) { + case 'hex': + return _hexSlice(self, start, end) + case 'utf8': + case 'utf-8': + case 'ucs2': // TODO: No support for ucs2 or utf16le encodings yet + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return _utf8Slice(self, start, end) + case 'ascii': + return _asciiSlice(self, start, end) + case 'binary': + return _binarySlice(self, start, end) + case 'base64': + return _base64Slice(self, start, end) + default: + throw new Error('Unknown encoding') + } +} + +Buffer.prototype.toJSON = function () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function (target, target_start, start, end) { + var source = this + + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (!target_start) target_start = 0 + + // Copy 0 bytes; we're done + if (end === start) return + if (target.length === 0 || source.length === 0) return + + // Fatal error conditions + assert(end >= start, 'sourceEnd < sourceStart') + assert(target_start >= 0 && target_start < target.length, + 'targetStart out of bounds') + assert(start >= 0 && start < source.length, 'sourceStart out of bounds') + assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) + end = this.length + if (target.length - target_start < end - start) + end = target.length - target_start + start + + // copy! + for (var i = 0; i < end - start; i++) + target[i + target_start] = this[i + start] +} + +function _base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function _utf8Slice (buf, start, end) { + var res = '' + var tmp = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; i++) { + if (buf[i] <= 0x7F) { + res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]) + tmp = '' + } else { + tmp += '%' + buf[i].toString(16) + } + } + + return res + decodeUtf8Char(tmp) +} + +function _asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; i++) + ret += String.fromCharCode(buf[i]) + return ret +} + +function _binarySlice (buf, start, end) { + return _asciiSlice(buf, start, end) +} + +function _hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; i++) { + out += toHex(buf[i]) + } + return out +} + +// http://nodejs.org/api/buffer.html#buffer_buf_slice_start_end +Buffer.prototype.slice = function (start, end) { + var len = this.length + start = clamp(start, len, 0) + end = clamp(end, len, len) + + if (Buffer._useTypedArrays) { + return augment(this.subarray(start, end)) + } else { + var sliceLen = end - start + var newBuf = new Buffer(sliceLen, undefined, true) + for (var i = 0; i < sliceLen; i++) { + newBuf[i] = this[i + start] + } + return newBuf + } +} + +// `get` will be removed in Node 0.13+ +Buffer.prototype.get = function (offset) { + console.log('.get() is deprecated. Access using array indexes instead.') + return this.readUInt8(offset) +} + +// `set` will be removed in Node 0.13+ +Buffer.prototype.set = function (v, offset) { + console.log('.set() is deprecated. Access using array indexes instead.') + return this.writeUInt8(v, offset) +} + +Buffer.prototype.readUInt8 = function (offset, noAssert) { + if (!noAssert) { + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset < this.length, 'Trying to read beyond buffer length') + } + + if (offset >= this.length) + return + + return this[offset] +} + +function _readUInt16 (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) + return + + var val + if (littleEndian) { + val = buf[offset] + if (offset + 1 < len) + val |= buf[offset + 1] << 8 + } else { + val = buf[offset] << 8 + if (offset + 1 < len) + val |= buf[offset + 1] + } + return val +} + +Buffer.prototype.readUInt16LE = function (offset, noAssert) { + return _readUInt16(this, offset, true, noAssert) +} + +Buffer.prototype.readUInt16BE = function (offset, noAssert) { + return _readUInt16(this, offset, false, noAssert) +} + +function _readUInt32 (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) + return + + var val + if (littleEndian) { + if (offset + 2 < len) + val = buf[offset + 2] << 16 + if (offset + 1 < len) + val |= buf[offset + 1] << 8 + val |= buf[offset] + if (offset + 3 < len) + val = val + (buf[offset + 3] << 24 >>> 0) + } else { + if (offset + 1 < len) + val = buf[offset + 1] << 16 + if (offset + 2 < len) + val |= buf[offset + 2] << 8 + if (offset + 3 < len) + val |= buf[offset + 3] + val = val + (buf[offset] << 24 >>> 0) + } + return val +} + +Buffer.prototype.readUInt32LE = function (offset, noAssert) { + return _readUInt32(this, offset, true, noAssert) +} + +Buffer.prototype.readUInt32BE = function (offset, noAssert) { + return _readUInt32(this, offset, false, noAssert) +} + +Buffer.prototype.readInt8 = function (offset, noAssert) { + if (!noAssert) { + assert(offset !== undefined && offset !== null, + 'missing offset') + assert(offset < this.length, 'Trying to read beyond buffer length') + } + + if (offset >= this.length) + return + + var neg = this[offset] & 0x80 + if (neg) + return (0xff - this[offset] + 1) * -1 + else + return this[offset] +} + +function _readInt16 (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) + return + + var val = _readUInt16(buf, offset, littleEndian, true) + var neg = val & 0x8000 + if (neg) + return (0xffff - val + 1) * -1 + else + return val +} + +Buffer.prototype.readInt16LE = function (offset, noAssert) { + return _readInt16(this, offset, true, noAssert) +} + +Buffer.prototype.readInt16BE = function (offset, noAssert) { + return _readInt16(this, offset, false, noAssert) +} + +function _readInt32 (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) + return + + var val = _readUInt32(buf, offset, littleEndian, true) + var neg = val & 0x80000000 + if (neg) + return (0xffffffff - val + 1) * -1 + else + return val +} + +Buffer.prototype.readInt32LE = function (offset, noAssert) { + return _readInt32(this, offset, true, noAssert) +} + +Buffer.prototype.readInt32BE = function (offset, noAssert) { + return _readInt32(this, offset, false, noAssert) +} + +function _readFloat (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') + } + + return ieee754.read(buf, offset, littleEndian, 23, 4) +} + +Buffer.prototype.readFloatLE = function (offset, noAssert) { + return _readFloat(this, offset, true, noAssert) +} + +Buffer.prototype.readFloatBE = function (offset, noAssert) { + return _readFloat(this, offset, false, noAssert) +} + +function _readDouble (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset + 7 < buf.length, 'Trying to read beyond buffer length') + } + + return ieee754.read(buf, offset, littleEndian, 52, 8) +} + +Buffer.prototype.readDoubleLE = function (offset, noAssert) { + return _readDouble(this, offset, true, noAssert) +} + +Buffer.prototype.readDoubleBE = function (offset, noAssert) { + return _readDouble(this, offset, false, noAssert) +} + +Buffer.prototype.writeUInt8 = function (value, offset, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset < this.length, 'trying to write beyond buffer length') + verifuint(value, 0xff) + } + + if (offset >= this.length) return + + this[offset] = value +} + +function _writeUInt16 (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 1 < buf.length, 'trying to write beyond buffer length') + verifuint(value, 0xffff) + } + + var len = buf.length + if (offset >= len) + return + + for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) { + buf[offset + i] = + (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> + (littleEndian ? i : 1 - i) * 8 + } +} + +Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) { + _writeUInt16(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) { + _writeUInt16(this, value, offset, false, noAssert) +} + +function _writeUInt32 (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 3 < buf.length, 'trying to write beyond buffer length') + verifuint(value, 0xffffffff) + } + + var len = buf.length + if (offset >= len) + return + + for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) { + buf[offset + i] = + (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff + } +} + +Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) { + _writeUInt32(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) { + _writeUInt32(this, value, offset, false, noAssert) +} + +Buffer.prototype.writeInt8 = function (value, offset, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset < this.length, 'Trying to write beyond buffer length') + verifsint(value, 0x7f, -0x80) + } + + if (offset >= this.length) + return + + if (value >= 0) + this.writeUInt8(value, offset, noAssert) + else + this.writeUInt8(0xff + value + 1, offset, noAssert) +} + +function _writeInt16 (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 1 < buf.length, 'Trying to write beyond buffer length') + verifsint(value, 0x7fff, -0x8000) + } + + var len = buf.length + if (offset >= len) + return + + if (value >= 0) + _writeUInt16(buf, value, offset, littleEndian, noAssert) + else + _writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert) +} + +Buffer.prototype.writeInt16LE = function (value, offset, noAssert) { + _writeInt16(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeInt16BE = function (value, offset, noAssert) { + _writeInt16(this, value, offset, false, noAssert) +} + +function _writeInt32 (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') + verifsint(value, 0x7fffffff, -0x80000000) + } + + var len = buf.length + if (offset >= len) + return + + if (value >= 0) + _writeUInt32(buf, value, offset, littleEndian, noAssert) + else + _writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert) +} + +Buffer.prototype.writeInt32LE = function (value, offset, noAssert) { + _writeInt32(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeInt32BE = function (value, offset, noAssert) { + _writeInt32(this, value, offset, false, noAssert) +} + +function _writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') + verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + + var len = buf.length + if (offset >= len) + return + + ieee754.write(buf, value, offset, littleEndian, 23, 4) +} + +Buffer.prototype.writeFloatLE = function (value, offset, noAssert) { + _writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function (value, offset, noAssert) { + _writeFloat(this, value, offset, false, noAssert) +} + +function _writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert(value !== undefined && value !== null, 'missing value') + assert(typeof littleEndian === 'boolean', 'missing or invalid endian') + assert(offset !== undefined && offset !== null, 'missing offset') + assert(offset + 7 < buf.length, + 'Trying to write beyond buffer length') + verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + + var len = buf.length + if (offset >= len) + return + + ieee754.write(buf, value, offset, littleEndian, 52, 8) +} + +Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) { + _writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) { + _writeDouble(this, value, offset, false, noAssert) +} + +// fill(value, start=0, end=buffer.length) +Buffer.prototype.fill = function (value, start, end) { + if (!value) value = 0 + if (!start) start = 0 + if (!end) end = this.length + + if (typeof value === 'string') { + value = value.charCodeAt(0) + } + + assert(typeof value === 'number' && !isNaN(value), 'value is not a number') + assert(end >= start, 'end < start') + + // Fill 0 bytes; we're done + if (end === start) return + if (this.length === 0) return + + assert(start >= 0 && start < this.length, 'start out of bounds') + assert(end >= 0 && end <= this.length, 'end out of bounds') + + for (var i = start; i < end; i++) { + this[i] = value + } +} + +Buffer.prototype.inspect = function () { + var out = [] + var len = this.length + for (var i = 0; i < len; i++) { + out[i] = toHex(this[i]) + if (i === exports.INSPECT_MAX_BYTES) { + out[i + 1] = '...' + break + } + } + return '' +} + +/** + * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. + * Added in Node 0.12. Only available in browsers that support ArrayBuffer. + */ +Buffer.prototype.toArrayBuffer = function () { + if (typeof Uint8Array === 'function') { + if (Buffer._useTypedArrays) { + return (new Buffer(this)).buffer + } else { + var buf = new Uint8Array(this.length) + for (var i = 0, len = buf.length; i < len; i += 1) + buf[i] = this[i] + return buf.buffer + } + } else { + throw new Error('Buffer.toArrayBuffer not supported in this browser') + } +} + +// HELPER FUNCTIONS +// ================ + +function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') +} + +var BP = Buffer.prototype + +/** + * Augment the Uint8Array *instance* (not the class!) with Buffer methods + */ +function augment (arr) { + arr._isBuffer = true + + // save reference to original Uint8Array get/set methods before overwriting + arr._get = arr.get + arr._set = arr.set + + // deprecated, will be removed in node 0.13+ + arr.get = BP.get + arr.set = BP.set + + arr.write = BP.write + arr.toString = BP.toString + arr.toLocaleString = BP.toString + arr.toJSON = BP.toJSON + arr.copy = BP.copy + arr.slice = BP.slice + arr.readUInt8 = BP.readUInt8 + arr.readUInt16LE = BP.readUInt16LE + arr.readUInt16BE = BP.readUInt16BE + arr.readUInt32LE = BP.readUInt32LE + arr.readUInt32BE = BP.readUInt32BE + arr.readInt8 = BP.readInt8 + arr.readInt16LE = BP.readInt16LE + arr.readInt16BE = BP.readInt16BE + arr.readInt32LE = BP.readInt32LE + arr.readInt32BE = BP.readInt32BE + arr.readFloatLE = BP.readFloatLE + arr.readFloatBE = BP.readFloatBE + arr.readDoubleLE = BP.readDoubleLE + arr.readDoubleBE = BP.readDoubleBE + arr.writeUInt8 = BP.writeUInt8 + arr.writeUInt16LE = BP.writeUInt16LE + arr.writeUInt16BE = BP.writeUInt16BE + arr.writeUInt32LE = BP.writeUInt32LE + arr.writeUInt32BE = BP.writeUInt32BE + arr.writeInt8 = BP.writeInt8 + arr.writeInt16LE = BP.writeInt16LE + arr.writeInt16BE = BP.writeInt16BE + arr.writeInt32LE = BP.writeInt32LE + arr.writeInt32BE = BP.writeInt32BE + arr.writeFloatLE = BP.writeFloatLE + arr.writeFloatBE = BP.writeFloatBE + arr.writeDoubleLE = BP.writeDoubleLE + arr.writeDoubleBE = BP.writeDoubleBE + arr.fill = BP.fill + arr.inspect = BP.inspect + arr.toArrayBuffer = BP.toArrayBuffer + + return arr +} + +// slice(start, end) +function clamp (index, len, defaultValue) { + if (typeof index !== 'number') return defaultValue + index = ~~index; // Coerce to integer. + if (index >= len) return len + if (index >= 0) return index + index += len + if (index >= 0) return index + return 0 +} + +function coerce (length) { + // Coerce length to a number (possibly NaN), round up + // in case it's fractional (e.g. 123.456) then do a + // double negate to coerce a NaN to 0. Easy, right? + length = ~~Math.ceil(+length) + return length < 0 ? 0 : length +} + +function isArray (subject) { + return (Array.isArray || function (subject) { + return Object.prototype.toString.call(subject) === '[object Array]' + })(subject) +} + +function isArrayish (subject) { + return isArray(subject) || Buffer.isBuffer(subject) || + subject && typeof subject === 'object' && + typeof subject.length === 'number' +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; i++) { + var b = str.charCodeAt(i) + if (b <= 0x7F) + byteArray.push(str.charCodeAt(i)) + else { + var start = i + if (b >= 0xD800 && b <= 0xDFFF) i++ + var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%') + for (var j = 0; j < h.length; j++) + byteArray.push(parseInt(h[j], 16)) + } + } + return byteArray +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; i++) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(str) +} + +function blitBuffer (src, dst, offset, length) { + var pos + for (var i = 0; i < length; i++) { + if ((i + offset >= dst.length) || (i >= src.length)) + break + dst[i + offset] = src[i] + } + return i +} + +function decodeUtf8Char (str) { + try { + return decodeURIComponent(str) + } catch (err) { + return String.fromCharCode(0xFFFD) // UTF 8 invalid char + } +} + +/* + * We have to make sure that the value is a valid integer. This means that it + * is non-negative. It has no fractional component and that it does not + * exceed the maximum allowed value. + */ +function verifuint (value, max) { + assert(typeof value == 'number', 'cannot write a non-number as a number') + assert(value >= 0, + 'specified a negative value for writing an unsigned value') + assert(value <= max, 'value is larger than maximum value for type') + assert(Math.floor(value) === value, 'value has a fractional component') +} + +function verifsint(value, max, min) { + assert(typeof value == 'number', 'cannot write a non-number as a number') + assert(value <= max, 'value larger than maximum allowed value') + assert(value >= min, 'value smaller than minimum allowed value') + assert(Math.floor(value) === value, 'value has a fractional component') +} + +function verifIEEE754(value, max, min) { + assert(typeof value == 'number', 'cannot write a non-number as a number') + assert(value <= max, 'value larger than maximum allowed value') + assert(value >= min, 'value smaller than minimum allowed value') +} + +function assert (test, message) { + if (!test) throw new Error(message || 'Failed assertion') +} + +},{"base64-js":3,"ieee754":4}],3:[function(require,module,exports){ +var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +;(function (exports) { + 'use strict'; + + var Arr = (typeof Uint8Array !== 'undefined') + ? Uint8Array + : Array + + var ZERO = '0'.charCodeAt(0) + var PLUS = '+'.charCodeAt(0) + var SLASH = '/'.charCodeAt(0) + var NUMBER = '0'.charCodeAt(0) + var LOWER = 'a'.charCodeAt(0) + var UPPER = 'A'.charCodeAt(0) + + function decode (elt) { + var code = elt.charCodeAt(0) + if (code === PLUS) + return 62 // '+' + if (code === SLASH) + return 63 // '/' + if (code < NUMBER) + return -1 //no match + if (code < NUMBER + 10) + return code - NUMBER + 26 + 26 + if (code < UPPER + 26) + return code - UPPER + if (code < LOWER + 26) + return code - LOWER + 26 + } + + function b64ToByteArray (b64) { + var i, j, l, tmp, placeHolders, arr + + if (b64.length % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + var len = b64.length + placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 + + // base64 is 4/3 + up to two characters of the original data + arr = new Arr(b64.length * 3 / 4 - placeHolders) + + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? b64.length - 4 : b64.length + + var L = 0 + + function push (v) { + arr[L++] = v + } + + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) + push((tmp & 0xFF0000) >> 16) + push((tmp & 0xFF00) >> 8) + push(tmp & 0xFF) + } + + if (placeHolders === 2) { + tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) + push(tmp & 0xFF) + } else if (placeHolders === 1) { + tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) + push((tmp >> 8) & 0xFF) + push(tmp & 0xFF) + } + + return arr + } + + function uint8ToBase64 (uint8) { + var i, + extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes + output = "", + temp, length + + function encode (num) { + return lookup.charAt(num) + } + + function tripletToBase64 (num) { + return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) + } + + // go through the array every three bytes, we'll deal with trailing stuff later + for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { + temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + output += tripletToBase64(temp) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + switch (extraBytes) { + case 1: + temp = uint8[uint8.length - 1] + output += encode(temp >> 2) + output += encode((temp << 4) & 0x3F) + output += '==' + break + case 2: + temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) + output += encode(temp >> 10) + output += encode((temp >> 4) & 0x3F) + output += encode((temp << 2) & 0x3F) + output += '=' + break + } + + return output + } + + module.exports.toByteArray = b64ToByteArray + module.exports.fromByteArray = uint8ToBase64 +}()) + +},{}],4:[function(require,module,exports){ +exports.read = function(buffer, offset, isLE, mLen, nBytes) { + var e, m, + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + nBits = -7, + i = isLE ? (nBytes - 1) : 0, + d = isLE ? -1 : 1, + s = buffer[offset + i]; + + i += d; + + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); + + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity); + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); +}; + +exports.write = function(buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c, + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), + i = isLE ? 0 : (nBytes - 1), + d = isLE ? 1 : -1, + s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); + + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); + + buffer[offset + i - d] |= s * 128; +}; + +},{}],5:[function(require,module,exports){ var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -241,9 +1345,6 @@ var process=require("__browserify_process");// Copyright Joyent, Inc. and other // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -var util = require('util'); -var shims = require('_shims'); - // 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 @@ -292,7 +1393,7 @@ exports.resolve = function() { var path = (i >= 0) ? arguments[i] : process.cwd(); // Skip empty and invalid entries - if (!util.isString(path)) { + if (typeof path !== 'string') { throw new TypeError('Arguments to path.resolve must be strings'); } else if (!path) { continue; @@ -306,7 +1407,7 @@ exports.resolve = function() { // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path - resolvedPath = normalizeArray(shims.filter(resolvedPath.split('/'), function(p) { + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { return !!p; }), !resolvedAbsolute).join('/'); @@ -317,10 +1418,10 @@ exports.resolve = function() { // posix version exports.normalize = function(path) { var isAbsolute = exports.isAbsolute(path), - trailingSlash = shims.substr(path, -1) === '/'; + trailingSlash = substr(path, -1) === '/'; // Normalize the path - path = normalizeArray(shims.filter(path.split('/'), function(p) { + path = normalizeArray(filter(path.split('/'), function(p) { return !!p; }), !isAbsolute).join('/'); @@ -342,8 +1443,8 @@ exports.isAbsolute = function(path) { // posix version exports.join = function() { var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(shims.filter(paths, function(p, index) { - if (!util.isString(p)) { + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { throw new TypeError('Arguments to path.join must be strings'); } return p; @@ -430,606 +1531,25 @@ exports.extname = function(path) { return splitPath(path)[3]; }; -},{"__browserify_process":4,"_shims":1,"util":3}],3:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var shims = require('_shims'); - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); } - return objects.join(' '); - } + return res; +} - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; +; -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - - -function arrayToHash(array) { - var hash = {}; - - shims.forEach(array, function(val, idx) { - hash[val] = true; - }); - - return hash; -} - - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = shims.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = shims.getOwnPropertyNames(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - - shims.forEach(keys, function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = shims.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (shims.indexOf(ctx.seen, desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = shims.reduce(output, function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return shims.isArray(ar); -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg; -} -exports.isObject = isObject; - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return isObject(e) && objectToString(e) === '[object Error]'; -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.binarySlice === 'function' - ; -} -exports.isBuffer = isBuffer; - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; - - -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = function(ctor, superCtor) { - ctor.super_ = superCtor; - ctor.prototype = shims.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); -}; - -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = shims.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -},{"_shims":1}],4:[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'); -}; - -},{}],5:[function(require,module,exports){ +},{"__browserify_process":1}],6:[function(require,module,exports){ /* Copyright (C) 2013 Ariya Hidayat Copyright (C) 2013 Thaddee Tyl @@ -1146,15 +1666,15 @@ parseYieldExpression: true TokenName[Token.RegularExpression] = 'RegularExpression'; // A function following one of those tokens is an expression. - FnExprTokens = ["(", "{", "[", "in", "typeof", "instanceof", "new", - "return", "case", "delete", "throw", "void", + FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', + 'return', 'case', 'delete', 'throw', 'void', // assignment operators - "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", - "&=", "|=", "^=", ",", + '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', + '&=', '|=', '^=', ',', // binary/unary operators - "+", "-", "*", "/", "%", "++", "--", "<<", ">>", ">>>", "&", - "|", "^", "!", "~", "&&", "||", "?", ":", "===", "==", ">=", - "<=", "<", ">", "!=", "!=="]; + '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', + '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', + '<=', '<', '>', '!=', '!==']; Syntax = { ArrayExpression: 'ArrayExpression', @@ -1238,7 +1758,7 @@ parseYieldExpression: true }; ClassPropertyType = { - static: 'static', + 'static': 'static', prototype: 'prototype' }; @@ -2411,31 +2931,31 @@ parseYieldExpression: true // Nothing before that: it cannot be a division. return scanRegExp(); } - if (prevToken.type === "Punctuator") { - if (prevToken.value === ")") { + 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")) { + checkToken.type === 'Keyword' && + (checkToken.value === 'if' || + checkToken.value === 'while' || + checkToken.value === 'for' || + checkToken.value === 'with')) { return scanRegExp(); } return scanPunctuator(); } - if (prevToken.value === "}") { + 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") { + 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") { + extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { // Named function. checkToken = extra.tokens[extra.openCurlyToken - 5]; if (!checkToken) { @@ -2455,7 +2975,7 @@ parseYieldExpression: true } return scanRegExp(); } - if (prevToken.type === "Keyword") { + if (prevToken.type === 'Keyword') { return scanRegExp(); } return scanPunctuator(); @@ -2464,12 +2984,10 @@ parseYieldExpression: true function advance() { var ch; - if (state.inXJSChild) { - return advanceXJSChild(); + if (!state.inXJSChild) { + skipComment(); } - skipComment(); - if (index >= length) { return { type: Token.EOF, @@ -2479,6 +2997,10 @@ parseYieldExpression: true }; } + if (state.inXJSChild) { + return advanceXJSChild(); + } + ch = source.charCodeAt(index); // Very common: ( and ) and ; @@ -2715,7 +3237,7 @@ parseYieldExpression: true type: Syntax.ForOfStatement, left: left, right: right, - body: body, + body: body }; }, @@ -2762,13 +3284,13 @@ parseYieldExpression: true }; }, - createTypeAnnotation: function (typeIdentifier, paramTypes, returnType, isNullable) { + createTypeAnnotation: function (typeIdentifier, paramTypes, returnType, nullable) { return { type: Syntax.TypeAnnotation, id: typeIdentifier, paramTypes: paramTypes, returnType: returnType, - isNullable: isNullable + nullable: nullable }; }, @@ -2799,11 +3321,8 @@ parseYieldExpression: true createXJSElement: function (openingElement, closingElement, children) { return { type: Syntax.XJSElement, - name: openingElement.name, - selfClosing: openingElement.selfClosing, openingElement: openingElement, closingElement: closingElement, - attributes: openingElement.attributes, children: children }; }, @@ -3064,7 +3583,7 @@ parseYieldExpression: true key: key, value: value, kind: kind, - 'static': propertyType === ClassPropertyType.static + 'static': propertyType === ClassPropertyType["static"] }; }, @@ -3223,7 +3742,7 @@ parseYieldExpression: true throwError(token, Messages.UnexpectedNumber); } - if (token.type === Token.StringLiteral) { + if (token.type === Token.StringLiteral || token.type === Token.XJSText) { throwError(token, Messages.UnexpectedString); } @@ -3359,7 +3878,7 @@ parseYieldExpression: true throwError({}, Messages.ComprehensionError); } matchKeyword('for'); - tmp = parseForStatement({ignore_body: true}); + tmp = parseForStatement({ignoreBody: true}); tmp.of = tmp.type === Syntax.ForOfStatement; tmp.type = Syntax.ComprehensionBlock; if (tmp.left.kind) { // can't be let or const @@ -3622,13 +4141,9 @@ parseYieldExpression: true ++state.parenthesizedCount; - state.allowArrowFunction = !state.allowArrowFunction; expr = parseExpression(); - state.allowArrowFunction = false; - if (expr.type !== Syntax.ArrowFunctionExpression) { - expect(')'); - } + expect(')'); return expr; } @@ -4135,30 +4650,38 @@ parseYieldExpression: true params.push(param); defaults.push(null); } else if (param.type === Syntax.SpreadElement) { - assert(i === len - 1, "It is guaranteed that SpreadElement is last element by parseExpression"); + assert(i === len - 1, 'It is guaranteed that SpreadElement is last element by parseExpression'); reinterpretAsDestructuredParameter(options, param.argument); rest = param.argument; } else if (param.type === Syntax.AssignmentExpression) { params.push(param.left); defaults.push(param.right); ++defaultCount; + validateParam(options, param.left, param.left.name); } else { return null; } } - if (options.firstRestricted) { - throwError(options.firstRestricted, options.message); - } - if (options.stricted) { - throwErrorTolerant(options.stricted, options.message); + if (options.message === Messages.StrictParamDupe) { + throwError( + strict ? options.stricted : options.firstRestricted, + options.message + ); } if (defaultCount === 0) { defaults = []; } - return { params: params, defaults: defaults, rest: rest }; + return { + params: params, + defaults: defaults, + rest: rest, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; } function parseArrowFunctionExpression(options) { @@ -4168,9 +4691,16 @@ parseYieldExpression: true previousStrict = strict; previousYieldAllowed = state.yieldAllowed; - strict = true; state.yieldAllowed = false; body = parseConciseBody(); + + if (strict && options.firstRestricted) { + throwError(options.firstRestricted, options.message); + } + if (strict && options.stricted) { + throwErrorTolerant(options.stricted, options.message); + } + strict = previousStrict; state.yieldAllowed = previousYieldAllowed; @@ -4200,12 +4730,16 @@ parseYieldExpression: true 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 ], defaults: [], rest: null }); + if (match('=>') && + (state.parenthesizedCount === oldParenthesizedCount || + state.parenthesizedCount === (oldParenthesizedCount + 1))) { + if (expr.type === Syntax.Identifier) { + params = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.SequenceExpression) { + params = reinterpretAsCoverFormalsList(expr.expressions); + } + if (params) { + return parseArrowFunctionExpression(params); } } @@ -4231,7 +4765,9 @@ parseYieldExpression: true // 11.14 Comma Operator function parseExpression() { - var expr, expressions, sequence, coverFormalsList, spreadFound, token; + var expr, expressions, sequence, coverFormalsList, spreadFound, oldParenthesizedCount; + + oldParenthesizedCount = state.parenthesizedCount; expr = parseAssignmentExpression(); expressions = [ expr ]; @@ -4258,23 +4794,19 @@ parseYieldExpression: true sequence = delegate.createSequenceExpression(expressions); } - if (state.allowArrowFunction && match(')')) { - token = lookahead2(); - if (token.value === '=>') { - lex(); - - state.allowArrowFunction = false; - expr = expressions; + if (match('=>')) { + // Do not allow nested parentheses on the LHS of the =>. + if (state.parenthesizedCount === oldParenthesizedCount || state.parenthesizedCount === (oldParenthesizedCount + 1)) { + expr = expr.type === Syntax.SequenceExpression ? expr.expressions : expressions; coverFormalsList = reinterpretAsCoverFormalsList(expr); if (coverFormalsList) { return parseArrowFunctionExpression(coverFormalsList); } - - throwUnexpected(token); } + throwUnexpected(lex()); } - if (spreadFound) { + if (spreadFound && lookahead2().value !== '=>') { throwError({}, Messages.IllegalSpread); } @@ -4317,7 +4849,7 @@ parseYieldExpression: true function parseTypeAnnotation(dontExpectColon) { var typeIdentifier = null, paramTypes = null, returnType = null, - isNullable = false; + nullable = false; if (!dontExpectColon) { expect(':'); @@ -4325,7 +4857,7 @@ parseYieldExpression: true if (match('?')) { lex(); - isNullable = true; + nullable = true; } if (lookahead.type === Token.Identifier) { @@ -4355,7 +4887,7 @@ parseYieldExpression: true typeIdentifier, paramTypes, returnType, - isNullable + nullable ); } @@ -4709,7 +5241,7 @@ parseYieldExpression: true expectKeyword('for'); // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each - if (matchContextualKeyword("each")) { + if (matchContextualKeyword('each')) { throwError({}, Messages.EachNotAllowed); } @@ -4778,7 +5310,7 @@ parseYieldExpression: true oldInIteration = state.inIteration; state.inIteration = true; - if (!(opts !== undefined && opts.ignore_body)) { + if (!(opts !== undefined && opts.ignoreBody)) { body = parseStatement(); } @@ -5356,7 +5888,7 @@ parseYieldExpression: true } function parseFunctionDeclaration() { - var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator, expression; + var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator; expectKeyword('function'); @@ -5394,9 +5926,7 @@ parseYieldExpression: true previousYieldAllowed = state.yieldAllowed; state.yieldAllowed = generator; - // here we redo some work in order to set 'expression' - expression = !match('{'); - body = parseConciseBody(); + body = parseFunctionSourceElements(); if (strict && firstRestricted) { throwError(firstRestricted, message); @@ -5410,12 +5940,12 @@ parseYieldExpression: true strict = previousStrict; state.yieldAllowed = previousYieldAllowed; - return delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, expression, + return delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false, tmp.returnTypeAnnotation); } function parseFunctionExpression() { - var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator, expression; + var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator; expectKeyword('function'); @@ -5454,9 +5984,7 @@ parseYieldExpression: true previousYieldAllowed = state.yieldAllowed; state.yieldAllowed = generator; - // here we redo some work in order to set 'expression' - expression = !match('{'); - body = parseConciseBody(); + body = parseFunctionSourceElements(); if (strict && firstRestricted) { throwError(firstRestricted, message); @@ -5470,12 +5998,12 @@ parseYieldExpression: true strict = previousStrict; state.yieldAllowed = previousYieldAllowed; - return delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, expression, + return delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false, tmp.returnTypeAnnotation); } function parseYieldExpression() { - var delegateFlag, expr, previousYieldAllowed; + var delegateFlag, expr; expectKeyword('yield'); @@ -5489,11 +6017,7 @@ parseYieldExpression: true 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); @@ -5505,7 +6029,7 @@ parseYieldExpression: true var token, key, param, propType, isValidDuplicateProp = false; if (lookahead.value === 'static') { - propType = ClassPropertyType.static; + propType = ClassPropertyType["static"]; lex(); } else { propType = ClassPropertyType.prototype; @@ -5615,7 +6139,7 @@ parseYieldExpression: true function parseClassBody() { var classElement, classElements = [], existingProps = {}; - existingProps[ClassPropertyType.static] = {}; + existingProps[ClassPropertyType["static"]] = {}; existingProps[ClassPropertyType.prototype] = {}; expect('{'); @@ -6394,6 +6918,8 @@ parseYieldExpression: true 'expression' ); } + } else if (match('<')) { + value = parseXJSElement(); } else if (lookahead.type === Token.XJSText) { value = delegate.createLiteral(lex()); } else { @@ -6454,30 +6980,35 @@ parseYieldExpression: true } 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; + var name, origInXJSChild, origInXJSTag; + origInXJSChild = state.inXJSChild; origInXJSTag = state.inXJSTag; - state.inXJSTag = true; state.inXJSChild = false; + state.inXJSTag = true; expect('<'); expect('/'); name = parseXJSIdentifier(); + // Because advance() (called by lex() called by expect()) expects there + // to be a valid token after >, it needs to know whether to look for a + // standard JS token or an XJS text node + state.inXJSChild = origInXJSChild; state.inXJSTag = origInXJSTag; expect('>'); return delegate.createXJSClosingElement(name); } function parseXJSOpeningElement() { - var name, attribute, attributes = [], selfClosing = false, origInXJSTag; + var name, attribute, attributes = [], selfClosing = false, origInXJSChild, origInXJSTag; + origInXJSChild = state.inXJSChild; origInXJSTag = state.inXJSTag; + state.inXJSChild = false; state.inXJSTag = true; expect('<'); @@ -6494,6 +7025,10 @@ parseYieldExpression: true if (lookahead.value === '/') { expect('/'); + // Because advance() (called by lex() called by expect()) expects + // there to be a valid token after >, it needs to know whether to + // look for a standard JS token or an XJS text node + state.inXJSChild = origInXJSChild; expect('>'); selfClosing = true; } else { @@ -6504,14 +7039,15 @@ parseYieldExpression: true } function parseXJSElement() { - var openingElement, closingElement, children = [], origInXJSChild; + var openingElement, closingElement, children = [], origInXJSChild, origInXJSTag; + origInXJSChild = state.inXJSChild; + origInXJSTag = state.inXJSTag; openingElement = parseXJSOpeningElement(); if (!openingElement.selfClosing) { - origInXJSChild = state.inXJSChild; while (index < length) { - state.inXJSChild = false; // 0 && !mappingSeparator.test(str.charAt(0))) { // Original source. temp = base64VLQ.decode(str); - if (aSourceRoot) { - mapping.source = util.join(aSourceRoot, this._sources.at(previousSource + temp.value)); - } - else { - mapping.source = this._sources.at(previousSource + temp.value); - } + mapping.source = this._sources.at(previousSource + temp.value); previousSource += temp.value; str = temp.rest; if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { @@ -7929,42 +8520,14 @@ define(function (require, exports, module) { } } - this._generatedMappings.push(mapping); - this._originalMappings.push(mapping); + 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; + this.__originalMappings.sort(util.compareByOriginalPositions); }; /** @@ -8017,11 +8580,15 @@ define(function (require, exports, module) { this._generatedMappings, "generatedLine", "generatedColumn", - this._compareGeneratedPositions) + util.compareByGeneratedPositions); if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } return { - source: util.getArg(mapping, 'source', null), + source: source, line: util.getArg(mapping, 'originalLine', null), column: util.getArg(mapping, 'originalColumn', null), name: util.getArg(mapping, 'name', null) @@ -8036,6 +8603,47 @@ define(function (require, exports, module) { }; }; + /** + * 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) { + aSource = util.relative(this.sourceRoot, aSource); + } + + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } + + var url; + if (this.sourceRoot + && (url = util.urlParse(this.sourceRoot))) { + // XXX: file:// URIs and absolute paths lead to unexpected behavior for + // many users. We can help them out when they expect file:// URIs to + // behave like it would if they were running a local HTTP server. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. + var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); + if (url.scheme == "file" + && this._sources.has(fileUriAbsPath)) { + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + } + + if ((!url.path || url.path == "/") + && 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 @@ -8058,11 +8666,15 @@ define(function (require, exports, module) { 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) + util.compareByOriginalPositions); if (mapping) { return { @@ -8085,8 +8697,7 @@ define(function (require, exports, module) { * generated line/column in this source map. * * @param Function aCallback - * The function that is called with each mapping. This function should - * not mutate the mapping. + * 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. @@ -8114,14 +8725,28 @@ define(function (require, exports, module) { throw new Error("Unknown order of iteration."); } - mappings.forEach(aCallback, context); + 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; }); -},{"./array-set":8,"./base64-vlq":9,"./binary-search":11,"./util":15,"amdefine":16}],13:[function(require,module,exports){ +},{"./array-set":9,"./base64-vlq":10,"./binary-search":12,"./util":16,"amdefine":17}],14:[function(require,module,exports){ /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors @@ -8129,7 +8754,7 @@ define(function (require, exports, module) { * http://opensource.org/licenses/BSD-3-Clause */ if (typeof define !== 'function') { - var define = require('amdefine')(module); + var define = require('amdefine')(module, require); } define(function (require, exports, module) { @@ -8151,10 +8776,58 @@ define(function (require, exports, module) { 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 @@ -8183,13 +8856,119 @@ define(function (require, exports, module) { } this._mappings.push({ - generated: generated, - original: original, + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, 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.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.originalLine = original.line; + mapping.originalColumn = 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: * @@ -8219,7 +8998,12 @@ define(function (require, exports, module) { return; } else { - throw new Error('Invalid mapping.'); + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); } }; @@ -8238,51 +9022,49 @@ define(function (require, exports, module) { var result = ''; var mapping; - // The mappings must be guarenteed to be in sorted order before we start + // The mappings must be guaranteed 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(function (mappingA, mappingB) { - var cmp = mappingA.generated.line - mappingB.generated.line; - return cmp === 0 - ? mappingA.generated.column - mappingB.generated.column - : cmp; - }); + this._mappings.sort(util.compareByGeneratedPositions); for (var i = 0, len = this._mappings.length; i < len; i++) { mapping = this._mappings[i]; - if (mapping.generated.line !== previousGeneratedLine) { + if (mapping.generatedLine !== previousGeneratedLine) { previousGeneratedColumn = 0; - while (mapping.generated.line !== previousGeneratedLine) { + while (mapping.generatedLine !== previousGeneratedLine) { result += ';'; previousGeneratedLine++; } } else { if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } result += ','; } } - result += base64VLQ.encode(mapping.generated.column + result += base64VLQ.encode(mapping.generatedColumn - previousGeneratedColumn); - previousGeneratedColumn = mapping.generated.column; + previousGeneratedColumn = mapping.generatedColumn; - if (mapping.source && mapping.original) { + if (mapping.source) { 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 + result += base64VLQ.encode(mapping.originalLine - 1 - previousOriginalLine); - previousOriginalLine = mapping.original.line - 1; + previousOriginalLine = mapping.originalLine - 1; - result += base64VLQ.encode(mapping.original.column + result += base64VLQ.encode(mapping.originalColumn - previousOriginalColumn); - previousOriginalColumn = mapping.original.column; + previousOriginalColumn = mapping.originalColumn; if (mapping.name) { result += base64VLQ.encode(this._names.indexOf(mapping.name) @@ -8295,6 +9077,23 @@ define(function (require, exports, module) { return result; }; + SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, + key) + ? this._sourcesContents[key] + : null; + }, this); + }; + /** * Externalize the source map. */ @@ -8310,6 +9109,10 @@ define(function (require, exports, module) { if (this._sourceRoot) { map.sourceRoot = this._sourceRoot; } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + return map; }; @@ -8325,7 +9128,7 @@ define(function (require, exports, module) { }); -},{"./array-set":8,"./base64-vlq":9,"./util":15,"amdefine":16}],14:[function(require,module,exports){ +},{"./array-set":9,"./base64-vlq":10,"./util":16,"amdefine":17}],15:[function(require,module,exports){ /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors @@ -8333,11 +9136,12 @@ define(function (require, exports, module) { * http://opensource.org/licenses/BSD-3-Clause */ if (typeof define !== 'function') { - var define = require('amdefine')(module); + var define = require('amdefine')(module, require); } 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 @@ -8349,15 +9153,121 @@ define(function (require, exports, module) { * @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) { + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { this.children = []; - this.line = aLine; - this.column = aColumn; - this.source = aSource; + 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 === null || 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. * @@ -8414,16 +9324,21 @@ define(function (require, exports, module) { * @param aFn The traversal function. */ SourceNode.prototype.walk = function SourceNode_walk(aFn) { - this.children.forEach(function (chunk) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; if (chunk instanceof SourceNode) { chunk.walk(aFn); } else { if (chunk !== '') { - aFn(chunk, { source: this.source, line: this.line, column: this.column }); + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); } } - }, this); + } }; /** @@ -8435,7 +9350,7 @@ define(function (require, exports, module) { SourceNode.prototype.join = function SourceNode_join(aSep) { var newChildren; var i; - var len = this.children.length + var len = this.children.length; if (len > 0) { newChildren = []; for (i = 0; i < len-1; i++) { @@ -8469,6 +9384,38 @@ define(function (require, exports, module) { 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) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); + } + }; + /** * Return the string representation of this source node. Walks over the tree * and concatenates all the various snippets together to one string. @@ -8492,25 +9439,50 @@ define(function (require, exports, module) { column: 0 }; var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; this.walk(function (chunk, original) { generated.code += chunk; - if (original.source != null - && original.line != null - && original.column != null) { + if (original.source !== null + && original.line !== null + && original.column !== null) { + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; + sourceMappingActive = true; + } else if (sourceMappingActive) { map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, generated: { line: generated.line, column: generated.column } }); + lastOriginalSource = null; + sourceMappingActive = false; } - chunk.split('').forEach(function (char) { - if (char === '\n') { + chunk.split('').forEach(function (ch) { + if (ch === '\n') { generated.line++; generated.column = 0; } else { @@ -8518,6 +9490,9 @@ define(function (require, exports, module) { } }); }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); return { code: generated.code, map: map }; }; @@ -8526,7 +9501,7 @@ define(function (require, exports, module) { }); -},{"./source-map-generator":13,"amdefine":16}],15:[function(require,module,exports){ +},{"./source-map-generator":14,"./util":16,"amdefine":17}],16:[function(require,module,exports){ /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors @@ -8534,7 +9509,7 @@ define(function (require, exports, module) { * http://opensource.org/licenses/BSD-3-Clause */ if (typeof define !== 'function') { - var define = require('amdefine')(module); + var define = require('amdefine')(module, require); } define(function (require, exports, module) { @@ -8559,16 +9534,181 @@ define(function (require, exports, module) { } exports.getArg = getArg; + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + 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] + }; + } + exports.urlParse = urlParse; + + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; + function join(aRoot, aPath) { - return aPath.charAt(0) === '/' - ? aPath - : aRoot.replace(/\/*$/, '') + '/' + aPath; + var url; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + 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(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + function strcmp(aStr1, aStr2) { + var s1 = aStr1 || ""; + var s2 = aStr2 || ""; + return (s1 > s2) - (s1 < s2); + } + + /** + * Comparator between two mappings where the original positions are compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. + */ + function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp; + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp || onlyCompareOriginal) { + return cmp; + } + + cmp = strcmp(mappingA.name, mappingB.name); + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + return mappingA.generatedColumn - mappingB.generatedColumn; + }; + exports.compareByOriginalPositions = compareByOriginalPositions; + + /** + * Comparator between two mappings where the generated positions are + * compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. + */ + function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) { + var cmp; + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp || onlyCompareGenerated) { + return cmp; + } + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp) { + return cmp; + } + + return strcmp(mappingA.name, mappingB.name); + }; + exports.compareByGeneratedPositions = compareByGeneratedPositions; + }); -},{"amdefine":16}],16:[function(require,module,exports){ +},{"amdefine":17}],17:[function(require,module,exports){ var process=require("__browserify_process"),__filename="/../node_modules/jstransform/node_modules/source-map/node_modules/amdefine/amdefine.js";/** vim: et:ts=4:sw=4:sts=4 * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. @@ -8869,7 +10009,7 @@ function amdefine(module, requireFn) { module.exports = amdefine; -},{"__browserify_process":4,"path":2}],17:[function(require,module,exports){ +},{"__browserify_process":1,"path":5}],18:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -8902,7 +10042,7 @@ function extract(contents) { var commentStartRe = /^\/\*\*?/; -var commentEndRe = /\*\/$/; +var commentEndRe = /\*+\/$/; var wsRe = /[\t ]+/g; var stringStartRe = /(\r?\n|^) *\*/g; var multilineRe = /(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *([^@\r\n\s][^@\r\n]+?) *\r?\n/g; @@ -8957,7 +10097,7 @@ exports.extract = extract; exports.parse = parse; exports.parseAsObject = parseAsObject; -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -8986,11 +10126,7 @@ exports.parseAsObject = parseAsObject; * AST tree, and returns the resulting output. */ var esprima = require('esprima-fb'); - -var createState = require('./utils').createState; -var catchup = require('./utils').catchup; -var updateState = require('./utils').updateState; -var analyzeAndTraverse = require('./utils').analyzeAndTraverse; +var utils = require('./utils'); var Syntax = esprima.Syntax; @@ -9040,11 +10176,11 @@ function traverse(node, path, state) { && node.body[0].expression.value === 'use strict'; if (node.type === Syntax.Program) { - state = updateState(state, { + state = utils.updateState(state, { scopeIsStrict: scopeIsStrict }); } else { - state = updateState(state, { + state = utils.updateState(state, { localScope: { parentNode: parentNode, parentScope: state.localScope, @@ -9081,7 +10217,7 @@ function traverse(node, path, state) { } if (_nodeIsBlockScopeBoundary(node, parentNode)) { - state = updateState(state, { + state = utils.updateState(state, { localScope: { parentNode: parentNode, parentScope: state.localScope, @@ -9098,16 +10234,16 @@ function traverse(node, path, state) { // Only catchup() before and after traversing a child node function traverser(node, path, state) { - node.range && catchup(node.range[0], state); + node.range && utils.catchup(node.range[0], state); traverse(node, path, state); - node.range && catchup(node.range[1], state); + node.range && utils.catchup(node.range[1], state); } - analyzeAndTraverse(walker, traverser, node, path, state); + utils.analyzeAndTraverse(walker, traverser, node, path, state); } function collectClosureIdentsAndTraverse(node, path, state) { - analyzeAndTraverse( + utils.analyzeAndTraverse( visitLocalClosureIdentifiers, collectClosureIdentsAndTraverse, node, @@ -9117,7 +10253,7 @@ function collectClosureIdentsAndTraverse(node, path, state) { } function collectBlockIdentsAndTraverse(node, path, state) { - analyzeAndTraverse( + utils.analyzeAndTraverse( visitLocalBlockIdentifiers, collectBlockIdentsAndTraverse, node, @@ -9185,7 +10321,7 @@ function transform(visitors, source, options) { e.message = 'Parse Error: ' + e.message; throw e; } - var state = createState(source, ast, options); + var state = utils.createState(source, ast, options); state.g.visitors = visitors; if (options.sourceMap) { @@ -9194,7 +10330,7 @@ function transform(visitors, source, options) { } traverse(ast, [], state); - catchup(source.length, state); + utils.catchup(source.length, state); var ret = {code: state.g.buffer}; if (options.sourceMap) { @@ -9206,7 +10342,7 @@ function transform(visitors, source, options) { exports.transform = transform; -},{"./utils":19,"esprima-fb":5,"source-map":7}],19:[function(require,module,exports){ +},{"./utils":20,"esprima-fb":6,"source-map":8}],20:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -9687,7 +10823,126 @@ exports.updateIndent = updateIndent; exports.updateState = updateState; exports.analyzeAndTraverse = analyzeAndTraverse; -},{"./docblock":17}],20:[function(require,module,exports){ +},{"./docblock":18}],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. + */ + +/*global exports:true*/ + +/** + * Desugars ES6 Arrow functions to ES3 function expressions. + * If the function contains `this` expression -- automatically + * binds the funciton to current value of `this`. + * + * Single parameter, simple expression: + * + * [1, 2, 3].map(x => x * x); + * + * [1, 2, 3].map(function(x) { return x * x; }); + * + * Several parameters, complex block: + * + * this.users.forEach((user, idx) => { + * return this.isActive(idx) && this.send(user); + * }); + * + * this.users.forEach(function(user, idx) { + * return this.isActive(idx) && this.send(user); + * }.bind(this)); + * + */ +var restParamVisitors = require('./es6-rest-param-visitors'); +var Syntax = require('esprima-fb').Syntax; +var utils = require('../src/utils'); + +/** + * @public + */ +function visitArrowFunction(traverse, node, path, state) { + // Prologue. + utils.append('function', state); + renderParams(node, state); + + // Skip arrow. + utils.catchupWhiteSpace(node.body.range[0], state); + + var renderBody = node.body.type == Syntax.BlockStatement + ? renderStatementBody + : renderExpressionBody; + + path.unshift(node); + renderBody(traverse, node, path, state); + path.shift(); + + // Bind the function only if `this` value is used + // inside it or inside any sub-expression. + if (utils.containsChildOfType(node.body, Syntax.ThisExpression)) { + utils.append('.bind(this)', state); + } + + return false; +} + +function renderParams(node, state) { + // To preserve inline typechecking directives, we + // distinguish between parens-free and paranthesized single param. + if (isParensFreeSingleParam(node, state) || !node.params.length) { + utils.append('(', state); + } + if (node.params.length !== 0) { + utils.catchup(node.params[node.params.length - 1].range[1], state); + } + utils.append(')', state); +} + +function isParensFreeSingleParam(node, state) { + return node.params.length === 1 && + state.g.source[state.g.position] !== '('; +} + +function renderExpressionBody(traverse, node, path, state) { + // Wrap simple expression bodies into a block + // with explicit return statement. + utils.append('{', state); + if (node.rest) { + utils.append( + restParamVisitors.renderRestParamSetup(node), + state + ); + } + utils.append('return ', state); + renderStatementBody(traverse, node, path, state); + utils.append(';}', state); +} + +function renderStatementBody(traverse, node, path, state) { + traverse(node.body, path, state); + utils.catchup(node.body.range[1], state); +} + +visitArrowFunction.test = function(node, path, state) { + return node.type === Syntax.ArrowFunctionExpression; +}; + +exports.visitorList = [ + visitArrowFunction +]; + + +},{"../src/utils":20,"./es6-rest-param-visitors":24,"esprima-fb":6}],22:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -9855,7 +11110,7 @@ function visitClassFunctionExpression(traverse, node, path, state) { methodName = _getMungedName(methodName, state); } - var prototypeOrStatic = methodNode.static ? '' : 'prototype.'; + var prototypeOrStatic = methodNode["static"] ? '' : 'prototype.'; utils.append( state.className + '.' + prototypeOrStatic + methodName + '=function', state @@ -10167,7 +11422,7 @@ exports.visitorList = [ visitSuperMemberExpression ]; -},{"../src/utils":19,"base62":6,"esprima-fb":5}],21:[function(require,module,exports){ +},{"../src/utils":20,"base62":7,"esprima-fb":6}],23:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -10183,6 +11438,292 @@ exports.visitorList = [ * See the License for the specific language governing permissions and * limitations under the License. */ + +/*jslint node: true*/ + +/** + * Desugars ES6 Object Literal short notations into ES3 full notation. + * + * // Easier return values. + * function foo(x, y) { + * return {x, y}; // {x: x, y: y} + * }; + * + * // Destrucruting. + * function init({port, ip, coords: {x, y}}) { ... } + * + */ +var Syntax = require('esprima-fb').Syntax; +var utils = require('../src/utils'); + +/** + * @public + */ +function visitObjectLiteralShortNotation(traverse, node, path, state) { + utils.catchup(node.key.range[1], state); + utils.append(':' + node.key.name, state); + return false; +} + +visitObjectLiteralShortNotation.test = function(node, path, state) { + return node.type === Syntax.Property && + node.kind === 'init' && + node.shorthand === true; +}; + +exports.visitorList = [ + visitObjectLiteralShortNotation +]; + + +},{"../src/utils":20,"esprima-fb":6}],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. + */ + +/*jslint node:true*/ + +/** + * Desugars ES6 rest parameters into ES3 arguments slicing. + * + * function printf(template, ...args) { + * args.forEach(...); + * }; + * + * function printf(template) { + * var args = [].slice.call(arguments, 1); + * args.forEach(...); + * }; + * + */ +var Syntax = require('esprima-fb').Syntax; +var utils = require('../src/utils'); + +function _nodeIsFunctionWithRestParam(node) { + return (node.type === Syntax.FunctionDeclaration + || node.type === Syntax.FunctionExpression + || node.type === Syntax.ArrowFunctionExpression) + && node.rest; +} + +function visitFunctionParamsWithRestParam(traverse, node, path, state) { + // Render params. + if (node.params.length) { + utils.catchup(node.params[node.params.length - 1].range[1], state); + } else { + // -3 is for ... of the rest. + utils.catchup(node.rest.range[0] - 3, state); + } + utils.catchupWhiteSpace(node.rest.range[1], state); +} + +visitFunctionParamsWithRestParam.test = function(node, path, state) { + return _nodeIsFunctionWithRestParam(node); +}; + +function renderRestParamSetup(functionNode) { + return 'var ' + functionNode.rest.name + '=Array.prototype.slice.call(' + + 'arguments,' + + functionNode.params.length + + ');'; +} + +function visitFunctionBodyWithRestParam(traverse, node, path, state) { + utils.catchup(node.range[0] + 1, state); + var parentNode = path[0]; + utils.append(renderRestParamSetup(parentNode), state); + traverse(node.body, path, state); + return false; +} + +visitFunctionBodyWithRestParam.test = function(node, path, state) { + return node.type === Syntax.BlockStatement + && _nodeIsFunctionWithRestParam(path[0]); +}; + +exports.renderRestParamSetup = renderRestParamSetup; +exports.visitorList = [ + visitFunctionParamsWithRestParam, + visitFunctionBodyWithRestParam +]; + +},{"../src/utils":20,"esprima-fb":6}],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. + */ + +/*jslint node:true*/ + +/** + * @typechecks + */ +'use strict'; + +var Syntax = require('esprima-fb').Syntax; +var utils = require('../src/utils'); + +/** + * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.1.9 + */ +function visitTemplateLiteral(traverse, node, path, state) { + var templateElements = node.quasis; + + utils.append('(', state); + for (var ii = 0; ii < templateElements.length; ii++) { + var templateElement = templateElements[ii]; + if (templateElement.value.raw !== '') { + utils.append(getCookedValue(templateElement), state); + if (!templateElement.tail) { + // + between element and substitution + utils.append(' + ', state); + } + // maintain line numbers + utils.move(templateElement.range[0], state); + utils.catchupNewlines(templateElement.range[1], state); + } + utils.move(templateElement.range[1], state); + if (!templateElement.tail) { + var substitution = node.expressions[ii]; + if (substitution.type === Syntax.Identifier || + substitution.type === Syntax.MemberExpression || + substitution.type === Syntax.CallExpression) { + utils.catchup(substitution.range[1], state); + } else { + utils.append('(', state); + traverse(substitution, path, state); + utils.catchup(substitution.range[1], state); + utils.append(')', state); + } + // if next templateElement isn't empty... + if (templateElements[ii + 1].value.cooked !== '') { + utils.append(' + ', state); + } + } + } + utils.move(node.range[1], state); + utils.append(')', state); + return false; +} + +visitTemplateLiteral.test = function(node, path, state) { + return node.type === Syntax.TemplateLiteral; +}; + +/** + * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.2.6 + */ +function visitTaggedTemplateExpression(traverse, node, path, state) { + var template = node.quasi; + var numQuasis = template.quasis.length; + + // print the tag + utils.move(node.tag.range[0], state); + traverse(node.tag, path, state); + utils.catchup(node.tag.range[1], state); + + // print array of template elements + utils.append('(function() { var siteObj = [', state); + for (var ii = 0; ii < numQuasis; ii++) { + utils.append(getCookedValue(template.quasis[ii]), state); + if (ii !== numQuasis - 1) { + utils.append(', ', state); + } + } + utils.append(']; siteObj.raw = [', state); + for (ii = 0; ii < numQuasis; ii++) { + utils.append(getRawValue(template.quasis[ii]), state); + if (ii !== numQuasis - 1) { + utils.append(', ', state); + } + } + utils.append( + ']; Object.freeze(siteObj.raw); Object.freeze(siteObj); return siteObj; }()', + state + ); + + // print substitutions + if (numQuasis > 1) { + for (ii = 0; ii < template.expressions.length; ii++) { + var expression = template.expressions[ii]; + utils.append(', ', state); + + // maintain line numbers by calling catchupWhiteSpace over the whole + // previous TemplateElement + utils.move(template.quasis[ii].range[0], state); + utils.catchupNewlines(template.quasis[ii].range[1], state); + + utils.move(expression.range[0], state); + traverse(expression, path, state); + utils.catchup(expression.range[1], state); + } + } + + // print blank lines to push the closing ) down to account for the final + // TemplateElement. + utils.catchupNewlines(node.range[1], state); + + utils.append(')', state); + + return false; +} + +visitTaggedTemplateExpression.test = function(node, path, state) { + return node.type === Syntax.TaggedTemplateExpression; +}; + +function getCookedValue(templateElement) { + return JSON.stringify(templateElement.value.cooked); +} + +function getRawValue(templateElement) { + return JSON.stringify(templateElement.value.raw); +} + +exports.visitorList = [ + visitTemplateLiteral, + visitTaggedTemplateExpression +]; + +},{"../src/utils":20,"esprima-fb":6}],26:[function(require,module,exports){ +/** + * Copyright 2013-2014 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. + */ /* jshint browser: true */ /* jslint evil: true */ @@ -10190,30 +11731,119 @@ exports.visitorList = [ var runScripts; var headEl; +var buffer = require('buffer'); var transform = require('jstransform').transform; var visitors = require('./fbtransform/visitors').transformVisitors; -var transform = transform.bind(null, visitors.react); var docblock = require('jstransform/src/docblock'); +// The source-map library relies on Object.defineProperty, but IE8 doesn't +// support it fully even with es5-sham. Indeed, es5-sham's defineProperty +// throws when Object.prototype.__defineGetter__ is missing, so we skip building +// the source map in that case. +var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__'); -exports.transform = transform; +function transformReact(source) { + return transform(visitors.react, source, { + sourceMap: supportsAccessors + }); +} + +exports.transform = transformReact; exports.exec = function(code) { - return eval(transform(code).code); + return eval(transformReact(code).code); }; -if (typeof window === "undefined" || window === null) { - return; -} -headEl = document.getElementsByTagName('head')[0]; +var inlineScriptCount = 0; -var run = exports.run = function(code) { +// This method returns a nicely formated line of code pointing the +// exactly location of the error `e`. +// The line is limited in size so big lines of code are also shown +// in a readable way. +// Example: +// +// ... x', overflow:'scroll'}} id={} onScroll={this.scroll} class=" ... +// ^ +var createSourceCodeErrorMessage = function(code, e) { + var sourceLines = code.split('\n'); + var erroneousLine = sourceLines[e.lineNumber - 1]; + + // Removes any leading indenting spaces and gets the number of + // chars indenting the `erroneousLine` + var indentation = 0; + erroneousLine = erroneousLine.replace(/^\s+/, function(leadingSpaces) { + indentation = leadingSpaces.length; + return ''; + }); + + // Defines the number of characters that are going to show + // before and after the erroneous code + var LIMIT = 30; + var errorColumn = e.column - indentation; + + if (errorColumn > LIMIT) { + erroneousLine = '... ' + erroneousLine.slice(errorColumn - LIMIT); + errorColumn = 4 + LIMIT; + } + if (erroneousLine.length - errorColumn > LIMIT) { + erroneousLine = erroneousLine.slice(0, errorColumn + LIMIT) + ' ...'; + } + var message = '\n\n' + erroneousLine + '\n'; + message += new Array(errorColumn - 1).join(' ') + '^'; + return message; +}; + +var transformCode = function(code, source) { var jsx = docblock.parseAsObject(docblock.extract(code)).jsx; - var functionBody = jsx ? transform(code).code : code; - var scriptEl = document.createElement('script'); + if (jsx) { + try { + var transformed = transformReact(code); + } catch(e) { + e.message += '\n at '; + if (source) { + if ('fileName' in e) { + // We set `fileName` if it's supported by this error object and + // a `source` was provided. + // The error will correctly point to `source` in Firefox. + e.fileName = source; + } + e.message += source + ':' + e.lineNumber + ':' + e.column; + } else { + e.message += location.href; + } + e.message += createSourceCodeErrorMessage(code, e); + throw e; + } - scriptEl.text = functionBody; + if (!transformed.sourceMap) { + return transformed.code; + } + + var map = transformed.sourceMap.toJSON(); + if (source == null) { + source = "Inline JSX script"; + inlineScriptCount++; + if (inlineScriptCount > 1) { + source += ' (' + inlineScriptCount + ')'; + } + } + map.sources = [source]; + map.sourcesContent = [code]; + + return ( + transformed.code + + '//# sourceMappingURL=data:application/json;base64,' + + buffer.Buffer(JSON.stringify(map)).toString('base64') + ); + } else { + return code; + } +}; + +var run = exports.run = function(code, source) { + var scriptEl = document.createElement('script'); + scriptEl.text = transformCode(code, source); headEl.appendChild(scriptEl); }; @@ -10231,7 +11861,7 @@ var load = exports.load = function(url, callback) { xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 0 || xhr.status === 200) { - run(xhr.responseText); + run(xhr.responseText, url); } else { throw new Error("Could not load " + url); } @@ -10245,7 +11875,7 @@ var load = exports.load = function(url, callback) { runScripts = function() { var scripts = document.getElementsByTagName('script'); - + // Array.prototype.slice cannot be used on NodeList on IE8 var jsxScripts = []; for (var i = 0; i < scripts.length; i++) { @@ -10253,27 +11883,31 @@ runScripts = function() { jsxScripts.push(scripts.item(i)); } } - + console.warn("You are using the in-browser JSX transformer. Be sure to precompile your JSX for production - http://facebook.github.io/react/docs/tooling-integration.html#jsx"); jsxScripts.forEach(function(script) { if (script.src) { load(script.src); } else { - run(script.innerHTML); + run(script.innerHTML, null); } }); }; -if (window.addEventListener) { - window.addEventListener('DOMContentLoaded', runScripts, false); -} else { - window.attachEvent('onload', runScripts); +if (typeof window !== "undefined" && window !== null) { + headEl = document.getElementsByTagName('head')[0]; + + if (window.addEventListener) { + window.addEventListener('DOMContentLoaded', runScripts, false); + } else { + window.attachEvent('onload', runScripts); + } } -},{"./fbtransform/visitors":25,"jstransform":18,"jstransform/src/docblock":17}],22:[function(require,module,exports){ +},{"./fbtransform/visitors":30,"buffer":2,"jstransform":19,"jstransform/src/docblock":18}],27:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -10315,44 +11949,40 @@ var quoteAttrName = require('./xjs').quoteAttrName; 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(',') + ')'; - } + throw new Error( + "cxName is no longer supported, use className={cx(...)} instead" + ); } }; function visitReactTag(traverse, object, path, state) { var jsxObjIdent = utils.getDocblock(state).jsx; + var openingElement = object.openingElement; + var nameObject = openingElement.name; + var attributesObject = openingElement.attributes; - utils.catchup(object.openingElement.range[0], state); + utils.catchup(openingElement.range[0], state); - if (object.name.namespace) { + if (nameObject.namespace) { throw new Error( 'Namespace tags are not supported. ReactJSX is not XML.'); } - var isFallbackTag = FALLBACK_TAGS[object.name.name]; + var isFallbackTag = FALLBACK_TAGS[nameObject.name]; utils.append( - (isFallbackTag ? jsxObjIdent + '.' : '') + (object.name.name) + '(', + (isFallbackTag ? jsxObjIdent + '.' : '') + (nameObject.name) + '(', state ); - utils.move(object.name.range[1], state); - - var childrenToRender = object.children.filter(function(child) { - return !(child.type === Syntax.Literal && !child.value.match(/\S/)); - }); + utils.move(nameObject.range[1], state); // if we don't have any attributes, pass in null - if (object.attributes.length === 0) { + if (attributesObject.length === 0) { utils.append('null', state); } // write attributes - object.attributes.forEach(function(attr, index) { + attributesObject.forEach(function(attr, index) { utils.catchup(attr.range[0], state); if (attr.name.namespace) { throw new Error( @@ -10360,7 +11990,7 @@ function visitReactTag(traverse, object, path, state) { } var name = attr.name.name; var isFirst = index === 0; - var isLast = index === object.attributes.length - 1; + var isLast = index === attributesObject.length - 1; if (isFirst) { utils.append('{', state); @@ -10399,22 +12029,24 @@ function visitReactTag(traverse, object, path, state) { utils.catchup(attr.range[1], state); }); - if (!object.selfClosing) { - utils.catchup(object.openingElement.range[1] - 1, state); - utils.move(object.openingElement.range[1], state); + if (!openingElement.selfClosing) { + utils.catchup(openingElement.range[1] - 1, state); + utils.move(openingElement.range[1], state); } // filter out whitespace + var childrenToRender = object.children.filter(function(child) { + return !(child.type === Syntax.Literal + && typeof child.value === 'string' + && child.value.match(/^[ \t]*[\r\n][ \t\r\n]*$/)); + }); if (childrenToRender.length > 0) { utils.append(', ', state); - object.children.forEach(function(child) { - if (child.type === Syntax.Literal && !child.value.match(/\S/)) { - return; - } + childrenToRender.forEach(function(child, index) { utils.catchup(child.range[0], state); - var isLast = child === childrenToRender[childrenToRender.length - 1]; + var isLast = index === childrenToRender.length - 1; if (child.type === Syntax.Literal) { renderXJSLiteral(child, isLast, state); @@ -10432,10 +12064,10 @@ function visitReactTag(traverse, object, path, state) { }); } - if (object.selfClosing) { + if (openingElement.selfClosing) { // everything up to /> - utils.catchup(object.openingElement.range[1] - 2, state); - utils.move(object.openingElement.range[1], state); + utils.catchup(openingElement.range[1] - 2, state); + utils.move(openingElement.range[1], state); } else { // everything up to utils.catchup(object.closingElement.range[0], state); @@ -10452,11 +12084,13 @@ visitReactTag.test = function(object, path, state) { return object.type === Syntax.XJSElement && jsx && jsx.length; }; -exports.visitReactTag = visitReactTag; +exports.visitorList = [ + visitReactTag +]; -},{"./xjs":24,"esprima-fb":5,"jstransform/src/utils":19}],23:[function(require,module,exports){ +},{"./xjs":29,"esprima-fb":6,"jstransform/src/utils":20}],28:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -10476,6 +12110,32 @@ exports.visitReactTag = visitReactTag; var Syntax = require('esprima-fb').Syntax; var utils = require('jstransform/src/utils'); +function addDisplayName(displayName, object, state) { + if (object && + object.type === Syntax.CallExpression && + object.callee.type === Syntax.MemberExpression && + object.callee.object.type === Syntax.Identifier && + object.callee.object.name === 'React' && + object.callee.property.type === Syntax.Identifier && + object.callee.property.name === 'createClass' && + object['arguments'].length === 1 && + object['arguments'][0].type === Syntax.ObjectExpression) { + // Verify that the displayName property isn't already set + var properties = object['arguments'][0].properties; + var safe = properties.every(function(property) { + var value = property.key.type === Syntax.Identifier ? + property.key.name : + property.key.value; + return value !== 'displayName'; + }); + + if (safe) { + utils.catchup(object['arguments'][0].range[0] + 1, state); + utils.append("displayName: '" + displayName + "',", state); + } + } +} + /** * Transforms the following: * @@ -10489,22 +12149,32 @@ var utils = require('jstransform/src/utils'); * displayName: 'MyComponent', * render: ... * }); + * + * Also catches: + * + * MyComponent = React.createClass(...); + * exports.MyComponent = React.createClass(...); + * module.exports = {MyComponent: React.createClass(...)}; */ function visitReactDisplayName(traverse, object, path, state) { - if (object.id.type === Syntax.Identifier && - object.init && - object.init.type === Syntax.CallExpression && - object.init.callee.type === Syntax.MemberExpression && - object.init.callee.object.type === Syntax.Identifier && - object.init.callee.object.name === 'React' && - object.init.callee.property.type === Syntax.Identifier && - object.init.callee.property.name === 'createClass' && - object.init['arguments'].length === 1 && - object.init['arguments'][0].type === Syntax.ObjectExpression) { + var left, right; - var displayName = object.id.name; - utils.catchup(object.init['arguments'][0].range[0] + 1, state); - utils.append("displayName: '" + displayName + "',", state); + if (object.type === Syntax.AssignmentExpression) { + left = object.left; + right = object.right; + } else if (object.type === Syntax.Property) { + left = object.key; + right = object.value; + } else if (object.type === Syntax.VariableDeclarator) { + left = object.id; + right = object.init; + } + + if (left && left.type === Syntax.MemberExpression) { + left = left.property; + } + if (left && left.type === Syntax.Identifier) { + addDisplayName(left.name, right, state); } } @@ -10512,14 +12182,24 @@ function visitReactDisplayName(traverse, object, path, state) { * Will only run on @jsx files for now. */ visitReactDisplayName.test = function(object, path, state) { - return object.type === Syntax.VariableDeclarator && !!utils.getDocblock(state).jsx; + if (utils.getDocblock(state).jsx) { + return ( + object.type === Syntax.AssignmentExpression || + object.type === Syntax.Property || + object.type === Syntax.VariableDeclarator + ); + } else { + return false; + } }; -exports.visitReactDisplayName = visitReactDisplayName; +exports.visitorList = [ + visitReactDisplayName +]; -},{"esprima-fb":5,"jstransform/src/utils":19}],24:[function(require,module,exports){ +},{"esprima-fb":6,"jstransform/src/utils":20}],29:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -10535,10 +12215,8 @@ exports.visitReactDisplayName = visitReactDisplayName; */ /*global exports:true*/ "use strict"; -var append = require('jstransform/src/utils').append; -var catchup = require('jstransform/src/utils').catchup; -var move = require('jstransform/src/utils').move; var Syntax = require('esprima-fb').Syntax; +var utils = require('jstransform/src/utils'); var knownTags = { a: true, @@ -10569,6 +12247,7 @@ var knownTags = { data: true, datalist: true, dd: true, + defs: true, del: true, details: true, dfn: true, @@ -10607,6 +12286,7 @@ var knownTags = { legend: true, li: true, line: true, + linearGradient: true, link: true, main: true, map: true, @@ -10630,6 +12310,7 @@ var knownTags = { pre: true, progress: true, q: true, + radialGradient: true, rect: true, rp: true, rt: true, @@ -10642,6 +12323,7 @@ var knownTags = { small: true, source: true, span: true, + stop: true, strong: true, style: true, sub: true, @@ -10667,134 +12349,81 @@ var knownTags = { 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); - var hasFinalNewLine = false; + var lines = object.value.split(/\r\n|\n|\r/); - if (trimmedChildValue) { - // head whitespace - append(object.value.match(/^[\t ]*/)[0], state); - if (start) { - append(start, state); + if (start) { + utils.append(start, state); + } + + var lastNonEmptyLine = 0; + + lines.forEach(function (line, index) { + if (line.match(/[^ \t]/)) { + lastNonEmptyLine = index; + } + }); + + lines.forEach(function (line, index) { + var isFirstLine = index === 0; + var isLastLine = index === lines.length - 1; + var isLastNonEmptyLine = index === lastNonEmptyLine; + + // replace rendered whitespace tabs with spaces + var trimmedLine = line.replace(/\t/g, ' '); + + // trim whitespace touching a newline + if (!isFirstLine) { + trimmedLine = trimmedLine.replace(/^[ ]+/, ''); + } + if (!isLastLine) { + trimmedLine = trimmedLine.replace(/[ ]+$/, ''); } - var trimmedChildValueWithSpace = trimWithSingleSpace(object.value); + utils.append(line.match(/^[ \t]*/)[0], state); - /** - */ - var initialLines = trimmedChildValue.split(/\r\n|\n|\r/); + if (trimmedLine || isLastNonEmptyLine) { + utils.append( + JSON.stringify(trimmedLine) + + (!isLastNonEmptyLine ? "+' '+" : ''), + state); - var lines = initialLines.filter(function(line) { - return safeTrim(line).length > 0; - }); - - var hasInitialNewLine = initialLines[0] !== lines[0]; - 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 = line.match(/^[ \t]*/)[0]; - - if (ii === 0) { - if (hasInitialNewLine) { - preString = ' '; - leading = '\n' + leading; - } - 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 = ' '; - } + if (isLastNonEmptyLine) { + if (end) { + utils.append(end, state); } - 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 = ' '; + if (!isLast) { + utils.append(',', state); } + } - append( - leading + - JSON.stringify( - preString + trimmedLine + postString - ) + - (lastLine ? '' : '+') + - line.match(/[ \t]*$/)[0], - state); + // only restore tail whitespace if line had literals + if (trimmedLine) { + utils.append(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); - } + if (!isLastLine) { + utils.append('\n', state); + } + }); - // tail whitespace - if (hasFinalNewLine) { - append('\n', state); - } - append(object.value.match(/[ \t]*$/)[0], state); - move(object.range[1], state); + utils.move(object.range[1], state); } function renderXJSExpressionContainer(traverse, object, isLast, path, state) { // Plus 1 to skip `{`. - move(object.range[0] + 1, state); + utils.move(object.range[0] + 1, state); traverse(object.expression, path, state); if (!isLast && object.expression.type !== Syntax.XJSEmptyExpression) { // If we need to append a comma, make sure to do so after the expression. - catchup(object.expression.range[1], state); - append(',', state); + utils.catchup(object.expression.range[1], state); + utils.append(',', state); } // Minus 1 to skip `}`. - catchup(object.range[1] - 1, state); - move(object.range[1], state); + utils.catchup(object.range[1] - 1, state); + utils.move(object.range[1], state); return false; } @@ -10811,9 +12440,13 @@ exports.renderXJSExpressionContainer = renderXJSExpressionContainer; exports.renderXJSLiteral = renderXJSLiteral; exports.quoteAttrName = quoteAttrName; -},{"esprima-fb":5,"jstransform/src/utils":19}],25:[function(require,module,exports){ +},{"esprima-fb":6,"jstransform/src/utils":20}],30:[function(require,module,exports){ /*global exports:true*/ -var es6Classes = require('jstransform/visitors/es6-class-visitors').visitorList; +var es6ArrowFunctions = require('jstransform/visitors/es6-arrow-function-visitors'); +var es6Classes = require('jstransform/visitors/es6-class-visitors'); +var es6ObjectShortNotation = require('jstransform/visitors/es6-object-short-notation-visitors'); +var es6RestParameters = require('jstransform/visitors/es6-rest-param-visitors'); +var es6Templates = require('jstransform/visitors/es6-template-visitors'); var react = require('./transforms/react'); var reactDisplayName = require('./transforms/reactDisplayName'); @@ -10821,18 +12454,23 @@ var reactDisplayName = require('./transforms/reactDisplayName'); * Map from transformName => orderedListOfVisitors. */ var transformVisitors = { - 'es6-classes': es6Classes, - 'react': [ - react.visitReactTag, - reactDisplayName.visitReactDisplayName - ] + 'es6-arrow-functions': es6ArrowFunctions.visitorList, + 'es6-classes': es6Classes.visitorList, + 'es6-object-short-notation': es6ObjectShortNotation.visitorList, + 'es6-rest-params': es6RestParameters.visitorList, + 'es6-templates': es6Templates.visitorList, + 'react': react.visitorList.concat(reactDisplayName.visitorList) }; /** * Specifies the order in which each transform should run. */ var transformRunOrder = [ + 'es6-arrow-functions', + 'es6-object-short-notation', 'es6-classes', + 'es6-rest-params', + 'es6-templates', 'react' ]; @@ -10843,7 +12481,7 @@ var transformRunOrder = [ * @param {array?} excludes * @return {array} */ -function getVisitorsList(excludes) { +function getAllVisitors(excludes) { var ret = []; for (var i = 0, il = transformRunOrder.length; i < il; i++) { if (!excludes || excludes.indexOf(transformRunOrder[i]) === -1) { @@ -10853,10 +12491,9 @@ function getVisitorsList(excludes) { return ret; } -exports.getVisitorsList = getVisitorsList; +exports.getAllVisitors = getAllVisitors; exports.transformVisitors = transformVisitors; -},{"./transforms/react":22,"./transforms/reactDisplayName":23,"jstransform/visitors/es6-class-visitors":20}]},{},[21]) -(21) -}); -; \ No newline at end of file +},{"./transforms/react":27,"./transforms/reactDisplayName":28,"jstransform/visitors/es6-arrow-function-visitors":21,"jstransform/visitors/es6-class-visitors":22,"jstransform/visitors/es6-object-short-notation-visitors":23,"jstransform/visitors/es6-rest-param-visitors":24,"jstransform/visitors/es6-template-visitors":25}]},{},[26]) +(26) +}); \ No newline at end of file diff --git a/bower_components/react/bower.json b/bower_components/react/bower.json index 9c06d22..3585b5e 100644 --- a/bower_components/react/bower.json +++ b/bower_components/react/bower.json @@ -1,5 +1,5 @@ { "name": "react", - "version": "0.8.0", + "version": "0.9.0", "main": "react.js" } \ No newline at end of file diff --git a/bower_components/react/react-with-addons.js b/bower_components/react/react-with-addons.js index fca1fe4..175bab8 100644 --- a/bower_components/react/react-with-addons.js +++ b/bower_components/react/react-with-addons.js @@ -1,9 +1,9 @@ /** - * React (with addons) v0.8.0 + * React (with addons) v0.9.0 */ -!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.React=e():"undefined"!=typeof global?global.React=e():"undefined"!=typeof self&&(self.React=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1; -} - var CSSCore = { /** @@ -116,7 +82,7 @@ var CSSCore = { if (className) { if (element.classList) { element.classList.add(className); - } else if (!hasClass(element, className)) { + } else if (!CSSCore.hasClass(element, className)) { element.className = element.className + ' ' + className; } } @@ -140,7 +106,7 @@ var CSSCore = { if (className) { if (element.classList) { element.classList.remove(className); - } else if (hasClass(element, className)) { + } else if (CSSCore.hasClass(element, className)) { element.className = element.className .replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1') .replace(/\s+/g, ' ') // multiple spaces to one @@ -160,14 +126,33 @@ var CSSCore = { */ conditionClass: function(element, className, bool) { return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className); + }, + + /** + * Tests whether the element has the class specified. + * + * @param {DOMNode|DOMWindow} element the element to set the class on + * @param {string} className the CSS className + * @returns {boolean} true if the element has the class, false if not + */ + hasClass: function(element, className) { + ("production" !== "development" ? invariant( + !/\s/.test(className), + 'CSS.hasClass takes only a single class name.' + ) : invariant(!/\s/.test(className))); + if (element.classList) { + return !!className && element.classList.contains(className); + } + return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1; } + }; module.exports = CSSCore; -},{"./invariant":109}],3:[function(require,module,exports){ +},{"./invariant":121}],3:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -190,15 +175,46 @@ module.exports = CSSCore; * CSS properties which accept numbers but are not in units of "px". */ var isUnitlessNumber = { + columnCount: true, fillOpacity: true, + flex: true, + flexGrow: true, + flexShrink: true, fontWeight: true, + lineClamp: true, lineHeight: true, opacity: true, + order: true, orphans: true, + widows: true, zIndex: true, zoom: true }; +/** + * @param {string} prefix vendor-specific prefix, eg: Webkit + * @param {string} key style name, eg: transitionDuration + * @return {string} style name prefixed with `prefix`, properly camelCased, eg: + * WebkitTransitionDuration + */ +function prefixKey(prefix, key) { + return prefix + key.charAt(0).toUpperCase() + key.substring(1); +} + +/** + * Support style names that may come passed in prefixed by adding permutations + * of vendor prefixes. + */ +var prefixes = ['Webkit', 'ms', 'Moz', 'O']; + +// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an +// infinite loop, because it iterates over the newly added props too. +Object.keys(isUnitlessNumber).forEach(function(prop) { + prefixes.forEach(function(prefix) { + isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; + }); +}); + /** * Most style properties can be unset by doing .style[prop] = '' but IE8 * doesn't like doing that with shorthand properties so for the properties that @@ -259,7 +275,7 @@ module.exports = CSSProperty; },{}],4:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -356,102 +372,9 @@ var CSSPropertyOperations = { module.exports = CSSPropertyOperations; -},{"./CSSProperty":3,"./dangerousStyleValue":93,"./escapeTextForBrowser":95,"./hyphenate":108,"./memoizeStringOnly":117}],5:[function(require,module,exports){ +},{"./CSSProperty":3,"./dangerousStyleValue":107,"./escapeTextForBrowser":109,"./hyphenate":120,"./memoizeStringOnly":129}],5:[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 - * @typechecks static-only - */ - -"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]`. - * - * @class CallbackRegistry - * @internal - */ -var CallbackRegistry = { - - /** - * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. - * - * @param {string} id ID of the DOM element. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @param {?function} listener The callback to store. - */ - putListener: function(id, registrationName, listener) { - var bankForRegistrationName = - listenerBank[registrationName] || (listenerBank[registrationName] = {}); - bankForRegistrationName[id] = listener; - }, - - /** - * @param {string} id ID of the DOM element. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @return {?function} The stored callback. - */ - getListener: function(id, registrationName) { - var bankForRegistrationName = listenerBank[registrationName]; - return bankForRegistrationName && bankForRegistrationName[id]; - }, - - /** - * Deletes a listener from the registration bank. - * - * @param {string} id ID of the DOM element. - * @param {string} registrationName Name of listener (e.g. `onClick`). - */ - deleteListener: function(id, registrationName) { - var bankForRegistrationName = listenerBank[registrationName]; - if (bankForRegistrationName) { - delete bankForRegistrationName[id]; - } - }, - - /** - * Deletes all listeners for the DOM element with the supplied ID. - * - * @param {string} id ID of the DOM element. - */ - deleteAllListeners: function(id) { - for (var registrationName in listenerBank) { - delete listenerBank[registrationName][id]; - } - }, - - /** - * This is needed for tests only. Do not use! - */ - __purge: function() { - listenerBank = {}; - } - -}; - -module.exports = CallbackRegistry; - -},{}],6:[function(require,module,exports){ -/** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -474,6 +397,7 @@ var EventConstants = require("./EventConstants"); var EventPluginHub = require("./EventPluginHub"); var EventPropagators = require("./EventPropagators"); var ExecutionEnvironment = require("./ExecutionEnvironment"); +var ReactUpdates = require("./ReactUpdates"); var SyntheticEvent = require("./SyntheticEvent"); var isEventSupported = require("./isEventSupported"); @@ -487,7 +411,17 @@ var eventTypes = { phasedRegistrationNames: { bubbled: keyOf({onChange: null}), captured: keyOf({onChangeCapture: null}) - } + }, + dependencies: [ + topLevelTypes.topBlur, + topLevelTypes.topChange, + topLevelTypes.topClick, + topLevelTypes.topFocus, + topLevelTypes.topInput, + topLevelTypes.topKeyDown, + topLevelTypes.topKeyUp, + topLevelTypes.topSelectionChange + ] } }; @@ -525,10 +459,21 @@ function manualDispatchChangeEvent(nativeEvent) { ); EventPropagators.accumulateTwoPhaseDispatches(event); - // If change bubbled, we'd just bind to it like all the other events - // and have it go through ReactEventTopLevelCallback. Since it doesn't, we - // manually listen for the change event and so we have to enqueue and + // If change and propertychange bubbled, we'd just bind to it like all the + // other events and have it go through ReactEventTopLevelCallback. Since it + // doesn't, we manually listen for the events and so we have to enqueue and // process the abstract event manually. + // + // Batching is necessary here in order to ensure that all event handlers run + // before the next rerender (including event handlers attached to ancestor + // elements instead of directly on the input). Without this, controlled + // components don't work properly in conjunction with event bubbling because + // the component is rerendered and the value reverted before all the event + // handlers can run. See https://github.com/facebook/react/issues/708. + ReactUpdates.batchedUpdates(runEventInBatch, event); +} + +function runEventInBatch(event) { EventPluginHub.enqueueEvents(event); EventPluginHub.processEventQueue(); } @@ -816,9 +761,41 @@ var ChangeEventPlugin = { module.exports = ChangeEventPlugin; -},{"./EventConstants":15,"./EventPluginHub":17,"./EventPropagators":20,"./ExecutionEnvironment":21,"./SyntheticEvent":76,"./isEventSupported":110,"./isTextInputElement":112,"./keyOf":116}],7:[function(require,module,exports){ +},{"./EventConstants":15,"./EventPluginHub":17,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactUpdates":80,"./SyntheticEvent":88,"./isEventSupported":122,"./isTextInputElement":124,"./keyOf":128}],6:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 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 ClientReactRootIndex + * @typechecks + */ + +"use strict"; + +var nextReactRootIndex = 0; + +var ClientReactRootIndex = { + createReactRootIndex: function() { + return nextReactRootIndex++; + } +}; + +module.exports = ClientReactRootIndex; + +},{}],7:[function(require,module,exports){ +/** + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -850,8 +827,22 @@ var keyOf = require("./keyOf"); var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space var START_KEYCODE = 229; -var useCompositionEvent = ExecutionEnvironment.canUseDOM && - 'CompositionEvent' in window; +var useCompositionEvent = ( + ExecutionEnvironment.canUseDOM && + 'CompositionEvent' in window +); + +// In IE9+, we have access to composition events, but the data supplied +// by the native compositionend event may be incorrect. In Korean, for example, +// the compositionend event contains only one character regardless of +// how many characters have been composed since compositionstart. +// We therefore use the fallback data while still using the native +// events as triggers. +var useFallbackData = ( + !useCompositionEvent || + 'documentMode' in document && document.documentMode > 8 +); + var topLevelTypes = EventConstants.topLevelTypes; var currentComposition = null; @@ -861,19 +852,43 @@ var eventTypes = { phasedRegistrationNames: { bubbled: keyOf({onCompositionEnd: null}), captured: keyOf({onCompositionEndCapture: null}) - } + }, + dependencies: [ + topLevelTypes.topBlur, + topLevelTypes.topCompositionEnd, + topLevelTypes.topKeyDown, + topLevelTypes.topKeyPress, + topLevelTypes.topKeyUp, + topLevelTypes.topMouseDown + ] }, compositionStart: { phasedRegistrationNames: { bubbled: keyOf({onCompositionStart: null}), captured: keyOf({onCompositionStartCapture: null}) - } + }, + dependencies: [ + topLevelTypes.topBlur, + topLevelTypes.topCompositionStart, + topLevelTypes.topKeyDown, + topLevelTypes.topKeyPress, + topLevelTypes.topKeyUp, + topLevelTypes.topMouseDown + ] }, compositionUpdate: { phasedRegistrationNames: { bubbled: keyOf({onCompositionUpdate: null}), captured: keyOf({onCompositionUpdateCapture: null}) - } + }, + dependencies: [ + topLevelTypes.topBlur, + topLevelTypes.topCompositionUpdate, + topLevelTypes.topKeyDown, + topLevelTypes.topKeyPress, + topLevelTypes.topKeyUp, + topLevelTypes.topMouseDown + ] } }; @@ -1002,13 +1017,23 @@ var CompositionEventPlugin = { eventType = getCompositionEventType(topLevelType); } else if (!currentComposition) { if (isFallbackStart(topLevelType, nativeEvent)) { - eventType = eventTypes.start; - currentComposition = new FallbackCompositionState(topLevelTarget); + eventType = eventTypes.compositionStart; } } else if (isFallbackEnd(topLevelType, nativeEvent)) { eventType = eventTypes.compositionEnd; - data = currentComposition.getData(); - currentComposition = null; + } + + if (useFallbackData) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!currentComposition && eventType === eventTypes.compositionStart) { + currentComposition = new FallbackCompositionState(topLevelTarget); + } else if (eventType === eventTypes.compositionEnd) { + if (currentComposition) { + data = currentComposition.getData(); + currentComposition = null; + } + } } if (eventType) { @@ -1030,9 +1055,9 @@ var CompositionEventPlugin = { module.exports = CompositionEventPlugin; -},{"./EventConstants":15,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactInputSelection":50,"./SyntheticCompositionEvent":75,"./getTextContentAccessor":106,"./keyOf":116}],8:[function(require,module,exports){ +},{"./EventConstants":15,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactInputSelection":56,"./SyntheticCompositionEvent":86,"./getTextContentAccessor":118,"./keyOf":128}],8:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1063,7 +1088,7 @@ var getTextContentAccessor = require("./getTextContentAccessor"); * @type {string} * @private */ -var textContentAccessor = getTextContentAccessor() || 'NA'; +var textContentAccessor = getTextContentAccessor(); /** * Inserts `childNode` as a child of `parentNode` at the `index`. @@ -1090,6 +1115,31 @@ function insertChildAt(parentNode, childNode, index) { } } +/** + * Sets the text content of `node` to `text`. + * + * @param {DOMElement} node Node to change + * @param {string} text New text content + */ +var updateTextContent; +if (textContentAccessor === 'textContent') { + updateTextContent = function(node, text) { + node.textContent = text; + }; +} else { + updateTextContent = function(node, text) { + // In order to preserve newlines correctly, we can't use .innerText to set + // the contents (see #1080), so we empty the element then append a text node + while (node.firstChild) { + node.removeChild(node.firstChild); + } + if (text) { + var doc = node.ownerDocument || document; + node.appendChild(doc.createTextNode(text)); + } + }; +} + /** * Operations for updating with DOM children. */ @@ -1097,6 +1147,8 @@ var DOMChildrenOperations = { dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + updateTextContent: updateTextContent, + /** * Updates a component's children by processing a series of updates. The * update configurations are each expected to have a `parentNode` property. @@ -1154,7 +1206,10 @@ var DOMChildrenOperations = { ); break; case ReactMultiChildUpdateTypes.TEXT_CONTENT: - update.parentNode[textContentAccessor] = update.textContent; + updateTextContent( + update.parentNode, + update.textContent + ); break; case ReactMultiChildUpdateTypes.REMOVE_NODE: // Already removed by the for-loop above. @@ -1167,9 +1222,9 @@ var DOMChildrenOperations = { module.exports = DOMChildrenOperations; -},{"./Danger":11,"./ReactMultiChildUpdateTypes":57,"./getTextContentAccessor":106}],9:[function(require,module,exports){ +},{"./Danger":11,"./ReactMultiChildUpdateTypes":63,"./getTextContentAccessor":118}],9:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1324,6 +1379,8 @@ var defaultValueCache = {}; */ var DOMProperty = { + ID_ATTRIBUTE_NAME: 'data-reactid', + /** * Checks whether a property name is a standard property. * @type {Object} @@ -1435,9 +1492,9 @@ var DOMProperty = { module.exports = DOMProperty; -},{"./invariant":109}],10:[function(require,module,exports){ +},{"./invariant":121}],10:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1474,7 +1531,6 @@ var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { if ("production" !== "development") { var reactProps = { - __owner__: true, children: true, dangerouslySetInnerHTML: true, key: true, @@ -1510,6 +1566,17 @@ if ("production" !== "development") { */ var DOMPropertyOperations = { + /** + * Creates markup for the ID property. + * + * @param {string} id Unescaped ID. + * @return {string} Markup string. + */ + createMarkupForID: function(id) { + return processAttributeNameAndPrefix(DOMProperty.ID_ATTRIBUTE_NAME) + + escapeTextForBrowser(id) + '"'; + }, + /** * Creates markup for a property. * @@ -1523,6 +1590,9 @@ var DOMPropertyOperations = { return ''; } var attributeName = DOMProperty.getAttributeName[name]; + if (DOMProperty.hasBooleanValue[name]) { + return escapeTextForBrowser(attributeName); + } return processAttributeNameAndPrefix(attributeName) + escapeTextForBrowser(value) + '"'; } else if (DOMProperty.isCustomAttribute(name)) { @@ -1605,9 +1675,9 @@ var DOMPropertyOperations = { module.exports = DOMPropertyOperations; -},{"./DOMProperty":9,"./escapeTextForBrowser":95,"./memoizeStringOnly":117}],11:[function(require,module,exports){ +},{"./DOMProperty":9,"./escapeTextForBrowser":109,"./memoizeStringOnly":129}],11:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1635,7 +1705,6 @@ var createNodesFromMarkup = require("./createNodesFromMarkup"); var emptyFunction = require("./emptyFunction"); var getMarkupWrap = require("./getMarkupWrap"); var invariant = require("./invariant"); -var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup"); var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/; var RESULT_INDEX_ATTR = 'data-danger-index'; @@ -1779,12 +1848,14 @@ var Danger = { 'immediately.' ) : invariant(ExecutionEnvironment.canUseDOM)); ("production" !== "development" ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup)); - // createNodesFromMarkup() won't work if the markup is rooted by - // since it has special semantic meaning. So we use an alternatie strategy. - if (oldChild.tagName.toLowerCase() === 'html') { - mutateHTMLNodeWithMarkup(oldChild, markup); - return; - } + ("production" !== "development" ? invariant( + oldChild.tagName.toLowerCase() !== 'html', + 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' + + ' node. This is because browser quirks make this unreliable ' + + 'and/or slow. If you want to render to the root you must use ' + + 'server rendering. See renderComponentToString().' + ) : invariant(oldChild.tagName.toLowerCase() !== 'html')); + var newChild = createNodesFromMarkup(markup, emptyFunction)[0]; oldChild.parentNode.replaceChild(newChild, oldChild); } @@ -1793,9 +1864,9 @@ var Danger = { module.exports = Danger; -},{"./ExecutionEnvironment":21,"./createNodesFromMarkup":90,"./emptyFunction":94,"./getMarkupWrap":103,"./invariant":109,"./mutateHTMLNodeWithMarkup":122}],12:[function(require,module,exports){ +},{"./ExecutionEnvironment":21,"./createNodesFromMarkup":104,"./emptyFunction":108,"./getMarkupWrap":115,"./invariant":121}],12:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1841,7 +1912,8 @@ var DefaultDOMPropertyConfig = { alt: null, async: HAS_BOOLEAN_VALUE, autoComplete: null, - autoFocus: HAS_BOOLEAN_VALUE, + // autoFocus is polyfilled/normalized by AutoFocusMixin + // autoFocus: HAS_BOOLEAN_VALUE, autoPlay: HAS_BOOLEAN_VALUE, cellPadding: null, cellSpacing: null, @@ -1854,18 +1926,22 @@ var DefaultDOMPropertyConfig = { contentEditable: null, contextMenu: MUST_USE_ATTRIBUTE, controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + crossOrigin: null, data: null, // For `` acts as `src`. dateTime: MUST_USE_ATTRIBUTE, defer: HAS_BOOLEAN_VALUE, dir: null, disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + download: null, draggable: null, encType: null, form: MUST_USE_ATTRIBUTE, + formNoValidate: HAS_BOOLEAN_VALUE, frameBorder: MUST_USE_ATTRIBUTE, height: MUST_USE_ATTRIBUTE, hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, href: null, + hrefLang: null, htmlFor: null, httpEquiv: null, icon: null, @@ -1876,10 +1952,13 @@ var DefaultDOMPropertyConfig = { loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, max: null, maxLength: MUST_USE_ATTRIBUTE, + mediaGroup: null, method: null, min: null, multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, name: null, + noValidate: HAS_BOOLEAN_VALUE, pattern: null, placeholder: null, poster: null, @@ -1891,12 +1970,17 @@ var DefaultDOMPropertyConfig = { role: MUST_USE_ATTRIBUTE, rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, rowSpan: null, + sandbox: null, + scope: null, scrollLeft: MUST_USE_PROPERTY, scrollTop: MUST_USE_PROPERTY, + seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, + span: HAS_POSITIVE_NUMERIC_VALUE, spellCheck: null, src: null, + srcDoc: MUST_USE_PROPERTY, step: null, style: null, tabIndex: null, @@ -1912,6 +1996,7 @@ var DefaultDOMPropertyConfig = { */ autoCapitalize: null, // Supported in Mobile Safari for keyboard hints autoCorrect: null, // Supported in Mobile Safari for keyboard hints + property: null, // Supports OG in meta tags /** * SVG Properties @@ -1964,8 +2049,10 @@ var DefaultDOMPropertyConfig = { autoFocus: 'autofocus', autoPlay: 'autoplay', encType: 'enctype', + hrefLang: 'hreflang', radioGroup: 'radiogroup', - spellCheck: 'spellcheck' + spellCheck: 'spellcheck', + srcDoc: 'srcdoc' }, DOMMutationMethods: { /** @@ -1984,7 +2071,7 @@ module.exports = DefaultDOMPropertyConfig; },{"./DOMProperty":9}],13:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2028,9 +2115,9 @@ var DefaultEventPluginOrder = [ module.exports = DefaultEventPluginOrder; -},{"./keyOf":116}],14:[function(require,module,exports){ +},{"./keyOf":128}],14:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2061,8 +2148,20 @@ var topLevelTypes = EventConstants.topLevelTypes; var getFirstReactDOM = ReactMount.getFirstReactDOM; var eventTypes = { - mouseEnter: {registrationName: keyOf({onMouseEnter: null})}, - mouseLeave: {registrationName: keyOf({onMouseLeave: null})} + mouseEnter: { + registrationName: keyOf({onMouseEnter: null}), + dependencies: [ + topLevelTypes.topMouseOut, + topLevelTypes.topMouseOver + ] + }, + mouseLeave: { + registrationName: keyOf({onMouseLeave: null}), + dependencies: [ + topLevelTypes.topMouseOut, + topLevelTypes.topMouseOver + ] + } }; var extractedEvents = [null, null]; @@ -2100,14 +2199,28 @@ var EnterLeaveEventPlugin = { return null; } + var win; + if (topLevelTarget.window === topLevelTarget) { + // `topLevelTarget` is probably a window object. + win = topLevelTarget; + } else { + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. + var doc = topLevelTarget.ownerDocument; + if (doc) { + win = doc.defaultView || doc.parentWindow; + } else { + win = window; + } + } + var from, to; if (topLevelType === topLevelTypes.topMouseOut) { from = topLevelTarget; to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || - window; + win; } else { - from = window; + from = win; to = topLevelTarget; } @@ -2124,11 +2237,18 @@ var EnterLeaveEventPlugin = { fromID, nativeEvent ); + leave.type = 'mouseleave'; + leave.target = from; + leave.relatedTarget = to; + var enter = SyntheticMouseEvent.getPooled( eventTypes.mouseEnter, toID, nativeEvent ); + enter.type = 'mouseenter'; + enter.target = to; + enter.relatedTarget = from; EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); @@ -2142,9 +2262,9 @@ var EnterLeaveEventPlugin = { module.exports = EnterLeaveEventPlugin; -},{"./EventConstants":15,"./EventPropagators":20,"./ReactMount":54,"./SyntheticMouseEvent":79,"./keyOf":116}],15:[function(require,module,exports){ +},{"./EventConstants":15,"./EventPropagators":20,"./ReactMount":60,"./SyntheticMouseEvent":91,"./keyOf":128}],15:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2189,17 +2309,20 @@ var topLevelTypes = keyMirror({ topDragOver: null, topDragStart: null, topDrop: null, + topError: null, topFocus: null, topInput: null, topKeyDown: null, topKeyPress: null, topKeyUp: null, + topLoad: null, topMouseDown: null, topMouseMove: null, topMouseOut: null, topMouseOver: null, topMouseUp: null, topPaste: null, + topReset: null, topScroll: null, topSelectionChange: null, topSubmit: null, @@ -2217,72 +2340,80 @@ var EventConstants = { module.exports = EventConstants; -},{"./keyMirror":115}],16:[function(require,module,exports){ +},{"./keyMirror":127}],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 EventListener */ +var emptyFunction = require("./emptyFunction"); + /** * Upstream version of event listener. Does not take into account specific * nature of platform. */ var EventListener = { /** - * Listens to bubbled events on a DOM node. + * Listen to DOM events during the bubble phase. * - * @param {Element} el DOM element to register listener on. - * @param {string} handlerBaseName 'click'/'mouseover' - * @param {Function!} cb Callback function + * @param {DOMEventTarget} target DOM element to register listener on. + * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. + * @param {function} callback Callback function. + * @return {object} Object with a `remove` method. */ - listen: function(el, handlerBaseName, cb) { - if (el.addEventListener) { - el.addEventListener(handlerBaseName, cb, false); - } else if (el.attachEvent) { - el.attachEvent('on' + handlerBaseName, cb); + listen: function(target, eventType, callback) { + if (target.addEventListener) { + target.addEventListener(eventType, callback, false); + return { + remove: function() { + target.removeEventListener(eventType, callback, false); + } + }; + } else if (target.attachEvent) { + target.attachEvent('on' + eventType, callback); + return { + remove: function() { + target.detachEvent(eventType, callback); + } + }; } }, /** - * Listens to captured events on a DOM node. + * Listen to DOM events during the capture phase. * - * @see `EventListener.listen` for params. - * @throws Exception if addEventListener is not supported. + * @param {DOMEventTarget} target DOM element to register listener on. + * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. + * @param {function} callback Callback function. + * @return {object} Object with a `remove` method. */ - capture: function(el, handlerBaseName, cb) { - if (!el.addEventListener) { + capture: function(target, eventType, callback) { + if (!target.addEventListener) { if ("production" !== "development") { console.error( - 'You are attempting to use addEventListener ' + - 'in a browser that does not support it.' + - 'This likely means that you will not receive events that ' + - 'your application relies on (such as scroll).'); + 'Attempted to listen to events during the capture phase on a ' + + 'browser that does not support the capture phase. Your application ' + + 'will not receive some events.' + ); } - return; + return { + remove: emptyFunction + }; } else { - el.addEventListener(handlerBaseName, cb, true); + target.addEventListener(eventType, callback, true); + return { + remove: function() { + target.removeEventListener(eventType, callback, true); + } + }; } } }; module.exports = EventListener; -},{}],17:[function(require,module,exports){ +},{"./emptyFunction":108}],17:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2301,15 +2432,19 @@ module.exports = EventListener; "use strict"; -var CallbackRegistry = require("./CallbackRegistry"); var EventPluginRegistry = require("./EventPluginRegistry"); var EventPluginUtils = require("./EventPluginUtils"); -var EventPropagators = require("./EventPropagators"); var ExecutionEnvironment = require("./ExecutionEnvironment"); var accumulate = require("./accumulate"); var forEachAccumulated = require("./forEachAccumulated"); var invariant = require("./invariant"); +var isEventSupported = require("./isEventSupported"); + +/** + * Internal store for event listeners + */ +var listenerBank = {}; /** * Internal queue of events that have accumulated their dispatches and are @@ -2339,6 +2474,21 @@ var executeDispatchesAndRelease = function(event) { } }; +/** + * - `InstanceHandle`: [required] Module that performs logical traversals of DOM + * hierarchy given ids of the logical DOM elements involved. + */ +var InstanceHandle = null; + +function validateInstanceHandle() { + var invalid = !InstanceHandle|| + !InstanceHandle.traverseTwoPhase || + !InstanceHandle.traverseEnterLeave; + if (invalid) { + throw new Error('InstanceHandle not injected before use!'); + } +} + /** * This is a unified interface for event plugins to be installed and configured. * @@ -2368,11 +2518,29 @@ var EventPluginHub = { */ injection: { + /** + * @param {object} InjectedMount + * @public + */ + injectMount: EventPluginUtils.injection.injectMount, + /** * @param {object} InjectedInstanceHandle * @public */ - injectInstanceHandle: EventPropagators.injection.injectInstanceHandle, + injectInstanceHandle: function(InjectedInstanceHandle) { + InstanceHandle = InjectedInstanceHandle; + if ("production" !== "development") { + validateInstanceHandle(); + } + }, + + getInstanceHandle: function() { + if ("production" !== "development") { + validateInstanceHandle(); + } + return InstanceHandle; + }, /** * @param {array} InjectedEventPluginOrder @@ -2387,15 +2555,74 @@ var EventPluginHub = { }, - registrationNames: EventPluginRegistry.registrationNames, + eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs, - putListener: CallbackRegistry.putListener, + registrationNameModules: EventPluginRegistry.registrationNameModules, - getListener: CallbackRegistry.getListener, + /** + * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {?function} listener The callback to store. + */ + putListener: function(id, registrationName, listener) { + ("production" !== "development" ? invariant( + ExecutionEnvironment.canUseDOM, + 'Cannot call putListener() in a non-DOM environment.' + ) : invariant(ExecutionEnvironment.canUseDOM)); + ("production" !== "development" ? invariant( + !listener || typeof listener === 'function', + 'Expected %s listener to be a function, instead got type %s', + registrationName, typeof listener + ) : invariant(!listener || typeof listener === 'function')); - deleteListener: CallbackRegistry.deleteListener, + if ("production" !== "development") { + // IE8 has no API for event capturing and the `onScroll` event doesn't + // bubble. + if (registrationName === 'onScroll' && + !isEventSupported('scroll', true)) { + console.warn('This browser doesn\'t support the `onScroll` event'); + } + } + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, - deleteAllListeners: CallbackRegistry.deleteAllListeners, + /** + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ + getListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + return bankForRegistrationName && bankForRegistrationName[id]; + }, + + /** + * Deletes a listener from the registration bank. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + */ + deleteListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + if (bankForRegistrationName) { + delete bankForRegistrationName[id]; + } + }, + + /** + * Deletes all listeners for the DOM element with the supplied ID. + * + * @param {string} id ID of the DOM element. + */ + deleteAllListeners: function(id) { + for (var registrationName in listenerBank) { + delete listenerBank[registrationName][id]; + } + }, /** * Allows registered plugins an opportunity to extract events from top-level @@ -2462,19 +2689,26 @@ var EventPluginHub = { 'processEventQueue(): Additional events were enqueued while processing ' + 'an event queue. Support for this has not yet been implemented.' ) : invariant(!eventQueue)); + }, + + /** + * These are needed for tests only. Do not use! + */ + __purge: function() { + listenerBank = {}; + }, + + __getListenerBank: function() { + return listenerBank; } }; -if (ExecutionEnvironment.canUseDOM) { - window.EventPluginHub = EventPluginHub; -} - module.exports = EventPluginHub; -},{"./CallbackRegistry":5,"./EventPluginRegistry":18,"./EventPluginUtils":19,"./EventPropagators":20,"./ExecutionEnvironment":21,"./accumulate":85,"./forEachAccumulated":99,"./invariant":109}],18:[function(require,module,exports){ +},{"./EventPluginRegistry":18,"./EventPluginUtils":19,"./ExecutionEnvironment":21,"./accumulate":97,"./forEachAccumulated":111,"./invariant":121,"./isEventSupported":122}],18:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2538,11 +2772,19 @@ function recomputePluginOrdering() { var publishedEvents = PluginModule.eventTypes; for (var eventName in publishedEvents) { ("production" !== "development" ? invariant( - publishEventForPlugin(publishedEvents[eventName], PluginModule), + publishEventForPlugin( + publishedEvents[eventName], + PluginModule, + eventName + ), 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName - ) : invariant(publishEventForPlugin(publishedEvents[eventName], PluginModule))); + ) : invariant(publishEventForPlugin( + publishedEvents[eventName], + PluginModule, + eventName + ))); } } } @@ -2555,18 +2797,34 @@ function recomputePluginOrdering() { * @return {boolean} True if the event was successfully published. * @private */ -function publishEventForPlugin(dispatchConfig, PluginModule) { +function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { + ("production" !== "development" ? invariant( + !EventPluginRegistry.eventNameDispatchConfigs[eventName], + 'EventPluginHub: More than one plugin attempted to publish the same ' + + 'event name, `%s`.', + eventName + ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs[eventName])); + EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; if (phasedRegistrationNames) { for (var phaseName in phasedRegistrationNames) { if (phasedRegistrationNames.hasOwnProperty(phaseName)) { var phasedRegistrationName = phasedRegistrationNames[phaseName]; - publishRegistrationName(phasedRegistrationName, PluginModule); + publishRegistrationName( + phasedRegistrationName, + PluginModule, + eventName + ); } } return true; } else if (dispatchConfig.registrationName) { - publishRegistrationName(dispatchConfig.registrationName, PluginModule); + publishRegistrationName( + dispatchConfig.registrationName, + PluginModule, + eventName + ); return true; } return false; @@ -2580,14 +2838,16 @@ function publishEventForPlugin(dispatchConfig, PluginModule) { * @param {object} PluginModule Plugin publishing the event. * @private */ -function publishRegistrationName(registrationName, PluginModule) { +function publishRegistrationName(registrationName, PluginModule, eventName) { ("production" !== "development" ? invariant( - !EventPluginRegistry.registrationNames[registrationName], + !EventPluginRegistry.registrationNameModules[registrationName], 'EventPluginHub: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', registrationName - ) : invariant(!EventPluginRegistry.registrationNames[registrationName])); - EventPluginRegistry.registrationNames[registrationName] = PluginModule; + ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName])); + EventPluginRegistry.registrationNameModules[registrationName] = PluginModule; + EventPluginRegistry.registrationNameDependencies[registrationName] = + PluginModule.eventTypes[eventName].dependencies; } /** @@ -2603,9 +2863,19 @@ var EventPluginRegistry = { plugins: [], /** - * Mapping from registration names to plugin modules. + * Mapping from event name to dispatch config */ - registrationNames: {}, + eventNameDispatchConfigs: {}, + + /** + * Mapping from registration name to plugin module + */ + registrationNameModules: {}, + + /** + * Mapping from registration name to event name + */ + registrationNameDependencies: {}, /** * Injects an ordering of plugins (by plugin name). This allows the ordering @@ -2669,7 +2939,7 @@ var EventPluginRegistry = { getPluginModuleForEvent: function(event) { var dispatchConfig = event.dispatchConfig; if (dispatchConfig.registrationName) { - return EventPluginRegistry.registrationNames[ + return EventPluginRegistry.registrationNameModules[ dispatchConfig.registrationName ] || null; } @@ -2677,7 +2947,7 @@ var EventPluginRegistry = { if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { continue; } - var PluginModule = EventPluginRegistry.registrationNames[ + var PluginModule = EventPluginRegistry.registrationNameModules[ dispatchConfig.phasedRegistrationNames[phase] ]; if (PluginModule) { @@ -2699,10 +2969,18 @@ var EventPluginRegistry = { } } EventPluginRegistry.plugins.length = 0; - var registrationNames = EventPluginRegistry.registrationNames; - for (var registrationName in registrationNames) { - if (registrationNames.hasOwnProperty(registrationName)) { - delete registrationNames[registrationName]; + + var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs; + for (var eventName in eventNameDispatchConfigs) { + if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { + delete eventNameDispatchConfigs[eventName]; + } + } + + var registrationNameModules = EventPluginRegistry.registrationNameModules; + for (var registrationName in registrationNameModules) { + if (registrationNameModules.hasOwnProperty(registrationName)) { + delete registrationNameModules[registrationName]; } } } @@ -2711,9 +2989,9 @@ var EventPluginRegistry = { module.exports = EventPluginRegistry; -},{"./invariant":109}],19:[function(require,module,exports){ +},{"./invariant":121}],19:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2736,6 +3014,28 @@ var EventConstants = require("./EventConstants"); var invariant = require("./invariant"); +/** + * Injected dependencies: + */ + +/** + * - `Mount`: [required] Module that can convert between React dom IDs and + * actual node references. + */ +var injection = { + Mount: null, + injectMount: function(InjectedMount) { + injection.Mount = InjectedMount; + if ("production" !== "development") { + ("production" !== "development" ? invariant( + InjectedMount && InjectedMount.getNode, + 'EventPluginUtils.injection.injectMount(...): Injected Mount module ' + + 'is missing getNode.' + ) : invariant(InjectedMount && InjectedMount.getNode)); + } + } +}; + var topLevelTypes = EventConstants.topLevelTypes; function isEndish(topLevelType) { @@ -2753,6 +3053,7 @@ function isStartish(topLevelType) { topLevelType === topLevelTypes.topTouchStart; } + var validateEventDispatches; if ("production" !== "development") { validateEventDispatches = function(event) { @@ -2804,7 +3105,10 @@ function forEachEventDispatch(event, cb) { * @param {string} domID DOM id to pass to the callback. */ function executeDispatch(event, listener, domID) { - listener(event, domID); + event.currentTarget = injection.Mount.getNode(domID); + var returnValue = listener(event, domID); + event.currentTarget = null; + return returnValue; } /** @@ -2889,18 +3193,21 @@ var EventPluginUtils = { isEndish: isEndish, isMoveish: isMoveish, isStartish: isStartish, + + executeDirectDispatch: executeDirectDispatch, + executeDispatch: executeDispatch, executeDispatchesInOrder: executeDispatchesInOrder, executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, - executeDirectDispatch: executeDirectDispatch, hasDispatches: hasDispatches, - executeDispatch: executeDispatch + injection: injection, + useTouchEvents: false }; module.exports = EventPluginUtils; -},{"./EventConstants":15,"./invariant":109}],20:[function(require,module,exports){ +},{"./EventConstants":15,"./invariant":121}],20:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2919,39 +3226,14 @@ module.exports = EventPluginUtils; "use strict"; -var CallbackRegistry = require("./CallbackRegistry"); var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); 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 ("production" !== "development") { - injection.validate(); - } - }, - validate: function() { - var invalid = !injection.InstanceHandle|| - !injection.InstanceHandle.traverseTwoPhase || - !injection.InstanceHandle.traverseEnterLeave; - if (invalid) { - throw new Error('InstanceHandle not injected before use!'); - } - } -}; +var getListener = EventPluginHub.getListener; /** * Some event types have a notion of different registration names for different @@ -2974,7 +3256,6 @@ function accumulateDirectionalDispatches(domID, upwards, event) { if (!domID) { throw new Error('Dispatching id must not be null'); } - injection.validate(); } var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; var listener = listenerAtPhase(domID, event, phase); @@ -2993,7 +3274,7 @@ function accumulateDirectionalDispatches(domID, upwards, event) { */ function accumulateTwoPhaseDispatchesSingle(event) { if (event && event.dispatchConfig.phasedRegistrationNames) { - injection.InstanceHandle.traverseTwoPhase( + EventPluginHub.injection.getInstanceHandle().traverseTwoPhase( event.dispatchMarker, accumulateDirectionalDispatches, event @@ -3030,17 +3311,11 @@ function accumulateDirectDispatchesSingle(event) { } function accumulateTwoPhaseDispatches(events) { - if ("production" !== "development") { - injection.validate(); - } forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); } function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { - if ("production" !== "development") { - injection.validate(); - } - injection.InstanceHandle.traverseEnterLeave( + EventPluginHub.injection.getInstanceHandle().traverseEnterLeave( fromID, toID, accumulateDispatches, @@ -3051,9 +3326,6 @@ function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { function accumulateDirectDispatches(events) { - if ("production" !== "development") { - injection.validate(); - } forEachAccumulated(events, accumulateDirectDispatchesSingle); } @@ -3073,15 +3345,14 @@ function accumulateDirectDispatches(events) { var EventPropagators = { accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, accumulateDirectDispatches: accumulateDirectDispatches, - accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, - injection: injection + accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches }; module.exports = EventPropagators; -},{"./CallbackRegistry":5,"./EventConstants":15,"./accumulate":85,"./forEachAccumulated":99}],21:[function(require,module,exports){ +},{"./EventConstants":15,"./EventPluginHub":17,"./accumulate":97,"./forEachAccumulated":111}],21:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3116,6 +3387,9 @@ var ExecutionEnvironment = { canUseWorkers: typeof Worker !== 'undefined', + canUseEventListeners: + canUseDOM && (window.addEventListener || window.attachEvent), + isInWorker: !canUseDOM // For now, this is true - might change in the future. }; @@ -3124,7 +3398,7 @@ module.exports = ExecutionEnvironment; },{}],22:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3170,9 +3444,9 @@ var LinkedStateMixin = { module.exports = LinkedStateMixin; -},{"./ReactLink":52,"./ReactStateSetters":64}],23:[function(require,module,exports){ +},{"./ReactLink":58,"./ReactStateSetters":74}],23:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3186,63 +3460,156 @@ module.exports = LinkedStateMixin; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule LinkedValueMixin + * @providesModule LinkedValueUtils * @typechecks static-only */ "use strict"; +var ReactPropTypes = require("./ReactPropTypes"); + var invariant = require("./invariant"); +var hasReadOnlyValue = { + 'button': true, + 'checkbox': true, + 'image': true, + 'hidden': true, + 'radio': true, + 'reset': true, + 'submit': true +}; + +function _assertSingleLink(input) { + ("production" !== "development" ? invariant( + input.props.checkedLink == null || input.props.valueLink == null, + 'Cannot provide a checkedLink and a valueLink. If you want to use ' + + 'checkedLink, you probably don\'t want to use valueLink and vice versa.' + ) : invariant(input.props.checkedLink == null || input.props.valueLink == null)); +} +function _assertValueLink(input) { + _assertSingleLink(input); + ("production" !== "development" ? invariant( + input.props.value == null && input.props.onChange == null, + 'Cannot provide a valueLink and a value or onChange event. If you want ' + + 'to use value or onChange, you probably don\'t want to use valueLink.' + ) : invariant(input.props.value == null && input.props.onChange == null)); +} + +function _assertCheckedLink(input) { + _assertSingleLink(input); + ("production" !== "development" ? invariant( + input.props.checked == null && input.props.onChange == null, + 'Cannot provide a checkedLink and a checked property or onChange event. ' + + 'If you want to use checked or onChange, you probably don\'t want to ' + + 'use checkedLink' + ) : invariant(input.props.checked == null && input.props.onChange == null)); +} + +/** + * @param {SyntheticEvent} e change event to handle + */ +function _handleLinkedValueChange(e) { + /*jshint validthis:true */ + this.props.valueLink.requestChange(e.target.value); +} + +/** + * @param {SyntheticEvent} e change event to handle + */ +function _handleLinkedCheckChange(e) { + /*jshint validthis:true */ + this.props.checkedLink.requestChange(e.target.checked); +} + /** * Provide a linked `value` attribute for controlled forms. You should not use * this outside of the ReactDOM controlled form components. */ -var LinkedValueMixin = { - _assertLink: function() { - ("production" !== "development" ? invariant( - this.props.value == null && this.props.onChange == null, - 'Cannot provide a valueLink and a value or onChange event. If you ' + - 'want to use value or onChange, you probably don\'t want to use ' + - 'valueLink' - ) : invariant(this.props.value == null && this.props.onChange == null)); +var LinkedValueUtils = { + Mixin: { + propTypes: { + value: function(props, propName, componentName) { + if ("production" !== "development") { + if (props[propName] && + !hasReadOnlyValue[props.type] && + !props.onChange && + !props.readOnly && + !props.disabled) { + console.warn( + 'You provided a `value` prop to a form field without an ' + + '`onChange` handler. This will render a read-only field. If ' + + 'the field should be mutable use `defaultValue`. Otherwise, ' + + 'set either `onChange` or `readOnly`.' + ); + } + } + }, + checked: function(props, propName, componentName) { + if ("production" !== "development") { + if (props[propName] && + !props.onChange && + !props.readOnly && + !props.disabled) { + console.warn( + 'You provided a `checked` prop to a form field without an ' + + '`onChange` handler. This will render a read-only field. If ' + + 'the field should be mutable use `defaultChecked`. Otherwise, ' + + 'set either `onChange` or `readOnly`.' + ); + } + } + }, + onChange: ReactPropTypes.func + } }, /** + * @param {ReactComponent} input Form component * @return {*} current value of the input either from value prop or link. */ - getValue: function() { - if (this.props.valueLink) { - this._assertLink(); - return this.props.valueLink.value; + getValue: function(input) { + if (input.props.valueLink) { + _assertValueLink(input); + return input.props.valueLink.value; } - return this.props.value; + return input.props.value; }, /** + * @param {ReactComponent} input Form component + * @return {*} current checked status of the input either from checked prop + * or link. + */ + getChecked: function(input) { + if (input.props.checkedLink) { + _assertCheckedLink(input); + return input.props.checkedLink.value; + } + return input.props.checked; + }, + + /** + * @param {ReactComponent} input Form component * @return {function} change callback either from onChange prop or link. */ - getOnChange: function() { - if (this.props.valueLink) { - this._assertLink(); - return this._handleLinkedValueChange; + getOnChange: function(input) { + if (input.props.valueLink) { + _assertValueLink(input); + return _handleLinkedValueChange; + } else if (input.props.checkedLink) { + _assertCheckedLink(input); + return _handleLinkedCheckChange; } - return this.props.onChange; - }, - - /** - * @param {SyntheticEvent} e change event to handle - */ - _handleLinkedValueChange: function(e) { - this.props.valueLink.requestChange(e.target.value); + return input.props.onChange; } }; -module.exports = LinkedValueMixin; +module.exports = LinkedValueUtils; -},{"./invariant":109}],24:[function(require,module,exports){ +},{"./ReactPropTypes":69,"./invariant":121}],24:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3305,9 +3672,9 @@ var MobileSafariClickEventPlugin = { module.exports = MobileSafariClickEventPlugin; -},{"./EventConstants":15,"./emptyFunction":94}],25:[function(require,module,exports){ +},{"./EventConstants":15,"./emptyFunction":108}],25:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3326,6 +3693,8 @@ module.exports = MobileSafariClickEventPlugin; "use strict"; +var invariant = require("./invariant"); + /** * Static poolers. Several custom versions for each potential number of * arguments. A completely generic pooler is easy to implement, but would @@ -3379,6 +3748,10 @@ var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { var standardReleaser = function(instance) { var Klass = this; + ("production" !== "development" ? invariant( + instance instanceof Klass, + 'Trying to release an instance into a pool of a different type.' + ) : invariant(instance instanceof Klass)); if (instance.destructor) { instance.destructor(); } @@ -3420,9 +3793,9 @@ var PooledClass = { module.exports = PooledClass; -},{}],26:[function(require,module,exports){ +},{"./invariant":121}],26:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3441,8 +3814,12 @@ module.exports = PooledClass; "use strict"; +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var EventPluginUtils = require("./EventPluginUtils"); +var ReactChildren = require("./ReactChildren"); var ReactComponent = require("./ReactComponent"); var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactContext = require("./ReactContext"); var ReactCurrentOwner = require("./ReactCurrentOwner"); var ReactDOM = require("./ReactDOM"); var ReactDOMComponent = require("./ReactDOMComponent"); @@ -3455,13 +3832,20 @@ var ReactPropTypes = require("./ReactPropTypes"); var ReactServerRendering = require("./ReactServerRendering"); var ReactTextComponent = require("./ReactTextComponent"); +var onlyChild = require("./onlyChild"); + ReactDefaultInjection.inject(); var React = { + Children: { + map: ReactChildren.map, + forEach: ReactChildren.forEach, + only: onlyChild + }, DOM: ReactDOM, PropTypes: ReactPropTypes, initializeTouchEvents: function(shouldUseTouch) { - ReactMount.useTouchEvents = shouldUseTouch; + EventPluginUtils.useTouchEvents = shouldUseTouch; }, createClass: ReactCompositeComponent.createClass, constructAndRenderComponent: ReactMount.constructAndRenderComponent, @@ -3473,13 +3857,14 @@ var React = { ), renderComponentToString: ReactServerRendering.renderComponentToString, unmountComponentAtNode: ReactMount.unmountComponentAtNode, - unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode, isValidClass: ReactCompositeComponent.isValidClass, isValidComponent: ReactComponent.isValidComponent, + withContext: ReactContext.withContext, __internals: { Component: ReactComponent, CurrentOwner: ReactCurrentOwner, DOMComponent: ReactDOMComponent, + DOMPropertyOperations: DOMPropertyOperations, InstanceHandles: ReactInstanceHandles, Mount: ReactMount, MultiChild: ReactMultiChild, @@ -3487,15 +3872,234 @@ var React = { } }; +if ("production" !== "development") { + var ExecutionEnvironment = require("./ExecutionEnvironment"); + if (ExecutionEnvironment.canUseDOM && + window.top === window.self && + navigator.userAgent.indexOf('Chrome') > -1) { + console.debug( + 'Download the React DevTools for a better development experience: ' + + 'http://fb.me/react-devtools' + ); + } +} + // Version exists only in the open-source version of React, not in Facebook's // internal version. -React.version = '0.8.0'; +React.version = '0.9.0'; module.exports = React; -},{"./ReactComponent":28,"./ReactCompositeComponent":31,"./ReactCurrentOwner":32,"./ReactDOM":33,"./ReactDOMComponent":35,"./ReactDefaultInjection":44,"./ReactInstanceHandles":51,"./ReactMount":54,"./ReactMultiChild":56,"./ReactPerf":59,"./ReactPropTypes":61,"./ReactServerRendering":63,"./ReactTextComponent":65}],27:[function(require,module,exports){ +},{"./DOMPropertyOperations":10,"./EventPluginUtils":19,"./ExecutionEnvironment":21,"./ReactChildren":29,"./ReactComponent":30,"./ReactCompositeComponent":33,"./ReactContext":34,"./ReactCurrentOwner":35,"./ReactDOM":36,"./ReactDOMComponent":38,"./ReactDefaultInjection":48,"./ReactInstanceHandles":57,"./ReactMount":60,"./ReactMultiChild":62,"./ReactPerf":65,"./ReactPropTypes":69,"./ReactServerRendering":73,"./ReactTextComponent":76,"./onlyChild":136}],27:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 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. + * + * @typechecks + * @providesModule ReactCSSTransitionGroup + * @jsx React.DOM + */ + +"use strict"; + +var React = require("./React"); + +var ReactTransitionGroup = require("./ReactTransitionGroup"); +var ReactCSSTransitionGroupChild = require("./ReactCSSTransitionGroupChild"); + +var ReactCSSTransitionGroup = React.createClass({displayName: 'ReactCSSTransitionGroup', + propTypes: { + transitionName: React.PropTypes.string.isRequired, + transitionEnter: React.PropTypes.bool, + transitionLeave: React.PropTypes.bool + }, + + getDefaultProps: function() { + return { + transitionEnter: true, + transitionLeave: true + }; + }, + + _wrapChild: function(child) { + // We need to provide this childFactory so that + // ReactCSSTransitionGroupChild can receive updates to name, enter, and + // leave while it is leaving. + return ( + ReactCSSTransitionGroupChild( + {name:this.props.transitionName, + enter:this.props.transitionEnter, + leave:this.props.transitionLeave}, + child + ) + ); + }, + + render: function() { + return this.transferPropsTo( + ReactTransitionGroup( {childFactory:this._wrapChild}, + this.props.children + ) + ); + } +}); + +module.exports = ReactCSSTransitionGroup; + +},{"./React":26,"./ReactCSSTransitionGroupChild":28,"./ReactTransitionGroup":79}],28:[function(require,module,exports){ +/** + * Copyright 2013-2014 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. + * + * @typechecks + * @providesModule ReactCSSTransitionGroupChild + */ + +"use strict"; + +var React = require("./React"); + +var CSSCore = require("./CSSCore"); +var ReactTransitionEvents = require("./ReactTransitionEvents"); + +var onlyChild = require("./onlyChild"); + +// We don't remove the element from the DOM until we receive an animationend or +// transitionend event. If the user screws up and forgets to add an animation +// their node will be stuck in the DOM forever, so we detect if an animation +// does not start and if it doesn't, we just call the end listener immediately. +var TICK = 17; +var NO_EVENT_TIMEOUT = 5000; + +var noEventListener = null; + + +if ("production" !== "development") { + noEventListener = function() { + console.warn( + 'transition(): tried to perform an animation without ' + + 'an animationend or transitionend event after timeout (' + + NO_EVENT_TIMEOUT + 'ms). You should either disable this ' + + 'transition in JS or add a CSS animation/transition.' + ); + }; +} + +var ReactCSSTransitionGroupChild = React.createClass({ + transition: function(animationType, finishCallback) { + var node = this.getDOMNode(); + var className = this.props.name + '-' + animationType; + var activeClassName = className + '-active'; + var noEventTimeout = null; + + var endListener = function() { + if ("production" !== "development") { + clearTimeout(noEventTimeout); + } + + CSSCore.removeClass(node, className); + CSSCore.removeClass(node, activeClassName); + + ReactTransitionEvents.removeEndEventListener(node, endListener); + + // Usually this optional callback is used for informing an owner of + // a leave animation and telling it to remove the child. + finishCallback && finishCallback(); + }; + + ReactTransitionEvents.addEndEventListener(node, endListener); + + CSSCore.addClass(node, className); + + // Need to do this to actually trigger a transition. + this.queueClass(activeClassName); + + if ("production" !== "development") { + noEventTimeout = setTimeout(noEventListener, NO_EVENT_TIMEOUT); + } + }, + + queueClass: function(className) { + this.classNameQueue.push(className); + + if (this.props.runNextTick) { + this.props.runNextTick(this.flushClassNameQueue); + return; + } + + if (!this.timeout) { + this.timeout = setTimeout(this.flushClassNameQueue, TICK); + } + }, + + flushClassNameQueue: function() { + if (this.isMounted()) { + this.classNameQueue.forEach( + CSSCore.addClass.bind(CSSCore, this.getDOMNode()) + ); + } + this.classNameQueue.length = 0; + this.timeout = null; + }, + + componentWillMount: function() { + this.classNameQueue = []; + }, + + componentWillUnmount: function() { + if (this.timeout) { + clearTimeout(this.timeout); + } + }, + + componentWillEnter: function(done) { + if (this.props.enter) { + this.transition('enter', done); + } else { + done(); + } + }, + + componentWillLeave: function(done) { + if (this.props.leave) { + this.transition('leave', done); + } else { + done(); + } + }, + + render: function() { + return onlyChild(this.props.children); + } +}); + +module.exports = ReactCSSTransitionGroupChild; + +},{"./CSSCore":2,"./React":26,"./ReactTransitionEvents":78,"./onlyChild":136}],29:[function(require,module,exports){ +/** + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3548,7 +4152,7 @@ function forEachSingleChild(traverseContext, child, name, i) { * The provided forEachFunc(child, index) will be called for each * leaf child. * - * @param {array} children + * @param {?*} children Children tree container. * @param {function(*, int)} forEachFunc. * @param {*} forEachContext Context for forEachContext. */ @@ -3603,10 +4207,10 @@ function mapSingleChildIntoContext(traverseContext, child, name, i) { * TODO: This may likely break any calls to `ReactChildren.map` that were * previously relying on the fact that we guarded against null children. * - * @param {array} children + * @param {?*} children Children tree container. * @param {function(*, int)} mapFunction. * @param {*} mapContext Context for mapFunction. - * @return {array} mirrored array with mapped children. + * @return {object} Object containing the ordered map of results. */ function mapChildren(children, func, context) { if (children == null) { @@ -3627,9 +4231,9 @@ var ReactChildren = { module.exports = ReactChildren; -},{"./PooledClass":25,"./invariant":109,"./traverseAllChildren":127}],28:[function(require,module,exports){ +},{"./PooledClass":25,"./invariant":121,"./traverseAllChildren":141}],30:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3673,16 +4277,20 @@ var ComponentLifeCycle = keyMirror({ }); /** - * Warn if there's no key explicitly set on dynamic arrays of children. - * This allows us to keep track of children between updates. + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. */ -var ownerHasWarned = {}; +var ownerHasExplicitKeyWarning = {}; +var ownerHasPropertyWarning = {}; + +var NUMERIC_PROPERTY_REGEX = /^\d+$/; /** * Warn if the component doesn't have an explicit key assigned to it. * This component is in an array. The array could grow and shrink or be - * reordered. All children, that hasn't already been validated, are required to + * reordered. All children that haven't already been validated are required to * have a "key" property assigned to it. * * @internal @@ -3701,18 +4309,18 @@ function validateExplicitKey(component) { // Name of the component whose render method tried to pass children. var currentName = ReactCurrentOwner.current.constructor.displayName; - if (ownerHasWarned.hasOwnProperty(currentName)) { + if (ownerHasExplicitKeyWarning.hasOwnProperty(currentName)) { return; } - ownerHasWarned[currentName] = true; + ownerHasExplicitKeyWarning[currentName] = true; var message = 'Each child in an array should have a unique "key" prop. ' + 'Check the render method of ' + currentName + '.'; if (!component.isOwnedBy(ReactCurrentOwner.current)) { // Name of the component that originally created this child. var childOwnerName = - component.props.__owner__ && - component.props.__owner__.constructor.displayName; + component._owner && + component._owner.constructor.displayName; // Usually the current owner is the offender, but if it accepts // children as a property, it may be the creator of the child that's @@ -3720,12 +4328,39 @@ function validateExplicitKey(component) { message += ' It was passed a child from ' + childOwnerName + '.'; } + message += ' See http://fb.me/react-warning-keys for more information.'; console.warn(message); } /** - * Ensure that every component either is passed in a static location or, if - * if it's passed in an array, has an explicit key property defined. + * Warn if the key is being defined as an object property but has an incorrect + * value. + * + * @internal + * @param {string} name Property name of the key. + * @param {ReactComponent} component Component that requires a key. + */ +function validatePropertyKey(name) { + if (NUMERIC_PROPERTY_REGEX.test(name)) { + // Name of the component whose render method tried to pass children. + var currentName = ReactCurrentOwner.current.constructor.displayName; + if (ownerHasPropertyWarning.hasOwnProperty(currentName)) { + return; + } + ownerHasPropertyWarning[currentName] = true; + + console.warn( + 'Child objects should have non-numeric keys so ordering is preserved. ' + + 'Check the render method of ' + currentName + '. ' + + 'See http://fb.me/react-warning-keys for more information.' + ); + } +} + +/** + * Ensure that every component either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. * * @internal * @param {*} component Statically passed child of any type. @@ -3742,6 +4377,10 @@ function validateChildKeys(component) { } else if (ReactComponent.isValidComponent(component)) { // This component was passed in a valid location. component.__keyValidated__ = true; + } else if (component && typeof component === 'object') { + for (var name in component) { + validatePropertyKey(name, component); + } } } @@ -3778,28 +4417,18 @@ var ReactComponent = { * @final */ isValidComponent: function(object) { - return !!( - object && - typeof object.mountComponentIntoNode === 'function' && - typeof object.receiveComponent === 'function' - ); - }, - - /** - * Generate a key string that identifies a component within a set. - * - * @param {*} component A component that could contain a manual key. - * @param {number} index Index that is used if a manual key is not provided. - * @return {string} - * @internal - */ - getKey: function(component, index) { - if (component && component.props && component.props.key != null) { - // Explicit key - return '{' + component.props.key + '}'; + if (!object || !object.type || !object.type.prototype) { + return false; } - // Implicit key determined by the index in the set - return '[' + index + ']'; + // This is the safer way of duck checking the type of instance this is. + // The object can be a generic descriptor but the type property refers to + // the constructor and it's prototype can be used to inspect the type that + // will actually get mounted. + var prototype = object.type.prototype; + return ( + typeof prototype.mountComponentIntoNode === 'function' && + typeof prototype.receiveComponent === 'function' + ); }, /** @@ -3814,7 +4443,7 @@ var ReactComponent = { * * @internal */ - DOMIDOperations: ReactComponentEnvironment.DOMIDOperations, + BackendIDOperations: ReactComponentEnvironment.BackendIDOperations, /** * Optionally injectable environment dependent cleanup hook. (server vs. @@ -3889,24 +4518,24 @@ var ReactComponent = { * @public */ replaceProps: function(props, callback) { - ("production" !== "development" ? 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.' - ) : invariant(!this.props.__owner__)); ("production" !== "development" ? invariant( this.isMounted(), 'replaceProps(...): Can only update a mounted component.' ) : invariant(this.isMounted())); + ("production" !== "development" ? invariant( + this._mountDepth === 0, + 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + + 'component with a parent. 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.' + ) : invariant(this._mountDepth === 0)); this._pendingProps = props; ReactUpdates.enqueueUpdate(this, callback); }, /** - * Base constructor for all React component. + * Base constructor for all React components. * * Subclasses that override this method should make sure to invoke * `ReactComponent.Mixin.construct.call(this, ...)`. @@ -3918,13 +4547,19 @@ var ReactComponent = { construct: function(initialProps, children) { this.props = initialProps || {}; // Record the component responsible for creating this component. - this.props.__owner__ = ReactCurrentOwner.current; + this._owner = ReactCurrentOwner.current; // All components start unmounted. this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; this._pendingProps = null; this._pendingCallbacks = null; + // Unlike _pendingProps and _pendingCallbacks, we won't use null to + // indicate that nothing is pending because it's possible for a component + // to have a null owner. Instead, an owner change is pending when + // this._owner !== this._pendingOwner. + this._pendingOwner = this._owner; + // Children can be more than one argument var childrenLength = arguments.length - 1; if (childrenLength === 1) { @@ -3961,12 +4596,14 @@ var ReactComponent = { mountComponent: function(rootID, transaction, mountDepth) { ("production" !== "development" ? invariant( !this.isMounted(), - 'mountComponent(%s, ...): Can only mount an unmounted component.', + 'mountComponent(%s, ...): Can only mount an unmounted component. ' + + 'Make sure to avoid storing components between renders or reusing a ' + + 'single component instance in multiple places.', rootID ) : invariant(!this.isMounted())); var props = this.props; if (props.ref != null) { - ReactOwner.addComponentAsRefTo(this, props.ref, props.__owner__); + ReactOwner.addComponentAsRefTo(this, props.ref, this._owner); } this._rootNodeID = rootID; this._lifeCycleState = ComponentLifeCycle.MOUNTED; @@ -3991,7 +4628,7 @@ var ReactComponent = { ) : invariant(this.isMounted())); var props = this.props; if (props.ref != null) { - ReactOwner.removeComponentAsRefFrom(this, props.ref, props.__owner__); + ReactOwner.removeComponentAsRefFrom(this, props.ref, this._owner); } ReactComponent.unmountIDFromEnvironment(this._rootNodeID); this._rootNodeID = null; @@ -4014,6 +4651,7 @@ var ReactComponent = { this.isMounted(), 'receiveComponent(...): Can only update a mounted component.' ) : invariant(this.isMounted())); + this._pendingOwner = nextComponent._owner; this._pendingProps = nextComponent.props; this._performUpdateIfNecessary(transaction); }, @@ -4041,9 +4679,11 @@ var ReactComponent = { return; } var prevProps = this.props; + var prevOwner = this._owner; this.props = this._pendingProps; + this._owner = this._pendingOwner; this._pendingProps = null; - this.updateComponent(transaction, prevProps); + this.updateComponent(transaction, prevProps, prevOwner); }, /** @@ -4053,21 +4693,20 @@ var ReactComponent = { * @param {object} prevProps * @internal */ - updateComponent: function(transaction, prevProps) { + updateComponent: function(transaction, prevProps, prevOwner) { 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 (props.__owner__ !== prevProps.__owner__ || - props.ref !== prevProps.ref) { + if (this._owner !== prevOwner || props.ref !== prevProps.ref) { if (prevProps.ref != null) { ReactOwner.removeComponentAsRefFrom( - this, prevProps.ref, prevProps.__owner__ + this, prevProps.ref, prevOwner ); } // Correct, even if the owner is the same, and only the ref has changed. if (props.ref != null) { - ReactOwner.addComponentAsRefTo(this, props.ref, props.__owner__); + ReactOwner.addComponentAsRefTo(this, props.ref, this._owner); } } }, @@ -4121,7 +4760,7 @@ var ReactComponent = { * @internal */ isOwnedBy: function(owner) { - return this.props.__owner__ === owner; + return this._owner === owner; }, /** @@ -4133,7 +4772,7 @@ var ReactComponent = { * @internal */ getSiblingByRef: function(ref) { - var owner = this.props.__owner__; + var owner = this._owner; if (!owner || !owner.refs) { return null; } @@ -4144,9 +4783,9 @@ var ReactComponent = { module.exports = ReactComponent; -},{"./ReactComponentEnvironment":30,"./ReactCurrentOwner":32,"./ReactOwner":58,"./ReactUpdates":70,"./invariant":109,"./keyMirror":115,"./merge":118}],29:[function(require,module,exports){ +},{"./ReactComponentEnvironment":32,"./ReactCurrentOwner":35,"./ReactOwner":64,"./ReactUpdates":80,"./invariant":121,"./keyMirror":127,"./merge":130}],31:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -4170,11 +4809,11 @@ module.exports = ReactComponent; var ReactDOMIDOperations = require("./ReactDOMIDOperations"); var ReactMarkupChecksum = require("./ReactMarkupChecksum"); var ReactMount = require("./ReactMount"); +var ReactPerf = require("./ReactPerf"); var ReactReconcileTransaction = require("./ReactReconcileTransaction"); var getReactRootElementInContainer = require("./getReactRootElementInContainer"); var invariant = require("./invariant"); -var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup"); var ELEMENT_NODE_TYPE = 1; @@ -4208,7 +4847,7 @@ var ReactComponentBrowserEnvironment = { ReactReconcileTransaction: ReactReconcileTransaction, - DOMIDOperations: ReactDOMIDOperations, + BackendIDOperations: ReactDOMIDOperations, /** * If a particular environment requires that some resources be cleaned up, @@ -4227,68 +4866,86 @@ var ReactComponentBrowserEnvironment = { * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the * container if possible. */ - mountImageIntoNode: function(markup, container, shouldReuseMarkup) { - ("production" !== "development" ? invariant( - container && ( + mountImageIntoNode: ReactPerf.measure( + 'ReactComponentBrowserEnvironment', + 'mountImageIntoNode', + function(markup, container, shouldReuseMarkup) { + ("production" !== "development" ? invariant( + container && ( + container.nodeType === ELEMENT_NODE_TYPE || + container.nodeType === DOC_NODE_TYPE + ), + 'mountComponentIntoNode(...): Target container is not valid.' + ) : invariant(container && ( container.nodeType === ELEMENT_NODE_TYPE || - container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender - ), - 'mountComponentIntoNode(...): Target container is not valid.' - ) : invariant(container && ( - container.nodeType === ELEMENT_NODE_TYPE || - container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender - ))); - if (shouldReuseMarkup) { - if (ReactMarkupChecksum.canReuseMarkup( - markup, - getReactRootElementInContainer(container))) { - return; - } else { - if ("production" !== "development") { - console.warn( - 'React attempted to use reuse markup in a container but the ' + - 'checksum was invalid. This generally means that you are using ' + - 'server rendering and the markup generated on the server was ' + - 'not what the client was expecting. React injected new markup ' + - 'to compensate which works but you have lost many of the ' + - 'benefits of server rendering. Instead, figure out why the ' + - 'markup being generated is different on the client or server.' - ); + container.nodeType === DOC_NODE_TYPE + ))); + + if (shouldReuseMarkup) { + if (ReactMarkupChecksum.canReuseMarkup( + markup, + getReactRootElementInContainer(container))) { + return; + } else { + ("production" !== "development" ? invariant( + container.nodeType !== DOC_NODE_TYPE, + 'You\'re trying to render a component to the document using ' + + 'server rendering but the checksum was invalid. This usually ' + + 'means you rendered a different component type or props on ' + + 'the client from the one on the server, or your render() ' + + 'methods are impure. React cannot handle this case due to ' + + 'cross-browser quirks by rendering at the document root. You ' + + 'should look for environment dependent code in your components ' + + 'and ensure the props are the same client and server side.' + ) : invariant(container.nodeType !== DOC_NODE_TYPE)); + + if ("production" !== "development") { + console.warn( + 'React attempted to use reuse markup in a container but the ' + + 'checksum was invalid. This generally means that you are ' + + 'using server rendering and the markup generated on the ' + + 'server was not what the client was expecting. React injected' + + 'new markup to compensate which works but you have lost many ' + + 'of the benefits of server rendering. Instead, figure out ' + + 'why the markup being generated is different on the client ' + + 'or server.' + ); + } } } - } - // You can't naively set the innerHTML of the entire document. You need - // to mutate documentElement which requires doing some crazy tricks. See - // mutateHTMLNodeWithMarkup() - if (container.nodeType === DOC_NODE_TYPE) { - mutateHTMLNodeWithMarkup(container.documentElement, markup); - return; - } + ("production" !== "development" ? invariant( + container.nodeType !== DOC_NODE_TYPE, + 'You\'re trying to render a component to the document but ' + + 'you didn\'t use server rendering. We can\'t do this ' + + 'without using server rendering due to cross-browser quirks. ' + + 'See renderComponentToString() for server rendering.' + ) : invariant(container.nodeType !== DOC_NODE_TYPE)); - // 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); + // 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 { - parent.appendChild(container); + container.innerHTML = markup; } - } else { - container.innerHTML = markup; } - } + ) }; module.exports = ReactComponentBrowserEnvironment; -},{"./ReactDOMIDOperations":37,"./ReactMarkupChecksum":53,"./ReactMount":54,"./ReactReconcileTransaction":62,"./getReactRootElementInContainer":105,"./invariant":109,"./mutateHTMLNodeWithMarkup":122}],30:[function(require,module,exports){ +},{"./ReactDOMIDOperations":40,"./ReactMarkupChecksum":59,"./ReactMount":60,"./ReactPerf":65,"./ReactReconcileTransaction":71,"./getReactRootElementInContainer":117,"./invariant":121}],32:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -4305,6 +4962,8 @@ module.exports = ReactComponentBrowserEnvironment; * @providesModule ReactComponentEnvironment */ +"use strict"; + var ReactComponentBrowserEnvironment = require("./ReactComponentBrowserEnvironment"); @@ -4312,9 +4971,9 @@ var ReactComponentEnvironment = ReactComponentBrowserEnvironment; module.exports = ReactComponentEnvironment; -},{"./ReactComponentBrowserEnvironment":29}],31:[function(require,module,exports){ +},{"./ReactComponentBrowserEnvironment":31}],33:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -4334,11 +4993,14 @@ module.exports = ReactComponentEnvironment; "use strict"; var ReactComponent = require("./ReactComponent"); +var ReactContext = require("./ReactContext"); var ReactCurrentOwner = require("./ReactCurrentOwner"); var ReactErrorUtils = require("./ReactErrorUtils"); var ReactOwner = require("./ReactOwner"); var ReactPerf = require("./ReactPerf"); var ReactPropTransferer = require("./ReactPropTransferer"); +var ReactPropTypeLocations = require("./ReactPropTypeLocations"); +var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames"); var ReactUpdates = require("./ReactUpdates"); var invariant = require("./invariant"); @@ -4346,6 +5008,7 @@ var keyMirror = require("./keyMirror"); var merge = require("./merge"); var mixInto = require("./mixInto"); var objMap = require("./objMap"); +var shouldUpdateReactComponent = require("./shouldUpdateReactComponent"); /** * Policies that describe methods in `ReactCompositeComponentInterface`. @@ -4404,15 +5067,38 @@ var ReactCompositeComponentInterface = { */ mixins: SpecPolicy.DEFINE_MANY, + /** + * An object containing properties and methods that should be defined on + * the component's constructor instead of its prototype (static methods). + * + * @type {object} + * @optional + */ + statics: SpecPolicy.DEFINE_MANY, + /** * Definition of prop types for this component. * * @type {object} * @optional */ - propTypes: SpecPolicy.DEFINE_ONCE, + propTypes: SpecPolicy.DEFINE_MANY, + /** + * Definition of context types for this component. + * + * @type {object} + * @optional + */ + contextTypes: SpecPolicy.DEFINE_MANY, + /** + * Definition of context types this component sets for its children. + * + * @type {object} + * @optional + */ + childContextTypes: SpecPolicy.DEFINE_MANY, // ==== Definition methods ==== @@ -4444,6 +5130,12 @@ var ReactCompositeComponentInterface = { */ getInitialState: SpecPolicy.DEFINE_MANY_MERGED, + /** + * @return {object} + * @optional + */ + getChildContext: SpecPolicy.DEFINE_MANY_MERGED, + /** * Uses props from `this.props` and state from `this.state` to render the * structure of the component. @@ -4493,7 +5185,7 @@ var ReactCompositeComponentInterface = { * 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) { + * componentWillReceiveProps: function(nextProps, nextContext) { * this.setState({ * likesIncreasing: nextProps.likeCount > this.props.likeCount * }); @@ -4510,17 +5202,21 @@ var ReactCompositeComponentInterface = { /** * Invoked while deciding if the component should be updated as a result of - * receiving new props and state. + * receiving new props, state and/or context. * * 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. + * transition to the new props/state/context will not require a component + * update. * - * shouldComponentUpdate: function(nextProps, nextState) { - * return !equal(nextProps, this.props) || !equal(nextState, this.state); + * shouldComponentUpdate: function(nextProps, nextState, nextContext) { + * return !equal(nextProps, this.props) || + * !equal(nextState, this.state) || + * !equal(nextContext, this.context); * } * * @param {object} nextProps * @param {?object} nextState + * @param {?object} nextContext * @return {boolean} True if the component should update. * @optional */ @@ -4528,7 +5224,8 @@ var ReactCompositeComponentInterface = { /** * Invoked when the component is about to update due to a transition from - * `this.props` and `this.state` to `nextProps` and `nextState`. + * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState` + * and `nextContext`. * * Use this as an opportunity to perform preparation before an update occurs. * @@ -4536,6 +5233,7 @@ var ReactCompositeComponentInterface = { * * @param {object} nextProps * @param {?object} nextState + * @param {?object} nextContext * @param {ReactReconcileTransaction} transaction * @optional */ @@ -4549,6 +5247,7 @@ var ReactCompositeComponentInterface = { * * @param {object} prevProps * @param {?object} prevState + * @param {?object} prevContext * @param {DOMElement} rootNode DOM element representing the component. * @optional */ @@ -4588,25 +5287,73 @@ var ReactCompositeComponentInterface = { /** * 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. + * Although these are declared like instance properties in the specification + * when defining classes using `React.createClass`, they are actually static + * and are accessible on the constructor instead of the prototype. Despite + * being static, they must be defined outside of the "statics" key under + * which all other static methods are defined. */ var RESERVED_SPEC_KEYS = { - displayName: function(Constructor, displayName) { - Constructor.displayName = displayName; + displayName: function(ConvenienceConstructor, displayName) { + ConvenienceConstructor.componentConstructor.displayName = displayName; }, - mixins: function(Constructor, mixins) { + mixins: function(ConvenienceConstructor, mixins) { if (mixins) { for (var i = 0; i < mixins.length; i++) { - mixSpecIntoComponent(Constructor, mixins[i]); + mixSpecIntoComponent(ConvenienceConstructor, mixins[i]); } } }, - propTypes: function(Constructor, propTypes) { - Constructor.propTypes = propTypes; + childContextTypes: function(ConvenienceConstructor, childContextTypes) { + var Constructor = ConvenienceConstructor.componentConstructor; + validateTypeDef( + Constructor, + childContextTypes, + ReactPropTypeLocations.childContext + ); + Constructor.childContextTypes = merge( + Constructor.childContextTypes, + childContextTypes + ); + }, + contextTypes: function(ConvenienceConstructor, contextTypes) { + var Constructor = ConvenienceConstructor.componentConstructor; + validateTypeDef( + Constructor, + contextTypes, + ReactPropTypeLocations.context + ); + Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes); + }, + propTypes: function(ConvenienceConstructor, propTypes) { + var Constructor = ConvenienceConstructor.componentConstructor; + validateTypeDef( + Constructor, + propTypes, + ReactPropTypeLocations.prop + ); + Constructor.propTypes = merge(Constructor.propTypes, propTypes); + }, + statics: function(ConvenienceConstructor, statics) { + mixStaticSpecIntoComponent(ConvenienceConstructor, statics); } }; +function validateTypeDef(Constructor, typeDef, location) { + for (var propName in typeDef) { + if (typeDef.hasOwnProperty(propName)) { + ("production" !== "development" ? invariant( + typeof typeDef[propName] == 'function', + '%s: %s type `%s` is invalid; it must be a function, usually from ' + + 'React.PropTypes.', + Constructor.displayName || 'ReactCompositeComponent', + ReactPropTypeLocationNames[location], + propName + ) : invariant(typeof typeDef[propName] == 'function')); + } + } +} + function validateMethodOverride(proto, name) { var specPolicy = ReactCompositeComponentInterface[name]; @@ -4635,7 +5382,6 @@ function validateMethodOverride(proto, name) { } } - function validateLifeCycleOnReplaceState(instance) { var compositeLifeCycleState = instance._compositeLifeCycleState; ("production" !== "development" ? invariant( @@ -4659,17 +5405,30 @@ function validateLifeCycleOnReplaceState(instance) { * Custom version of `mixInto` which handles policy validation and reserved * specification keys when building `ReactCompositeComponent` classses. */ -function mixSpecIntoComponent(Constructor, spec) { +function mixSpecIntoComponent(ConvenienceConstructor, spec) { + ("production" !== "development" ? invariant( + !isValidClass(spec), + 'ReactCompositeComponent: You\'re attempting to ' + + 'use a component class as a mixin. Instead, just use a regular object.' + ) : invariant(!isValidClass(spec))); + ("production" !== "development" ? invariant( + !ReactComponent.isValidComponent(spec), + 'ReactCompositeComponent: You\'re attempting to ' + + 'use a component as a mixin. Instead, just use a regular object.' + ) : invariant(!ReactComponent.isValidComponent(spec))); + + var Constructor = ConvenienceConstructor.componentConstructor; var proto = Constructor.prototype; for (var name in spec) { var property = spec[name]; - if (!spec.hasOwnProperty(name) || !property) { + if (!spec.hasOwnProperty(name)) { continue; } + validateMethodOverride(proto, name); if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { - RESERVED_SPEC_KEYS[name](Constructor, property); + RESERVED_SPEC_KEYS[name](ConvenienceConstructor, property); } else { // Setup methods on prototype: // The following member methods should not be automatically bound: @@ -4677,7 +5436,7 @@ function mixSpecIntoComponent(Constructor, spec) { // 2. Overridden methods (that were mixed in). var isCompositeComponentMethod = name in ReactCompositeComponentInterface; var isInherited = name in proto; - var markedDontBind = property.__reactDontBind; + var markedDontBind = property && property.__reactDontBind; var isFunction = typeof property === 'function'; var shouldAutoBind = isFunction && @@ -4709,6 +5468,37 @@ function mixSpecIntoComponent(Constructor, spec) { } } +function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) { + if (!statics) { + return; + } + for (var name in statics) { + var property = statics[name]; + if (!statics.hasOwnProperty(name) || !property) { + return; + } + + var isInherited = name in ConvenienceConstructor; + var result = property; + if (isInherited) { + var existingProperty = ConvenienceConstructor[name]; + var existingType = typeof existingProperty; + var propertyType = typeof property; + ("production" !== "development" ? invariant( + existingType === 'function' && propertyType === 'function', + 'ReactCompositeComponent: You are attempting to define ' + + '`%s` on your component more than once, but that is only supported ' + + 'for functions, which are chained together. This conflict may be ' + + 'due to a mixin.', + name + ) : invariant(existingType === 'function' && propertyType === 'function')); + result = createChainedFunction(existingProperty, property); + } + ConvenienceConstructor[name] = result; + ConvenienceConstructor.componentConstructor[name] = result; + } +} + /** * Merge two objects, but throw if both contain the same key. * @@ -4744,10 +5534,14 @@ function mergeObjectsWithNoDuplicateKeys(one, two) { */ function createMergedResultFunction(one, two) { return function mergedResult() { - return mergeObjectsWithNoDuplicateKeys( - one.apply(this, arguments), - two.apply(this, arguments) - ); + var a = one.apply(this, arguments); + var b = two.apply(this, arguments); + if (a == null) { + return b; + } else if (b == null) { + return a; + } + return mergeObjectsWithNoDuplicateKeys(a, b); }; } @@ -4766,6 +5560,118 @@ function createChainedFunction(one, two) { }; } +if ("production" !== "development") { + + var unmountedPropertyWhitelist = { + constructor: true, + construct: true, + isOwnedBy: true, // should be deprecated but can have code mod (internal) + mountComponent: true, + mountComponentIntoNode: true, + props: true, + type: true, + _checkPropTypes: true, + _mountComponentIntoNode: true, + _processContext: true + }; + + var hasWarnedOnComponentType = {}; + + var warnIfUnmounted = function(instance, key) { + if (instance.__hasBeenMounted) { + return; + } + var name = instance.constructor.displayName || 'Unknown'; + var owner = ReactCurrentOwner.current; + var ownerName = (owner && owner.constructor.displayName) || 'Unknown'; + var warningKey = key + '|' + name + '|' + ownerName; + if (hasWarnedOnComponentType.hasOwnProperty(warningKey)) { + // We have already warned for this combination. Skip it this time. + return; + } + hasWarnedOnComponentType[warningKey] = true; + + var context = owner ? ' in ' + ownerName + '.' : ' at the top level.'; + var staticMethodExample = '<' + name + ' />.type.' + key + '(...)'; + + console.warn( + 'Invalid access to component property "' + key + '" on ' + name + + context + ' See http://fb.me/react-warning-descriptors .' + + ' Use a static method instead: ' + staticMethodExample + ); + }; + + var defineMembraneProperty = function(membrane, prototype, key) { + Object.defineProperty(membrane, key, { + + configurable: false, + enumerable: true, + + get: function() { + if (this !== membrane) { + // When this is accessed through a prototype chain we need to check if + // this component was mounted. + warnIfUnmounted(this, key); + } + return prototype[key]; + }, + + set: function(value) { + if (this !== membrane) { + // When this is accessed through a prototype chain, we first check if + // this component was mounted. Then we define a value on "this" + // instance, effectively disabling the membrane on that prototype + // chain. + warnIfUnmounted(this, key); + Object.defineProperty(this, key, { + enumerable: true, + configurable: true, + writable: true, + value: value + }); + } else { + // Otherwise, this should modify the prototype + prototype[key] = value; + } + } + + }); + }; + + /** + * Creates a membrane prototype which wraps the original prototype. If any + * property is accessed in an unmounted state, a warning is issued. + * + * @param {object} prototype Original prototype. + * @return {object} The membrane prototype. + * @private + */ + var createMountWarningMembrane = function(prototype) { + try { + var membrane = Object.create(prototype); + for (var key in prototype) { + if (unmountedPropertyWhitelist.hasOwnProperty(key)) { + continue; + } + defineMembraneProperty(membrane, prototype, key); + } + + membrane.mountComponent = function() { + this.__hasBeenMounted = true; + return prototype.mountComponent.apply(this, arguments); + }; + + return membrane; + } catch(x) { + // In IE8 define property will fail on non-DOM objects. If anything in + // the membrane creation fails, we'll bail out and just use the prototype + // without warnings. + return prototype; + } + }; + +} + /** * `ReactCompositeComponent` maintains an auxiliary life cycle state in * `this._compositeLifeCycleState` (which can be null). @@ -4831,8 +5737,14 @@ var ReactCompositeComponentMixin = { construct: function(initialProps, children) { // Children can be either an array or more than one argument ReactComponent.Mixin.construct.apply(this, arguments); + this.state = null; this._pendingState = null; + + this.context = this._processContext(ReactContext.current); + this._currentContext = ReactContext.current; + this._pendingContext = null; + this._compositeLifeCycleState = null; }, @@ -4870,13 +5782,19 @@ var ReactCompositeComponentMixin = { this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null; - this._processProps(this.props); + this.props = this._processProps(this.props); if (this.__reactAutoBindMap) { this._bindAutoBindMethods(); } this.state = this.getInitialState ? this.getInitialState() : null; + ("production" !== "development" ? invariant( + typeof this.state === 'object' && !Array.isArray(this.state), + '%s.getInitialState(): must return an object or null', + this.constructor.displayName || 'ReactCompositeComponent' + ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state))); + this._pendingState = null; this._pendingForceUpdate = false; @@ -4921,10 +5839,11 @@ var ReactCompositeComponentMixin = { this._defaultProps = null; - ReactComponent.Mixin.unmountComponent.call(this); this._renderedComponent.unmountComponent(); this._renderedComponent = null; + ReactComponent.Mixin.unmountComponent.call(this); + if (this.refs) { this.refs = null; } @@ -4953,6 +5872,18 @@ var ReactCompositeComponentMixin = { * @protected */ setState: function(partialState, callback) { + ("production" !== "development" ? invariant( + typeof partialState === 'object' || partialState == null, + 'setState(...): takes an object of state variables to update.' + ) : invariant(typeof partialState === 'object' || partialState == null)); + if ("production" !== "development") { + if (partialState == null) { + console.warn( + 'setState(...): You passed an undefined or null state object; ' + + 'instead, use forceUpdate().' + ); + } + } // Merge with `_pendingState` if it exists, otherwise with existing state. this.replaceState( merge(this._pendingState || this.state, partialState), @@ -4979,28 +5910,106 @@ var ReactCompositeComponentMixin = { }, /** - * Processes props by setting default values for unspecified props and - * asserting that the props are valid. + * Filters the context object to only contain keys specified in + * `contextTypes`, and asserts that they are valid. * - * @param {object} props + * @param {object} context + * @return {?object} * @private */ - _processProps: function(props) { - var propName; + _processContext: function(context) { + var maskedContext = null; + var contextTypes = this.constructor.contextTypes; + if (contextTypes) { + maskedContext = {}; + for (var contextName in contextTypes) { + maskedContext[contextName] = context[contextName]; + } + if ("production" !== "development") { + this._checkPropTypes( + contextTypes, + maskedContext, + ReactPropTypeLocations.context + ); + } + } + return maskedContext; + }, + + /** + * @param {object} currentContext + * @return {object} + * @private + */ + _processChildContext: function(currentContext) { + var childContext = this.getChildContext && this.getChildContext(); + var displayName = this.constructor.displayName || 'ReactCompositeComponent'; + if (childContext) { + ("production" !== "development" ? invariant( + typeof this.constructor.childContextTypes === 'object', + '%s.getChildContext(): childContextTypes must be defined in order to ' + + 'use getChildContext().', + displayName + ) : invariant(typeof this.constructor.childContextTypes === 'object')); + if ("production" !== "development") { + this._checkPropTypes( + this.constructor.childContextTypes, + childContext, + ReactPropTypeLocations.childContext + ); + } + for (var name in childContext) { + ("production" !== "development" ? invariant( + name in this.constructor.childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + displayName, + name + ) : invariant(name in this.constructor.childContextTypes)); + } + return merge(currentContext, childContext); + } + return currentContext; + }, + + /** + * Processes props by setting default values for unspecified props and + * asserting that the props are valid. Does not mutate its argument; returns + * a new props object with defaults merged in. + * + * @param {object} newProps + * @return {object} + * @private + */ + _processProps: function(newProps) { + var props = merge(newProps); var defaultProps = this._defaultProps; - for (propName in defaultProps) { - if (!(propName in props)) { + for (var propName in defaultProps) { + if (typeof props[propName] === 'undefined') { props[propName] = defaultProps[propName]; } } - var propTypes = this.constructor.propTypes; - if (propTypes) { - var componentName = this.constructor.displayName; - for (propName in propTypes) { - var checkProp = propTypes[propName]; - if (checkProp) { - checkProp(props, propName, componentName); - } + if ("production" !== "development") { + var propTypes = this.constructor.propTypes; + if (propTypes) { + this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop); + } + } + return props; + }, + + /** + * Assert that the props are valid + * + * @param {object} propTypes Map of prop name to a ReactPropType + * @param {object} props + * @param {string} location e.g. "prop", "context", "child context" + * @private + */ + _checkPropTypes: function(propTypes, props, location) { + var componentName = this.constructor.displayName; + for (var propName in propTypes) { + if (propTypes.hasOwnProperty(propName)) { + propTypes[propName](props, propName, componentName, location); } } }, @@ -5026,41 +6035,63 @@ var ReactCompositeComponentMixin = { _performUpdateIfNecessary: function(transaction) { if (this._pendingProps == null && this._pendingState == null && + this._pendingContext == null && !this._pendingForceUpdate) { return; } + var nextFullContext = this._pendingContext || this._currentContext; + var nextContext = this._processContext(nextFullContext); + this._pendingContext = null; + var nextProps = this.props; if (this._pendingProps != null) { - nextProps = this._pendingProps; - this._processProps(nextProps); + nextProps = this._processProps(this._pendingProps); this._pendingProps = null; this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; if (this.componentWillReceiveProps) { - this.componentWillReceiveProps(nextProps, transaction); + this.componentWillReceiveProps(nextProps, nextContext); } } this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; + // Unlike props, state, and context, we specifically don't want to set + // _pendingOwner to null here because it's possible for a component to have + // a null owner, so we instead make `this._owner === this._pendingOwner` + // mean that there's no owner change pending. + var nextOwner = this._pendingOwner; + var nextState = this._pendingState || this.state; this._pendingState = null; - if (this._pendingForceUpdate || - !this.shouldComponentUpdate || - this.shouldComponentUpdate(nextProps, nextState)) { - this._pendingForceUpdate = false; - // 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; + try { + if (this._pendingForceUpdate || + !this.shouldComponentUpdate || + this.shouldComponentUpdate(nextProps, nextState, nextContext)) { + this._pendingForceUpdate = false; + // Will set `this.props`, `this.state` and `this.context`. + this._performComponentUpdate( + nextProps, + nextOwner, + nextState, + nextFullContext, + nextContext, + transaction + ); + } else { + // If it's determined that a component should not update, we still want + // to set props and state. + this.props = nextProps; + this._owner = nextOwner; + this.state = nextState; + this._currentContext = nextFullContext; + this.context = nextContext; + } + } finally { + this._compositeLifeCycleState = null; } - - this._compositeLifeCycleState = null; }, /** @@ -5068,31 +6099,68 @@ var ReactCompositeComponentMixin = { * performs update. * * @param {object} nextProps Next object to set as properties. + * @param {?ReactComponent} nextOwner Next component to set as owner * @param {?object} nextState Next object to set as state. + * @param {?object} nextFullContext Next object to set as _currentContext. + * @param {?object} nextContext Next object to set as context. * @param {ReactReconcileTransaction} transaction * @private */ - _performComponentUpdate: function(nextProps, nextState, transaction) { + _performComponentUpdate: function( + nextProps, + nextOwner, + nextState, + nextFullContext, + nextContext, + transaction + ) { var prevProps = this.props; + var prevOwner = this._owner; var prevState = this.state; + var prevContext = this.context; if (this.componentWillUpdate) { - this.componentWillUpdate(nextProps, nextState, transaction); + this.componentWillUpdate(nextProps, nextState, nextContext); } this.props = nextProps; + this._owner = nextOwner; this.state = nextState; + this._currentContext = nextFullContext; + this.context = nextContext; - this.updateComponent(transaction, prevProps, prevState); + this.updateComponent( + transaction, + prevProps, + prevOwner, + prevState, + prevContext + ); if (this.componentDidUpdate) { transaction.getReactMountReady().enqueue( this, - this.componentDidUpdate.bind(this, prevProps, prevState) + this.componentDidUpdate.bind(this, prevProps, prevState, prevContext) ); } }, + receiveComponent: function(nextComponent, transaction) { + if (nextComponent === this) { + // Since props and context are immutable after the component is + // mounted, we can do a cheap identity compare here to determine + // if this is a superfluous reconcile. + return; + } + + this._pendingContext = nextComponent._currentContext; + ReactComponent.Mixin.receiveComponent.call( + this, + nextComponent, + transaction + ); + }, + /** * Updates the component's currently mounted DOM representation. * @@ -5101,32 +6169,39 @@ var ReactCompositeComponentMixin = { * * @param {ReactReconcileTransaction} transaction * @param {object} prevProps + * @param {?ReactComponent} prevOwner * @param {?object} prevState + * @param {?object} prevContext * @internal * @overridable */ updateComponent: ReactPerf.measure( 'ReactCompositeComponent', 'updateComponent', - function(transaction, prevProps, prevState) { - ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps); - var currentComponent = this._renderedComponent; + function(transaction, prevProps, prevOwner, prevState, prevContext) { + ReactComponent.Mixin.updateComponent.call( + this, + transaction, + prevProps, + prevOwner + ); + var prevComponent = this._renderedComponent; var nextComponent = this._renderValidatedComponent(); - if (currentComponent.constructor === nextComponent.constructor) { - currentComponent.receiveComponent(nextComponent, transaction); + if (shouldUpdateReactComponent(prevComponent, nextComponent)) { + prevComponent.receiveComponent(nextComponent, 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 prevComponentID = prevComponent._rootNodeID; + prevComponent.unmountComponent(); this._renderedComponent = nextComponent; var nextMarkup = nextComponent.mountComponent( thisID, transaction, this._mountDepth + 1 ); - ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( - currentComponentID, + ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID( + prevComponentID, nextMarkup ); } @@ -5170,25 +6245,29 @@ var ReactCompositeComponentMixin = { /** * @private */ - _renderValidatedComponent: function() { - var renderedComponent; - ReactCurrentOwner.current = this; - try { - renderedComponent = this.render(); - } catch (error) { - // IE8 requires `catch` in order to use `finally`. - throw error; - } finally { - ReactCurrentOwner.current = null; + _renderValidatedComponent: ReactPerf.measure( + 'ReactCompositeComponent', + '_renderValidatedComponent', + function() { + var renderedComponent; + var previousContext = ReactContext.current; + ReactContext.current = this._processChildContext(this._currentContext); + ReactCurrentOwner.current = this; + try { + renderedComponent = this.render(); + } finally { + ReactContext.current = previousContext; + ReactCurrentOwner.current = null; + } + ("production" !== "development" ? invariant( + ReactComponent.isValidComponent(renderedComponent), + '%s.render(): A valid ReactComponent must be returned. You may have ' + + 'returned null, undefined, an array, or some other invalid object.', + this.constructor.displayName || 'ReactCompositeComponent' + ) : invariant(ReactComponent.isValidComponent(renderedComponent))); + return renderedComponent; } - ("production" !== "development" ? invariant( - ReactComponent.isValidComponent(renderedComponent), - '%s.render(): A valid ReactComponent must be returned. You may have ' + - 'returned null, undefined, an array, or some other invalid object.', - this.constructor.displayName || 'ReactCompositeComponent' - ) : invariant(ReactComponent.isValidComponent(renderedComponent))); - return renderedComponent; - }, + ), /** * @private @@ -5223,7 +6302,7 @@ var ReactCompositeComponentMixin = { boundMethod.__reactBoundArguments = null; var componentName = component.constructor.displayName; var _bind = boundMethod.bind; - boundMethod.bind = function(newThis) { + boundMethod.bind = function(newThis ) {var args=Array.prototype.slice.call(arguments,1); // User is trying to bind() an autobound method; we effectively will // ignore the value of "this" that the user is trying to use, so // let's warn. @@ -5232,7 +6311,7 @@ var ReactCompositeComponentMixin = { 'bind(): React component methods may only be bound to the ' + 'component instance. See ' + componentName ); - } else if (arguments.length === 1) { + } else if (!args.length) { console.warn( 'bind(): You are binding a component method to the component. ' + 'React does this for you automatically in a high-performance ' + @@ -5243,8 +6322,7 @@ var ReactCompositeComponentMixin = { var reboundMethod = _bind.apply(boundMethod, arguments); reboundMethod.__reactBoundContext = component; reboundMethod.__reactBoundMethod = method; - reboundMethod.__reactBoundArguments = - Array.prototype.slice.call(arguments, 1); + reboundMethod.__reactBoundArguments = args; return reboundMethod; }; } @@ -5258,6 +6336,18 @@ mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); +/** + * Checks if a value is a valid component constructor. + * + * @param {*} + * @return {boolean} + * @public + */ +function isValidClass(componentClass) { + return componentClass instanceof Function && + 'componentConstructor' in componentClass && + componentClass.componentConstructor instanceof Function; +} /** * Module for creating composite components. * @@ -5283,7 +6373,17 @@ var ReactCompositeComponent = { var Constructor = function() {}; Constructor.prototype = new ReactCompositeComponentBase(); Constructor.prototype.constructor = Constructor; - mixSpecIntoComponent(Constructor, spec); + + var ConvenienceConstructor = function(props, children) { + var instance = new Constructor(); + instance.construct.apply(instance, arguments); + return instance; + }; + ConvenienceConstructor.componentConstructor = Constructor; + Constructor.ConvenienceConstructor = ConvenienceConstructor; + ConvenienceConstructor.originalSpec = spec; + + mixSpecIntoComponent(ConvenienceConstructor, spec); ("production" !== "development" ? invariant( Constructor.prototype.render, @@ -5301,6 +6401,14 @@ var ReactCompositeComponent = { } } + // Expose the convience constructor on the prototype so that it can be + // easily accessed on descriptors. E.g. .type === Foo.type and for + // static methods like .type.staticMethod(); + // This should not be named constructor since this may not be the function + // that created the descriptor, and it may not even be a constructor. + ConvenienceConstructor.type = Constructor; + Constructor.prototype.type = Constructor; + // Reduce time spent doing lookups by setting these on the prototype. for (var methodName in ReactCompositeComponentInterface) { if (!Constructor.prototype[methodName]) { @@ -5308,35 +6416,90 @@ var ReactCompositeComponent = { } } - var ConvenienceConstructor = function(props, children) { - var instance = new Constructor(); - instance.construct.apply(instance, arguments); - return instance; - }; - ConvenienceConstructor.componentConstructor = Constructor; - ConvenienceConstructor.originalSpec = spec; + if ("production" !== "development") { + Constructor.prototype = createMountWarningMembrane(Constructor.prototype); + } + return ConvenienceConstructor; }, - /** - * Checks if a value is a valid component constructor. - * - * @param {*} - * @return {boolean} - * @public - */ - isValidClass: function(componentClass) { - return componentClass instanceof Function && - 'componentConstructor' in componentClass && - componentClass.componentConstructor instanceof Function; - } + isValidClass: isValidClass }; module.exports = ReactCompositeComponent; -},{"./ReactComponent":28,"./ReactCurrentOwner":32,"./ReactErrorUtils":46,"./ReactOwner":58,"./ReactPerf":59,"./ReactPropTransferer":60,"./ReactUpdates":70,"./invariant":109,"./keyMirror":115,"./merge":118,"./mixInto":121,"./objMap":123}],32:[function(require,module,exports){ +},{"./ReactComponent":30,"./ReactContext":34,"./ReactCurrentOwner":35,"./ReactErrorUtils":51,"./ReactOwner":64,"./ReactPerf":65,"./ReactPropTransferer":66,"./ReactPropTypeLocationNames":67,"./ReactPropTypeLocations":68,"./ReactUpdates":80,"./invariant":121,"./keyMirror":127,"./merge":130,"./mixInto":133,"./objMap":134,"./shouldUpdateReactComponent":139}],34:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 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 ReactContext + */ + +"use strict"; + +var merge = require("./merge"); + +/** + * Keeps track of the current context. + * + * The context is automatically passed down the component ownership hierarchy + * and is accessible via `this.context` on ReactCompositeComponents. + */ +var ReactContext = { + + /** + * @internal + * @type {object} + */ + current: {}, + + /** + * Temporarily extends the current context while executing scopedCallback. + * + * A typical use case might look like + * + * render: function() { + * var children = ReactContext.withContext({foo: 'foo'} () => ( + * + * )); + * return
{children}
; + * } + * + * @param {object} newContext New context to merge into the existing context + * @param {function} scopedCallback Callback to run with the new context + * @return {ReactComponent|array} + */ + withContext: function(newContext, scopedCallback) { + var result; + var previousContext = ReactContext.current; + ReactContext.current = merge(previousContext, newContext); + try { + result = scopedCallback(); + } finally { + ReactContext.current = previousContext; + } + return result; + } + +}; + +module.exports = ReactContext; + +},{"./merge":130}],35:[function(require,module,exports){ +/** + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -5375,9 +6538,9 @@ var ReactCurrentOwner = { module.exports = ReactCurrentOwner; -},{}],33:[function(require,module,exports){ +},{}],36:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -5428,6 +6591,14 @@ function createDOMComponentClass(tag, omitClose) { instance.construct.apply(instance, arguments); return instance; }; + + // Expose the constructor on the ConvenienceConstructor and prototype so that + // it can be easily easily accessed on descriptors. + // E.g.
.type === div.type + ConvenienceConstructor.type = Constructor; + Constructor.prototype.type = Constructor; + + Constructor.ConvenienceConstructor = ConvenienceConstructor; ConvenienceConstructor.componentConstructor = Constructor; return ConvenienceConstructor; } @@ -5552,11 +6723,16 @@ var ReactDOM = objMapKeyVal({ // SVG circle: false, + defs: false, g: false, line: false, + linearGradient: false, path: false, + polygon: false, polyline: false, + radialGradient: false, rect: false, + stop: false, svg: false, text: false }, createDOMComponentClass); @@ -5571,9 +6747,9 @@ ReactDOM.injection = injection; module.exports = ReactDOM; -},{"./ReactDOMComponent":35,"./mergeInto":120,"./objMapKeyVal":124}],34:[function(require,module,exports){ +},{"./ReactDOMComponent":38,"./mergeInto":132,"./objMapKeyVal":135}],37:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -5592,6 +6768,7 @@ module.exports = ReactDOM; "use strict"; +var AutoFocusMixin = require("./AutoFocusMixin"); var ReactCompositeComponent = require("./ReactCompositeComponent"); var ReactDOM = require("./ReactDOM"); @@ -5618,6 +6795,9 @@ var mouseListenerNames = keyMirror({ * when `disabled` is set. */ var ReactDOMButton = ReactCompositeComponent.createClass({ + displayName: 'ReactDOMButton', + + mixins: [AutoFocusMixin], render: function() { var props = {}; @@ -5637,9 +6817,9 @@ var ReactDOMButton = ReactCompositeComponent.createClass({ module.exports = ReactDOMButton; -},{"./ReactCompositeComponent":31,"./ReactDOM":33,"./keyMirror":115}],35:[function(require,module,exports){ +},{"./AutoFocusMixin":1,"./ReactCompositeComponent":33,"./ReactDOM":36,"./keyMirror":127}],38:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -5664,8 +6844,8 @@ var DOMProperty = require("./DOMProperty"); var DOMPropertyOperations = require("./DOMPropertyOperations"); var ReactComponent = require("./ReactComponent"); var ReactEventEmitter = require("./ReactEventEmitter"); -var ReactMultiChild = require("./ReactMultiChild"); var ReactMount = require("./ReactMount"); +var ReactMultiChild = require("./ReactMultiChild"); var ReactPerf = require("./ReactPerf"); var escapeTextForBrowser = require("./escapeTextForBrowser"); @@ -5674,15 +6854,17 @@ var keyOf = require("./keyOf"); var merge = require("./merge"); var mixInto = require("./mixInto"); -var putListener = ReactEventEmitter.putListener; var deleteListener = ReactEventEmitter.deleteListener; -var registrationNames = ReactEventEmitter.registrationNames; +var listenTo = ReactEventEmitter.listenTo; +var registrationNameModules = ReactEventEmitter.registrationNameModules; // For quickly matching children type, to test if can be treated as content. var CONTENT_TYPES = {'string': true, 'number': true}; var STYLE = keyOf({style: null}); +var ELEMENT_NODE_TYPE = 1; + /** * @param {?object} props */ @@ -5702,6 +6884,22 @@ function assertValidProps(props) { ) : invariant(props.style == null || typeof props.style === 'object')); } +function putListener(id, registrationName, listener, transaction) { + var container = ReactMount.findReactContainerForID(id); + if (container) { + var doc = container.nodeType === ELEMENT_NODE_TYPE ? + container.ownerDocument : + container; + listenTo(registrationName, doc); + } + transaction.getPutListenerQueue().enqueuePutListener( + id, + registrationName, + listener + ); +} + + /** * @constructor ReactDOMComponent * @extends ReactComponent @@ -5737,7 +6935,7 @@ ReactDOMComponent.Mixin = { ); assertValidProps(this.props); return ( - this._createOpenTagMarkup() + + this._createOpenTagMarkupAndPutListeners(transaction) + this._createContentMarkup(transaction) + this._tagClose ); @@ -5753,9 +6951,10 @@ ReactDOMComponent.Mixin = { * @see http://jsperf.com/obj-vs-arr-iteration * * @private + * @param {ReactReconcileTransaction} transaction * @return {string} Markup of opening tag. */ - _createOpenTagMarkup: function() { + _createOpenTagMarkupAndPutListeners: function(transaction) { var props = this.props; var ret = this._tagOpen; @@ -5767,8 +6966,8 @@ ReactDOMComponent.Mixin = { if (propValue == null) { continue; } - if (registrationNames[propKey]) { - putListener(this._rootNodeID, propKey, propValue); + if (registrationNameModules[propKey]) { + putListener(this._rootNodeID, propKey, propValue, transaction); } else { if (propKey === STYLE) { if (propValue) { @@ -5784,8 +6983,8 @@ ReactDOMComponent.Mixin = { } } - var escapedID = escapeTextForBrowser(this._rootNodeID); - return ret + ' ' + ReactMount.ATTR_NAME + '="' + escapedID + '">'; + var idMarkup = DOMPropertyOperations.createMarkupForID(this._rootNodeID); + return ret + ' ' + idMarkup + '>'; }, /** @@ -5840,9 +7039,14 @@ ReactDOMComponent.Mixin = { updateComponent: ReactPerf.measure( 'ReactDOMComponent', 'updateComponent', - function(transaction, prevProps) { - ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps); - this._updateDOMProperties(prevProps); + function(transaction, prevProps, prevOwner) { + ReactComponent.Mixin.updateComponent.call( + this, + transaction, + prevProps, + prevOwner + ); + this._updateDOMProperties(prevProps, transaction); this._updateDOMChildren(prevProps, transaction); } ), @@ -5860,8 +7064,9 @@ ReactDOMComponent.Mixin = { * * @private * @param {object} lastProps + * @param {ReactReconcileTransaction} transaction */ - _updateDOMProperties: function(lastProps) { + _updateDOMProperties: function(lastProps, transaction) { var nextProps = this.props; var propKey; var styleName; @@ -5879,12 +7084,12 @@ ReactDOMComponent.Mixin = { styleUpdates[styleName] = ''; } } - } else if (registrationNames[propKey]) { + } else if (registrationNameModules[propKey]) { deleteListener(this._rootNodeID, propKey); } else if ( DOMProperty.isStandardName[propKey] || DOMProperty.isCustomAttribute(propKey)) { - ReactComponent.DOMIDOperations.deletePropertyByID( + ReactComponent.BackendIDOperations.deletePropertyByID( this._rootNodeID, propKey ); @@ -5921,12 +7126,12 @@ ReactDOMComponent.Mixin = { // Relies on `updateStylesByID` not mutating `styleUpdates`. styleUpdates = nextProp; } - } else if (registrationNames[propKey]) { - putListener(this._rootNodeID, propKey, nextProp); + } else if (registrationNameModules[propKey]) { + putListener(this._rootNodeID, propKey, nextProp, transaction); } else if ( DOMProperty.isStandardName[propKey] || DOMProperty.isCustomAttribute(propKey)) { - ReactComponent.DOMIDOperations.updatePropertyByID( + ReactComponent.BackendIDOperations.updatePropertyByID( this._rootNodeID, propKey, nextProp @@ -5934,7 +7139,7 @@ ReactDOMComponent.Mixin = { } } if (styleUpdates) { - ReactComponent.DOMIDOperations.updateStylesByID( + ReactComponent.BackendIDOperations.updateStylesByID( this._rootNodeID, styleUpdates ); @@ -5983,7 +7188,7 @@ ReactDOMComponent.Mixin = { } } else if (nextHtml != null) { if (lastHtml !== nextHtml) { - ReactComponent.DOMIDOperations.updateInnerHTMLByID( + ReactComponent.BackendIDOperations.updateInnerHTMLByID( this._rootNodeID, nextHtml ); @@ -6000,9 +7205,9 @@ ReactDOMComponent.Mixin = { * @internal */ unmountComponent: function() { + this.unmountChildren(); ReactEventEmitter.deleteAllListeners(this._rootNodeID); ReactComponent.Mixin.unmountComponent.call(this); - this.unmountChildren(); } }; @@ -6013,9 +7218,9 @@ mixInto(ReactDOMComponent, ReactMultiChild.Mixin); module.exports = ReactDOMComponent; -},{"./CSSPropertyOperations":4,"./DOMProperty":9,"./DOMPropertyOperations":10,"./ReactComponent":28,"./ReactEventEmitter":47,"./ReactMount":54,"./ReactMultiChild":56,"./ReactPerf":59,"./escapeTextForBrowser":95,"./invariant":109,"./keyOf":116,"./merge":118,"./mixInto":121}],36:[function(require,module,exports){ +},{"./CSSPropertyOperations":4,"./DOMProperty":9,"./DOMPropertyOperations":10,"./ReactComponent":30,"./ReactEventEmitter":52,"./ReactMount":60,"./ReactMultiChild":62,"./ReactPerf":65,"./escapeTextForBrowser":109,"./invariant":121,"./keyOf":128,"./merge":130,"./mixInto":133}],39:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -6049,6 +7254,8 @@ var form = ReactDOM.form; * composite component and use `componentDidMount` to attach the event handlers. */ var ReactDOMForm = ReactCompositeComponent.createClass({ + displayName: 'ReactDOMForm', + 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 @@ -6056,20 +7263,25 @@ var ReactDOMForm = ReactCompositeComponent.createClass({ return this.transferPropsTo(form(null, this.props.children)); }, - componentDidMount: function(node) { + componentDidMount: function() { + ReactEventEmitter.trapBubbledEvent( + EventConstants.topLevelTypes.topReset, + 'reset', + this.getDOMNode() + ); ReactEventEmitter.trapBubbledEvent( EventConstants.topLevelTypes.topSubmit, 'submit', - node + this.getDOMNode() ); } }); module.exports = ReactDOMForm; -},{"./EventConstants":15,"./ReactCompositeComponent":31,"./ReactDOM":33,"./ReactEventEmitter":47}],37:[function(require,module,exports){ +},{"./EventConstants":15,"./ReactCompositeComponent":33,"./ReactDOM":36,"./ReactEventEmitter":52}],40:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -6095,8 +7307,8 @@ var CSSPropertyOperations = require("./CSSPropertyOperations"); var DOMChildrenOperations = require("./DOMChildrenOperations"); var DOMPropertyOperations = require("./DOMPropertyOperations"); var ReactMount = require("./ReactMount"); +var ReactPerf = require("./ReactPerf"); -var getTextContentAccessor = require("./getTextContentAccessor"); var invariant = require("./invariant"); /** @@ -6111,19 +7323,11 @@ var INVALID_PROPERTY_ERRORS = { style: '`style` must be set using `updateStylesByID()`.' }; -/** - * The DOM property to use when setting text content. - * - * @type {string} - * @private - */ -var textContentAccessor = getTextContentAccessor() || 'NA'; - -var LEADING_SPACE = /^ /; +var useWhitespaceWorkaround; /** * Operations used to process updates to DOM nodes. This is made injectable via - * `ReactComponent.DOMIDOperations`. + * `ReactComponent.BackendIDOperations`. */ var ReactDOMIDOperations = { @@ -6136,23 +7340,27 @@ var ReactDOMIDOperations = { * @param {*} value New value of the property. * @internal */ - updatePropertyByID: function(id, name, value) { - var node = ReactMount.getNode(id); - ("production" !== "development" ? invariant( - !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), - 'updatePropertyByID(...): %s', - INVALID_PROPERTY_ERRORS[name] - ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); + updatePropertyByID: ReactPerf.measure( + 'ReactDOMIDOperations', + 'updatePropertyByID', + function(id, name, value) { + var node = ReactMount.getNode(id); + ("production" !== "development" ? invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); - // If we're updating to null or undefined, we should remove the property - // from the DOM node instead of inadvertantly setting to a string. This - // brings us in line with the same behavior we have on initial render. - if (value != null) { - DOMPropertyOperations.setValueForProperty(node, name, value); - } else { - DOMPropertyOperations.deleteValueForProperty(node, name); + // If we're updating to null or undefined, we should remove the property + // from the DOM node instead of inadvertantly setting to a string. This + // brings us in line with the same behavior we have on initial render. + if (value != null) { + DOMPropertyOperations.setValueForProperty(node, name, value); + } else { + DOMPropertyOperations.deleteValueForProperty(node, name); + } } - }, + ), /** * Updates a DOM node to remove a property. This should only be used to remove @@ -6162,15 +7370,19 @@ var ReactDOMIDOperations = { * @param {string} name A property name to remove, see `DOMProperty`. * @internal */ - deletePropertyByID: function(id, name, value) { - var node = ReactMount.getNode(id); - ("production" !== "development" ? invariant( - !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), - 'updatePropertyByID(...): %s', - INVALID_PROPERTY_ERRORS[name] - ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); - DOMPropertyOperations.deleteValueForProperty(node, name, value); - }, + deletePropertyByID: ReactPerf.measure( + 'ReactDOMIDOperations', + 'deletePropertyByID', + function(id, name, value) { + var node = ReactMount.getNode(id); + ("production" !== "development" ? invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); + DOMPropertyOperations.deleteValueForProperty(node, name, value); + } + ), /** * Updates a DOM node with new style values. If a value is specified as '', @@ -6180,10 +7392,14 @@ var ReactDOMIDOperations = { * @param {object} styles Mapping from styles to values. * @internal */ - updateStylesByID: function(id, styles) { - var node = ReactMount.getNode(id); - CSSPropertyOperations.setValueForStyles(node, styles); - }, + updateStylesByID: ReactPerf.measure( + 'ReactDOMIDOperations', + 'updateStylesByID', + function(id, styles) { + var node = ReactMount.getNode(id); + CSSPropertyOperations.setValueForStyles(node, styles); + } + ), /** * Updates a DOM node's innerHTML. @@ -6192,12 +7408,42 @@ var ReactDOMIDOperations = { * @param {string} html An HTML string. * @internal */ - updateInnerHTMLByID: function(id, html) { - var node = ReactMount.getNode(id); - // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces. - // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html - node.innerHTML = html.replace(LEADING_SPACE, ' '); - }, + updateInnerHTMLByID: ReactPerf.measure( + 'ReactDOMIDOperations', + 'updateInnerHTMLByID', + function(id, html) { + var node = ReactMount.getNode(id); + + // IE8: When updating a just created node with innerHTML only leading + // whitespace is removed. When updating an existing node with innerHTML + // whitespace in root TextNodes is also collapsed. + // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html + + if (useWhitespaceWorkaround === undefined) { + // Feature detection; only IE8 is known to behave improperly like this. + var temp = document.createElement('div'); + temp.innerHTML = ' '; + useWhitespaceWorkaround = temp.innerHTML === ''; + } + + if (useWhitespaceWorkaround) { + // Magic theory: IE8 supposedly differentiates between added and updated + // nodes when processing innerHTML, innerHTML on updated nodes suffers + // from worse whitespace behavior. Re-adding a node like this triggers + // the initial and more favorable whitespace behavior. + node.parentNode.replaceChild(node, node); + } + + if (useWhitespaceWorkaround && html.match(/^[ \r\n\t\f]/)) { + // Recover leading whitespace by temporarily prepending any character. + // \uFEFF has the potential advantage of being zero-width/invisible. + node.innerHTML = '\uFEFF' + html; + node.firstChild.deleteData(0, 1); + } else { + node.innerHTML = html; + } + } + ), /** * Updates a DOM node's text content set by `props.content`. @@ -6206,10 +7452,14 @@ var ReactDOMIDOperations = { * @param {string} content Text content. * @internal */ - updateTextContentByID: function(id, content) { - var node = ReactMount.getNode(id); - node[textContentAccessor] = content; - }, + updateTextContentByID: ReactPerf.measure( + 'ReactDOMIDOperations', + 'updateTextContentByID', + function(id, content) { + var node = ReactMount.getNode(id); + DOMChildrenOperations.updateTextContent(node, content); + } + ), /** * Replaces a DOM node that exists in the document with markup. @@ -6219,10 +7469,14 @@ var ReactDOMIDOperations = { * @internal * @see {Danger.dangerouslyReplaceNodeWithMarkup} */ - dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { - var node = ReactMount.getNode(id); - DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); - }, + dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure( + 'ReactDOMIDOperations', + 'dangerouslyReplaceNodeWithMarkupByID', + function(id, markup) { + var node = ReactMount.getNode(id); + DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); + } + ), /** * Updates a component's children by processing a series of updates. @@ -6231,20 +7485,83 @@ var ReactDOMIDOperations = { * @param {array} markup List of markup strings. * @internal */ - dangerouslyProcessChildrenUpdates: function(updates, markup) { - for (var i = 0; i < updates.length; i++) { - updates[i].parentNode = ReactMount.getNode(updates[i].parentID); + dangerouslyProcessChildrenUpdates: ReactPerf.measure( + 'ReactDOMIDOperations', + 'dangerouslyProcessChildrenUpdates', + function(updates, markup) { + for (var i = 0; i < updates.length; i++) { + updates[i].parentNode = ReactMount.getNode(updates[i].parentID); + } + DOMChildrenOperations.processUpdates(updates, markup); } - DOMChildrenOperations.processUpdates(updates, markup); - } - + ) }; module.exports = ReactDOMIDOperations; -},{"./CSSPropertyOperations":4,"./DOMChildrenOperations":8,"./DOMPropertyOperations":10,"./ReactMount":54,"./getTextContentAccessor":106,"./invariant":109}],38:[function(require,module,exports){ +},{"./CSSPropertyOperations":4,"./DOMChildrenOperations":8,"./DOMPropertyOperations":10,"./ReactMount":60,"./ReactPerf":65,"./invariant":121}],41:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 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 ReactDOMImg + */ + +"use strict"; + +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); +var ReactEventEmitter = require("./ReactEventEmitter"); +var EventConstants = require("./EventConstants"); + +// Store a reference to the `ReactDOMComponent`. +var img = ReactDOM.img; + +/** + * Since onLoad 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 ReactDOMImg = ReactCompositeComponent.createClass({ + displayName: 'ReactDOMImg', + tagName: 'IMG', + + render: function() { + return img(this.props); + }, + + componentDidMount: function() { + var node = this.getDOMNode(); + ReactEventEmitter.trapBubbledEvent( + EventConstants.topLevelTypes.topLoad, + 'load', + node + ); + ReactEventEmitter.trapBubbledEvent( + EventConstants.topLevelTypes.topError, + 'error', + node + ); + } +}); + +module.exports = ReactDOMImg; + +},{"./EventConstants":15,"./ReactCompositeComponent":33,"./ReactDOM":36,"./ReactEventEmitter":52}],42:[function(require,module,exports){ +/** + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -6263,8 +7580,9 @@ module.exports = ReactDOMIDOperations; "use strict"; +var AutoFocusMixin = require("./AutoFocusMixin"); var DOMPropertyOperations = require("./DOMPropertyOperations"); -var LinkedValueMixin = require("./LinkedValueMixin"); +var LinkedValueUtils = require("./LinkedValueUtils"); var ReactCompositeComponent = require("./ReactCompositeComponent"); var ReactDOM = require("./ReactDOM"); var ReactMount = require("./ReactMount"); @@ -6294,7 +7612,9 @@ var instancesByReactID = {}; * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html */ var ReactDOMInput = ReactCompositeComponent.createClass({ - mixins: [LinkedValueMixin], + displayName: 'ReactDOMInput', + + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin], getInitialState: function() { var defaultValue = this.props.defaultValue; @@ -6315,19 +7635,20 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ props.defaultChecked = null; props.defaultValue = null; - props.checked = - this.props.checked != null ? this.props.checked : this.state.checked; - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); props.value = value != null ? value : this.state.value; + var checked = LinkedValueUtils.getChecked(this); + props.checked = checked != null ? checked : this.state.checked; + props.onChange = this._handleChange; return input(props, this.props.children); }, - componentDidMount: function(rootNode) { - var id = ReactMount.getID(rootNode); + componentDidMount: function() { + var id = ReactMount.getID(this.getDOMNode()); instancesByReactID[id] = this; }, @@ -6337,7 +7658,8 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ delete instancesByReactID[id]; }, - componentDidUpdate: function(prevProps, prevState, rootNode) { + componentDidUpdate: function(prevProps, prevState, prevContext) { + var rootNode = this.getDOMNode(); if (this.props.checked != null) { DOMPropertyOperations.setValueForProperty( rootNode, @@ -6346,7 +7668,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ ); } - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); if (value != null) { // Cast `value` to a string to ensure the value is set correctly. While // browsers typically do this as necessary, jsdom doesn't. @@ -6356,10 +7678,10 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ _handleChange: function(event) { var returnValue; - var onChange = this.getOnChange(); + var onChange = LinkedValueUtils.getOnChange(this); if (onChange) { this._isChanging = true; - returnValue = onChange(event); + returnValue = onChange.call(this, event); this._isChanging = false; } this.setState({ @@ -6370,17 +7692,24 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ var name = this.props.name; if (this.props.type === 'radio' && name != null) { var rootNode = this.getDOMNode(); + var queryRoot = rootNode; + + while (queryRoot.parentNode) { + queryRoot = queryRoot.parentNode; + } + // If `rootNode.form` was non-null, then we could try `form.elements`, // but that sometimes behaves strangely in IE8. We could also try using // `form.getElementsByName`, but that will only return direct children // and won't include inputs that use the HTML5 `form=` attribute. Since // the input might not even be in a form, let's just use the global - // `getElementsByName` to ensure we don't miss anything. - var group = document.getElementsByName(name); + // `querySelectorAll` to ensure we don't miss anything. + var group = queryRoot.querySelectorAll( + 'input[name=' + JSON.stringify('' + name) + '][type="radio"]'); + for (var i = 0, groupLen = group.length; i < groupLen; i++) { var otherNode = group[i]; if (otherNode === rootNode || - otherNode.nodeName !== 'INPUT' || otherNode.type !== 'radio' || otherNode.form !== rootNode.form) { continue; } @@ -6413,9 +7742,9 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ module.exports = ReactDOMInput; -},{"./DOMPropertyOperations":10,"./LinkedValueMixin":23,"./ReactCompositeComponent":31,"./ReactDOM":33,"./ReactMount":54,"./invariant":109,"./merge":118}],39:[function(require,module,exports){ +},{"./AutoFocusMixin":1,"./DOMPropertyOperations":10,"./LinkedValueUtils":23,"./ReactCompositeComponent":33,"./ReactDOM":36,"./ReactMount":60,"./invariant":121,"./merge":130}],43:[function(require,module,exports){ /** - * Copyright 2013 Facebook, Inc. + * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -6444,6 +7773,7 @@ var option = ReactDOM.option; * Implements an