diff --git a/.coverage b/.coverage index ce2da6a..f4a01dc 100644 --- a/.coverage +++ b/.coverage @@ -1 +1 @@ -!coverage.py: This is a private format, don't read it directly!{"lines": {"/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/__init__.py": [1], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/views.py": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 24, 27, 60], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/urls.py": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/image_edit.py": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 127, 128, 130, 132, 133, 134, 135, 136, 138, 139, 140, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 157, 158, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 175], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/image_processor.py": [1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/permissions.py": [1, 4, 6, 7], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/serializers.py": [1, 2, 3, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 102, 103, 104, 105, 106, 108, 109, 111, 112, 114, 115, 116, 118, 119], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/views.py": [1, 2, 3, 4, 5, 6, 7, 11, 12, 15, 16, 19, 20, 21, 22, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 88, 99, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 118, 128, 130, 131, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 148, 149, 150, 151, 152, 153, 154, 156, 157, 159, 160, 161, 162, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 191, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218, 219, 220, 221, 222, 223, 225, 226, 227, 229, 230, 231, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 247, 248]}} \ No newline at end of file +!coverage.py: This is a private format, don't read it directly!{"lines": {"/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/__init__.py": [1], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/views.py": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 24, 27, 60], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/urls.py": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/image_edit.py": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 127, 128, 130, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/image_processor.py": [1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/permissions.py": [1, 4, 6, 7], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/serializers.py": [1, 2, 3, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 102, 103, 104, 105, 106, 108, 109, 111, 112, 114, 115, 116, 118, 119], "/Users/andela/Documents/projects/django-app/photo-editing/app/photos/api/views.py": [1, 2, 3, 4, 5, 6, 7, 11, 12, 15, 16, 19, 20, 21, 22, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 88, 99, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 118, 128, 130, 131, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 148, 149, 150, 151, 152, 153, 154, 156, 157, 159, 160, 161, 162, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 191, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218, 219, 220, 221, 222, 223, 225, 226, 227, 229, 230, 231, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 247, 248]}} \ No newline at end of file diff --git a/app/photos/api/image_edit.py b/app/photos/api/image_edit.py index 81aaecb..5e25b3f 100644 --- a/app/photos/api/image_edit.py +++ b/app/photos/api/image_edit.py @@ -118,15 +118,14 @@ def rotate(self, value): self.output = self.output.rotate(int(actual_value)) def colorize(self, black="#000", white="#fff"): + """ applies colors to black and white image """ self.black_and_white() self.output = ImageOps.colorize(self.output, black, white) def expand(self, border=10, fill="#ff0"): + """ Add border to image """ self.output = ImageOps.expand(self.output, border=border, fill=fill) - def crop(self, box): - self.output = self.output.crop(box) - def vertical_flip(self): """ Flip the image vertically (top to bottom). """ self.output = ImageOps.flip(self.output) @@ -135,37 +134,30 @@ def mirror(self): """ Flip image horizontally (left to right). """ self.output = ImageOps.mirror(self.output) - def set_font(self, font='Honey-I-spilt-Verdana.ttf', font_size=100): + def set_font(self, font_size=100, font_name="Honey-I-spilt-Verdana.ttf"): + """ Sets the font to be used for text drawing """ fonts_path = os.path.join( os.path.dirname(os.path.dirname( os.path.dirname(__file__))), 'static/fonts') - self.font = ImageFont.truetype(fonts_path + '/' + font, font_size) + font_file = fonts_path + '/' + font_name + self.font = ImageFont.truetype(font_file, font_size) - def text(self, text, x, y, fill=(255, 255, 255)): + def text(self, text, x, y, fill=(255, 255, 255), font_size=100, font_name="Honey-I-spilt-Verdana.ttf"): + """ Write text on an image """ draw = ImageDraw.Draw(self.output) if not self.font: - self.set_font() + self.set_font(font_size, font_name) draw.text((x, y), text, font=self.font, fill=fill) del draw - def line(self, start_x=0, end_x=100, start_y=0, - end_y=100, fill="#fff", width=50): - draw = ImageDraw.Draw(self.output) - draw.line((start_x, start_y, end_x, end_y), fill=fill, width=width) - del draw - - def rectangle(self, start_x=0, end_x=100, - start_y=0, end_y=100, fill="#fff"): - draw = ImageDraw.Draw(self.output) - draw.rectangle((start_x, start_y, end_x, end_y), fill=fill) - del draw - def preview(self): + """ Returns a base64 converted image """ buffered = cStringIO.StringIO() self.output.save(buffered, format=self.image_format) return base64.b64encode(buffered.getvalue()) def save(self): + """ Saves modified image """ path = self.path.replace('main', 'edited') edit_path = os.path.join( os.path.dirname(os.path.dirname( diff --git a/app/photos/api/image_processor.py b/app/photos/api/image_processor.py index bee0532..fb0f6ad 100644 --- a/app/photos/api/image_processor.py +++ b/app/photos/api/image_processor.py @@ -11,9 +11,12 @@ def process(self, effect_obj): for effect_type in effect_obj: effect_data = effect_obj[effect_type] if(effect_data): - editor_method = getattr(self, effect_type) - if editor_method: - editor_method(effect_data) + try: + editor_method = getattr(self, effect_type) + if editor_method: + editor_method(effect_data) + except: + pass def preview(self): return self.image_editor.preview() @@ -37,6 +40,30 @@ def transform(self, effect_data): if method: method() + def text_overlay(self, effect_data): + height = self.image._get_height() + width = self.image._get_width() + x = effect_data.get('x', 50) + y = effect_data.get('y', 50) + font_size = effect_data.get('fontSize', 50) + text = effect_data.get('textValue', 'Hello') + color = effect_data.get('color', '#000') + font_name = effect_data.get('font_name', 'Honey-I-spilt-Verdana.ttf') + actual_x = int(float(x)/100 * int(width)) + actual_y = int(float(y)/100 * int(height)) + actual_font_size = int(float(font_size)/100 * (int(width)/ 2)) + self.image_editor.text(text, actual_x, actual_y, color, actual_font_size, font_name) + + def colorize(self, effect_data): + black = effect_data.get('black','#000') + white = effect_data.get('white','#fff') + self.image_editor.colorize(black, white) + + def border(self, effect_data): + color = effect_data.get('border_color', '#000') + size = effect_data.get('size', 10) + self.image_editor.expand(int(size), color) + def effect(self, effect_data): for effect_data_type in effect_data: method = getattr(self.image_editor, effect_data_type) diff --git a/app/photos/tests/test_api.py b/app/photos/tests/test_api.py index f34edcb..9220af3 100644 --- a/app/photos/tests/test_api.py +++ b/app/photos/tests/test_api.py @@ -105,6 +105,18 @@ def setUp(self): """Set up base user and details for test running.""" login(self.client) + + def photo_effect(self, effects): + response = create_photo(self.client) + result = decode_json(response) + photo_id = result.get('id', 0) + data = { + 'photo_id':photo_id, + 'effects':effects + } + response = self.client.post('/api/v1/photos/' + str(photo_id) + '/preview/', data) + return decode_json(response) + def test_photo_create_without_folder(self): response = create_photo(self.client) self.assertEqual(response.status_code, 201) @@ -172,14 +184,25 @@ def test_photo_effect_update(self): def test_photo_effect_preview(self): response = create_photo(self.client) - result = decode_json(response) - photo_id = result.get('id', 0) - data = { - 'photo_id':photo_id, - 'effects':'{"transform":{"vertical_flip":"true","invert":"true","grayscale":"true","black_and_white":"true","equalize":"true"}}' - } - response = self.client.post('/api/v1/photos/' + str(photo_id) + '/preview/', data) - result = decode_json(response) + result = self.photo_effect('{"transform":{"vertical_flip":"true","invert":"true","grayscale":"true","black_and_white":"true","equalize":"true"}}') + self.assertNotEqual(result.get('image'), '') + self.assertNotEqual(result.get('image'), None) + + def test_photo_effect_text_overlay(self): + response = create_photo(self.client) + result = self.photo_effect('{"text_overlay":{"textValue":"love is key","fontSize":"26","x":"22","y":"24","color":"#ff3400","font_name":"dahot2.Filxgirl.ttf"}}') + self.assertNotEqual(result.get('image'), '') + self.assertNotEqual(result.get('image'), None) + + def test_photo_effect_colorize(self): + response = create_photo(self.client) + result = self.photo_effect('{"colorize":{"black":"#5f1212","white":"#8b572a"}}') + self.assertNotEqual(result.get('image'), '') + self.assertNotEqual(result.get('image'), None) + + def test_photo_effect_border(self): + response = create_photo(self.client) + result = self.photo_effect('{"border":{"size":"26","border_color":"#ff3737"}}') self.assertNotEqual(result.get('image'), '') self.assertNotEqual(result.get('image'), None) diff --git a/app/static/build/client.min.js b/app/static/build/client.min.js index 86211c0..1c85fec 100644 --- a/app/static/build/client.min.js +++ b/app/static/build/client.min.js @@ -88,11 +88,11 @@ var _EditImage2 = _interopRequireDefault(_EditImage); - var _FolderContent = __webpack_require__(448); + var _FolderContent = __webpack_require__(670); var _FolderContent2 = _interopRequireDefault(_FolderContent); - var _FolderUntitled = __webpack_require__(449); + var _FolderUntitled = __webpack_require__(671); var _FolderUntitled2 = _interopRequireDefault(_FolderUntitled); @@ -50112,6 +50112,11 @@ _this.emit('sharePhoto', { status: result.status, data: JSON.parse(result.text) }); }); } + }, { + key: 'broadcastColor', + value: function broadcastColor(content) { + this.emit('color', { data: content }); + } }, { key: 'handlerAction', value: function handlerAction(action) { @@ -50128,6 +50133,9 @@ case 'DELETE_PHOTO': this.delete(action.id); break; + case 'COLOR_CHANGE': + this.broadcastColor(action.content); + break; } } }]); @@ -53023,7 +53031,8 @@ _this.updateComplete = _this.updateComplete.bind(_this); _this.previewComplete = _this.previewComplete.bind(_this); _this.detail = _this.detail.bind(_this); - _this.defaultEffects = { 'enhance': {}, 'filter': {}, 'transform': {}, 'effect': {} }; + _this.changeColor = _this.changeColor.bind(_this); + _this.defaultEffects = { 'enhance': {}, 'filter': {}, 'transform': {}, 'effect': {}, 'text_overlay': {}, 'colorize': {}, 'border': {} }; return _this; } @@ -53037,6 +53046,7 @@ _PhotoStore2.default.on('updatePhoto', this.updateComplete); _PhotoStore2.default.on('previewPhoto', this.previewComplete); _PhotoStore2.default.on('photo', this.detail); + _PhotoStore2.default.on('color', this.changeColor); _PhotoStore2.default.get(id); } }, { @@ -53064,6 +53074,7 @@ _PhotoStore2.default.removeListener('updatePhoto', this.updateComplete); _PhotoStore2.default.removeListener('previewPhoto', this.previewComplete); _PhotoStore2.default.removeListener('photo', this.detail); + _PhotoStore2.default.removeListener('color', this.changeColor); } }, { key: 'detail', @@ -53100,6 +53111,11 @@ var type = $(e.target).attr('data-type'); this.updateEffect(type, name, value); } + }, { + key: 'changeColor', + value: function changeColor(result) { + this.updateEffect(result.data.type, result.data.name, result.data.value); + } }, { key: 'addEffect', value: function addEffect(type, name, value) { @@ -53134,6 +53150,7 @@ }, { key: 'decodeEffects', value: function decodeEffects(effectString) { + console.log(effectString); var effects = JSON.parse(effectString); for (var singleEffect in effects) { for (var effect_type in effects[singleEffect]) { @@ -53265,14 +53282,26 @@ var _react2 = _interopRequireDefault(_react); - var _RangeField = __webpack_require__(446); + var _RangeField = __webpack_require__(666); var _RangeField2 = _interopRequireDefault(_RangeField); - var _CheckboxField = __webpack_require__(447); + var _InputField = __webpack_require__(667); + + var _InputField2 = _interopRequireDefault(_InputField); + + var _CheckboxField = __webpack_require__(668); var _CheckboxField2 = _interopRequireDefault(_CheckboxField); + var _SelectField = __webpack_require__(669); + + var _SelectField2 = _interopRequireDefault(_SelectField); + + var _ColorField = __webpack_require__(672); + + var _ColorField2 = _interopRequireDefault(_ColorField); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -53287,7 +53316,10 @@ function _class() { _classCallCheck(this, _class); - return _possibleConstructorReturn(this, Object.getPrototypeOf(_class).apply(this, arguments)); + var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(_class).call(this)); + + _this.fonts = [{ label: 'Honey I spilt Verdana', name: 'Honey-I-spilt-Verdana.ttf' }, { label: 'Design Graffiti', name: 'design.graffiti.jd.ttf' }, { label: 'Complete in Him', name: 'dahot.Complete in Him.ttf' }, { label: 'Comes in Handy', name: 'dahot2.comesinhandy.ttf' }, { label: 'Filxgirl', name: 'dahot2.Filxgirl.ttf' }, { label: 'Heart', name: 'hearts1.ttf' }, { label: 'Mashyval', name: 'mashyval.ttf' }, { label: 'Manipulative Lovers', name: 'SC Manipulative Lovers Demo.ttf' }, { label: 'Unicode Freehand', name: 'unicode.freehani.ttf' }]; + return _this; } _createClass(_class, [{ @@ -53315,7 +53347,7 @@ ), _react2.default.createElement( 'li', - { className: '' }, + null, _react2.default.createElement( 'a', { href: '/#filter', 'data-toggle': 'tab', 'aria-expanded': 'false' }, @@ -53324,7 +53356,7 @@ ), _react2.default.createElement( 'li', - { className: '' }, + null, _react2.default.createElement( 'a', { href: '/#transform', 'data-toggle': 'tab', 'aria-expanded': 'false' }, @@ -53333,12 +53365,53 @@ ), _react2.default.createElement( 'li', - { className: '' }, + null, _react2.default.createElement( 'a', { href: '/#effects', 'data-toggle': 'tab', 'aria-expanded': 'false' }, 'Effects' ) + ), + _react2.default.createElement( + 'li', + { className: 'dropdown' }, + _react2.default.createElement( + 'a', + { className: 'dropdown-toggle', 'data-toggle': 'dropdown', href: '#' }, + 'More ', + _react2.default.createElement('span', { className: 'caret' }) + ), + _react2.default.createElement( + 'ul', + { className: 'dropdown-menu' }, + _react2.default.createElement( + 'li', + null, + _react2.default.createElement( + 'a', + { href: '/#textLayer', 'data-toggle': 'tab', 'aria-expanded': 'false' }, + 'Text Overlay' + ) + ), + _react2.default.createElement( + 'li', + null, + _react2.default.createElement( + 'a', + { href: '#image_colorize', 'data-toggle': 'tab' }, + 'Colorize' + ) + ), + _react2.default.createElement( + 'li', + null, + _react2.default.createElement( + 'a', + { href: '#image_border', 'data-toggle': 'tab' }, + 'Border' + ) + ) + ) ) ), _react2.default.createElement( @@ -53390,12 +53463,25 @@ ), _react2.default.createElement( 'div', - { className: 'tab-pane fade ', id: 'other' }, - _react2.default.createElement( - 'p', - null, - 'Overlay here' - ) + { className: 'tab-pane fade ', id: 'textLayer' }, + _react2.default.createElement(_InputField2.default, { id: 'textValue', label: 'Text', value: effects.text_overlay.textValue, check: check, change: change, type: 'text_overlay' }), + _react2.default.createElement(_RangeField2.default, { id: 'fontSize', label: 'Font Size', value: effects.text_overlay.fontSize, check: check, change: change, type: 'text_overlay' }), + _react2.default.createElement(_RangeField2.default, { id: 'x', label: 'Horizontal Position', value: effects.text_overlay.x, check: check, change: change, type: 'text_overlay' }), + _react2.default.createElement(_RangeField2.default, { id: 'y', label: 'Vertical Position', value: effects.text_overlay.y, check: check, change: change, type: 'text_overlay' }), + _react2.default.createElement(_InputField2.default, { id: 'color', label: 'Color Code(Hex)', value: effects.text_overlay.color, check: check, change: change, type: 'text_overlay' }), + _react2.default.createElement(_SelectField2.default, { id: 'font_name', label: 'Font', value: effects.text_overlay.font_name, check: check, change: change, options: this.fonts, defaultOption: 'Honey-I-spilt-Verdana.ttf', type: 'text_overlay' }) + ), + _react2.default.createElement( + 'div', + { className: 'tab-pane fade ', id: 'image_colorize' }, + _react2.default.createElement(_ColorField2.default, { id: 'black', label: 'Black Color', value: effects.colorize.black, check: check, change: change, defaultColor: '#000000', type: 'colorize' }), + _react2.default.createElement(_ColorField2.default, { id: 'white', label: 'White Color', value: effects.colorize.white, check: check, change: change, defaultColor: '#ffffff', type: 'colorize' }) + ), + _react2.default.createElement( + 'div', + { className: 'tab-pane fade ', id: 'image_border' }, + _react2.default.createElement(_RangeField2.default, { id: 'size', label: 'Size', value: effects.border.size, check: check, change: change, type: 'border' }), + _react2.default.createElement(_ColorField2.default, { id: 'border_color', label: 'Border Color', value: effects.border.border_color, check: check, change: change, defaultColor: '#000000', type: 'border' }) ) ) ); @@ -53411,84 +53497,102 @@ /* 446 */ /***/ function(module, exports, __webpack_require__) { - "use strict"; + 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); + exports.default = exports.CustomPicker = exports.SwatchesPicker = exports.SliderPicker = exports.SketchPicker = exports.PhotoshopPicker = exports.MaterialPicker = exports.CompactPicker = exports.ChromePicker = undefined; - var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + var _Chrome = __webpack_require__(447); - var _react = __webpack_require__(1); + Object.defineProperty(exports, 'ChromePicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Chrome).default; + } + }); - var _react2 = _interopRequireDefault(_react); + var _Compact = __webpack_require__(640); - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + Object.defineProperty(exports, 'CompactPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Compact).default; + } + }); - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + var _Material = __webpack_require__(650); - function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + Object.defineProperty(exports, 'MaterialPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Material).default; + } + }); - function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + var _Photoshop = __webpack_require__(651); - var _class = function (_React$Component) { - _inherits(_class, _React$Component); + Object.defineProperty(exports, 'PhotoshopPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Photoshop).default; + } + }); - function _class() { - _classCallCheck(this, _class); + var _Sketch = __webpack_require__(655); - return _possibleConstructorReturn(this, Object.getPrototypeOf(_class).apply(this, arguments)); + Object.defineProperty(exports, 'SketchPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Sketch).default; } + }); - _createClass(_class, [{ - key: "render", - value: function render() { - var _props = this.props; - var id = _props.id; - var value = _props.value; - var check = _props.check; - var change = _props.change; - var label = _props.label; - var type = _props.type; + var _Slider = __webpack_require__(658); - return _react2.default.createElement( - "div", - { className: "form-group" }, - _react2.default.createElement( - "label", - { className: "control-label w100", htmlFor: id }, - _react2.default.createElement( - "span", - { className: "left" }, - label, - value ? "(" + value + "%)" : "", - " " - ), - _react2.default.createElement( - "span", - { className: "right" }, - _react2.default.createElement("input", { type: "checkbox", onChange: check, value: id, checked: value }) - ) - ), - _react2.default.createElement("input", { type: "range", id: id, onChange: change, disabled: !value, "data-type": type, min: "1", max: "99", defaultValue: value }) - ); - } - }]); + Object.defineProperty(exports, 'SliderPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Slider).default; + } + }); - return _class; - }(_react2.default.Component); + var _Swatches = __webpack_require__(662); - exports.default = _class; + Object.defineProperty(exports, 'SwatchesPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Swatches).default; + } + }); + + var _ColorWrap = __webpack_require__(633); + + Object.defineProperty(exports, 'CustomPicker', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_ColorWrap).default; + } + }); + + var _Chrome2 = _interopRequireDefault(_Chrome); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + exports.default = _Chrome2.default; /***/ }, /* 447 */ /***/ function(module, exports, __webpack_require__) { - "use strict"; - + 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); + exports.Chrome = undefined; + + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); @@ -53496,6 +53600,28 @@ var _react2 = _interopRequireDefault(_react); + var _reactcss = __webpack_require__(448); + + var _reactcss2 = _interopRequireDefault(_reactcss); + + var _common = __webpack_require__(623); + + var _ChromeFields = __webpack_require__(637); + + var _ChromeFields2 = _interopRequireDefault(_ChromeFields); + + var _ChromePointer = __webpack_require__(638); + + var _ChromePointer2 = _interopRequireDefault(_ChromePointer); + + var _ChromePointerCircle = __webpack_require__(639); + + var _ChromePointerCircle2 = _interopRequireDefault(_ChromePointerCircle); + + var _reactAddonsShallowCompare = __webpack_require__(625); + + var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -53504,151 +53630,55947 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - var _class = function (_React$Component) { - _inherits(_class, _React$Component); + var Chrome = exports.Chrome = function (_ReactCSS$Component) { + _inherits(Chrome, _ReactCSS$Component); - function _class() { - _classCallCheck(this, _class); + function Chrome() { + var _Object$getPrototypeO; - return _possibleConstructorReturn(this, Object.getPrototypeOf(_class).apply(this, arguments)); + var _temp, _this, _ret; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + _classCallCheck(this, Chrome); + + return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(Chrome)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.shouldComponentUpdate = _reactAddonsShallowCompare2.default.bind(_this, _this, arguments[0], arguments[1]), _this.handleChange = function (data) { + _this.props.onChange(data); + }, _temp), _possibleConstructorReturn(_this, _ret); } - _createClass(_class, [{ - key: "render", + _createClass(Chrome, [{ + key: 'classes', + value: function classes() { + return { + 'default': { + picker: { + background: '#fff', + borderRadius: '2px', + boxShadow: '0 0 2px rgba(0,0,0,.3), 0 4px 8px rgba(0,0,0,.3)', + boxSizing: 'initial', + width: '225px', + fontFamily: 'Menlo' + }, + saturation: { + width: '100%', + paddingBottom: '55%', + position: 'relative', + borderRadius: '2px 2px 0 0', + overflow: 'hidden' + }, + Saturation: { + radius: '2px 2px 0 0' + }, + body: { + padding: '16px 16px 12px' + }, + controls: { + display: 'flex' + }, + color: { + width: '32px' + }, + swatch: { + marginTop: '6px', + width: '16px', + height: '16px', + borderRadius: '8px', + position: 'relative', + overflow: 'hidden' + }, + active: { + Absolute: '0px 0px 0px 0px', + borderRadius: '8px', + boxShadow: 'inset 0 0 0 1px rgba(0,0,0,.1)', + background: 'rgba(' + this.props.rgb.r + ', ' + this.props.rgb.g + ', ' + this.props.rgb.b + ', ' + this.props.rgb.a + ')', + zIndex: '2' + }, + toggles: { + flex: '1' + }, + hue: { + height: '10px', + position: 'relative', + marginBottom: '8px' + }, + Hue: { + radius: '2px' + }, + alpha: { + height: '10px', + position: 'relative' + }, + Alpha: { + radius: '2px' + } + }, + 'disableAlpha': { + color: { + width: '22px' + }, + alpha: { + display: 'none' + }, + hue: { + marginBottom: '0px' + }, + swatch: { + width: '10px', + height: '10px', + marginTop: '0px' + } + } + }; + } + }, { + key: 'render', value: function render() { - var _props = this.props; - var id = _props.id; - var value = _props.value; - var check = _props.check; - var label = _props.label; - var type = _props.type; - + console.log(this.props.rgb); return _react2.default.createElement( - "div", - { className: "form-group" }, + 'div', + { style: this.styles().picker }, _react2.default.createElement( - "label", - { className: "control-label w100", htmlFor: id }, + 'div', + { style: this.styles().saturation }, + _react2.default.createElement(_common.Saturation, _extends({}, this.styles().Saturation, this.props, { pointer: _ChromePointerCircle2.default, onChange: this.handleChange })) + ), + _react2.default.createElement( + 'div', + { style: this.styles().body }, _react2.default.createElement( - "span", - { className: "left" }, - label, - " " + 'div', + { style: this.styles().controls, className: 'flexbox-fix' }, + _react2.default.createElement( + 'div', + { style: this.styles().color }, + _react2.default.createElement( + 'div', + { style: this.styles().swatch }, + _react2.default.createElement('div', { style: this.styles().active }), + _react2.default.createElement(_common.Checkboard, null) + ) + ), + _react2.default.createElement( + 'div', + { style: this.styles().toggles }, + _react2.default.createElement( + 'div', + { style: this.styles().hue }, + _react2.default.createElement(_common.Hue, _extends({}, this.styles().Hue, this.props, { pointer: _ChromePointer2.default, onChange: this.handleChange })) + ), + _react2.default.createElement( + 'div', + { style: this.styles().alpha }, + _react2.default.createElement(_common.Alpha, _extends({}, this.styles().Alpha, this.props, { pointer: _ChromePointer2.default, onChange: this.handleChange })) + ) + ) ), - _react2.default.createElement( - "span", - { className: "right" }, - _react2.default.createElement("input", { type: "checkbox", onChange: check, value: id, checked: value }) - ) - ), - _react2.default.createElement("input", { type: "hidden", id: id, "data-type": type, value: true }) + _react2.default.createElement(_ChromeFields2.default, _extends({}, this.props, { onChange: this.handleChange, disableAlpha: this.props.disableAlpha })) + ) ); } }]); - return _class; - }(_react2.default.Component); + return Chrome; + }(_reactcss2.default.Component); - exports.default = _class; + exports.default = (0, _common.ColorWrap)(Chrome); /***/ }, /* 448 */ +/***/ function(module, exports, __webpack_require__) { + + "use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _transform=__webpack_require__(449),_transform2=_interopRequireDefault(_transform),_Component=__webpack_require__(615),_Component2=_interopRequireDefault(_Component),_inline=__webpack_require__(609),_inline2=_interopRequireDefault(_inline),_Hover=__webpack_require__(621),_Hover2=_interopRequireDefault(_Hover),_loopable=__webpack_require__(622),_loopable2=_interopRequireDefault(_loopable),ReactCSS=_transform2["default"];ReactCSS.Component=_Component2["default"],ReactCSS.inline=_inline2["default"],ReactCSS.mixin={css:_inline2["default"]},ReactCSS.Hover=_Hover2["default"],ReactCSS.loopable=_loopable2["default"],exports["default"]=ReactCSS; + +/***/ }, +/* 449 */ +/***/ function(module, exports, __webpack_require__) { + + "use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function ReactCSS(e){return function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,Object.getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),_createClass(t,[{key:"styles",value:function(){return _inline2["default"].call(this,_get(Object.getPrototypeOf(t.prototype),"activations",this)&&_get(Object.getPrototypeOf(t.prototype),"activations",this).call(this))}},{key:"render",value:function(){return transformElement(this,_get(Object.getPrototypeOf(t.prototype),"render",this).call(this),_get(Object.getPrototypeOf(t.prototype),"classes",this)&&_get(Object.getPrototypeOf(t.prototype),"classes",this).call(this))}}]),t}(e)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) { + console.debug('Download the React DevTools for a better development experience: ' + 'https://fb.me/react-devtools'); + } } - }]); - return _class; - }(_react2.default.Component); + // If we're in IE8, check to see if we are in compatibility mode and provide + // information on preventing compatibility mode + var ieCompatibilityMode = document.documentMode && document.documentMode < 8; - exports.default = _class; + process.env.NODE_ENV !== 'production' ? warning(!ieCompatibilityMode, 'Internet Explorer is running in compatibility mode; please add the ' + 'following tag to your HTML to prevent this from happening: ' + '') : undefined; + + var expectedFeatures = [ + // shims + Array.isArray, Array.prototype.every, Array.prototype.forEach, Array.prototype.indexOf, Array.prototype.map, Date.now, Function.prototype.bind, Object.keys, String.prototype.split, String.prototype.trim, + + // shams + Object.create, Object.freeze]; + + for (var i = 0; i < expectedFeatures.length; i++) { + if (!expectedFeatures[i]) { + console.error('One or more ES5 shim/shams expected by React are not available: ' + 'https://fb.me/react-warning-polyfills'); + break; + } + } + } + } + + module.exports = React; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) /***/ }, -/* 449 */ -/***/ function(module, exports, __webpack_require__) { +/* 453 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactCurrentOwner + */ 'use strict'; - Object.defineProperty(exports, "__esModule", { - value: true - }); + /** + * Keeps track of the current owner. + * + * The current owner is the component who should own any components that are + * currently being constructed. + */ + var ReactCurrentOwner = { - var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + /** + * @internal + * @type {ReactComponent} + */ + current: null - var _react = __webpack_require__(1); + }; - var _react2 = _interopRequireDefault(_react); + module.exports = ReactCurrentOwner; - var _Photos = __webpack_require__(441); +/***/ }, +/* 454 */ +/***/ function(module, exports, __webpack_require__) { - var _Photos2 = _interopRequireDefault(_Photos); + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMTextComponent + * @typechecks static-only + */ - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + 'use strict'; - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + var DOMChildrenOperations = __webpack_require__(455); + var DOMPropertyOperations = __webpack_require__(470); + var ReactComponentBrowserEnvironment = __webpack_require__(474); + var ReactMount = __webpack_require__(476); - function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + var assign = __webpack_require__(487); + var escapeTextContentForBrowser = __webpack_require__(469); + var setTextContent = __webpack_require__(468); + var validateDOMNesting = __webpack_require__(518); - function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + /** + * Text nodes violate a couple assumptions that React makes about components: + * + * - When mounting text into the DOM, adjacent text nodes are merged. + * - Text nodes cannot be assigned a React root ID. + * + * This component is used to wrap strings in elements so that they can undergo + * the same reconciliation that is applied to elements. + * + * TODO: Investigate representing React components in the DOM with text nodes. + * + * @class ReactDOMTextComponent + * @extends ReactComponent + * @internal + */ + var ReactDOMTextComponent = function (props) { + // This constructor and its argument is currently used by mocks. + }; - var _class = function (_React$Component) { - _inherits(_class, _React$Component); + assign(ReactDOMTextComponent.prototype, { - function _class() { - _classCallCheck(this, _class); + /** + * @param {ReactText} text + * @internal + */ + construct: function (text) { + // TODO: This is really a ReactText (ReactNode), not a ReactElement + this._currentElement = text; + this._stringText = '' + text; - return _possibleConstructorReturn(this, Object.getPrototypeOf(_class).apply(this, arguments)); - } + // Properties + this._rootNodeID = null; + this._mountIndex = 0; + }, - _createClass(_class, [{ - key: 'render', - value: function render() { - $('#active-folder').val(0); - return _react2.default.createElement(_Photos2.default, { folder_id: 0 }); + /** + * Creates the markup for this text node. This node is not intended to have + * any features besides containing text content. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {string} Markup for this text node. + * @internal + */ + mountComponent: function (rootID, transaction, context) { + if (process.env.NODE_ENV !== 'production') { + if (context[validateDOMNesting.ancestorInfoContextKey]) { + validateDOMNesting('span', null, context[validateDOMNesting.ancestorInfoContextKey]); + } } - }]); - return _class; + this._rootNodeID = rootID; + if (transaction.useCreateElement) { + var ownerDocument = context[ReactMount.ownerDocumentContextKey]; + var el = ownerDocument.createElement('span'); + DOMPropertyOperations.setAttributeForID(el, rootID); + // Populate node cache + ReactMount.getID(el); + setTextContent(el, this._stringText); + return el; + } else { + var escapedText = escapeTextContentForBrowser(this._stringText); + + if (transaction.renderToStaticMarkup) { + // Normally we'd wrap this in a `span` for the reasons stated above, but + // since this is a situation where React won't take over (static pages), + // we can simply return the text as it is. + return escapedText; + } + + return '' + escapedText + ''; + } + }, + + /** + * Updates this component by updating the text content. + * + * @param {ReactText} nextText The next text content + * @param {ReactReconcileTransaction} transaction + * @internal + */ + receiveComponent: function (nextText, transaction) { + if (nextText !== this._currentElement) { + this._currentElement = nextText; + var nextStringText = '' + nextText; + if (nextStringText !== this._stringText) { + // TODO: Save this as pending props and use performUpdateIfNecessary + // and/or updateComponent to do the actual update for consistency with + // other component types? + this._stringText = nextStringText; + var node = ReactMount.getNode(this._rootNodeID); + DOMChildrenOperations.updateTextContent(node, nextStringText); + } + } + }, + + unmountComponent: function () { + ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID); + } + + }); + + module.exports = ReactDOMTextComponent; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 455 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMChildrenOperations + * @typechecks static-only + */ + + 'use strict'; + + var Danger = __webpack_require__(456); + var ReactMultiChildUpdateTypes = __webpack_require__(464); + var ReactPerf = __webpack_require__(466); + + var setInnerHTML = __webpack_require__(467); + var setTextContent = __webpack_require__(468); + var invariant = __webpack_require__(461); + + /** + * Inserts `childNode` as a child of `parentNode` at the `index`. + * + * @param {DOMElement} parentNode Parent node in which to insert. + * @param {DOMElement} childNode Child node to insert. + * @param {number} index Index at which to insert the child. + * @internal + */ + function insertChildAt(parentNode, childNode, index) { + // By exploiting arrays returning `undefined` for an undefined index, we can + // rely exclusively on `insertBefore(node, null)` instead of also using + // `appendChild(node)`. However, using `undefined` is not allowed by all + // browsers so we must replace it with `null`. + + // fix render order error in safari + // IE8 will throw error when index out of list size. + var beforeChild = index >= parentNode.childNodes.length ? null : parentNode.childNodes.item(index); + + parentNode.insertBefore(childNode, beforeChild); + } + + /** + * Operations for updating with DOM children. + */ + var DOMChildrenOperations = { + + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + + updateTextContent: setTextContent, + + /** + * Updates a component's children by processing a series of updates. The + * update configurations are each expected to have a `parentNode` property. + * + * @param {array} updates List of update configurations. + * @param {array} markupList List of markup strings. + * @internal + */ + processUpdates: function (updates, markupList) { + var update; + // Mapping from parent IDs to initial child orderings. + var initialChildren = null; + // List of children that will be moved or removed. + var updatedChildren = null; + + for (var i = 0; i < updates.length; i++) { + update = updates[i]; + if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) { + var updatedIndex = update.fromIndex; + var updatedChild = update.parentNode.childNodes[updatedIndex]; + var parentID = update.parentID; + + !updatedChild ? process.env.NODE_ENV !== 'production' ? invariant(false, 'processUpdates(): Unable to find child %s of element. This ' + 'probably means the DOM was unexpectedly mutated (e.g., by the ' + 'browser), usually due to forgetting a when using tables, ' + 'nesting tags like
,

, or , or using non-SVG elements ' + 'in an parent. Try inspecting the child nodes of the element ' + 'with React ID `%s`.', updatedIndex, parentID) : invariant(false) : undefined; + + initialChildren = initialChildren || {}; + initialChildren[parentID] = initialChildren[parentID] || []; + initialChildren[parentID][updatedIndex] = updatedChild; + + updatedChildren = updatedChildren || []; + updatedChildren.push(updatedChild); + } + } + + var renderedMarkup; + // markupList is either a list of markup or just a list of elements + if (markupList.length && typeof markupList[0] === 'string') { + renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); + } else { + renderedMarkup = markupList; + } + + // Remove updated children first so that `toIndex` is consistent. + if (updatedChildren) { + for (var j = 0; j < updatedChildren.length; j++) { + updatedChildren[j].parentNode.removeChild(updatedChildren[j]); + } + } + + for (var k = 0; k < updates.length; k++) { + update = updates[k]; + switch (update.type) { + case ReactMultiChildUpdateTypes.INSERT_MARKUP: + insertChildAt(update.parentNode, renderedMarkup[update.markupIndex], update.toIndex); + break; + case ReactMultiChildUpdateTypes.MOVE_EXISTING: + insertChildAt(update.parentNode, initialChildren[update.parentID][update.fromIndex], update.toIndex); + break; + case ReactMultiChildUpdateTypes.SET_MARKUP: + setInnerHTML(update.parentNode, update.content); + break; + case ReactMultiChildUpdateTypes.TEXT_CONTENT: + setTextContent(update.parentNode, update.content); + break; + case ReactMultiChildUpdateTypes.REMOVE_NODE: + // Already removed by the for-loop above. + break; + } + } + } + + }; + + ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', { + updateTextContent: 'updateTextContent' + }); + + module.exports = DOMChildrenOperations; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 456 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Danger + * @typechecks static-only + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(457); + + var createNodesFromMarkup = __webpack_require__(458); + var emptyFunction = __webpack_require__(463); + var getMarkupWrap = __webpack_require__(462); + var invariant = __webpack_require__(461); + + var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/; + var RESULT_INDEX_ATTR = 'data-danger-index'; + + /** + * Extracts the `nodeName` from a string of markup. + * + * NOTE: Extracting the `nodeName` does not require a regular expression match + * because we make assumptions about React-generated markup (i.e. there are no + * spaces surrounding the opening tag and there is at least one attribute). + * + * @param {string} markup String of markup. + * @return {string} Node name of the supplied markup. + * @see http://jsperf.com/extract-nodename + */ + function getNodeName(markup) { + return markup.substring(1, markup.indexOf(' ')); + } + + var Danger = { + + /** + * Renders markup into an array of nodes. The markup is expected to render + * into a list of root nodes. Also, the length of `resultList` and + * `markupList` should be the same. + * + * @param {array} markupList List of markup strings to render. + * @return {array} List of rendered nodes. + * @internal + */ + dangerouslyRenderMarkup: function (markupList) { + !ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' + 'thread. Make sure `window` and `document` are available globally ' + 'before requiring React when unit testing or use ' + 'ReactDOMServer.renderToString for server rendering.') : invariant(false) : undefined; + var nodeName; + var markupByNodeName = {}; + // Group markup by `nodeName` if a wrap is necessary, else by '*'. + for (var i = 0; i < markupList.length; i++) { + !markupList[i] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyRenderMarkup(...): Missing markup.') : invariant(false) : undefined; + nodeName = getNodeName(markupList[i]); + nodeName = getMarkupWrap(nodeName) ? nodeName : '*'; + markupByNodeName[nodeName] = markupByNodeName[nodeName] || []; + markupByNodeName[nodeName][i] = markupList[i]; + } + var resultList = []; + var resultListAssignmentCount = 0; + for (nodeName in markupByNodeName) { + if (!markupByNodeName.hasOwnProperty(nodeName)) { + continue; + } + var markupListByNodeName = markupByNodeName[nodeName]; + + // This for-in loop skips the holes of the sparse array. The order of + // iteration should follow the order of assignment, which happens to match + // numerical index order, but we don't rely on that. + var resultIndex; + for (resultIndex in markupListByNodeName) { + if (markupListByNodeName.hasOwnProperty(resultIndex)) { + var markup = markupListByNodeName[resultIndex]; + + // Push the requested markup with an additional RESULT_INDEX_ATTR + // attribute. If the markup does not start with a < character, it + // will be discarded below (with an appropriate console.error). + markupListByNodeName[resultIndex] = markup.replace(OPEN_TAG_NAME_EXP, + // This index will be parsed back out below. + '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '); + } + } + + // Render each group of markup with similar wrapping `nodeName`. + var renderNodes = createNodesFromMarkup(markupListByNodeName.join(''), emptyFunction // Do nothing special with ', '
']; + var trWrap = [3, '', '
']; + + var svgWrap = [1, '', '']; + + var markupWrap = { + '*': [1, '?

', '
'], + + 'area': [1, '', ''], + 'col': [2, '', '
'], + 'legend': [1, '
', '
'], + 'param': [1, '', ''], + 'tr': [2, '', '
'], + + 'optgroup': selectWrap, + 'option': selectWrap, + + 'caption': tableWrap, + 'colgroup': tableWrap, + 'tbody': tableWrap, + 'tfoot': tableWrap, + 'thead': tableWrap, + + 'td': trWrap, + 'th': trWrap + }; + + // Initialize the SVG elements since we know they'll always need to be wrapped + // consistently. If they are created inside a
they will be initialized in + // the wrong namespace (and will not display). + var svgElements = ['circle', 'clipPath', 'defs', 'ellipse', 'g', 'image', 'line', 'linearGradient', 'mask', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'stop', 'text', 'tspan']; + svgElements.forEach(function (nodeName) { + markupWrap[nodeName] = svgWrap; + shouldWrap[nodeName] = true; + }); + + /** + * Gets the markup wrap configuration for the supplied `nodeName`. + * + * NOTE: This lazily detects which wraps are necessary for the current browser. + * + * @param {string} nodeName Lowercase `nodeName`. + * @return {?array} Markup wrap configuration, if applicable. + */ + function getMarkupWrap(nodeName) { + !!!dummyNode ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Markup wrapping node not initialized') : invariant(false) : undefined; + if (!markupWrap.hasOwnProperty(nodeName)) { + nodeName = '*'; + } + if (!shouldWrap.hasOwnProperty(nodeName)) { + if (nodeName === '*') { + dummyNode.innerHTML = ''; + } else { + dummyNode.innerHTML = '<' + nodeName + '>'; + } + shouldWrap[nodeName] = !dummyNode.firstChild; + } + return shouldWrap[nodeName] ? markupWrap[nodeName] : null; + } + + module.exports = getMarkupWrap; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 463 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule emptyFunction + */ + + "use strict"; + + function makeEmptyFunction(arg) { + return function () { + return arg; + }; + } + + /** + * This function accepts and discards inputs; it has no side effects. This is + * primarily useful idiomatically for overridable function endpoints which + * always need to be callable, since JS lacks a null-call idiom ala Cocoa. + */ + function emptyFunction() {} + + emptyFunction.thatReturns = makeEmptyFunction; + emptyFunction.thatReturnsFalse = makeEmptyFunction(false); + emptyFunction.thatReturnsTrue = makeEmptyFunction(true); + emptyFunction.thatReturnsNull = makeEmptyFunction(null); + emptyFunction.thatReturnsThis = function () { + return this; + }; + emptyFunction.thatReturnsArgument = function (arg) { + return arg; + }; + + module.exports = emptyFunction; + +/***/ }, +/* 464 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactMultiChildUpdateTypes + */ + + 'use strict'; + + var keyMirror = __webpack_require__(465); + + /** + * When a component's children are updated, a series of update configuration + * objects are created in order to batch and serialize the required changes. + * + * Enumerates all the possible types of update configurations. + * + * @internal + */ + var ReactMultiChildUpdateTypes = keyMirror({ + INSERT_MARKUP: null, + MOVE_EXISTING: null, + REMOVE_NODE: null, + SET_MARKUP: null, + TEXT_CONTENT: null + }); + + module.exports = ReactMultiChildUpdateTypes; + +/***/ }, +/* 465 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule keyMirror + * @typechecks static-only + */ + + 'use strict'; + + var invariant = __webpack_require__(461); + + /** + * Constructs an enumeration with keys equal to their value. + * + * For example: + * + * var COLORS = keyMirror({blue: null, red: null}); + * var myColor = COLORS.blue; + * var isColorValid = !!COLORS[myColor]; + * + * The last line could not be performed if the values of the generated enum were + * not equal to their keys. + * + * Input: {key1: val1, key2: val2} + * Output: {key1: key1, key2: key2} + * + * @param {object} obj + * @return {object} + */ + var keyMirror = function (obj) { + var ret = {}; + var key; + !(obj instanceof Object && !Array.isArray(obj)) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'keyMirror(...): Argument must be an object.') : invariant(false) : undefined; + for (key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + ret[key] = key; + } + return ret; + }; + + module.exports = keyMirror; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 466 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPerf + * @typechecks static-only + */ + + 'use strict'; + + /** + * ReactPerf is a general AOP system designed to measure performance. This + * module only has the hooks: see ReactDefaultPerf for the analysis tool. + */ + var ReactPerf = { + /** + * Boolean to enable/disable measurement. Set to false by default to prevent + * accidental logging and perf loss. + */ + enableMeasure: false, + + /** + * Holds onto the measure function in use. By default, don't measure + * anything, but we'll override this if we inject a measure function. + */ + storedMeasure: _noMeasure, + + /** + * @param {object} object + * @param {string} objectName + * @param {object} methodNames + */ + measureMethods: function (object, objectName, methodNames) { + if (process.env.NODE_ENV !== 'production') { + for (var key in methodNames) { + if (!methodNames.hasOwnProperty(key)) { + continue; + } + object[key] = ReactPerf.measure(objectName, methodNames[key], object[key]); + } + } + }, + + /** + * Use this to wrap methods you want to measure. Zero overhead in production. + * + * @param {string} objName + * @param {string} fnName + * @param {function} func + * @return {function} + */ + measure: function (objName, fnName, func) { + if (process.env.NODE_ENV !== 'production') { + var measuredFunc = null; + var wrapper = function () { + if (ReactPerf.enableMeasure) { + if (!measuredFunc) { + measuredFunc = ReactPerf.storedMeasure(objName, fnName, func); + } + return measuredFunc.apply(this, arguments); + } + return func.apply(this, arguments); + }; + wrapper.displayName = objName + '_' + fnName; + return wrapper; + } + return func; + }, + + injection: { + /** + * @param {function} measure + */ + injectMeasure: function (measure) { + ReactPerf.storedMeasure = measure; + } + } + }; + + /** + * Simply passes through the measured function, without measuring it. + * + * @param {string} objName + * @param {string} fnName + * @param {function} func + * @return {function} + */ + function _noMeasure(objName, fnName, func) { + return func; + } + + module.exports = ReactPerf; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 467 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule setInnerHTML + */ + + /* globals MSApp */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(457); + + var WHITESPACE_TEST = /^[ \r\n\t\f]/; + var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/; + + /** + * Set the innerHTML property of a node, ensuring that whitespace is preserved + * even in IE8. + * + * @param {DOMElement} node + * @param {string} html + * @internal + */ + var setInnerHTML = function (node, html) { + node.innerHTML = html; + }; + + // Win8 apps: Allow all html to be inserted + if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { + setInnerHTML = function (node, html) { + MSApp.execUnsafeLocalFunction(function () { + node.innerHTML = html; + }); + }; + } + + if (ExecutionEnvironment.canUseDOM) { + // 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 + + // Feature detection; only IE8 is known to behave improperly like this. + var testElement = document.createElement('div'); + testElement.innerHTML = ' '; + if (testElement.innerHTML === '') { + setInnerHTML = function (node, html) { + // 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. + // TODO: What to do on a detached node? + if (node.parentNode) { + node.parentNode.replaceChild(node, node); + } + + // We also implement a workaround for non-visible tags disappearing into + // thin air on IE8, this only happens if there is no visible text + // in-front of the non-visible tags. Piggyback on the whitespace fix + // and simply check if any non-visible tags appear in the source. + if (WHITESPACE_TEST.test(html) || html[0] === '<' && NONVISIBLE_TEST.test(html)) { + // Recover leading whitespace by temporarily prepending any character. + // \uFEFF has the potential advantage of being zero-width/invisible. + // UglifyJS drops U+FEFF chars when parsing, so use String.fromCharCode + // in hopes that this is preserved even if "\uFEFF" is transformed to + // the actual Unicode character (by Babel, for example). + // https://github.com/mishoo/UglifyJS2/blob/v2.4.20/lib/parse.js#L216 + node.innerHTML = String.fromCharCode(0xFEFF) + html; + + // deleteData leaves an empty `TextNode` which offsets the index of all + // children. Definitely want to avoid this. + var textNode = node.firstChild; + if (textNode.data.length === 1) { + node.removeChild(textNode); + } else { + textNode.deleteData(0, 1); + } + } else { + node.innerHTML = html; + } + }; + } + } + + module.exports = setInnerHTML; + +/***/ }, +/* 468 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule setTextContent + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(457); + var escapeTextContentForBrowser = __webpack_require__(469); + var setInnerHTML = __webpack_require__(467); + + /** + * Set the textContent property of a node, ensuring that whitespace is preserved + * even in IE8. innerText is a poor substitute for textContent and, among many + * issues, inserts
instead of the literal newline chars. innerHTML behaves + * as it should. + * + * @param {DOMElement} node + * @param {string} text + * @internal + */ + var setTextContent = function (node, text) { + node.textContent = text; + }; + + if (ExecutionEnvironment.canUseDOM) { + if (!('textContent' in document.documentElement)) { + setTextContent = function (node, text) { + setInnerHTML(node, escapeTextContentForBrowser(text)); + }; + } + } + + module.exports = setTextContent; + +/***/ }, +/* 469 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule escapeTextContentForBrowser + */ + + 'use strict'; + + var ESCAPE_LOOKUP = { + '&': '&', + '>': '>', + '<': '<', + '"': '"', + '\'': ''' + }; + + var ESCAPE_REGEX = /[&><"']/g; + + function escaper(match) { + return ESCAPE_LOOKUP[match]; + } + + /** + * Escapes text to prevent scripting attacks. + * + * @param {*} text Text value to escape. + * @return {string} An escaped string. + */ + function escapeTextContentForBrowser(text) { + return ('' + text).replace(ESCAPE_REGEX, escaper); + } + + module.exports = escapeTextContentForBrowser; + +/***/ }, +/* 470 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMPropertyOperations + * @typechecks static-only + */ + + 'use strict'; + + var DOMProperty = __webpack_require__(471); + var ReactPerf = __webpack_require__(466); + + var quoteAttributeValueForBrowser = __webpack_require__(472); + var warning = __webpack_require__(473); + + // Simplified subset + var VALID_ATTRIBUTE_NAME_REGEX = /^[a-zA-Z_][\w\.\-]*$/; + var illegalAttributeNameCache = {}; + var validatedAttributeNameCache = {}; + + function isAttributeNameSafe(attributeName) { + if (validatedAttributeNameCache.hasOwnProperty(attributeName)) { + return true; + } + if (illegalAttributeNameCache.hasOwnProperty(attributeName)) { + return false; + } + if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { + validatedAttributeNameCache[attributeName] = true; + return true; + } + illegalAttributeNameCache[attributeName] = true; + process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid attribute name: `%s`', attributeName) : undefined; + return false; + } + + function shouldIgnoreValue(propertyInfo, value) { + return value == null || propertyInfo.hasBooleanValue && !value || propertyInfo.hasNumericValue && isNaN(value) || propertyInfo.hasPositiveNumericValue && value < 1 || propertyInfo.hasOverloadedBooleanValue && value === false; + } + + if (process.env.NODE_ENV !== 'production') { + var reactProps = { + children: true, + dangerouslySetInnerHTML: true, + key: true, + ref: true + }; + var warnedProperties = {}; + + var warnUnknownProperty = function (name) { + if (reactProps.hasOwnProperty(name) && reactProps[name] || warnedProperties.hasOwnProperty(name) && warnedProperties[name]) { + return; + } + + warnedProperties[name] = true; + var lowerCasedName = name.toLowerCase(); + + // data-* attributes should be lowercase; suggest the lowercase version + var standardName = DOMProperty.isCustomAttribute(lowerCasedName) ? lowerCasedName : DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ? DOMProperty.getPossibleStandardName[lowerCasedName] : null; + + // For now, only warn when we have a suggested correction. This prevents + // logging too much when using transferPropsTo. + process.env.NODE_ENV !== 'production' ? warning(standardName == null, 'Unknown DOM property %s. Did you mean %s?', name, standardName) : undefined; + }; + } + + /** + * Operations for dealing with DOM properties. + */ + var DOMPropertyOperations = { + + /** + * Creates markup for the ID property. + * + * @param {string} id Unescaped ID. + * @return {string} Markup string. + */ + createMarkupForID: function (id) { + return DOMProperty.ID_ATTRIBUTE_NAME + '=' + quoteAttributeValueForBrowser(id); + }, + + setAttributeForID: function (node, id) { + node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id); + }, + + /** + * Creates markup for a property. + * + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. + */ + createMarkupForProperty: function (name, value) { + var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; + if (propertyInfo) { + if (shouldIgnoreValue(propertyInfo, value)) { + return ''; + } + var attributeName = propertyInfo.attributeName; + if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) { + return attributeName + '=""'; + } + return attributeName + '=' + quoteAttributeValueForBrowser(value); + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + return ''; + } + return name + '=' + quoteAttributeValueForBrowser(value); + } else if (process.env.NODE_ENV !== 'production') { + warnUnknownProperty(name); + } + return null; + }, + + /** + * Creates markup for a custom property. + * + * @param {string} name + * @param {*} value + * @return {string} Markup string, or empty string if the property was invalid. + */ + createMarkupForCustomAttribute: function (name, value) { + if (!isAttributeNameSafe(name) || value == null) { + return ''; + } + return name + '=' + quoteAttributeValueForBrowser(value); + }, + + /** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ + setValueForProperty: function (node, name, value) { + var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; + if (propertyInfo) { + var mutationMethod = propertyInfo.mutationMethod; + if (mutationMethod) { + mutationMethod(node, value); + } else if (shouldIgnoreValue(propertyInfo, value)) { + this.deleteValueForProperty(node, name); + } else if (propertyInfo.mustUseAttribute) { + var attributeName = propertyInfo.attributeName; + var namespace = propertyInfo.attributeNamespace; + // `setAttribute` with objects becomes only `[object]` in IE8/9, + // ('' + value) makes it output the correct toString()-value. + if (namespace) { + node.setAttributeNS(namespace, attributeName, '' + value); + } else if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) { + node.setAttribute(attributeName, ''); + } else { + node.setAttribute(attributeName, '' + value); + } + } else { + var propName = propertyInfo.propertyName; + // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the + // property type before comparing; only `value` does and is string. + if (!propertyInfo.hasSideEffects || '' + node[propName] !== '' + value) { + // Contrary to `setAttribute`, object properties are properly + // `toString`ed by IE8/9. + node[propName] = value; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + DOMPropertyOperations.setValueForAttribute(node, name, value); + } else if (process.env.NODE_ENV !== 'production') { + warnUnknownProperty(name); + } + }, + + setValueForAttribute: function (node, name, value) { + if (!isAttributeNameSafe(name)) { + return; + } + if (value == null) { + node.removeAttribute(name); + } else { + node.setAttribute(name, '' + value); + } + }, + + /** + * Deletes the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + */ + deleteValueForProperty: function (node, name) { + var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; + if (propertyInfo) { + var mutationMethod = propertyInfo.mutationMethod; + if (mutationMethod) { + mutationMethod(node, undefined); + } else if (propertyInfo.mustUseAttribute) { + node.removeAttribute(propertyInfo.attributeName); + } else { + var propName = propertyInfo.propertyName; + var defaultValue = DOMProperty.getDefaultValueForProperty(node.nodeName, propName); + if (!propertyInfo.hasSideEffects || '' + node[propName] !== defaultValue) { + node[propName] = defaultValue; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.removeAttribute(name); + } else if (process.env.NODE_ENV !== 'production') { + warnUnknownProperty(name); + } + } + + }; + + ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', { + setValueForProperty: 'setValueForProperty', + setValueForAttribute: 'setValueForAttribute', + deleteValueForProperty: 'deleteValueForProperty' + }); + + module.exports = DOMPropertyOperations; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 471 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMProperty + * @typechecks static-only + */ + + 'use strict'; + + var invariant = __webpack_require__(461); + + function checkMask(value, bitmask) { + return (value & bitmask) === bitmask; + } + + var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_ATTRIBUTE: 0x1, + MUST_USE_PROPERTY: 0x2, + HAS_SIDE_EFFECTS: 0x4, + HAS_BOOLEAN_VALUE: 0x8, + HAS_NUMERIC_VALUE: 0x10, + HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10, + HAS_OVERLOADED_BOOLEAN_VALUE: 0x40, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * isCustomAttribute: function that given an attribute name will return true + * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* + * attributes where it's impossible to enumerate all of the possible + * attribute names, + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMAttributeNamespaces: object mapping React attribute name to the DOM + * attribute namespace URL. (Attribute names not specified use no namespace.) + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function (domPropertyConfig) { + var Injection = DOMPropertyInjection; + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; + + if (domPropertyConfig.isCustomAttribute) { + DOMProperty._isCustomAttributeFunctions.push(domPropertyConfig.isCustomAttribute); + } + + for (var propName in Properties) { + !!DOMProperty.properties.hasOwnProperty(propName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' + '\'%s\' which has already been injected. You may be accidentally ' + 'injecting the same DOM property config twice, or you may be ' + 'injecting two configs that have conflicting property names.', propName) : invariant(false) : undefined; + + var lowerCased = propName.toLowerCase(); + var propConfig = Properties[propName]; + + var propertyInfo = { + attributeName: lowerCased, + attributeNamespace: null, + propertyName: propName, + mutationMethod: null, + + mustUseAttribute: checkMask(propConfig, Injection.MUST_USE_ATTRIBUTE), + mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY), + hasSideEffects: checkMask(propConfig, Injection.HAS_SIDE_EFFECTS), + hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE), + hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE), + hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE), + hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE) + }; + + !(!propertyInfo.mustUseAttribute || !propertyInfo.mustUseProperty) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'DOMProperty: Cannot require using both attribute and property: %s', propName) : invariant(false) : undefined; + !(propertyInfo.mustUseProperty || !propertyInfo.hasSideEffects) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'DOMProperty: Properties that have side effects must use property: %s', propName) : invariant(false) : undefined; + !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'DOMProperty: Value can be one of boolean, overloaded boolean, or ' + 'numeric value, but not a combination: %s', propName) : invariant(false) : undefined; + + if (process.env.NODE_ENV !== 'production') { + DOMProperty.getPossibleStandardName[lowerCased] = propName; + } + + if (DOMAttributeNames.hasOwnProperty(propName)) { + var attributeName = DOMAttributeNames[propName]; + propertyInfo.attributeName = attributeName; + if (process.env.NODE_ENV !== 'production') { + DOMProperty.getPossibleStandardName[attributeName] = propName; + } + } + + if (DOMAttributeNamespaces.hasOwnProperty(propName)) { + propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName]; + } + + if (DOMPropertyNames.hasOwnProperty(propName)) { + propertyInfo.propertyName = DOMPropertyNames[propName]; + } + + if (DOMMutationMethods.hasOwnProperty(propName)) { + propertyInfo.mutationMethod = DOMMutationMethods[propName]; + } + + DOMProperty.properties[propName] = propertyInfo; + } + } + }; + var defaultValueCache = {}; + + /** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ + var DOMProperty = { + + ID_ATTRIBUTE_NAME: 'data-reactid', + + /** + * Map from property "standard name" to an object with info about how to set + * the property in the DOM. Each object contains: + * + * attributeName: + * Used when rendering markup or with `*Attribute()`. + * attributeNamespace + * propertyName: + * Used on DOM node instances. (This includes properties that mutate due to + * external factors.) + * mutationMethod: + * If non-null, used instead of the property or `setAttribute()` after + * initial render. + * mustUseAttribute: + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * mustUseProperty: + * Whether the property must be accessed and mutated as an object property. + * hasSideEffects: + * Whether or not setting a value causes side effects such as triggering + * resources to be loaded or text selection changes. If true, we read from + * the DOM before updating to ensure that the value is only set if it has + * changed. + * hasBooleanValue: + * Whether the property should be removed when set to a falsey value. + * hasNumericValue: + * Whether the property must be numeric or parse as a numeric and should be + * removed when set to a falsey value. + * hasPositiveNumericValue: + * Whether the property must be positive numeric or parse as a positive + * numeric and should be removed when set to a falsey value. + * hasOverloadedBooleanValue: + * Whether the property can be used as a flag as well as with a value. + * Removed when strictly equal to false; present without a value when + * strictly equal to true; present with a value otherwise. + */ + properties: {}, + + /** + * Mapping from lowercase property names to the properly cased version, used + * to warn in the case of missing properties. Available only in __DEV__. + * @type {Object} + */ + getPossibleStandardName: process.env.NODE_ENV !== 'production' ? {} : null, + + /** + * All of the isCustomAttribute() functions that have been injected. + */ + _isCustomAttributeFunctions: [], + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: function (attributeName) { + for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) { + var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i]; + if (isCustomAttributeFn(attributeName)) { + return true; + } + } + return false; + }, + + /** + * Returns the default property value for a DOM property (i.e., not an + * attribute). Most default values are '' or false, but not all. Worse yet, + * some (in particular, `type`) vary depending on the type of element. + * + * TODO: Is it better to grab all the possible properties when creating an + * element to avoid having to create the same element twice? + */ + getDefaultValueForProperty: function (nodeName, prop) { + var nodeDefaults = defaultValueCache[nodeName]; + var testElement; + if (!nodeDefaults) { + defaultValueCache[nodeName] = nodeDefaults = {}; + } + if (!(prop in nodeDefaults)) { + testElement = document.createElement(nodeName); + nodeDefaults[prop] = testElement[prop]; + } + return nodeDefaults[prop]; + }, + + injection: DOMPropertyInjection + }; + + module.exports = DOMProperty; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 472 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule quoteAttributeValueForBrowser + */ + + 'use strict'; + + var escapeTextContentForBrowser = __webpack_require__(469); + + /** + * Escapes attribute value to prevent scripting attacks. + * + * @param {*} value Value to escape. + * @return {string} An escaped string. + */ + function quoteAttributeValueForBrowser(value) { + return '"' + escapeTextContentForBrowser(value) + '"'; + } + + module.exports = quoteAttributeValueForBrowser; + +/***/ }, +/* 473 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule warning + */ + + 'use strict'; + + var emptyFunction = __webpack_require__(463); + + /** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + + var warning = emptyFunction; + + if (process.env.NODE_ENV !== 'production') { + warning = function (condition, format) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; + } + + if (format === undefined) { + throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); + } + + if (format.indexOf('Failed Composite propType: ') === 0) { + return; // Ignore CompositeComponent proptype check. + } + + if (!condition) { + var argIndex = 0; + var message = 'Warning: ' + format.replace(/%s/g, function () { + return args[argIndex++]; + }); + if (typeof console !== 'undefined') { + console.error(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + } + }; + } + + module.exports = warning; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 474 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentBrowserEnvironment + */ + + 'use strict'; + + var ReactDOMIDOperations = __webpack_require__(475); + var ReactMount = __webpack_require__(476); + + /** + * Abstracts away all functionality of the reconciler that requires knowledge of + * the browser context. TODO: These callers should be refactored to avoid the + * need for this injection. + */ + var ReactComponentBrowserEnvironment = { + + processChildrenUpdates: ReactDOMIDOperations.dangerouslyProcessChildrenUpdates, + + replaceNodeWithMarkupByID: ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID, + + /** + * If a particular environment requires that some resources be cleaned up, + * specify this in the injected Mixin. In the DOM, we would likely want to + * purge any cached node ID lookups. + * + * @private + */ + unmountIDFromEnvironment: function (rootNodeID) { + ReactMount.purgeID(rootNodeID); + } + + }; + + module.exports = ReactComponentBrowserEnvironment; + +/***/ }, +/* 475 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMIDOperations + * @typechecks static-only + */ + + 'use strict'; + + var DOMChildrenOperations = __webpack_require__(455); + var DOMPropertyOperations = __webpack_require__(470); + var ReactMount = __webpack_require__(476); + var ReactPerf = __webpack_require__(466); + + var invariant = __webpack_require__(461); + + /** + * Errors for properties that should not be updated with `updatePropertyByID()`. + * + * @type {object} + * @private + */ + var INVALID_PROPERTY_ERRORS = { + dangerouslySetInnerHTML: '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', + style: '`style` must be set using `updateStylesByID()`.' + }; + + /** + * Operations used to process updates to DOM nodes. + */ + var ReactDOMIDOperations = { + + /** + * Updates a DOM node with new property values. This should only be used to + * update DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A valid property name, see `DOMProperty`. + * @param {*} value New value of the property. + * @internal + */ + updatePropertyByID: function (id, name, value) { + var node = ReactMount.getNode(id); + !!INVALID_PROPERTY_ERRORS.hasOwnProperty(name) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(false) : undefined; + + // 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); + } + }, + + /** + * Replaces a DOM node that exists in the document with markup. + * + * @param {string} id ID of child to be replaced. + * @param {string} markup Dangerous markup to inject in place of child. + * @internal + * @see {Danger.dangerouslyReplaceNodeWithMarkup} + */ + dangerouslyReplaceNodeWithMarkupByID: function (id, markup) { + var node = ReactMount.getNode(id); + DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); + }, + + /** + * Updates a component's children by processing a series of updates. + * + * @param {array} updates List of update configurations. + * @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); + } + DOMChildrenOperations.processUpdates(updates, markup); + } + }; + + ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', { + dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID', + dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates' + }); + + module.exports = ReactDOMIDOperations; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 476 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactMount + */ + + 'use strict'; + + var DOMProperty = __webpack_require__(471); + var ReactBrowserEventEmitter = __webpack_require__(477); + var ReactCurrentOwner = __webpack_require__(453); + var ReactDOMFeatureFlags = __webpack_require__(489); + var ReactElement = __webpack_require__(490); + var ReactEmptyComponentRegistry = __webpack_require__(492); + var ReactInstanceHandles = __webpack_require__(493); + var ReactInstanceMap = __webpack_require__(495); + var ReactMarkupChecksum = __webpack_require__(496); + var ReactPerf = __webpack_require__(466); + var ReactReconciler = __webpack_require__(498); + var ReactUpdateQueue = __webpack_require__(501); + var ReactUpdates = __webpack_require__(502); + + var assign = __webpack_require__(487); + var emptyObject = __webpack_require__(506); + var containsNode = __webpack_require__(507); + var instantiateReactComponent = __webpack_require__(510); + var invariant = __webpack_require__(461); + var setInnerHTML = __webpack_require__(467); + var shouldUpdateReactComponent = __webpack_require__(515); + var validateDOMNesting = __webpack_require__(518); + var warning = __webpack_require__(473); + + var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; + var nodeCache = {}; + + var ELEMENT_NODE_TYPE = 1; + var DOC_NODE_TYPE = 9; + var DOCUMENT_FRAGMENT_NODE_TYPE = 11; + + var ownerDocumentContextKey = '__ReactMount_ownerDocument$' + Math.random().toString(36).slice(2); + + /** Mapping from reactRootID to React component instance. */ + var instancesByReactRootID = {}; + + /** Mapping from reactRootID to `container` nodes. */ + var containersByReactRootID = {}; + + if (process.env.NODE_ENV !== 'production') { + /** __DEV__-only mapping from reactRootID to root elements. */ + var rootElementsByReactRootID = {}; + } + + // Used to store breadth-first search state in findComponentRoot. + var findComponentRootReusableArray = []; + + /** + * Finds the index of the first character + * that's not common between the two given strings. + * + * @return {number} the index of the character where the strings diverge + */ + function firstDifferenceIndex(string1, string2) { + var minLen = Math.min(string1.length, string2.length); + for (var i = 0; i < minLen; i++) { + if (string1.charAt(i) !== string2.charAt(i)) { + return i; + } + } + return string1.length === string2.length ? -1 : minLen; + } + + /** + * @param {DOMElement|DOMDocument} container DOM element that may contain + * a React component + * @return {?*} DOM element that may have the reactRoot ID, or null. + */ + function getReactRootElementInContainer(container) { + if (!container) { + return null; + } + + if (container.nodeType === DOC_NODE_TYPE) { + return container.documentElement; + } else { + return container.firstChild; + } + } + + /** + * @param {DOMElement} container DOM element that may contain a React component. + * @return {?string} A "reactRoot" ID, if a React component is rendered. + */ + function getReactRootID(container) { + var rootElement = getReactRootElementInContainer(container); + return rootElement && ReactMount.getID(rootElement); + } + + /** + * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form + * element can return its control whose name or ID equals ATTR_NAME. All + * DOM nodes support `getAttributeNode` but this can also get called on + * other objects so just return '' if we're given something other than a + * DOM node (such as window). + * + * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node. + * @return {string} ID of the supplied `domNode`. + */ + function getID(node) { + var id = internalGetID(node); + if (id) { + if (nodeCache.hasOwnProperty(id)) { + var cached = nodeCache[id]; + if (cached !== node) { + !!isValid(cached, id) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactMount: Two valid but unequal nodes with the same `%s`: %s', ATTR_NAME, id) : invariant(false) : undefined; + + nodeCache[id] = node; + } + } else { + nodeCache[id] = node; + } + } + + return id; + } + + function internalGetID(node) { + // If node is something like a window, document, or text node, none of + // which support attributes or a .getAttribute method, gracefully return + // the empty string, as if the attribute were missing. + return node && node.getAttribute && node.getAttribute(ATTR_NAME) || ''; + } + + /** + * Sets the React-specific ID of the given node. + * + * @param {DOMElement} node The DOM node whose ID will be set. + * @param {string} id The value of the ID attribute. + */ + function setID(node, id) { + var oldID = internalGetID(node); + if (oldID !== id) { + delete nodeCache[oldID]; + } + node.setAttribute(ATTR_NAME, id); + nodeCache[id] = node; + } + + /** + * Finds the node with the supplied React-generated DOM ID. + * + * @param {string} id A React-generated DOM ID. + * @return {DOMElement} DOM node with the suppled `id`. + * @internal + */ + function getNode(id) { + if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) { + nodeCache[id] = ReactMount.findReactNodeByID(id); + } + return nodeCache[id]; + } + + /** + * Finds the node with the supplied public React instance. + * + * @param {*} instance A public React instance. + * @return {?DOMElement} DOM node with the suppled `id`. + * @internal + */ + function getNodeFromInstance(instance) { + var id = ReactInstanceMap.get(instance)._rootNodeID; + if (ReactEmptyComponentRegistry.isNullComponentID(id)) { + return null; + } + if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) { + nodeCache[id] = ReactMount.findReactNodeByID(id); + } + return nodeCache[id]; + } + + /** + * A node is "valid" if it is contained by a currently mounted container. + * + * This means that the node does not have to be contained by a document in + * order to be considered valid. + * + * @param {?DOMElement} node The candidate DOM node. + * @param {string} id The expected ID of the node. + * @return {boolean} Whether the node is contained by a mounted container. + */ + function isValid(node, id) { + if (node) { + !(internalGetID(node) === id) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactMount: Unexpected modification of `%s`', ATTR_NAME) : invariant(false) : undefined; + + var container = ReactMount.findReactContainerForID(id); + if (container && containsNode(container, node)) { + return true; + } + } + + return false; + } + + /** + * Causes the cache to forget about one React-specific ID. + * + * @param {string} id The ID to forget. + */ + function purgeID(id) { + delete nodeCache[id]; + } + + var deepestNodeSoFar = null; + function findDeepestCachedAncestorImpl(ancestorID) { + var ancestor = nodeCache[ancestorID]; + if (ancestor && isValid(ancestor, ancestorID)) { + deepestNodeSoFar = ancestor; + } else { + // This node isn't populated in the cache, so presumably none of its + // descendants are. Break out of the loop. + return false; + } + } + + /** + * Return the deepest cached node whose ID is a prefix of `targetID`. + */ + function findDeepestCachedAncestor(targetID) { + deepestNodeSoFar = null; + ReactInstanceHandles.traverseAncestors(targetID, findDeepestCachedAncestorImpl); + + var foundNode = deepestNodeSoFar; + deepestNodeSoFar = null; + return foundNode; + } + + /** + * Mounts this component and inserts it into the DOM. + * + * @param {ReactComponent} componentInstance The instance to mount. + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {ReactReconcileTransaction} transaction + * @param {boolean} shouldReuseMarkup If true, do not insert markup + */ + function mountComponentIntoNode(componentInstance, rootID, container, transaction, shouldReuseMarkup, context) { + if (ReactDOMFeatureFlags.useCreateElement) { + context = assign({}, context); + if (container.nodeType === DOC_NODE_TYPE) { + context[ownerDocumentContextKey] = container; + } else { + context[ownerDocumentContextKey] = container.ownerDocument; + } + } + if (process.env.NODE_ENV !== 'production') { + if (context === emptyObject) { + context = {}; + } + var tag = container.nodeName.toLowerCase(); + context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(null, tag, null); + } + var markup = ReactReconciler.mountComponent(componentInstance, rootID, transaction, context); + componentInstance._renderedComponent._topLevelWrapper = componentInstance; + ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup, transaction); + } + + /** + * Batched mount. + * + * @param {ReactComponent} componentInstance The instance to mount. + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {boolean} shouldReuseMarkup If true, do not insert markup + */ + function batchedMountComponentIntoNode(componentInstance, rootID, container, shouldReuseMarkup, context) { + var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( + /* forceHTML */shouldReuseMarkup); + transaction.perform(mountComponentIntoNode, null, componentInstance, rootID, container, transaction, shouldReuseMarkup, context); + ReactUpdates.ReactReconcileTransaction.release(transaction); + } + + /** + * Unmounts a component and removes it from the DOM. + * + * @param {ReactComponent} instance React component instance. + * @param {DOMElement} container DOM element to unmount from. + * @final + * @internal + * @see {ReactMount.unmountComponentAtNode} + */ + function unmountComponentFromNode(instance, container) { + ReactReconciler.unmountComponent(instance); + + if (container.nodeType === DOC_NODE_TYPE) { + container = container.documentElement; + } + + // http://jsperf.com/emptying-a-node + while (container.lastChild) { + container.removeChild(container.lastChild); + } + } + + /** + * True if the supplied DOM node has a direct React-rendered child that is + * not a React root element. Useful for warning in `render`, + * `unmountComponentAtNode`, etc. + * + * @param {?DOMElement} node The candidate DOM node. + * @return {boolean} True if the DOM element contains a direct child that was + * rendered by React but is not a root element. + * @internal + */ + function hasNonRootReactChild(node) { + var reactRootID = getReactRootID(node); + return reactRootID ? reactRootID !== ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID) : false; + } + + /** + * Returns the first (deepest) ancestor of a node which is rendered by this copy + * of React. + */ + function findFirstReactDOMImpl(node) { + // This node might be from another React instance, so we make sure not to + // examine the node cache here + for (; node && node.parentNode !== node; node = node.parentNode) { + if (node.nodeType !== 1) { + // Not a DOMElement, therefore not a React component + continue; + } + var nodeID = internalGetID(node); + if (!nodeID) { + continue; + } + var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID); + + // If containersByReactRootID contains the container we find by crawling up + // the tree, we know that this instance of React rendered the node. + // nb. isValid's strategy (with containsNode) does not work because render + // trees may be nested and we don't want a false positive in that case. + var current = node; + var lastID; + do { + lastID = internalGetID(current); + current = current.parentNode; + if (current == null) { + // The passed-in node has been detached from the container it was + // originally rendered into. + return null; + } + } while (lastID !== reactRootID); + + if (current === containersByReactRootID[reactRootID]) { + return node; + } + } + return null; + } + + /** + * Temporary (?) hack so that we can store all top-level pending updates on + * composites instead of having to worry about different types of components + * here. + */ + var TopLevelWrapper = function () {}; + TopLevelWrapper.prototype.isReactComponent = {}; + if (process.env.NODE_ENV !== 'production') { + TopLevelWrapper.displayName = 'TopLevelWrapper'; + } + TopLevelWrapper.prototype.render = function () { + // this.props is actually a ReactElement + return this.props; + }; + + /** + * Mounting is the process of initializing a React component by creating its + * representative DOM elements and inserting them into a supplied `container`. + * Any prior content inside `container` is destroyed in the process. + * + * ReactMount.render( + * component, + * document.getElementById('container') + * ); + * + *
<-- Supplied `container`. + *
<-- Rendered reactRoot of React + * // ... component. + *
+ *
+ * + * Inside of `container`, the first element rendered is the "reactRoot". + */ + var ReactMount = { + + TopLevelWrapper: TopLevelWrapper, + + /** Exposed for debugging purposes **/ + _instancesByReactRootID: instancesByReactRootID, + + /** + * This is a hook provided to support rendering React components while + * ensuring that the apparent scroll position of its `container` does not + * change. + * + * @param {DOMElement} container The `container` being rendered into. + * @param {function} renderCallback This must be called once to do the render. + */ + scrollMonitor: function (container, renderCallback) { + renderCallback(); + }, + + /** + * Take a component that's already mounted into the DOM and replace its props + * @param {ReactComponent} prevComponent component instance already in the DOM + * @param {ReactElement} nextElement component instance to render + * @param {DOMElement} container container to render into + * @param {?function} callback function triggered on completion + */ + _updateRootComponent: function (prevComponent, nextElement, container, callback) { + ReactMount.scrollMonitor(container, function () { + ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement); + if (callback) { + ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback); + } + }); + + if (process.env.NODE_ENV !== 'production') { + // Record the root element in case it later gets transplanted. + rootElementsByReactRootID[getReactRootID(container)] = getReactRootElementInContainer(container); + } + + return prevComponent; + }, + + /** + * Register a component into the instance map and starts scroll value + * monitoring + * @param {ReactComponent} nextComponent component instance to render + * @param {DOMElement} container container to render into + * @return {string} reactRoot ID prefix + */ + _registerComponent: function (nextComponent, container) { + !(container && (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE || container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '_registerComponent(...): Target container is not a DOM element.') : invariant(false) : undefined; + + ReactBrowserEventEmitter.ensureScrollValueMonitoring(); + + var reactRootID = ReactMount.registerContainer(container); + instancesByReactRootID[reactRootID] = nextComponent; + return reactRootID; + }, + + /** + * Render a new component into the DOM. + * @param {ReactElement} nextElement element to render + * @param {DOMElement} container container to render into + * @param {boolean} shouldReuseMarkup if we should skip the markup insertion + * @return {ReactComponent} nextComponent + */ + _renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, context) { + // Various parts of our code (such as ReactCompositeComponent's + // _renderValidatedComponent) assume that calls to render aren't nested; + // verify that that's the case. + process.env.NODE_ENV !== 'production' ? warning(ReactCurrentOwner.current == null, '_renderNewRootComponent(): Render methods should be a pure function ' + 'of props and state; triggering nested component updates from ' + 'render is not allowed. If necessary, trigger nested updates in ' + 'componentDidUpdate. Check the render method of %s.', ReactCurrentOwner.current && ReactCurrentOwner.current.getName() || 'ReactCompositeComponent') : undefined; + + var componentInstance = instantiateReactComponent(nextElement, null); + var reactRootID = ReactMount._registerComponent(componentInstance, container); + + // The initial render is synchronous but any updates that happen during + // rendering, in componentWillMount or componentDidMount, will be batched + // according to the current batching strategy. + + ReactUpdates.batchedUpdates(batchedMountComponentIntoNode, componentInstance, reactRootID, container, shouldReuseMarkup, context); + + if (process.env.NODE_ENV !== 'production') { + // Record the root element in case it later gets transplanted. + rootElementsByReactRootID[reactRootID] = getReactRootElementInContainer(container); + } + + return componentInstance; + }, + + /** + * Renders a React component into the DOM in the supplied `container`. + * + * If the React component was previously rendered into `container`, this will + * perform an update on it and only mutate the DOM as necessary to reflect the + * latest React component. + * + * @param {ReactComponent} parentComponent The conceptual parent of this render tree. + * @param {ReactElement} nextElement Component element to render. + * @param {DOMElement} container DOM element to render into. + * @param {?function} callback function triggered on completion + * @return {ReactComponent} Component instance rendered in `container`. + */ + renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) { + !(parentComponent != null && parentComponent._reactInternalInstance != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'parentComponent must be a valid React Component') : invariant(false) : undefined; + return ReactMount._renderSubtreeIntoContainer(parentComponent, nextElement, container, callback); + }, + + _renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) { + !ReactElement.isValidElement(nextElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOM.render(): Invalid component element.%s', typeof nextElement === 'string' ? ' Instead of passing an element string, make sure to instantiate ' + 'it by passing it to React.createElement.' : typeof nextElement === 'function' ? ' Instead of passing a component class, make sure to instantiate ' + 'it by passing it to React.createElement.' : + // Check if it quacks like an element + nextElement != null && nextElement.props !== undefined ? ' This may be caused by unintentionally loading two independent ' + 'copies of React.' : '') : invariant(false) : undefined; + + process.env.NODE_ENV !== 'production' ? warning(!container || !container.tagName || container.tagName.toUpperCase() !== 'BODY', 'render(): Rendering components directly into document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try rendering into a container element created ' + 'for your app.') : undefined; + + var nextWrappedElement = new ReactElement(TopLevelWrapper, null, null, null, null, null, nextElement); + + var prevComponent = instancesByReactRootID[getReactRootID(container)]; + + if (prevComponent) { + var prevWrappedElement = prevComponent._currentElement; + var prevElement = prevWrappedElement.props; + if (shouldUpdateReactComponent(prevElement, nextElement)) { + var publicInst = prevComponent._renderedComponent.getPublicInstance(); + var updatedCallback = callback && function () { + callback.call(publicInst); + }; + ReactMount._updateRootComponent(prevComponent, nextWrappedElement, container, updatedCallback); + return publicInst; + } else { + ReactMount.unmountComponentAtNode(container); + } + } + + var reactRootElement = getReactRootElementInContainer(container); + var containerHasReactMarkup = reactRootElement && !!internalGetID(reactRootElement); + var containerHasNonRootReactChild = hasNonRootReactChild(container); + + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(!containerHasNonRootReactChild, 'render(...): Replacing React-rendered children with a new root ' + 'component. If you intended to update the children of this node, ' + 'you should instead have the existing children update their state ' + 'and render the new components instead of calling ReactDOM.render.') : undefined; + + if (!containerHasReactMarkup || reactRootElement.nextSibling) { + var rootElementSibling = reactRootElement; + while (rootElementSibling) { + if (internalGetID(rootElementSibling)) { + process.env.NODE_ENV !== 'production' ? warning(false, 'render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.') : undefined; + break; + } + rootElementSibling = rootElementSibling.nextSibling; + } + } + } + + var shouldReuseMarkup = containerHasReactMarkup && !prevComponent && !containerHasNonRootReactChild; + var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, parentComponent != null ? parentComponent._reactInternalInstance._processChildContext(parentComponent._reactInternalInstance._context) : emptyObject)._renderedComponent.getPublicInstance(); + if (callback) { + callback.call(component); + } + return component; + }, + + /** + * Renders a React component into the DOM in the supplied `container`. + * + * If the React component was previously rendered into `container`, this will + * perform an update on it and only mutate the DOM as necessary to reflect the + * latest React component. + * + * @param {ReactElement} nextElement Component element to render. + * @param {DOMElement} container DOM element to render into. + * @param {?function} callback function triggered on completion + * @return {ReactComponent} Component instance rendered in `container`. + */ + render: function (nextElement, container, callback) { + return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback); + }, + + /** + * Registers a container node into which React components will be rendered. + * This also creates the "reactRoot" ID that will be assigned to the element + * rendered within. + * + * @param {DOMElement} container DOM element to register as a container. + * @return {string} The "reactRoot" ID of elements rendered within. + */ + registerContainer: function (container) { + var reactRootID = getReactRootID(container); + if (reactRootID) { + // If one exists, make sure it is a valid "reactRoot" ID. + reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID); + } + if (!reactRootID) { + // No valid "reactRoot" ID found, create one. + reactRootID = ReactInstanceHandles.createReactRootID(); + } + containersByReactRootID[reactRootID] = container; + return reactRootID; + }, + + /** + * Unmounts and destroys the React component rendered in the `container`. + * + * @param {DOMElement} container DOM element containing a React component. + * @return {boolean} True if a component was found in and unmounted from + * `container` + */ + unmountComponentAtNode: function (container) { + // Various parts of our code (such as ReactCompositeComponent's + // _renderValidatedComponent) assume that calls to render aren't nested; + // verify that that's the case. (Strictly speaking, unmounting won't cause a + // render but we still don't expect to be in a render call here.) + process.env.NODE_ENV !== 'production' ? warning(ReactCurrentOwner.current == null, 'unmountComponentAtNode(): Render methods should be a pure function ' + 'of props and state; triggering nested component updates from render ' + 'is not allowed. If necessary, trigger nested updates in ' + 'componentDidUpdate. Check the render method of %s.', ReactCurrentOwner.current && ReactCurrentOwner.current.getName() || 'ReactCompositeComponent') : undefined; + + !(container && (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE || container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'unmountComponentAtNode(...): Target container is not a DOM element.') : invariant(false) : undefined; + + var reactRootID = getReactRootID(container); + var component = instancesByReactRootID[reactRootID]; + if (!component) { + // Check if the node being unmounted was rendered by React, but isn't a + // root node. + var containerHasNonRootReactChild = hasNonRootReactChild(container); + + // Check if the container itself is a React root node. + var containerID = internalGetID(container); + var isContainerReactRoot = containerID && containerID === ReactInstanceHandles.getReactRootIDFromNodeID(containerID); + + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(!containerHasNonRootReactChild, 'unmountComponentAtNode(): The node you\'re attempting to unmount ' + 'was rendered by React and is not a top-level container. %s', isContainerReactRoot ? 'You may have accidentally passed in a React root node instead ' + 'of its container.' : 'Instead, have the parent component update its state and ' + 'rerender in order to remove this component.') : undefined; + } + + return false; + } + ReactUpdates.batchedUpdates(unmountComponentFromNode, component, container); + delete instancesByReactRootID[reactRootID]; + delete containersByReactRootID[reactRootID]; + if (process.env.NODE_ENV !== 'production') { + delete rootElementsByReactRootID[reactRootID]; + } + return true; + }, + + /** + * Finds the container DOM element that contains React component to which the + * supplied DOM `id` belongs. + * + * @param {string} id The ID of an element rendered by a React component. + * @return {?DOMElement} DOM element that contains the `id`. + */ + findReactContainerForID: function (id) { + var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); + var container = containersByReactRootID[reactRootID]; + + if (process.env.NODE_ENV !== 'production') { + var rootElement = rootElementsByReactRootID[reactRootID]; + if (rootElement && rootElement.parentNode !== container) { + process.env.NODE_ENV !== 'production' ? warning( + // Call internalGetID here because getID calls isValid which calls + // findReactContainerForID (this function). + internalGetID(rootElement) === reactRootID, 'ReactMount: Root element ID differed from reactRootID.') : undefined; + var containerChild = container.firstChild; + if (containerChild && reactRootID === internalGetID(containerChild)) { + // If the container has a new child with the same ID as the old + // root element, then rootElementsByReactRootID[reactRootID] is + // just stale and needs to be updated. The case that deserves a + // warning is when the container is empty. + rootElementsByReactRootID[reactRootID] = containerChild; + } else { + process.env.NODE_ENV !== 'production' ? warning(false, 'ReactMount: Root element has been removed from its original ' + 'container. New container: %s', rootElement.parentNode) : undefined; + } + } + } + + return container; + }, + + /** + * Finds an element rendered by React with the supplied ID. + * + * @param {string} id ID of a DOM node in the React component. + * @return {DOMElement} Root DOM node of the React component. + */ + findReactNodeByID: function (id) { + var reactRoot = ReactMount.findReactContainerForID(id); + return ReactMount.findComponentRoot(reactRoot, id); + }, + + /** + * Traverses up the ancestors of the supplied node to find a node that is a + * DOM representation of a React component rendered by this copy of React. + * + * @param {*} node + * @return {?DOMEventTarget} + * @internal + */ + getFirstReactDOM: function (node) { + return findFirstReactDOMImpl(node); + }, + + /** + * Finds a node with the supplied `targetID` inside of the supplied + * `ancestorNode`. Exploits the ID naming scheme to perform the search + * quickly. + * + * @param {DOMEventTarget} ancestorNode Search from this root. + * @pararm {string} targetID ID of the DOM representation of the component. + * @return {DOMEventTarget} DOM node with the supplied `targetID`. + * @internal + */ + findComponentRoot: function (ancestorNode, targetID) { + var firstChildren = findComponentRootReusableArray; + var childIndex = 0; + + var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode; + + if (process.env.NODE_ENV !== 'production') { + // This will throw on the next line; give an early warning + process.env.NODE_ENV !== 'production' ? warning(deepestAncestor != null, 'React can\'t find the root component node for data-reactid value ' + '`%s`. If you\'re seeing this message, it probably means that ' + 'you\'ve loaded two copies of React on the page. At this time, only ' + 'a single copy of React can be loaded at a time.', targetID) : undefined; + } + + firstChildren[0] = deepestAncestor.firstChild; + firstChildren.length = 1; + + while (childIndex < firstChildren.length) { + var child = firstChildren[childIndex++]; + var targetChild; + + while (child) { + var childID = ReactMount.getID(child); + if (childID) { + // Even if we find the node we're looking for, we finish looping + // through its siblings to ensure they're cached so that we don't have + // to revisit this node again. Otherwise, we make n^2 calls to getID + // when visiting the many children of a single node in order. + + if (targetID === childID) { + targetChild = child; + } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) { + // If we find a child whose ID is an ancestor of the given ID, + // then we can be sure that we only want to search the subtree + // rooted at this child, so we can throw out the rest of the + // search state. + firstChildren.length = childIndex = 0; + firstChildren.push(child.firstChild); + } + } else { + // If this child had no ID, then there's a chance that it was + // injected automatically by the browser, as when a `` + // element sprouts an extra `` child as a side effect of + // `.innerHTML` parsing. Optimistically continue down this + // branch, but not before examining the other siblings. + firstChildren.push(child.firstChild); + } + + child = child.nextSibling; + } + + if (targetChild) { + // Emptying firstChildren/findComponentRootReusableArray is + // not necessary for correctness, but it helps the GC reclaim + // any nodes that were left at the end of the search. + firstChildren.length = 0; + + return targetChild; + } + } + + firstChildren.length = 0; + + true ? process.env.NODE_ENV !== 'production' ? invariant(false, 'findComponentRoot(..., %s): Unable to find element. This probably ' + 'means the DOM was unexpectedly mutated (e.g., by the browser), ' + 'usually due to forgetting a when using tables, nesting tags ' + 'like ,

, or , or using non-SVG elements in an ' + 'parent. ' + 'Try inspecting the child nodes of the element with React ID `%s`.', targetID, ReactMount.getID(ancestorNode)) : invariant(false) : undefined; + }, + + _mountImageIntoNode: function (markup, container, shouldReuseMarkup, transaction) { + !(container && (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE || container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'mountComponentIntoNode(...): Target container is not valid.') : invariant(false) : undefined; + + if (shouldReuseMarkup) { + var rootElement = getReactRootElementInContainer(container); + if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) { + return; + } else { + var checksum = rootElement.getAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME); + rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME); + + var rootMarkup = rootElement.outerHTML; + rootElement.setAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME, checksum); + + var normalizedMarkup = markup; + if (process.env.NODE_ENV !== 'production') { + // because rootMarkup is retrieved from the DOM, various normalizations + // will have occurred which will not be present in `markup`. Here, + // insert markup into a

or