From 16aab232df57bd88d80fd5efdde7d036431c089f Mon Sep 17 00:00:00 2001 From: abhilash Date: Wed, 13 Apr 2016 13:25:01 +0530 Subject: [PATCH 1/2] update to react 15 --- example/dist/app.js | 5 +- example/dist/bundle.js | 49 +- example/dist/codemirror.css | 98 +- example/dist/codemirror.js | 962 ++-- example/dist/common.js | 8263 ++++++++++++++++++----------------- example/dist/javascript.js | 102 +- package.json | 8 +- 7 files changed, 5032 insertions(+), 4455 deletions(-) diff --git a/example/dist/app.js b/example/dist/app.js index 88d5585..6563b72 100644 --- a/example/dist/app.js +++ b/example/dist/app.js @@ -1,4 +1,4 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } .cm-searching { background: #ffa; diff --git a/example/dist/codemirror.js b/example/dist/codemirror.js index 53b3532..638d834 100644 --- a/example/dist/codemirror.js +++ b/example/dist/codemirror.js @@ -13,7 +13,7 @@ else if (typeof define == "function" && define.amd) // AMD return define([], mod); else // Plain browser env - this.CodeMirror = mod(); + (this || window).CodeMirror = mod(); })(function() { "use strict"; @@ -21,27 +21,29 @@ // Kludges for bugs and behavior differences that can't be feature // detected are enabled based on userAgent etc sniffing. + var userAgent = navigator.userAgent; + var platform = navigator.platform; - var gecko = /gecko\/\d/i.test(navigator.userAgent); - var ie_upto10 = /MSIE \d/.test(navigator.userAgent); - var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); + var gecko = /gecko\/\d/i.test(userAgent); + var ie_upto10 = /MSIE \d/.test(userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); var ie = ie_upto10 || ie_11up; var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); - var webkit = /WebKit\//.test(navigator.userAgent); - var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); - var chrome = /Chrome\//.test(navigator.userAgent); - var presto = /Opera\//.test(navigator.userAgent); + var webkit = /WebKit\//.test(userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); + var chrome = /Chrome\//.test(userAgent); + var presto = /Opera\//.test(userAgent); var safari = /Apple Computer/.test(navigator.vendor); - var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); - var phantom = /PhantomJS/.test(navigator.userAgent); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); + var phantom = /PhantomJS/.test(userAgent); - var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); // This is woefully incomplete. Suggestions for alternative methods welcome. - var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); - var mac = ios || /Mac/.test(navigator.platform); - var windows = /win/i.test(navigator.platform); + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); + var mac = ios || /Mac/.test(platform); + var windows = /win/i.test(platform); - var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); + var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); if (presto_version) presto_version = Number(presto_version[1]); if (presto_version && presto_version >= 15) { presto = false; webkit = true; } // Some browsers use the wrong event properties to signal cmd/ctrl on OS X @@ -65,7 +67,7 @@ setGuttersForLineNumbers(options); var doc = options.value; - if (typeof doc == "string") doc = new Doc(doc, options.mode); + if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator); this.doc = doc; var input = new CodeMirror.inputStyles[options.inputStyle](this); @@ -82,12 +84,16 @@ keyMaps: [], // stores maps added by addKeyMap overlays: [], // highlighting overlays, as added by addOverlay modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info - overwrite: false, focused: false, + overwrite: false, + delayingBlurEvent: false, + focused: false, suppressEdits: false, // used to disable editing during key handlers when in readOnly mode pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + selectingText: false, draggingText: false, highlight: new Delayed(), // stores highlight worker timeout - keySeq: null // Unfinished key sequence + keySeq: null, // Unfinished key sequence + specialChars: null }; var cm = this; @@ -404,7 +410,7 @@ if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); }); - this.checkedOverlay = false; + this.checkedZeroWidth = false; // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; } @@ -439,29 +445,43 @@ this.horiz.firstChild.style.width = "0"; } - if (!this.checkedOverlay && measure.clientHeight > 0) { - if (sWidth == 0) this.overlayHack(); - this.checkedOverlay = true; + if (!this.checkedZeroWidth && measure.clientHeight > 0) { + if (sWidth == 0) this.zeroWidthHack(); + this.checkedZeroWidth = true; } return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; }, setScrollLeft: function(pos) { if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; + if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz); }, setScrollTop: function(pos) { if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; + if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert); }, - overlayHack: function() { + zeroWidthHack: function() { var w = mac && !mac_geMountainLion ? "12px" : "18px"; - this.horiz.style.minHeight = this.vert.style.minWidth = w; - var self = this; - var barMouseDown = function(e) { - if (e_target(e) != self.vert && e_target(e) != self.horiz) - operation(self.cm, onMouseDown)(e); - }; - on(this.vert, "mousedown", barMouseDown); - on(this.horiz, "mousedown", barMouseDown); + this.horiz.style.height = this.vert.style.width = w; + this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; + this.disableHoriz = new Delayed; + this.disableVert = new Delayed; + }, + enableZeroWidthBar: function(bar, delay) { + bar.style.pointerEvents = "auto"; + function maybeDisable() { + // To find out whether the scrollbar is still visible, we + // check whether the element under the pixel in the bottom + // left corner of the scrollbar box is the scrollbar box + // itself (when the bar is still visible) or its filler child + // (when the bar is hidden). If it is still visible, we keep + // it enabled, if it's hidden, we disable pointer events. + var box = bar.getBoundingClientRect(); + var elt = document.elementFromPoint(box.left + 1, box.bottom - 1); + if (elt != bar) bar.style.pointerEvents = "none"; + else delay.set(1000, maybeDisable); + } + delay.set(1000, maybeDisable); }, clear: function() { var parent = this.horiz.parentNode; @@ -523,6 +543,7 @@ d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" if (sizes.right && sizes.bottom) { d.scrollbarFiller.style.display = "block"; @@ -591,7 +612,7 @@ "CodeMirror-linenumber CodeMirror-gutter-elt")); var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; display.lineGutter.style.width = ""; - display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding); + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; display.lineNumWidth = display.lineNumInnerWidth + padding; display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; display.lineGutter.style.width = display.lineNumWidth + "px"; @@ -711,7 +732,7 @@ // width and height. removeChildren(display.cursorDiv); removeChildren(display.selectionDiv); - display.gutters.style.height = 0; + display.gutters.style.height = display.sizer.style.minHeight = 0; if (different) { display.lastWrapHeight = update.wrapperHeight; @@ -725,12 +746,10 @@ } function postUpdateDisplay(cm, update) { - var force = update.force, viewport = update.viewport; + var viewport = update.viewport; + for (var first = true;; first = false) { - if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) { - force = true; - } else { - force = false; + if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { // Clip forced viewport to actual scrollable area. if (viewport && viewport.top != null) viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; @@ -744,8 +763,8 @@ updateHeightsInViewport(cm); var barMeasure = measureForScrollbars(cm); updateSelection(cm); - setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); + setDocumentHeight(cm, barMeasure); } update.signal(cm, "update", cm); @@ -762,17 +781,16 @@ postUpdateDisplay(cm, update); var barMeasure = measureForScrollbars(cm); updateSelection(cm); - setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); + setDocumentHeight(cm, barMeasure); update.finish(); } } function setDocumentHeight(cm, measure) { cm.display.sizer.style.minHeight = measure.docHeight + "px"; - var total = measure.docHeight + cm.display.barHeight; - cm.display.heightForcer.style.top = total + "px"; - cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; + cm.display.heightForcer.style.top = measure.docHeight + "px"; + cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px"; } // Read the actual heights of the rendered lines, and update their @@ -806,7 +824,7 @@ // given line. function updateWidgetHeight(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) - line.widgets[i].height = line.widgets[i].node.offsetHeight; + line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; } // Do a bulk-read of the DOM positions and sizes needed to draw the @@ -955,12 +973,22 @@ lineView.node.removeChild(lineView.gutter); lineView.gutter = null; } + if (lineView.gutterBackground) { + lineView.node.removeChild(lineView.gutterBackground); + lineView.gutterBackground = null; + } + if (lineView.line.gutterClass) { + var wrap = ensureLineWrapped(lineView); + lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, + "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + + "px; width: " + dims.gutterTotalWidth + "px"); + wrap.insertBefore(lineView.gutterBackground, lineView.text); + } var markers = lineView.line.gutterMarkers; if (cm.options.lineNumbers || markers) { var wrap = ensureLineWrapped(lineView); var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + - (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + - "px; width: " + dims.gutterTotalWidth + "px"); + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"); cm.display.input.setUneditable(gutterWrap); wrap.insertBefore(gutterWrap, lineView.text); if (lineView.line.gutterClass) @@ -1067,27 +1095,29 @@ if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } } - function isReadOnly(cm) { - return cm.options.readOnly || cm.doc.cantEdit; - } - // This will be set to an array of strings when copying, so that, // when pasting, we know what kind of selections the copied text // was made out of. var lastCopied = null; - function applyTextInput(cm, inserted, deleted, sel) { + function applyTextInput(cm, inserted, deleted, sel, origin) { var doc = cm.doc; cm.display.shift = false; if (!sel) sel = doc.sel; - var textLines = splitLines(inserted), multiPaste = null; + var paste = cm.state.pasteIncoming || origin == "paste"; + var textLines = doc.splitLines(inserted), multiPaste = null; // When pasing N lines into N selections, insert one line per selection - if (cm.state.pasteIncoming && sel.ranges.length > 1) { - if (lastCopied && lastCopied.join("\n") == inserted) - multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); - else if (textLines.length == sel.ranges.length) + if (paste && sel.ranges.length > 1) { + if (lastCopied && lastCopied.join("\n") == inserted) { + if (sel.ranges.length % lastCopied.length == 0) { + multiPaste = []; + for (var i = 0; i < lastCopied.length; i++) + multiPaste.push(doc.splitLines(lastCopied[i])); + } + } else if (textLines.length == sel.ranges.length) { multiPaste = map(textLines, function(l) { return [l]; }); + } } // Normal behavior is to insert the new text into every selection @@ -1097,38 +1127,58 @@ if (range.empty()) { if (deleted && deleted > 0) // Handle deletion from = Pos(from.line, from.ch - deleted); - else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite + else if (cm.state.overwrite && !paste) // Handle overwrite to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } var updateInput = cm.curOp.updateInput; var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, - origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; + origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")}; makeChange(cm.doc, changeEvent); signalLater(cm, "inputRead", cm, changeEvent); - // When an 'electric' character is inserted, immediately trigger a reindent - if (inserted && !cm.state.pasteIncoming && cm.options.electricChars && - cm.options.smartIndent && range.head.ch < 100 && - (!i || sel.ranges[i - 1].head.line != range.head.line)) { - var mode = cm.getModeAt(range.head); - var end = changeEnd(changeEvent); - if (mode.electricChars) { - for (var j = 0; j < mode.electricChars.length; j++) - if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indentLine(cm, end.line, "smart"); - break; - } - } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) - indentLine(cm, end.line, "smart"); - } - } } + if (inserted && !paste) + triggerElectric(cm, inserted); + ensureCursorVisible(cm); cm.curOp.updateInput = updateInput; cm.curOp.typing = true; cm.state.pasteIncoming = cm.state.cutIncoming = false; } + function handlePaste(e, cm) { + var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); + if (pasted) { + e.preventDefault(); + if (!cm.isReadOnly() && !cm.options.disableInput) + runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); }); + return true; + } + } + + function triggerElectric(cm, inserted) { + // When an 'electric' character is inserted, immediately trigger a reindent + if (!cm.options.electricChars || !cm.options.smartIndent) return; + var sel = cm.doc.sel; + + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; + var mode = cm.getModeAt(range.head); + var indented = false; + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indented = indentLine(cm, range.head.line, "smart"); + break; + } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + indented = indentLine(cm, range.head.line, "smart"); + } + if (indented) signalLater(cm, "electricInput", cm, range.head.line); + } + } + function copyableRanges(cm) { var text = [], ranges = []; for (var i = 0; i < cm.doc.sel.ranges.length; i++) { @@ -1164,6 +1214,7 @@ this.inaccurateSelection = false; // Used to work around IE issue with selection being forgotten when focus moves away from textarea this.hasSelection = false; + this.composing = null; }; function hiddenTextarea() { @@ -1200,26 +1251,15 @@ input.poll(); }); - on(te, "paste", function() { - // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 - // Add a char to the end of textarea before paste occur so that - // selection doesn't span to the end of textarea. - if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { - var start = te.selectionStart, end = te.selectionEnd; - te.value += "$"; - // The selection end needs to be set before the start, otherwise there - // can be an intermediate non-empty selection between the two, which - // can override the middle-click paste buffer on linux and cause the - // wrong thing to get pasted. - te.selectionEnd = end; - te.selectionStart = start; - cm.state.fakedLastChar = true; - } + on(te, "paste", function(e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return + cm.state.pasteIncoming = true; input.fastPoll(); }); function prepareCopyCut(e) { + if (signalDOMEvent(cm, e)) return if (cm.somethingSelected()) { lastCopied = cm.getSelections(); if (input.inaccurateSelection) { @@ -1228,6 +1268,8 @@ te.value = lastCopied.join("\n"); selectInput(te); } + } else if (!cm.options.lineWiseCopyCut) { + return; } else { var ranges = copyableRanges(cm); lastCopied = ranges.text; @@ -1245,7 +1287,7 @@ on(te, "copy", prepareCopyCut); on(display.scroller, "paste", function(e) { - if (eventInWidget(display, e)) return; + if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return; cm.state.pasteIncoming = true; input.focus(); }); @@ -1254,6 +1296,22 @@ on(display.lineSpace, "selectstart", function(e) { if (!eventInWidget(display, e)) e_preventDefault(e); }); + + on(te, "compositionstart", function() { + var start = cm.getCursor("from"); + if (input.composing) input.composing.range.clear() + input.composing = { + start: start, + range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) + }; + }); + on(te, "compositionend", function() { + if (input.composing) { + input.poll(); + input.composing.range.clear(); + input.composing = null; + } + }); }, prepareSelection: function() { @@ -1361,14 +1419,11 @@ // possible when it is clear that nothing happened. hasSelection // will be the case when there is a lot of text in the textarea, // in which case reading its value would be expensive. - if (!cm.state.focused || (hasSelection(input) && !prevInput) || - isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) + if (this.contextMenuPending || !cm.state.focused || + (hasSelection(input) && !prevInput && !this.composing) || + cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) return false; - // See paste handler for more on the fakedLastChar kludge - if (cm.state.pasteIncoming && cm.state.fakedLastChar) { - input.value = input.value.substring(0, input.value.length - 1); - cm.state.fakedLastChar = false; - } + var text = input.value; // If nothing changed, bail. if (text == prevInput && !cm.somethingSelected()) return false; @@ -1381,19 +1436,29 @@ return false; } - if (text.charCodeAt(0) == 0x200b && cm.doc.sel == cm.display.selForContextMenu && !prevInput) - prevInput = "\u200b"; + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) prevInput = "\u200b"; + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + } // Find the part of the input that is actually new var same = 0, l = Math.min(prevInput.length, text.length); while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; var self = this; runInOp(cm, function() { - applyTextInput(cm, text.slice(same), prevInput.length - same); + applyTextInput(cm, text.slice(same), prevInput.length - same, + null, self.composing ? "*compose" : null); // Don't leave long text in the textarea, since it makes further polling slow if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; else self.prevInput = text; + + if (self.composing) { + self.composing.range.clear(); + self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), + {className: "CodeMirror-composing"}); + } }); return true; }, @@ -1418,10 +1483,11 @@ if (reset && cm.doc.sel.contains(pos) == -1) operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); - var oldCSS = te.style.cssText; - input.wrapper.style.position = "absolute"; - te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + - "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; + input.wrapper.style.cssText = "position: absolute" + var wrapperBox = input.wrapper.getBoundingClientRect() + te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) @@ -1440,7 +1506,9 @@ function prepareSelectAllHack() { if (te.selectionStart != null) { var selected = cm.somethingSelected(); - var extval = te.value = "\u200b" + (selected ? te.value : ""); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; input.prevInput = selected ? "" : "\u200b"; te.selectionStart = 1; te.selectionEnd = extval.length; // Re-set this, in case some other handler touched the @@ -1450,7 +1518,7 @@ } function rehide() { input.contextMenuPending = false; - input.wrapper.style.position = "relative"; + input.wrapper.style.cssText = oldWrapperCSS te.style.cssText = oldCSS; if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); @@ -1458,7 +1526,8 @@ if (te.selectionStart != null) { if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); var i = 0, poll = function() { - if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0) + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") operation(cm, commands.selectAll)(cm); else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); else display.input.reset(); @@ -1480,6 +1549,10 @@ } }, + readOnlyChanged: function(val) { + if (!val) this.reset(); + }, + setUneditable: nothing, needsContentAttribute: false @@ -1491,22 +1564,18 @@ this.cm = cm; this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; this.polling = new Delayed(); + this.gracePeriod = false; } ContentEditableInput.prototype = copyObj({ init: function(display) { var input = this, cm = input.cm; var div = input.div = display.lineDiv; - div.contentEditable = "true"; disableBrowserMagic(div); on(div, "paste", function(e) { - var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); - if (pasted) { - e.preventDefault(); - cm.replaceSelection(pasted, null, "paste"); - } - }); + if (!signalDOMEvent(cm, e)) handlePaste(e, cm); + }) on(div, "compositionstart", function(e) { var data = e.data; @@ -1544,14 +1613,17 @@ on(div, "input", function() { if (input.composing) return; - if (!input.pollContent()) + if (cm.isReadOnly() || !input.pollContent()) runInOp(input.cm, function() {regChange(cm);}); }); function onCopyCut(e) { + if (signalDOMEvent(cm, e)) return if (cm.somethingSelected()) { lastCopied = cm.getSelections(); if (e.type == "cut") cm.replaceSelection("", null, "cut"); + } else if (!cm.options.lineWiseCopyCut) { + return; } else { var ranges = copyableRanges(cm); lastCopied = ranges.text; @@ -1622,13 +1694,29 @@ try { var rng = range(start.node, start.offset, end.offset, end.node); } catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible if (rng) { - sel.removeAllRanges(); - sel.addRange(rng); + if (!gecko && this.cm.state.focused) { + sel.collapse(start.node, start.offset); + if (!rng.collapsed) sel.addRange(rng); + } else { + sel.removeAllRanges(); + sel.addRange(rng); + } if (old && sel.anchorNode == null) sel.addRange(old); + else if (gecko) this.startGracePeriod(); } this.rememberSelection(); }, + startGracePeriod: function() { + var input = this; + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function() { + input.gracePeriod = false; + if (input.selectionChanged()) + input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); + }, 20); + }, + showMultipleSelections: function(info) { removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); @@ -1671,12 +1759,15 @@ this.polling.set(this.cm.options.pollInterval, poll); }, - pollSelection: function() { - if (this.composing) return; + selectionChanged: function() { + var sel = window.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + }, - var sel = window.getSelection(), cm = this.cm; - if (sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || - sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset) { + pollSelection: function() { + if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + var sel = window.getSelection(), cm = this.cm; this.rememberSelection(); var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); var head = domToPos(cm, sel.focusNode, sel.focusOffset); @@ -1703,13 +1794,13 @@ var toIndex = findViewIndex(cm, to.line); if (toIndex == display.view.length - 1) { var toLine = display.viewTo - 1; - var toNode = display.view[toIndex].node; + var toNode = display.lineDiv.lastChild; } else { var toLine = lineNo(display.view[toIndex + 1].line) - 1; var toNode = display.view[toIndex + 1].node.previousSibling; } - var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); while (newText.length > 1 && oldText.length > 1) { if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } @@ -1753,17 +1844,24 @@ this.div.focus(); }, applyComposition: function(composing) { - if (composing.data && composing.data != composing.startData) + if (this.cm.isReadOnly()) + operation(this.cm, regChange)(this.cm) + else if (composing.data && composing.data != composing.startData) operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); }, setUneditable: function(node) { - node.setAttribute("contenteditable", "false"); + node.contentEditable = "false" }, onKeyPress: function(e) { e.preventDefault(); - operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + if (!this.cm.isReadOnly()) + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + }, + + readOnlyChanged: function(val) { + this.div.contentEditable = String(val != "nocursor") }, onContextMenu: nothing, @@ -1783,7 +1881,7 @@ var partPos = getBidiPartAt(order, pos.ch); side = partPos % 2 ? "right" : "left"; } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left"); + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); result.offset = result.collapse == "right" ? result.end : result.start; return result; } @@ -1865,7 +1963,7 @@ } function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false; + var text = "", closing = false, lineSep = cm.doc.lineSeparator(); function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } function walk(node) { if (node.nodeType == 1) { @@ -1879,7 +1977,7 @@ if (markerID) { var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); if (found.length && (range = found[0].find())) - text += getBetween(cm.doc, range.from, range.to).join("\n"); + text += getBetween(cm.doc, range.from, range.to).join(lineSep); return; } if (node.getAttribute("contenteditable") == "false") return; @@ -1891,7 +1989,7 @@ var val = node.nodeValue; if (!val) return; if (closing) { - text += "\n"; + text += lineSep; closing = false; } text += val; @@ -2063,7 +2161,7 @@ // Give beforeSelectionChange handlers a change to influence a // selection update. - function filterSelectionChange(doc, sel) { + function filterSelectionChange(doc, sel, options) { var obj = { ranges: sel.ranges, update: function(ranges) { @@ -2071,7 +2169,8 @@ for (var i = 0; i < ranges.length; i++) this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)); - } + }, + origin: options && options.origin }; signal(doc, "beforeSelectionChange", doc, obj); if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); @@ -2097,7 +2196,7 @@ function setSelectionNoUndo(doc, sel, options) { if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) - sel = filterSelectionChange(doc, sel); + sel = filterSelectionChange(doc, sel, options); var bias = options && options.bias || (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); @@ -2131,8 +2230,9 @@ var out; for (var i = 0; i < sel.ranges.length; i++) { var range = sel.ranges[i]; - var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); - var newHead = skipAtomic(doc, range.head, bias, mayClear); + var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); if (out || newAnchor != range.anchor || newHead != range.head) { if (!out) out = sel.ranges.slice(0, i); out[i] = new Range(newAnchor, newHead); @@ -2141,54 +2241,61 @@ return out ? normalizeSelection(out, sel.primIndex) : sel; } - // Ensure a given position is not inside an atomic range. - function skipAtomic(doc, pos, bias, mayClear) { - var flipped = false, curPos = pos; - var dir = bias || 1; - doc.cantEdit = false; - search: for (;;) { - var line = getLine(doc, curPos.line); - if (line.markedSpans) { - for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker; - if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && - (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { - if (mayClear) { - signal(m, "beforeCursorEnter"); - if (m.explicitlyCleared) { - if (!line.markedSpans) break; - else {--i; continue;} - } - } - if (!m.atomic) continue; - var newPos = m.find(dir < 0 ? -1 : 1); - if (cmp(newPos, curPos) == 0) { - newPos.ch += dir; - if (newPos.ch < 0) { - if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); - else newPos = null; - } else if (newPos.ch > line.text.length) { - if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); - else newPos = null; - } - if (!newPos) { - if (flipped) { - // Driven in a corner -- no valid cursor position found at all - // -- try again *with* clearing, if we didn't already - if (!mayClear) return skipAtomic(doc, pos, bias, true); - // Otherwise, turn off editing until further notice, and return the start of the doc - doc.cantEdit = true; - return Pos(doc.first, 0); - } - flipped = true; newPos = pos; dir = -dir; - } - } - curPos = newPos; - continue search; + function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { + var line = getLine(doc, pos.line); + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} } } + if (!m.atomic) continue; + + if (oldPos) { + var near = m.find(dir < 0 ? 1 : -1), diff; + if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) + near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); + if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) + return skipAtomicInner(doc, near, pos, dir, mayClear); + } + + var far = m.find(dir < 0 ? -1 : 1); + if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) + far = movePos(doc, far, dir, far.line == pos.line ? line : null); + return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null; } - return curPos; + } + return pos; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, oldPos, bias, mayClear) { + var dir = bias || 1; + var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || + skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); + if (!found) { + doc.cantEdit = true; + return Pos(doc.first, 0); + } + return found; + } + + function movePos(doc, pos, dir, line) { + if (dir < 0 && pos.ch == 0) { + if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)); + else return null; + } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { + if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0); + else return null; + } else { + return new Pos(pos.line, pos.ch + dir); } } @@ -2206,9 +2313,10 @@ for (var i = 0; i < doc.sel.ranges.length; i++) { if (primary === false && i == doc.sel.primIndex) continue; var range = doc.sel.ranges[i]; + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue; var collapsed = range.empty(); if (collapsed || cm.options.showCursorWhenSelecting) - drawSelectionCursor(cm, range, curFragment); + drawSelectionCursor(cm, range.head, curFragment); if (!collapsed) drawSelectionRange(cm, range, selFragment); } @@ -2216,8 +2324,8 @@ } // Draws a cursor for the given range - function drawSelectionCursor(cm, range, output) { - var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); + function drawSelectionCursor(cm, head, output) { + var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); cursor.style.left = pos.left + "px"; @@ -2341,8 +2449,8 @@ doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { if (doc.frontier >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles; - var highlighted = highlightLine(cm, line, state, true); + var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength; + var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true); line.styles = highlighted.styles; var oldCls = line.styleClasses, newCls = highlighted.classes; if (newCls) line.styleClasses = newCls; @@ -2351,9 +2459,10 @@ oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; if (ischange) changedLines.push(doc.frontier); - line.stateAfter = copyState(doc.mode, state); + line.stateAfter = tooLong ? state : copyState(doc.mode, state); } else { - processLine(cm, line.text, state); + if (line.text.length <= cm.options.maxHighlightLength) + processLine(cm, line.text, state); line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; } ++doc.frontier; @@ -2498,10 +2607,12 @@ function prepareMeasureForLine(cm, line) { var lineN = lineNo(line); var view = findViewForLine(cm, lineN); - if (view && !view.text) + if (view && !view.text) { view = null; - else if (view && view.changes) + } else if (view && view.changes) { updateLineForChanges(cm, view, lineN, getDimensions(cm)); + cm.curOp.forceUpdate = true; + } if (!view) view = updateExternalMeasurement(cm, line); @@ -2895,6 +3006,7 @@ updateMaxLine: false, // Set when the widest line needs to be determined anew scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet scrollToPos: null, // Used to scroll to a specific position + focus: false, id: ++nextOpId // Unique ID }; if (operationGroup) { @@ -2913,12 +3025,12 @@ var callbacks = group.delayedCallbacks, i = 0; do { for (; i < callbacks.length; i++) - callbacks[i](); + callbacks[i].call(null); for (var j = 0; j < group.ops.length; j++) { var op = group.ops[j]; if (op.cursorActivityHandlers) while (op.cursorActivityCalled < op.cursorActivityHandlers.length) - op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); + op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } } while (i < callbacks.length); } @@ -3003,15 +3115,17 @@ if (op.preparedSelection) cm.display.input.showSelection(op.preparedSelection); - if (op.updatedDisplay) - setDocumentHeight(cm, op.barMeasure); if (op.updatedDisplay || op.startHeight != cm.doc.height) updateScrollbars(cm, op.barMeasure); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); if (op.selectionChanged) restartBlink(cm); if (cm.state.focused && op.updateInput) cm.display.input.reset(op.typing); + if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())) + ensureFocus(op.cm); } function endOperation_finish(op) { @@ -3030,7 +3144,7 @@ display.scroller.scrollTop = doc.scrollTop; } if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { - doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); display.scrollbars.setScrollLeft(doc.scrollLeft); display.scroller.scrollLeft = doc.scrollLeft; alignHorizontally(cm); @@ -3326,7 +3440,7 @@ return dx * dx + dy * dy > 20 * 20; } on(d.scroller, "touchstart", function(e) { - if (!isMouseLikeTouchEvent(e)) { + if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { clearTimeout(touchFinished); var now = +new Date; d.activeTouch = {start: now, moved: false, @@ -3376,15 +3490,13 @@ // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - function drag_(e) { - if (!signalDOMEvent(cm, e)) e_stop(e); - } - if (cm.options.dragDrop) { - on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); - on(d.scroller, "dragenter", drag_); - on(d.scroller, "dragover", drag_); - on(d.scroller, "drop", operation(cm, onDrop)); - } + d.dragFunctions = { + enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, + over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }}, + start: function(e){onDragStart(cm, e);}, + drop: operation(cm, onDrop), + leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }} + }; var inp = d.input.getField(); on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); @@ -3394,6 +3506,19 @@ on(inp, "blur", bind(onBlur, cm)); } + function dragDropChanged(cm, value, old) { + var wasOn = old && old != CodeMirror.Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.enter); + toggle(cm.display.scroller, "dragover", funcs.over); + toggle(cm.display.scroller, "dragleave", funcs.leave); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + // Called when the window resizes function onResize(cm) { var d = cm.display; @@ -3444,7 +3569,7 @@ // not interfere with, such as a scrollbar or widget. function onMouseDown(e) { var cm = this, display = cm.display; - if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; + if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return; display.shift = e.shiftKey; if (eventInWidget(display, e)) { @@ -3462,7 +3587,10 @@ switch (e_button(e)) { case 1: - if (start) + // #3261: make sure, that we're not starting a second selection + if (cm.state.selectingText) + cm.state.selectingText(e); + else if (start) leftButtonDown(cm, e, start); else if (e_target(e) == display.scroller) e_preventDefault(e); @@ -3475,6 +3603,7 @@ break; case 3: if (captureRightClick) onContextMenu(cm, e); + else delayBlurEvent(cm); break; } } @@ -3482,7 +3611,7 @@ var lastClick, lastDoubleClick; function leftButtonDown(cm, e, start) { if (ie) setTimeout(bind(ensureFocus, cm), 0); - else ensureFocus(cm); + else cm.curOp.focus = activeElt(); var now = +new Date, type; if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { @@ -3496,9 +3625,10 @@ } var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; - if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && + if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && type == "single" && (contained = sel.contains(start)) > -1 && - !sel.ranges[contained].empty()) + (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && + (cmp(contained.to(), start) > 0 || start.xRel < 0)) leftButtonStartDrag(cm, e, start, modifier); else leftButtonSelect(cm, e, start, type, modifier); @@ -3507,7 +3637,7 @@ // Start a text drag. When it ends, see if any dragging actually // happen, and treat as a click if it didn't. function leftButtonStartDrag(cm, e, start, modifier) { - var display = cm.display; + var display = cm.display, startTime = +new Date; var dragEnd = operation(cm, function(e2) { if (webkit) display.scroller.draggable = false; cm.state.draggingText = false; @@ -3515,12 +3645,13 @@ off(display.scroller, "drop", dragEnd); if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { e_preventDefault(e2); - if (!modifier) + if (!modifier && +new Date - 200 < startTime) extendSelection(cm.doc, start); - display.input.focus(); - // Work around unexplainable focus problem in IE9 (#2127) - if (ie && ie_version == 9) + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) setTimeout(function() {document.body.focus(); display.input.focus();}, 20); + else + display.input.focus(); } }); // Let the drag handler handle this. @@ -3546,6 +3677,7 @@ ourRange = new Range(start, start); } else { ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; } if (e.altKey) { @@ -3577,8 +3709,9 @@ ourIndex = ranges.length; setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), {scroll: false, origin: "*mouse"}); - } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single") { - setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), + {scroll: false, origin: "*mouse"}); startSel = doc.sel; } else { replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); @@ -3640,7 +3773,7 @@ var cur = posFromMouse(cm, e, true, type == "rect"); if (!cur) return; if (cmp(cur, lastPos) != 0) { - ensureFocus(cm); + cm.curOp.focus = activeElt(); extendTo(cur); var visible = visibleLines(display, doc); if (cur.line >= visible.to || cur.line < visible.from) @@ -3656,6 +3789,7 @@ } function done(e) { + cm.state.selectingText = false; counter = Infinity; e_preventDefault(e); display.input.focus(); @@ -3669,13 +3803,14 @@ else extend(e); }); var up = operation(cm, done); + cm.state.selectingText = up; on(document, "mousemove", move); on(document, "mouseup", up); } // Determines whether an event happened in the gutter, and fires the // handlers for the corresponding event. - function gutterEvent(cm, e, type, prevent, signalfn) { + function gutterEvent(cm, e, type, prevent) { try { var mX = e.clientX, mY = e.clientY; } catch(e) { return false; } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; @@ -3692,14 +3827,14 @@ if (g && g.getBoundingClientRect().right >= mX) { var line = lineAtHeight(cm.doc, mY); var gutter = cm.options.gutters[i]; - signalfn(cm, type, cm, line, gutter, e); + signal(cm, type, cm, line, gutter, e); return e_defaultPrevented(e); } } } function clickInGutter(cm, e) { - return gutterEvent(cm, e, "gutterClick", true, signalLater); + return gutterEvent(cm, e, "gutterClick", true); } // Kludge to work around strange IE behavior where it'll sometimes @@ -3708,23 +3843,32 @@ function onDrop(e) { var cm = this; + clearDragCursor(cm); if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; e_preventDefault(e); if (ie) lastDrop = +new Date; var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; - if (!pos || isReadOnly(cm)) return; + if (!pos || cm.isReadOnly()) return; // Might be a file drop, in which case we simply extract the text // and insert it. if (files && files.length && window.FileReader && window.File) { var n = files.length, text = Array(n), read = 0; var loadFile = function(file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) + return; + var reader = new FileReader; reader.onload = operation(cm, function() { - text[i] = reader.result; + var content = reader.result; + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = ""; + text[i] = content; if (++read == n) { pos = clipPos(cm.doc, pos); - var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; + var change = {from: pos, to: pos, + text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), + origin: "paste"}; makeChange(cm.doc, change); setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); } @@ -3743,7 +3887,7 @@ try { var text = e.dataTransfer.getData("Text"); if (text) { - if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey)) + if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) var selected = cm.listSelections(); setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); if (selected) for (var i = 0; i < selected.length; ++i) @@ -3778,6 +3922,25 @@ } } + function onDragOver(cm, e) { + var pos = posFromMouse(cm, e); + if (!pos) return; + var frag = document.createDocumentFragment(); + drawSelectionCursor(cm, pos, frag); + if (!cm.display.dragCursor) { + cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); + cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); + } + removeChildrenAndAdd(cm.display.dragCursor, frag); + } + + function clearDragCursor(cm) { + if (cm.display.dragCursor) { + cm.display.lineSpace.removeChild(cm.display.dragCursor); + cm.display.dragCursor = null; + } + } + // SCROLL EVENTS // Sync the scrollable area and scrollbars, ensure the viewport @@ -3842,8 +4005,9 @@ var display = cm.display, scroll = display.scroller; // Quit if there's nothing to scroll here - if (!(dx && scroll.scrollWidth > scroll.clientWidth || - dy && scroll.scrollHeight > scroll.clientHeight)) return; + var canScrollX = scroll.scrollWidth > scroll.clientWidth; + var canScrollY = scroll.scrollHeight > scroll.clientHeight; + if (!(dx && canScrollX || dy && canScrollY)) return; // Webkit browsers on OS X abort momentum scrolls when the target // of the scroll event is removed from the scrollable element. @@ -3867,10 +4031,15 @@ // scrolling entirely here. It'll be slightly off from native, but // better than glitching out. if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { - if (dy) + if (dy && canScrollY) setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); - e_preventDefault(e); + // Only prevent default scrolling if vertical scrolling is + // actually possible. Otherwise, it causes vertical scroll + // jitter on OSX trackpads when deltaX is small and deltaY + // is large (issue #3579) + if (!dy || (dy && canScrollY)) + e_preventDefault(e); display.wheelStartX = null; // Abort measurement, if in progress return; } @@ -3919,7 +4088,7 @@ cm.display.input.ensurePolled(); var prevShift = cm.display.shift, done = false; try { - if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (cm.isReadOnly()) cm.state.suppressEdits = true; if (dropShift) cm.display.shift = false; done = bound(cm) != Pass; } finally { @@ -3998,7 +4167,7 @@ var lastStoppedKey = null; function onKeyDown(e) { var cm = this; - ensureFocus(cm); + cm.curOp.focus = activeElt(); if (signalDOMEvent(cm, e)) return; // IE does strange things with escape. if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; @@ -4050,7 +4219,19 @@ // FOCUS/BLUR EVENTS + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function() { + if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } + }, 100); + } + function onFocus(cm) { + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + if (cm.options.readOnly == "nocursor") return; if (!cm.state.focused) { signal(cm, "focus", cm); @@ -4068,6 +4249,8 @@ restartBlink(cm); } function onBlur(cm) { + if (cm.state.delayingBlurEvent) return; + if (cm.state.focused) { signal(cm, "blur", cm); cm.state.focused = false; @@ -4084,12 +4267,13 @@ // right-click take effect on it. function onContextMenu(cm, e) { if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; + if (signalDOMEvent(cm, e, "contextmenu")) return; cm.display.input.onContextMenu(e); } function contextMenuInGutter(cm, e) { if (!hasHandler(cm, "gutterContextMenu")) return false; - return gutterEvent(cm, e, "gutterContextMenu", false, signal); + return gutterEvent(cm, e, "gutterContextMenu", false); } // UPDATING @@ -4393,7 +4577,7 @@ function replaceRange(doc, code, from, to, origin) { if (!to) to = from; if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } - if (typeof code == "string") code = splitLines(code); + if (typeof code == "string") code = doc.splitLines(code); makeChange(doc, {from: from, to: to, text: code, origin: origin}); } @@ -4572,6 +4756,8 @@ if (indentString != curSpaceString) { replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + line.stateAfter = null; + return true; } else { // Ensure that, if the cursor was in the whitespace at the start // of the line, it is moved to the end of that space. @@ -4584,7 +4770,6 @@ } } } - line.stateAfter = null; } // Utility for applying a change to a line by handle or number, @@ -4636,10 +4821,9 @@ function findPosH(doc, pos, dir, unit, visually) { var line = pos.line, ch = pos.ch, origDir = dir; var lineObj = getLine(doc, line); - var possible = true; function findNextLine() { var l = line + dir; - if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + if (l < doc.first || l >= doc.first + doc.size) return false line = l; return lineObj = getLine(doc, l); } @@ -4649,14 +4833,16 @@ if (!boundToLine && findNextLine()) { if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); else ch = dir < 0 ? lineObj.text.length : 0; - } else return (possible = false); + } else return false } else ch = next; return true; } - if (unit == "char") moveOnce(); - else if (unit == "column") moveOnce(true); - else if (unit == "word" || unit == "group") { + if (unit == "char") { + moveOnce() + } else if (unit == "column") { + moveOnce(true) + } else if (unit == "word" || unit == "group") { var sawType = null, group = unit == "group"; var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); for (var first = true;; first = false) { @@ -4676,8 +4862,8 @@ if (dir > 0 && !moveOnce(!first)) break; } } - var result = skipAtomic(doc, Pos(line, ch), origDir, true); - if (!possible) result.hitSide = true; + var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true); + if (!cmp(pos, result)) result.hitSide = true; return result; } @@ -4824,7 +5010,7 @@ getHelpers: function(pos, type) { var found = []; - if (!helpers.hasOwnProperty(type)) return helpers; + if (!helpers.hasOwnProperty(type)) return found; var help = helpers[type], mode = this.getModeAt(pos); if (typeof mode[type] == "string") { if (help[mode[type]]) found.push(help[mode[type]]); @@ -4874,10 +5060,15 @@ return lineAtHeight(this.doc, height + this.display.viewOffset); }, heightAtLine: function(line, mode) { - var end = false, last = this.doc.first + this.doc.size - 1; - if (line < this.doc.first) line = this.doc.first; - else if (line > last) { line = last; end = true; } - var lineObj = getLine(this.doc, line); + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + (end ? this.doc.height - heightAtLine(lineObj) : 0); }, @@ -4906,12 +5097,6 @@ }); }), - addLineWidget: methodOp(function(handle, node, options) { - return addLineWidget(this, handle, node, options); - }), - - removeLineWidget: function(widget) { widget.clear(); }, - lineInfo: function(line) { if (typeof line == "number") { if (!isLine(this.doc, line)) return null; @@ -4970,9 +5155,11 @@ execCommand: function(cmd) { if (commands.hasOwnProperty(cmd)) - return commands[cmd](this); + return commands[cmd].call(null, this); }, + triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), + findPosH: function(from, amount, unit, visually) { var dir = 1; if (amount < 0) { dir = -1; amount = -amount; } @@ -5063,6 +5250,7 @@ signal(this, "overwriteToggle", this, this.state.overwrite); }, hasFocus: function() { return this.display.input.getField() == activeElt(); }, + isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); }, scrollTo: methodOp(function(x, y) { if (x != null || y != null) resolveScrollToPos(this); @@ -5186,10 +5374,26 @@ clearCaches(cm); regChange(cm); }, true); - option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val) { - cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); - cm.refresh(); - }, true); + option("lineSeparator", null, function(cm, val) { + cm.doc.lineSep = val; + if (!val) return; + var newBreaks = [], lineNo = cm.doc.first; + cm.doc.iter(function(line) { + for (var pos = 0;;) { + var found = line.text.indexOf(val, pos); + if (found == -1) break; + pos = found + val.length; + newBreaks.push(Pos(lineNo, found)); + } + lineNo++; + }); + for (var i = newBreaks.length - 1; i >= 0; i--) + replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) + }); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != CodeMirror.Init) cm.refresh(); + }); option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); option("electricChars", true); option("inputStyle", mobile ? "contenteditable" : "textarea", function() { @@ -5235,6 +5439,7 @@ option("showCursorWhenSelecting", false, updateSelection, true); option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); option("readOnly", false, function(cm, val) { if (val == "nocursor") { @@ -5243,11 +5448,12 @@ cm.display.disabled = true; } else { cm.display.disabled = false; - if (!val) cm.display.input.reset(); } + cm.display.input.readOnlyChanged(val) }); option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); - option("dragDrop", true); + option("dragDrop", true, dragDropChanged); + option("allowDropFileTypes", null); option("cursorBlinkRate", 530); option("cursorScrollMargin", 0); @@ -5535,7 +5741,8 @@ } else if (cur.line > cm.doc.first) { var prev = getLine(cm.doc, cur.line - 1).text; if (prev) - cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), + cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + + prev.charAt(prev.length - 1), Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); } } @@ -5549,10 +5756,10 @@ var len = cm.listSelections().length; for (var i = 0; i < len; i++) { var range = cm.listSelections()[i]; - cm.replaceRange("\n", range.anchor, range.head, "+input"); + cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input"); cm.indentLine(range.from().line + 1, null, true); - ensureCursorVisible(cm); } + ensureCursorVisible(cm); }); }, toggleOverwrite: function(cm) {cm.toggleOverwrite();} @@ -5639,7 +5846,7 @@ for (var i = 0; i < keys.length; i++) { var val, name; if (i == keys.length - 1) { - name = keyname; + name = keys.join(" "); val = value; } else { name = keys.slice(0, i + 1).join(" "); @@ -6431,10 +6638,10 @@ // Line widgets are block elements displayed above or below a line. - var LineWidget = CodeMirror.LineWidget = function(cm, node, options) { + var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { if (options) for (var opt in options) if (options.hasOwnProperty(opt)) this[opt] = options[opt]; - this.cm = cm; + this.doc = doc; this.node = node; }; eventMixin(LineWidget); @@ -6445,52 +6652,55 @@ } LineWidget.prototype.clear = function() { - var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); if (no == null || !ws) return; for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); if (!ws.length) line.widgets = null; var height = widgetHeight(this); - runInOp(cm, function() { + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) runInOp(cm, function() { adjustScrollWhenAboveVisible(cm, line, -height); regLineChange(cm, no, "widget"); - updateLineHeight(line, Math.max(0, line.height - height)); }); }; LineWidget.prototype.changed = function() { - var oldH = this.height, cm = this.cm, line = this.line; + var oldH = this.height, cm = this.doc.cm, line = this.line; this.height = null; var diff = widgetHeight(this) - oldH; if (!diff) return; - runInOp(cm, function() { + updateLineHeight(line, line.height + diff); + if (cm) runInOp(cm, function() { cm.curOp.forceUpdate = true; adjustScrollWhenAboveVisible(cm, line, diff); - updateLineHeight(line, line.height + diff); }); }; function widgetHeight(widget) { if (widget.height != null) return widget.height; + var cm = widget.doc.cm; + if (!cm) return 0; if (!contains(document.body, widget.node)) { var parentStyle = "position: relative;"; if (widget.coverGutter) - parentStyle += "margin-left: -" + widget.cm.display.gutters.offsetWidth + "px;"; + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; if (widget.noHScroll) - parentStyle += "width: " + widget.cm.display.wrapper.clientWidth + "px;"; - removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, parentStyle)); + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); } - return widget.height = widget.node.offsetHeight; + return widget.height = widget.node.parentNode.offsetHeight; } - function addLineWidget(cm, handle, node, options) { - var widget = new LineWidget(cm, node, options); - if (widget.noHScroll) cm.display.alignWidgets = true; - changeLine(cm.doc, handle, "widget", function(line) { + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) cm.display.alignWidgets = true; + changeLine(doc, handle, "widget", function(line) { var widgets = line.widgets || (line.widgets = []); if (widget.insertAt == null) widgets.push(widget); else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); widget.line = line; - if (!lineIsHidden(cm.doc, line)) { - var aboveVisible = heightAtLine(line) < cm.doc.scrollTop; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); if (aboveVisible) addToScrollPos(cm, null, widget.height); cm.curOp.forceUpdate = true; @@ -6666,7 +6876,9 @@ function getLineStyles(cm, line, updateFrontier) { if (!line.styles || line.styles[0] != cm.state.modeGen) { - var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + var state = getStateBefore(cm, lineNo(line)); + var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state); + line.stateAfter = state; line.styles = result.styles; if (result.classes) line.styleClasses = result.classes; else if (line.styleClasses) line.styleClasses = null; @@ -6683,7 +6895,7 @@ var stream = new StringStream(text, cm.options.tabSize); stream.start = stream.pos = startAt || 0; if (text == "") callBlankLine(mode, state); - while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + while (!stream.eol()) { readToken(mode, stream, state); stream.start = stream.pos; } @@ -6710,7 +6922,9 @@ // is needed on Webkit to be able to get line-level bounding // rectangles for it (in measureChar). var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); - var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm}; + var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content, + col: 0, pos: 0, cm: cm, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; lineView.measure = {}; // Iterate over the logical lines that make up this visual line. @@ -6720,8 +6934,6 @@ builder.addToken = buildToken; // Optionally wire in some hacks into the token-rendering // algorithm, to deal with browser quirks. - if ((ie || webkit) && cm.getOption("lineWrapping")) - builder.addToken = buildTokenSplitSpaces(builder.addToken); if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) builder.addToken = buildTokenBadBidi(builder.addToken, order); builder.map = []; @@ -6770,10 +6982,11 @@ // the line map. Takes care to render special characters separately. function buildToken(builder, text, style, startStyle, endStyle, title, css) { if (!text) return; - var special = builder.cm.options.specialChars, mustWrap = false; + var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; + var special = builder.cm.state.specialChars, mustWrap = false; if (!special.test(text)) { builder.col += text.length; - var content = document.createTextNode(text); + var content = document.createTextNode(displayText); builder.map.push(builder.pos, builder.pos + text.length, content); if (ie && ie_version < 9) mustWrap = true; builder.pos += text.length; @@ -6784,7 +6997,7 @@ var m = special.exec(text); var skipped = m ? m.index - pos : text.length - pos; if (skipped) { - var txt = document.createTextNode(text.slice(pos, pos + skipped)); + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); else content.appendChild(txt); builder.map.push(builder.pos, builder.pos + skipped, txt); @@ -6799,6 +7012,10 @@ txt.setAttribute("role", "presentation"); txt.setAttribute("cm-text", "\t"); builder.col += tabWidth; + } else if (m[0] == "\r" || m[0] == "\n") { + var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); + txt.setAttribute("cm-text", m[0]); + builder.col += 1; } else { var txt = builder.cm.options.specialCharPlaceholder(m[0]); txt.setAttribute("cm-text", m[0]); @@ -6821,22 +7038,17 @@ builder.content.appendChild(content); } - function buildTokenSplitSpaces(inner) { - function split(old) { - var out = " "; - for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; - out += " "; - return out; - } - return function(builder, text, style, startStyle, endStyle, title) { - inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title); - }; + function splitSpaces(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; } // Work around nonsense dimensions being reported for stretches of // right-to-left text. function buildTokenBadBidi(inner, order) { - return function(builder, text, style, startStyle, endStyle, title) { + return function(builder, text, style, startStyle, endStyle, title, css) { style = style ? style + " cm-force-border" : "cm-force-border"; var start = builder.pos, end = start + text.length; for (;;) { @@ -6845,8 +7057,8 @@ var part = order[i]; if (part.to > start && part.from <= start) break; } - if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title); - inner(builder, text.slice(0, part.to - start), style, startStyle, null, title); + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); startStyle = null; text = text.slice(part.to - start); start = part.to; @@ -6885,30 +7097,38 @@ if (nextChange == pos) { // Update current marker set spanStyle = spanEndStyle = spanStartStyle = title = css = ""; collapsed = null; nextChange = Infinity; - var foundBookmarks = []; + var foundBookmarks = [], endStyles for (var j = 0; j < spans.length; ++j) { var sp = spans[j], m = sp.marker; - if (sp.from <= pos && (sp.to == null || sp.to > pos)) { - if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { + foundBookmarks.push(m); + } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { + if (sp.to != null && sp.to != pos && nextChange > sp.to) { + nextChange = sp.to; + spanEndStyle = ""; + } if (m.className) spanStyle += " " + m.className; - if (m.css) css = m.css; + if (m.css) css = (css ? css + ";" : "") + m.css; if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; - if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to) if (m.title && !title) title = m.title; if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) collapsed = sp; } else if (sp.from > pos && nextChange > sp.from) { nextChange = sp.from; } - if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m); } + if (endStyles) for (var j = 0; j < endStyles.length; j += 2) + if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j] + + if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); if (collapsed && (collapsed.from || 0) == pos) { buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, collapsed.marker, collapsed.from == null); if (collapsed.to == null) return; + if (collapsed.to == pos) collapsed = false; } - if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) - buildCollapsedSpan(builder, 0, foundBookmarks[j]); } if (pos >= len) break; @@ -7144,8 +7364,8 @@ }; var nextDocId = 0; - var Doc = CodeMirror.Doc = function(text, mode, firstLine) { - if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep); if (firstLine == null) firstLine = 0; BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); @@ -7159,8 +7379,10 @@ this.history = new History(null); this.id = ++nextDocId; this.modeOption = mode; + this.lineSep = lineSep; + this.extend = false; - if (typeof text == "string") text = splitLines(text); + if (typeof text == "string") text = this.splitLines(text); updateDoc(this, {from: start, to: start, text: text}); setSelection(this, simpleSelection(start), sel_dontScroll); }; @@ -7190,12 +7412,12 @@ getValue: function(lineSep) { var lines = getLines(this, this.first, this.first + this.size); if (lineSep === false) return lines; - return lines.join(lineSep || "\n"); + return lines.join(lineSep || this.lineSeparator()); }, setValue: docMethodOp(function(code) { var top = Pos(this.first, 0), last = this.first + this.size - 1; makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), - text: splitLines(code), origin: "setValue", full: true}, true); + text: this.splitLines(code), origin: "setValue", full: true}, true); setSelection(this, simpleSelection(top)); }), replaceRange: function(code, from, to, origin) { @@ -7206,7 +7428,7 @@ getRange: function(from, to, lineSep) { var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); if (lineSep === false) return lines; - return lines.join(lineSep || "\n"); + return lines.join(lineSep || this.lineSeparator()); }, getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, @@ -7246,10 +7468,11 @@ extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); }), extendSelections: docMethodOp(function(heads, options) { - extendSelections(this, clipPosArray(this, heads, options)); + extendSelections(this, clipPosArray(this, heads), options); }), extendSelectionsBy: docMethodOp(function(f, options) { - extendSelections(this, map(this.sel.ranges, f), options); + var heads = map(this.sel.ranges, f); + extendSelections(this, clipPosArray(this, heads), options); }), setSelections: docMethodOp(function(ranges, primary, options) { if (!ranges.length) return; @@ -7272,13 +7495,13 @@ lines = lines ? lines.concat(sel) : sel; } if (lineSep === false) return lines; - else return lines.join(lineSep || "\n"); + else return lines.join(lineSep || this.lineSeparator()); }, getSelections: function(lineSep) { var parts = [], ranges = this.sel.ranges; for (var i = 0; i < ranges.length; i++) { var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) sel = sel.join(lineSep || "\n"); + if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()); parts[i] = sel; } return parts; @@ -7293,7 +7516,7 @@ var changes = [], sel = this.sel; for (var i = 0; i < sel.ranges.length; i++) { var range = sel.ranges[i]; - changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; + changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}; } var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); for (var i = changes.length - 1; i >= 0; i--) @@ -7368,13 +7591,19 @@ }); }), + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + removeLineWidget: function(widget) { widget.clear(); }, + markText: function(from, to, options) { - return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range"); }, setBookmark: function(pos, options) { var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), insertLeft: options && options.insertLeft, - clearWhenEmpty: false, shared: options && options.shared}; + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents}; pos = clipPos(this, pos); return markText(this, pos, pos, realOpts, "bookmark"); }, @@ -7396,9 +7625,9 @@ var spans = line.markedSpans; if (spans) for (var i = 0; i < spans.length; i++) { var span = spans[i]; - if (!(lineNo == from.line && from.ch > span.to || - span.from == null && lineNo != from.line|| - lineNo == to.line && span.from > to.ch) && + if (!(span.to != null && lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line || + span.from != null && lineNo == to.line && span.from > to.ch) && (!filter || filter(span.marker))) found.push(span.marker.parent || span.marker); } @@ -7437,7 +7666,8 @@ }, copy: function(copyHistory) { - var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + var doc = new Doc(getLines(this, this.first, this.first + this.size), + this.modeOption, this.first, this.lineSep); doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; doc.sel = this.sel; doc.extend = false; @@ -7453,7 +7683,7 @@ var from = this.first, to = this.first + this.size; if (options.from != null && options.from > from) from = options.from; if (options.to != null && options.to < to) to = options.to; - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep); if (options.sharedHist) copy.history = this.history; (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; @@ -7482,14 +7712,20 @@ iterLinkedDocs: function(f) {linkedDocs(this, f);}, getMode: function() {return this.mode;}, - getEditor: function() {return this.cm;} + getEditor: function() {return this.cm;}, + + splitLines: function(str) { + if (this.lineSep) return str.split(this.lineSep); + return splitLinesAuto(str); + }, + lineSeparator: function() { return this.lineSep || "\n"; } }); // Public alias. Doc.prototype.eachLine = Doc.prototype.iter; // Set up methods on CodeMirror's prototype to redirect to the editor's document. - var dontDelegate = "iter insert remove copy getEditor".split(" "); + var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) CodeMirror.prototype[prop] = (function(method) { return function() {return method.apply(this.doc, arguments);}; @@ -7922,24 +8158,30 @@ } }; + var noHandlers = [] + function getHandlers(emitter, type, copy) { + var arr = emitter._handlers && emitter._handlers[type] + if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers + else return arr || noHandlers + } + var off = CodeMirror.off = function(emitter, type, f) { if (emitter.removeEventListener) emitter.removeEventListener(type, f, false); else if (emitter.detachEvent) emitter.detachEvent("on" + type, f); else { - var arr = emitter._handlers && emitter._handlers[type]; - if (!arr) return; - for (var i = 0; i < arr.length; ++i) - if (arr[i] == f) { arr.splice(i, 1); break; } + var handlers = getHandlers(emitter, type, false) + for (var i = 0; i < handlers.length; ++i) + if (handlers[i] == f) { handlers.splice(i, 1); break; } } }; var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { - var arr = emitter._handlers && emitter._handlers[type]; - if (!arr) return; + var handlers = getHandlers(emitter, type, true) + if (!handlers.length) return; var args = Array.prototype.slice.call(arguments, 2); - for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args); }; var orphanDelayedCallbacks = null; @@ -7952,8 +8194,8 @@ // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. function signalLater(emitter, type /*, values...*/) { - var arr = emitter._handlers && emitter._handlers[type]; - if (!arr) return; + var arr = getHandlers(emitter, type, false) + if (!arr.length) return; var args = Array.prototype.slice.call(arguments, 2), list; if (operationGroup) { list = operationGroup.delayedCallbacks; @@ -7993,8 +8235,7 @@ } function hasHandler(emitter, type) { - var arr = emitter._handlers && emitter._handlers[type]; - return arr && arr.length > 0; + return getHandlers(emitter, type).length > 0 } // Add on and off methods to a constructor's prototype, to make @@ -8041,7 +8282,7 @@ // The inverse of countColumn -- find the offset that corresponds to // a particular column. - function findColumn(string, goal, tabSize) { + var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) { for (var pos = 0, col = 0;;) { var nextTab = string.indexOf("\t", pos); if (nextTab == -1) nextTab = string.length; @@ -8108,7 +8349,7 @@ return function(){return f.apply(null, args);}; } - var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; var isWordCharBasic = CodeMirror.isWordChar = function(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); @@ -8181,7 +8422,12 @@ } while (child = child.parentNode); }; - function activeElt() { return document.activeElement; } + function activeElt() { + var activeElement = document.activeElement; + while (activeElement && activeElement.root && activeElement.root.activeElement) + activeElement = activeElement.root.activeElement; + return activeElement; + } // Older versions of IE throws unspecified error when touching // document.activeElement in some cases (during loading, in iframe) if (ie && ie_version < 11) activeElt = function() { @@ -8283,7 +8529,7 @@ // See if "".split is the broken IE version, if so, provide an // alternative way to split lines. - var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { var pos = 0, result = [], l = string.length; while (pos <= l) { var nl = string.indexOf("\n", pos); @@ -8329,14 +8575,16 @@ // KEY NAMES - var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", - 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", - 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", - 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", - 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", - 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; - CodeMirror.keyNames = keyNames; + var keyNames = CodeMirror.keyNames = { + 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", + 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" + }; (function() { // Number keys for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); @@ -8630,6 +8878,8 @@ lst(order).to -= m[0].length; order.push(new BidiSpan(0, len - m[0].length, len)); } + if (order[0].level == 2) + order.unshift(new BidiSpan(1, order[0].to, order[0].to)); if (order[0].level != lst(order).level) order.push(new BidiSpan(order[0].level, len, len)); @@ -8639,7 +8889,7 @@ // THE END - CodeMirror.version = "5.0.0"; + CodeMirror.version = "5.13.4"; return CodeMirror; }); diff --git a/example/dist/common.js b/example/dist/common.js index 7b8d4d3..1136010 100644 --- a/example/dist/common.js +++ b/example/dist/common.js @@ -1,4 +1,4 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1) { - warnHyphenatedStyleName(name); + warnHyphenatedStyleName(name, owner); } else if (badVendoredStyleNamePattern.test(name)) { - warnBadVendoredStyleName(name); + warnBadVendoredStyleName(name, owner); } else if (badStyleValueWithSemicolonPattern.test(value)) { - warnStyleValueWithSemicolon(name, value); + warnStyleValueWithSemicolon(name, value, owner); + } + + if (typeof value === 'number' && isNaN(value)) { + warnStyleValueIsNaN(name, value, owner); } }; } @@ -782,9 +790,10 @@ var CSSPropertyOperations = { * The result should be HTML-escaped before insertion into the DOM. * * @param {object} styles + * @param {ReactDOMComponent} component * @return {?string} */ - createMarkupForStyles: function (styles) { + createMarkupForStyles: function (styles, component) { var serialized = ''; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { @@ -792,11 +801,11 @@ var CSSPropertyOperations = { } var styleValue = styles[styleName]; if (process.env.NODE_ENV !== 'production') { - warnValidStyle(styleName, styleValue); + warnValidStyle(styleName, styleValue, component); } if (styleValue != null) { serialized += processStyleName(styleName) + ':'; - serialized += dangerousStyleValue(styleName, styleValue) + ';'; + serialized += dangerousStyleValue(styleName, styleValue, component) + ';'; } } return serialized || null; @@ -808,18 +817,19 @@ var CSSPropertyOperations = { * * @param {DOMElement} node * @param {object} styles + * @param {ReactDOMComponent} component */ - setValueForStyles: function (node, styles) { + setValueForStyles: function (node, styles, component) { var style = node.style; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { continue; } if (process.env.NODE_ENV !== 'production') { - warnValidStyle(styleName, styles[styleName]); + warnValidStyle(styleName, styles[styleName], component); } - var styleValue = dangerousStyleValue(styleName, styles[styleName]); - if (styleName === 'float') { + var styleValue = dangerousStyleValue(styleName, styles[styleName], component); + if (styleName === 'float' || styleName === 'cssFloat') { styleName = styleFloatAccessor; } if (styleValue) { @@ -847,11 +857,10 @@ ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', { module.exports = CSSPropertyOperations; }).call(this,require('_process')) - -},{"./CSSProperty":"/Users/yuanyan/React/halogen/node_modules/react/lib/CSSProperty.js","./ReactPerf":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactPerf.js","./dangerousStyleValue":"/Users/yuanyan/React/halogen/node_modules/react/lib/dangerousStyleValue.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/ExecutionEnvironment":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js","fbjs/lib/camelizeStyleName":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/camelizeStyleName.js","fbjs/lib/hyphenateStyleName":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/hyphenateStyleName.js","fbjs/lib/memoizeStringOnly":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/memoizeStringOnly.js","fbjs/lib/warning":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/warning.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/CallbackQueue.js":[function(require,module,exports){ +},{"./CSSProperty":4,"./ReactPerf":80,"./dangerousStyleValue":112,"_process":1,"fbjs/lib/ExecutionEnvironment":138,"fbjs/lib/camelizeStyleName":140,"fbjs/lib/hyphenateStyleName":151,"fbjs/lib/memoizeStringOnly":158,"fbjs/lib/warning":162}],6:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -863,9 +872,10 @@ module.exports = CSSPropertyOperations; 'use strict'; +var _assign = require('object-assign'); + var PooledClass = require('./PooledClass'); -var assign = require('./Object.assign'); var invariant = require('fbjs/lib/invariant'); /** @@ -884,7 +894,7 @@ function CallbackQueue() { this._contexts = null; } -assign(CallbackQueue.prototype, { +_assign(CallbackQueue.prototype, { /** * Enqueues a callback to be invoked when `notifyAll` is invoked. @@ -910,7 +920,7 @@ assign(CallbackQueue.prototype, { var callbacks = this._callbacks; var contexts = this._contexts; if (callbacks) { - !(callbacks.length === contexts.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Mismatched list of contexts in callback queue') : invariant(false) : undefined; + !(callbacks.length === contexts.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Mismatched list of contexts in callback queue') : invariant(false) : void 0; this._callbacks = null; this._contexts = null; for (var i = 0; i < callbacks.length; i++) { @@ -921,6 +931,17 @@ assign(CallbackQueue.prototype, { } }, + checkpoint: function () { + return this._callbacks ? this._callbacks.length : 0; + }, + + rollback: function (len) { + if (this._callbacks) { + this._callbacks.length = len; + this._contexts.length = len; + } + }, + /** * Resets the internal queue. * @@ -944,10 +965,9 @@ PooledClass.addPoolingTo(CallbackQueue); module.exports = CallbackQueue; }).call(this,require('_process')) - -},{"./Object.assign":"/Users/yuanyan/React/halogen/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/yuanyan/React/halogen/node_modules/react/lib/PooledClass.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/ChangeEventPlugin.js":[function(require,module,exports){ +},{"./PooledClass":24,"_process":1,"fbjs/lib/invariant":152,"object-assign":163}],7:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -963,6 +983,7 @@ var EventConstants = require('./EventConstants'); var EventPluginHub = require('./EventPluginHub'); var EventPropagators = require('./EventPropagators'); var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); +var ReactDOMComponentTree = require('./ReactDOMComponentTree'); var ReactUpdates = require('./ReactUpdates'); var SyntheticEvent = require('./SyntheticEvent'); @@ -987,7 +1008,7 @@ var eventTypes = { * For IE shims */ var activeElement = null; -var activeElementID = null; +var activeElementInst = null; var activeElementValue = null; var activeElementValueProp = null; @@ -1006,7 +1027,7 @@ if (ExecutionEnvironment.canUseDOM) { } function manualDispatchChangeEvent(nativeEvent) { - var event = SyntheticEvent.getPooled(eventTypes.change, activeElementID, nativeEvent, getEventTarget(nativeEvent)); + var event = SyntheticEvent.getPooled(eventTypes.change, activeElementInst, nativeEvent, getEventTarget(nativeEvent)); EventPropagators.accumulateTwoPhaseDispatches(event); // If change and propertychange bubbled, we'd just bind to it like all the @@ -1028,9 +1049,9 @@ function runEventInBatch(event) { EventPluginHub.processEventQueue(false); } -function startWatchingForChangeEventIE8(target, targetID) { +function startWatchingForChangeEventIE8(target, targetInst) { activeElement = target; - activeElementID = targetID; + activeElementInst = targetInst; activeElement.attachEvent('onchange', manualDispatchChangeEvent); } @@ -1040,20 +1061,20 @@ function stopWatchingForChangeEventIE8() { } activeElement.detachEvent('onchange', manualDispatchChangeEvent); activeElement = null; - activeElementID = null; + activeElementInst = null; } -function getTargetIDForChangeEvent(topLevelType, topLevelTarget, topLevelTargetID) { +function getTargetInstForChangeEvent(topLevelType, targetInst) { if (topLevelType === topLevelTypes.topChange) { - return topLevelTargetID; + return targetInst; } } -function handleEventsForChangeEventIE8(topLevelType, topLevelTarget, topLevelTargetID) { +function handleEventsForChangeEventIE8(topLevelType, target, targetInst) { if (topLevelType === topLevelTypes.topFocus) { // stopWatching() should be a noop here but we call it just in case we // missed a blur event somehow. stopWatchingForChangeEventIE8(); - startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID); + startWatchingForChangeEventIE8(target, targetInst); } else if (topLevelType === topLevelTypes.topBlur) { stopWatchingForChangeEventIE8(); } @@ -1065,12 +1086,14 @@ function handleEventsForChangeEventIE8(topLevelType, topLevelTarget, topLevelTar var isInputEventSupported = false; if (ExecutionEnvironment.canUseDOM) { // IE9 claims to support the input event but fails to trigger it when - // deleting text, so we ignore its input events - isInputEventSupported = isEventSupported('input') && (!('documentMode' in document) || document.documentMode > 9); + // deleting text, so we ignore its input events. + // IE10+ fire input events to often, such when a placeholder + // changes or when an input with a placeholder is focused. + isInputEventSupported = isEventSupported('input') && (!('documentMode' in document) || document.documentMode > 11); } /** - * (For old IE.) Replacement getter/setter for the `value` property that gets + * (For IE <=11) Replacement getter/setter for the `value` property that gets * set on the active element. */ var newValueProp = { @@ -1085,24 +1108,28 @@ var newValueProp = { }; /** - * (For old IE.) Starts tracking propertychange events on the passed-in element + * (For IE <=11) Starts tracking propertychange events on the passed-in element * and override the value property so that we can distinguish user events from * value changes in JS. */ -function startWatchingForValueChange(target, targetID) { +function startWatchingForValueChange(target, targetInst) { activeElement = target; - activeElementID = targetID; + activeElementInst = targetInst; activeElementValue = target.value; activeElementValueProp = Object.getOwnPropertyDescriptor(target.constructor.prototype, 'value'); // Not guarded in a canDefineProperty check: IE8 supports defineProperty only // on DOM elements Object.defineProperty(activeElement, 'value', newValueProp); - activeElement.attachEvent('onpropertychange', handlePropertyChange); + if (activeElement.attachEvent) { + activeElement.attachEvent('onpropertychange', handlePropertyChange); + } else { + activeElement.addEventListener('propertychange', handlePropertyChange, false); + } } /** - * (For old IE.) Removes the event listeners from the currently-tracked element, + * (For IE <=11) Removes the event listeners from the currently-tracked element, * if any exists. */ function stopWatchingForValueChange() { @@ -1112,16 +1139,21 @@ function stopWatchingForValueChange() { // delete restores the original property definition delete activeElement.value; - activeElement.detachEvent('onpropertychange', handlePropertyChange); + + if (activeElement.detachEvent) { + activeElement.detachEvent('onpropertychange', handlePropertyChange); + } else { + activeElement.removeEventListener('propertychange', handlePropertyChange, false); + } activeElement = null; - activeElementID = null; + activeElementInst = null; activeElementValue = null; activeElementValueProp = null; } /** - * (For old IE.) Handles a propertychange event, sending a `change` event if + * (For IE <=11) Handles a propertychange event, sending a `change` event if * the value of the active element has changed. */ function handlePropertyChange(nativeEvent) { @@ -1140,21 +1172,20 @@ function handlePropertyChange(nativeEvent) { /** * If a `change` event should be fired, returns the target's ID. */ -function getTargetIDForInputEvent(topLevelType, topLevelTarget, topLevelTargetID) { +function getTargetInstForInputEvent(topLevelType, targetInst) { if (topLevelType === topLevelTypes.topInput) { // In modern browsers (i.e., not IE8 or IE9), the input event is exactly // what we want so fall through here and trigger an abstract event - return topLevelTargetID; + return targetInst; } } -// For IE8 and IE9. -function handleEventsForInputEventIE(topLevelType, topLevelTarget, topLevelTargetID) { +function handleEventsForInputEventIE(topLevelType, target, targetInst) { if (topLevelType === topLevelTypes.topFocus) { // In IE8, we can capture almost all .value changes by adding a // propertychange handler and looking for events with propertyName // equal to 'value' - // In IE9, propertychange fires for most input events but is buggy and + // In IE9-11, propertychange fires for most input events but is buggy and // doesn't fire when text is deleted, but conveniently, selectionchange // appears to fire in all of the remaining cases so we catch those and // forward the event if the value has changed @@ -1165,14 +1196,14 @@ function handleEventsForInputEventIE(topLevelType, topLevelTarget, topLevelTarge // stopWatching() should be a noop here but we call it just in case we // missed a blur event somehow. stopWatchingForValueChange(); - startWatchingForValueChange(topLevelTarget, topLevelTargetID); + startWatchingForValueChange(target, targetInst); } else if (topLevelType === topLevelTypes.topBlur) { stopWatchingForValueChange(); } } // For IE8 and IE9. -function getTargetIDForInputEventIE(topLevelType, topLevelTarget, topLevelTargetID) { +function getTargetInstForInputEventIE(topLevelType, targetInst) { if (topLevelType === topLevelTypes.topSelectionChange || topLevelType === topLevelTypes.topKeyUp || topLevelType === topLevelTypes.topKeyDown) { // On the selectionchange event, the target is just document which isn't // helpful for us so just check activeElement instead. @@ -1186,7 +1217,7 @@ function getTargetIDForInputEventIE(topLevelType, topLevelTarget, topLevelTarget // fire selectionchange normally. if (activeElement && activeElement.value !== activeElementValue) { activeElementValue = activeElement.value; - return activeElementID; + return activeElementInst; } } } @@ -1201,9 +1232,9 @@ function shouldUseClickEvent(elem) { return elem.nodeName && elem.nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); } -function getTargetIDForClickEvent(topLevelType, topLevelTarget, topLevelTargetID) { +function getTargetInstForClickEvent(topLevelType, targetInst) { if (topLevelType === topLevelTypes.topClick) { - return topLevelTargetID; + return targetInst; } } @@ -1221,38 +1252,31 @@ var ChangeEventPlugin = { eventTypes: eventTypes, - /** - * @param {string} topLevelType Record from `EventConstants`. - * @param {DOMEventTarget} topLevelTarget The listening component root node. - * @param {string} topLevelTargetID ID of `topLevelTarget`. - * @param {object} nativeEvent Native browser event. - * @return {*} An accumulation of synthetic events. - * @see {EventPluginHub.extractEvents} - */ - extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) { + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var targetNode = targetInst ? ReactDOMComponentTree.getNodeFromInstance(targetInst) : window; - var getTargetIDFunc, handleEventFunc; - if (shouldUseChangeEvent(topLevelTarget)) { + var getTargetInstFunc, handleEventFunc; + if (shouldUseChangeEvent(targetNode)) { if (doesChangeEventBubble) { - getTargetIDFunc = getTargetIDForChangeEvent; + getTargetInstFunc = getTargetInstForChangeEvent; } else { handleEventFunc = handleEventsForChangeEventIE8; } - } else if (isTextInputElement(topLevelTarget)) { + } else if (isTextInputElement(targetNode)) { if (isInputEventSupported) { - getTargetIDFunc = getTargetIDForInputEvent; + getTargetInstFunc = getTargetInstForInputEvent; } else { - getTargetIDFunc = getTargetIDForInputEventIE; + getTargetInstFunc = getTargetInstForInputEventIE; handleEventFunc = handleEventsForInputEventIE; } - } else if (shouldUseClickEvent(topLevelTarget)) { - getTargetIDFunc = getTargetIDForClickEvent; + } else if (shouldUseClickEvent(targetNode)) { + getTargetInstFunc = getTargetInstForClickEvent; } - if (getTargetIDFunc) { - var targetID = getTargetIDFunc(topLevelType, topLevelTarget, topLevelTargetID); - if (targetID) { - var event = SyntheticEvent.getPooled(eventTypes.change, targetID, nativeEvent, nativeEventTarget); + if (getTargetInstFunc) { + var inst = getTargetInstFunc(topLevelType, targetInst); + if (inst) { + var event = SyntheticEvent.getPooled(eventTypes.change, inst, nativeEvent, nativeEventTarget); event.type = 'change'; EventPropagators.accumulateTwoPhaseDispatches(event); return event; @@ -1260,41 +1284,16 @@ var ChangeEventPlugin = { } if (handleEventFunc) { - handleEventFunc(topLevelType, topLevelTarget, topLevelTargetID); + handleEventFunc(topLevelType, targetNode, targetInst); } } }; module.exports = ChangeEventPlugin; -},{"./EventConstants":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventConstants.js","./EventPluginHub":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginHub.js","./EventPropagators":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPropagators.js","./ReactUpdates":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactUpdates.js","./SyntheticEvent":"/Users/yuanyan/React/halogen/node_modules/react/lib/SyntheticEvent.js","./getEventTarget":"/Users/yuanyan/React/halogen/node_modules/react/lib/getEventTarget.js","./isEventSupported":"/Users/yuanyan/React/halogen/node_modules/react/lib/isEventSupported.js","./isTextInputElement":"/Users/yuanyan/React/halogen/node_modules/react/lib/isTextInputElement.js","fbjs/lib/ExecutionEnvironment":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js","fbjs/lib/keyOf":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/keyOf.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/ClientReactRootIndex.js":[function(require,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 ClientReactRootIndex - * @typechecks - */ - -'use strict'; - -var nextReactRootIndex = 0; - -var ClientReactRootIndex = { - createReactRootIndex: function () { - return nextReactRootIndex++; - } -}; - -module.exports = ClientReactRootIndex; -},{}],"/Users/yuanyan/React/halogen/node_modules/react/lib/DOMChildrenOperations.js":[function(require,module,exports){ -(function (process){ +},{"./EventConstants":16,"./EventPluginHub":17,"./EventPropagators":20,"./ReactDOMComponentTree":39,"./ReactUpdates":88,"./SyntheticEvent":97,"./getEventTarget":120,"./isEventSupported":127,"./isTextInputElement":128,"fbjs/lib/ExecutionEnvironment":138,"fbjs/lib/keyOf":156}],8:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1302,18 +1301,27 @@ module.exports = ClientReactRootIndex; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule DOMChildrenOperations - * @typechecks static-only */ 'use strict'; +var DOMLazyTree = require('./DOMLazyTree'); var Danger = require('./Danger'); var ReactMultiChildUpdateTypes = require('./ReactMultiChildUpdateTypes'); var ReactPerf = require('./ReactPerf'); +var createMicrosoftUnsafeLocalFunction = require('./createMicrosoftUnsafeLocalFunction'); var setInnerHTML = require('./setInnerHTML'); var setTextContent = require('./setTextContent'); -var invariant = require('fbjs/lib/invariant'); + +function getNodeAfter(parentNode, node) { + // Special case for text components, which return [open, close] comments + // from getNativeNode. + if (Array.isArray(node)) { + node = node[1]; + } + return node ? node.nextSibling : parentNode.firstChild; +} /** * Inserts `childNode` as a child of `parentNode` at the `index`. @@ -1323,17 +1331,78 @@ var invariant = require('fbjs/lib/invariant'); * @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`. +var insertChildAt = createMicrosoftUnsafeLocalFunction(function (parentNode, childNode, referenceNode) { + // We rely exclusively on `insertBefore(node, null)` instead of also using + // `appendChild(node)`. (Using `undefined` is not allowed by all browsers so + // we are careful to use `null`.) + parentNode.insertBefore(childNode, referenceNode); +}); + +function insertLazyTreeChildAt(parentNode, childTree, referenceNode) { + DOMLazyTree.insertTreeBefore(parentNode, childTree, referenceNode); +} + +function moveChild(parentNode, childNode, referenceNode) { + if (Array.isArray(childNode)) { + moveDelimitedText(parentNode, childNode[0], childNode[1], referenceNode); + } else { + insertChildAt(parentNode, childNode, referenceNode); + } +} + +function removeChild(parentNode, childNode) { + if (Array.isArray(childNode)) { + var closingComment = childNode[1]; + childNode = childNode[0]; + removeDelimitedText(parentNode, childNode, closingComment); + parentNode.removeChild(closingComment); + } + parentNode.removeChild(childNode); +} - // 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); +function moveDelimitedText(parentNode, openingComment, closingComment, referenceNode) { + var node = openingComment; + while (true) { + var nextNode = node.nextSibling; + insertChildAt(parentNode, node, referenceNode); + if (node === closingComment) { + break; + } + node = nextNode; + } +} + +function removeDelimitedText(parentNode, startNode, closingComment) { + while (true) { + var node = startNode.nextSibling; + if (node === closingComment) { + // The closing comment is removed by ReactMultiChild. + break; + } else { + parentNode.removeChild(node); + } + } +} - parentNode.insertBefore(childNode, beforeChild); +function replaceDelimitedText(openingComment, closingComment, stringText) { + var parentNode = openingComment.parentNode; + var nodeAfterComment = openingComment.nextSibling; + if (nodeAfterComment === closingComment) { + // There are no text nodes between the opening and closing comments; insert + // a new one if stringText isn't empty. + if (stringText) { + insertChildAt(parentNode, document.createTextNode(stringText), nodeAfterComment); + } + } else { + if (stringText) { + // Set the text content of the first node after the opening comment, and + // remove all following nodes up until the closing comment. + setTextContent(nodeAfterComment, stringText); + removeDelimitedText(parentNode, nodeAfterComment, closingComment); + } else { + removeDelimitedText(parentNode, openingComment, closingComment); + } + } } /** @@ -1343,73 +1412,33 @@ var DOMChildrenOperations = { dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, - updateTextContent: setTextContent, + replaceDelimitedText: replaceDelimitedText, /** * 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]); - } - } - + processUpdates: function (parentNode, updates) { for (var k = 0; k < updates.length; k++) { - update = updates[k]; + var update = updates[k]; switch (update.type) { case ReactMultiChildUpdateTypes.INSERT_MARKUP: - insertChildAt(update.parentNode, renderedMarkup[update.markupIndex], update.toIndex); + insertLazyTreeChildAt(parentNode, update.content, getNodeAfter(parentNode, update.afterNode)); break; case ReactMultiChildUpdateTypes.MOVE_EXISTING: - insertChildAt(update.parentNode, initialChildren[update.parentID][update.fromIndex], update.toIndex); + moveChild(parentNode, update.fromNode, getNodeAfter(parentNode, update.afterNode)); break; case ReactMultiChildUpdateTypes.SET_MARKUP: - setInnerHTML(update.parentNode, update.content); + setInnerHTML(parentNode, update.content); break; case ReactMultiChildUpdateTypes.TEXT_CONTENT: - setTextContent(update.parentNode, update.content); + setTextContent(parentNode, update.content); break; case ReactMultiChildUpdateTypes.REMOVE_NODE: - // Already removed by the for-loop above. + removeChild(parentNode, update.fromNode); break; } } @@ -1418,16 +1447,141 @@ var DOMChildrenOperations = { }; ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', { - updateTextContent: 'updateTextContent' + replaceDelimitedText: 'replaceDelimitedText' }); module.exports = DOMChildrenOperations; -}).call(this,require('_process')) +},{"./DOMLazyTree":9,"./Danger":13,"./ReactMultiChildUpdateTypes":75,"./ReactPerf":80,"./createMicrosoftUnsafeLocalFunction":111,"./setInnerHTML":132,"./setTextContent":133}],9:[function(require,module,exports){ +/** + * Copyright 2015-present, 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 DOMLazyTree + */ + +'use strict'; + +var createMicrosoftUnsafeLocalFunction = require('./createMicrosoftUnsafeLocalFunction'); +var setTextContent = require('./setTextContent'); + +/** + * In IE (8-11) and Edge, appending nodes with no children is dramatically + * faster than appending a full subtree, so we essentially queue up the + * .appendChild calls here and apply them so each node is added to its parent + * before any children are added. + * + * In other browsers, doing so is slower or neutral compared to the other order + * (in Firefox, twice as slow) so we only do this inversion in IE. + * + * See https://github.com/spicyj/innerhtml-vs-createelement-vs-clonenode. + */ +var enableLazy = typeof document !== 'undefined' && typeof document.documentMode === 'number' || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && /\bEdge\/\d/.test(navigator.userAgent); + +function insertTreeChildren(tree) { + if (!enableLazy) { + return; + } + var node = tree.node; + var children = tree.children; + if (children.length) { + for (var i = 0; i < children.length; i++) { + insertTreeBefore(node, children[i], null); + } + } else if (tree.html != null) { + node.innerHTML = tree.html; + } else if (tree.text != null) { + setTextContent(node, tree.text); + } +} + +var insertTreeBefore = createMicrosoftUnsafeLocalFunction(function (parentNode, tree, referenceNode) { + // DocumentFragments aren't actually part of the DOM after insertion so + // appending children won't update the DOM. We need to ensure the fragment + // is properly populated first, breaking out of our lazy approach for just + // this level. + if (tree.node.nodeType === 11) { + insertTreeChildren(tree); + parentNode.insertBefore(tree.node, referenceNode); + } else { + parentNode.insertBefore(tree.node, referenceNode); + insertTreeChildren(tree); + } +}); + +function replaceChildWithTree(oldNode, newTree) { + oldNode.parentNode.replaceChild(newTree.node, oldNode); + insertTreeChildren(newTree); +} + +function queueChild(parentTree, childTree) { + if (enableLazy) { + parentTree.children.push(childTree); + } else { + parentTree.node.appendChild(childTree.node); + } +} + +function queueHTML(tree, html) { + if (enableLazy) { + tree.html = html; + } else { + tree.node.innerHTML = html; + } +} + +function queueText(tree, text) { + if (enableLazy) { + tree.text = text; + } else { + setTextContent(tree.node, text); + } +} + +function DOMLazyTree(node) { + return { + node: node, + children: [], + html: null, + text: null + }; +} + +DOMLazyTree.insertTreeBefore = insertTreeBefore; +DOMLazyTree.replaceChildWithTree = replaceChildWithTree; +DOMLazyTree.queueChild = queueChild; +DOMLazyTree.queueHTML = queueHTML; +DOMLazyTree.queueText = queueText; -},{"./Danger":"/Users/yuanyan/React/halogen/node_modules/react/lib/Danger.js","./ReactMultiChildUpdateTypes":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactMultiChildUpdateTypes.js","./ReactPerf":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactPerf.js","./setInnerHTML":"/Users/yuanyan/React/halogen/node_modules/react/lib/setInnerHTML.js","./setTextContent":"/Users/yuanyan/React/halogen/node_modules/react/lib/setTextContent.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/DOMProperty.js":[function(require,module,exports){ +module.exports = DOMLazyTree; +},{"./createMicrosoftUnsafeLocalFunction":111,"./setTextContent":133}],10:[function(require,module,exports){ +/** + * Copyright 2013-present, 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 DOMNamespaces + */ + +'use strict'; + +var DOMNamespaces = { + html: 'http://www.w3.org/1999/xhtml', + mathml: 'http://www.w3.org/1998/Math/MathML', + svg: 'http://www.w3.org/2000/svg' +}; + +module.exports = DOMNamespaces; +},{}],11:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1435,7 +1589,6 @@ module.exports = DOMChildrenOperations; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule DOMProperty - * @typechecks static-only */ 'use strict'; @@ -1451,13 +1604,12 @@ 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, + MUST_USE_PROPERTY: 0x1, + HAS_SIDE_EFFECTS: 0x2, + HAS_BOOLEAN_VALUE: 0x4, + HAS_NUMERIC_VALUE: 0x8, + HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8, + HAS_OVERLOADED_BOOLEAN_VALUE: 0x20, /** * Inject some specialized knowledge about the DOM. This takes a config object @@ -1500,7 +1652,7 @@ var DOMPropertyInjection = { } 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; + !!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) : void 0; var lowerCased = propName.toLowerCase(); var propConfig = Properties[propName]; @@ -1511,7 +1663,6 @@ var DOMPropertyInjection = { 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), @@ -1520,9 +1671,8 @@ var DOMPropertyInjection = { 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; + !(propertyInfo.mustUseProperty || !propertyInfo.hasSideEffects) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'DOMProperty: Properties that have side effects must use property: %s', propName) : invariant(false) : void 0; + !(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) : void 0; if (process.env.NODE_ENV !== 'production') { DOMProperty.getPossibleStandardName[lowerCased] = propName; @@ -1552,7 +1702,10 @@ var DOMPropertyInjection = { } } }; -var defaultValueCache = {}; + +/* eslint-disable max-len */ +var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD'; +/* eslint-enable max-len */ /** * DOMProperty exports lookup objects that can be used like functions: @@ -1570,6 +1723,10 @@ var defaultValueCache = {}; var DOMProperty = { ID_ATTRIBUTE_NAME: 'data-reactid', + ROOT_ATTRIBUTE_NAME: 'data-reactroot', + + ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR, + ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\uB7\\u0300-\\u036F\\u203F-\\u2040', /** * Map from property "standard name" to an object with info about how to set @@ -1584,9 +1741,6 @@ var DOMProperty = { * 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: @@ -1635,37 +1789,15 @@ var DOMProperty = { 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; }).call(this,require('_process')) - -},{"_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/DOMPropertyOperations.js":[function(require,module,exports){ +},{"_process":1,"fbjs/lib/invariant":152}],12:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1673,19 +1805,18 @@ module.exports = DOMProperty; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule DOMPropertyOperations - * @typechecks static-only */ 'use strict'; var DOMProperty = require('./DOMProperty'); +var ReactDOMInstrumentation = require('./ReactDOMInstrumentation'); var ReactPerf = require('./ReactPerf'); var quoteAttributeValueForBrowser = require('./quoteAttributeValueForBrowser'); var warning = require('fbjs/lib/warning'); -// Simplified subset -var VALID_ATTRIBUTE_NAME_REGEX = /^[a-zA-Z_][\w\.\-]*$/; +var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + DOMProperty.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'); var illegalAttributeNameCache = {}; var validatedAttributeNameCache = {}; @@ -1701,7 +1832,7 @@ function isAttributeNameSafe(attributeName) { return true; } illegalAttributeNameCache[attributeName] = true; - process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid attribute name: `%s`', attributeName) : undefined; + process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid attribute name: `%s`', attributeName) : void 0; return false; } @@ -1709,32 +1840,6 @@ 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. */ @@ -1754,6 +1859,14 @@ var DOMPropertyOperations = { node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id); }, + createMarkupForRoot: function () { + return DOMProperty.ROOT_ATTRIBUTE_NAME + '=""'; + }, + + setAttributeForRoot: function (node) { + node.setAttribute(DOMProperty.ROOT_ATTRIBUTE_NAME, ''); + }, + /** * Creates markup for a property. * @@ -1762,6 +1875,9 @@ var DOMPropertyOperations = { * @return {?string} Markup string, or null if the property was invalid. */ createMarkupForProperty: function (name, value) { + if (process.env.NODE_ENV !== 'production') { + ReactDOMInstrumentation.debugTool.onCreateMarkupForProperty(name, value); + } var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; if (propertyInfo) { if (shouldIgnoreValue(propertyInfo, value)) { @@ -1777,8 +1893,6 @@ var DOMPropertyOperations = { return ''; } return name + '=' + quoteAttributeValueForBrowser(value); - } else if (process.env.NODE_ENV !== 'production') { - warnUnknownProperty(name); } return null; }, @@ -1805,6 +1919,9 @@ var DOMPropertyOperations = { * @param {*} value */ setValueForProperty: function (node, name, value) { + if (process.env.NODE_ENV !== 'production') { + ReactDOMInstrumentation.debugTool.onSetValueForProperty(node, name, value); + } var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; if (propertyInfo) { var mutationMethod = propertyInfo.mutationMethod; @@ -1812,7 +1929,16 @@ var DOMPropertyOperations = { mutationMethod(node, value); } else if (shouldIgnoreValue(propertyInfo, value)) { this.deleteValueForProperty(node, name); - } else if (propertyInfo.mustUseAttribute) { + } else if (propertyInfo.mustUseProperty) { + 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 { var attributeName = propertyInfo.attributeName; var namespace = propertyInfo.attributeNamespace; // `setAttribute` with objects becomes only `[object]` in IE8/9, @@ -1824,20 +1950,9 @@ var DOMPropertyOperations = { } 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); } }, @@ -1859,24 +1974,29 @@ var DOMPropertyOperations = { * @param {string} name */ deleteValueForProperty: function (node, name) { + if (process.env.NODE_ENV !== 'production') { + ReactDOMInstrumentation.debugTool.onDeleteValueForProperty(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 { + } else if (propertyInfo.mustUseProperty) { var propName = propertyInfo.propertyName; - var defaultValue = DOMProperty.getDefaultValueForProperty(node.nodeName, propName); - if (!propertyInfo.hasSideEffects || '' + node[propName] !== defaultValue) { - node[propName] = defaultValue; + if (propertyInfo.hasBooleanValue) { + // No HAS_SIDE_EFFECTS logic here, only `value` has it and is string. + node[propName] = false; + } else { + if (!propertyInfo.hasSideEffects || '' + node[propName] !== '') { + node[propName] = ''; + } } + } else { + node.removeAttribute(propertyInfo.attributeName); } } else if (DOMProperty.isCustomAttribute(name)) { node.removeAttribute(name); - } else if (process.env.NODE_ENV !== 'production') { - warnUnknownProperty(name); } } @@ -1890,11 +2010,10 @@ ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', { module.exports = DOMPropertyOperations; }).call(this,require('_process')) - -},{"./DOMProperty":"/Users/yuanyan/React/halogen/node_modules/react/lib/DOMProperty.js","./ReactPerf":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactPerf.js","./quoteAttributeValueForBrowser":"/Users/yuanyan/React/halogen/node_modules/react/lib/quoteAttributeValueForBrowser.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/warning":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/warning.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/Danger.js":[function(require,module,exports){ +},{"./DOMProperty":11,"./ReactDOMInstrumentation":47,"./ReactPerf":80,"./quoteAttributeValueForBrowser":130,"_process":1,"fbjs/lib/warning":162}],13:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1902,11 +2021,11 @@ module.exports = DOMPropertyOperations; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule Danger - * @typechecks static-only */ 'use strict'; +var DOMLazyTree = require('./DOMLazyTree'); var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); var createNodesFromMarkup = require('fbjs/lib/createNodesFromMarkup'); @@ -1944,12 +2063,12 @@ var Danger = { * @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; + !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) : void 0; 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; + !markupList[i] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyRenderMarkup(...): Missing markup.') : invariant(false) : void 0; nodeName = getNodeName(markupList[i]); nodeName = getMarkupWrap(nodeName) ? nodeName : '*'; markupByNodeName[nodeName] = markupByNodeName[nodeName] || []; @@ -1991,7 +2110,7 @@ var Danger = { resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR); renderNode.removeAttribute(RESULT_INDEX_ATTR); - !!resultList.hasOwnProperty(resultIndex) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Danger: Assigning to an already-occupied result index.') : invariant(false) : undefined; + !!resultList.hasOwnProperty(resultIndex) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Danger: Assigning to an already-occupied result index.') : invariant(false) : void 0; resultList[resultIndex] = renderNode; @@ -2006,9 +2125,9 @@ var Danger = { // Although resultList was populated out of order, it should now be a dense // array. - !(resultListAssignmentCount === resultList.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Danger: Did not assign to every index of resultList.') : invariant(false) : undefined; + !(resultListAssignmentCount === resultList.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Danger: Did not assign to every index of resultList.') : invariant(false) : void 0; - !(resultList.length === markupList.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Danger: Expected markup to render %s nodes, but rendered %s.', markupList.length, resultList.length) : invariant(false) : undefined; + !(resultList.length === markupList.length) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Danger: Expected markup to render %s nodes, but rendered %s.', markupList.length, resultList.length) : invariant(false) : void 0; return resultList; }, @@ -2022,27 +2141,25 @@ var Danger = { * @internal */ dangerouslyReplaceNodeWithMarkup: function (oldChild, markup) { - !ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): 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; - !markup ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(false) : undefined; - !(oldChild.tagName.toLowerCase() !== 'html') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' + ' node. This is because browser quirks make this unreliable ' + 'and/or slow. If you want to render to the root you must use ' + 'server rendering. See ReactDOMServer.renderToString().') : invariant(false) : undefined; + !ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): 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) : void 0; + !markup ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(false) : void 0; + !(oldChild.nodeName !== 'HTML') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' + ' node. This is because browser quirks make this unreliable ' + 'and/or slow. If you want to render to the root you must use ' + 'server rendering. See ReactDOMServer.renderToString().') : invariant(false) : void 0; - var newChild; if (typeof markup === 'string') { - newChild = createNodesFromMarkup(markup, emptyFunction)[0]; + var newChild = createNodesFromMarkup(markup, emptyFunction)[0]; + oldChild.parentNode.replaceChild(newChild, oldChild); } else { - newChild = markup; + DOMLazyTree.replaceChildWithTree(oldChild, markup); } - oldChild.parentNode.replaceChild(newChild, oldChild); } }; module.exports = Danger; }).call(this,require('_process')) - -},{"_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/ExecutionEnvironment":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js","fbjs/lib/createNodesFromMarkup":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/createNodesFromMarkup.js","fbjs/lib/emptyFunction":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/emptyFunction.js","fbjs/lib/getMarkupWrap":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/getMarkupWrap.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/DefaultEventPluginOrder.js":[function(require,module,exports){ +},{"./DOMLazyTree":9,"_process":1,"fbjs/lib/ExecutionEnvironment":138,"fbjs/lib/createNodesFromMarkup":143,"fbjs/lib/emptyFunction":144,"fbjs/lib/getMarkupWrap":148,"fbjs/lib/invariant":152}],14:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -2068,9 +2185,9 @@ var keyOf = require('fbjs/lib/keyOf'); var DefaultEventPluginOrder = [keyOf({ ResponderEventPlugin: null }), keyOf({ SimpleEventPlugin: null }), keyOf({ TapEventPlugin: null }), keyOf({ EnterLeaveEventPlugin: null }), keyOf({ ChangeEventPlugin: null }), keyOf({ SelectEventPlugin: null }), keyOf({ BeforeInputEventPlugin: null })]; module.exports = DefaultEventPluginOrder; -},{"fbjs/lib/keyOf":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/keyOf.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/EnterLeaveEventPlugin.js":[function(require,module,exports){ +},{"fbjs/lib/keyOf":156}],15:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -2078,20 +2195,18 @@ module.exports = DefaultEventPluginOrder; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule EnterLeaveEventPlugin - * @typechecks static-only */ 'use strict'; var EventConstants = require('./EventConstants'); var EventPropagators = require('./EventPropagators'); +var ReactDOMComponentTree = require('./ReactDOMComponentTree'); var SyntheticMouseEvent = require('./SyntheticMouseEvent'); -var ReactMount = require('./ReactMount'); var keyOf = require('fbjs/lib/keyOf'); var topLevelTypes = EventConstants.topLevelTypes; -var getFirstReactDOM = ReactMount.getFirstReactDOM; var eventTypes = { mouseEnter: { @@ -2104,8 +2219,6 @@ var eventTypes = { } }; -var extractedEvents = [null, null]; - var EnterLeaveEventPlugin = { eventTypes: eventTypes, @@ -2116,15 +2229,8 @@ var EnterLeaveEventPlugin = { * we do not extract duplicate events. However, moving the mouse into the * browser from outside will not fire a `mouseout` event. In this case, we use * the `mouseover` top-level event. - * - * @param {string} topLevelType Record from `EventConstants`. - * @param {DOMEventTarget} topLevelTarget The listening component root node. - * @param {string} topLevelTargetID ID of `topLevelTarget`. - * @param {object} nativeEvent Native browser event. - * @return {*} An accumulation of synthetic events. - * @see {EventPluginHub.extractEvents} */ - extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) { + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { if (topLevelType === topLevelTypes.topMouseOver && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { return null; } @@ -2134,12 +2240,12 @@ var EnterLeaveEventPlugin = { } var win; - if (topLevelTarget.window === topLevelTarget) { - // `topLevelTarget` is probably a window object. - win = topLevelTarget; + if (nativeEventTarget.window === nativeEventTarget) { + // `nativeEventTarget` is probably a window object. + win = nativeEventTarget; } else { // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. - var doc = topLevelTarget.ownerDocument; + var doc = nativeEventTarget.ownerDocument; if (doc) { win = doc.defaultView || doc.parentWindow; } else { @@ -2149,22 +2255,14 @@ var EnterLeaveEventPlugin = { var from; var to; - var fromID = ''; - var toID = ''; if (topLevelType === topLevelTypes.topMouseOut) { - from = topLevelTarget; - fromID = topLevelTargetID; - to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement); - if (to) { - toID = ReactMount.getID(to); - } else { - to = win; - } - to = to || win; + from = targetInst; + var related = nativeEvent.relatedTarget || nativeEvent.toElement; + to = related ? ReactDOMComponentTree.getClosestInstanceFromNode(related) : null; } else { - from = win; - to = topLevelTarget; - toID = topLevelTargetID; + // Moving to a node from outside the window. + from = null; + to = targetInst; } if (from === to) { @@ -2172,30 +2270,30 @@ var EnterLeaveEventPlugin = { return null; } - var leave = SyntheticMouseEvent.getPooled(eventTypes.mouseLeave, fromID, nativeEvent, nativeEventTarget); + var fromNode = from == null ? win : ReactDOMComponentTree.getNodeFromInstance(from); + var toNode = to == null ? win : ReactDOMComponentTree.getNodeFromInstance(to); + + var leave = SyntheticMouseEvent.getPooled(eventTypes.mouseLeave, from, nativeEvent, nativeEventTarget); leave.type = 'mouseleave'; - leave.target = from; - leave.relatedTarget = to; + leave.target = fromNode; + leave.relatedTarget = toNode; - var enter = SyntheticMouseEvent.getPooled(eventTypes.mouseEnter, toID, nativeEvent, nativeEventTarget); + var enter = SyntheticMouseEvent.getPooled(eventTypes.mouseEnter, to, nativeEvent, nativeEventTarget); enter.type = 'mouseenter'; - enter.target = to; - enter.relatedTarget = from; + enter.target = toNode; + enter.relatedTarget = fromNode; - EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); + EventPropagators.accumulateEnterLeaveDispatches(leave, enter, from, to); - extractedEvents[0] = leave; - extractedEvents[1] = enter; - - return extractedEvents; + return [leave, enter]; } }; module.exports = EnterLeaveEventPlugin; -},{"./EventConstants":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventConstants.js","./EventPropagators":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPropagators.js","./ReactMount":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactMount.js","./SyntheticMouseEvent":"/Users/yuanyan/React/halogen/node_modules/react/lib/SyntheticMouseEvent.js","fbjs/lib/keyOf":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/keyOf.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/EventConstants.js":[function(require,module,exports){ +},{"./EventConstants":16,"./EventPropagators":20,"./ReactDOMComponentTree":39,"./SyntheticMouseEvent":101,"fbjs/lib/keyOf":156}],16:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -2216,6 +2314,9 @@ var PropagationPhases = keyMirror({ bubbled: null, captured: null }); */ var topLevelTypes = keyMirror({ topAbort: null, + topAnimationEnd: null, + topAnimationIteration: null, + topAnimationStart: null, topBlur: null, topCanPlay: null, topCanPlayThrough: null, @@ -2243,6 +2344,7 @@ var topLevelTypes = keyMirror({ topError: null, topFocus: null, topInput: null, + topInvalid: null, topKeyDown: null, topKeyPress: null, topKeyUp: null, @@ -2275,6 +2377,7 @@ var topLevelTypes = keyMirror({ topTouchEnd: null, topTouchMove: null, topTouchStart: null, + topTransitionEnd: null, topVolumeChange: null, topWaiting: null, topWheel: null @@ -2286,10 +2389,10 @@ var EventConstants = { }; module.exports = EventConstants; -},{"fbjs/lib/keyMirror":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/keyMirror.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginHub.js":[function(require,module,exports){ +},{"fbjs/lib/keyMirror":155}],17:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -2308,7 +2411,6 @@ var ReactErrorUtils = require('./ReactErrorUtils'); var accumulateInto = require('./accumulateInto'); var forEachAccumulated = require('./forEachAccumulated'); var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); /** * Internal store for event listeners @@ -2344,17 +2446,6 @@ var executeDispatchesAndReleaseTopLevel = function (e) { return executeDispatchesAndRelease(e, false); }; -/** - * - `InstanceHandle`: [required] Module that performs logical traversals of DOM - * hierarchy given ids of the logical DOM elements involved. - */ -var InstanceHandle = null; - -function validateInstanceHandle() { - var valid = InstanceHandle && InstanceHandle.traverseTwoPhase && InstanceHandle.traverseEnterLeave; - process.env.NODE_ENV !== 'production' ? warning(valid, 'InstanceHandle not injected before use!') : undefined; -} - /** * This is a unified interface for event plugins to be installed and configured. * @@ -2384,30 +2475,6 @@ var EventPluginHub = { */ injection: { - /** - * @param {object} InjectedMount - * @public - */ - injectMount: EventPluginUtils.injection.injectMount, - - /** - * @param {object} InjectedInstanceHandle - * @public - */ - injectInstanceHandle: function (InjectedInstanceHandle) { - InstanceHandle = InjectedInstanceHandle; - if (process.env.NODE_ENV !== 'production') { - validateInstanceHandle(); - } - }, - - getInstanceHandle: function () { - if (process.env.NODE_ENV !== 'production') { - validateInstanceHandle(); - } - return InstanceHandle; - }, - /** * @param {array} InjectedEventPluginOrder * @public @@ -2421,75 +2488,71 @@ var EventPluginHub = { }, - eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs, - - registrationNameModules: EventPluginRegistry.registrationNameModules, - /** * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. * - * @param {string} id ID of the DOM element. + * @param {object} inst The instance, which is the source of events. * @param {string} registrationName Name of listener (e.g. `onClick`). - * @param {?function} listener The callback to store. + * @param {function} listener The callback to store. */ - putListener: function (id, registrationName, listener) { - !(typeof listener === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected %s listener to be a function, instead got type %s', registrationName, typeof listener) : invariant(false) : undefined; + putListener: function (inst, registrationName, listener) { + !(typeof listener === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected %s listener to be a function, instead got type %s', registrationName, typeof listener) : invariant(false) : void 0; var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {}); - bankForRegistrationName[id] = listener; + bankForRegistrationName[inst._rootNodeID] = listener; var PluginModule = EventPluginRegistry.registrationNameModules[registrationName]; if (PluginModule && PluginModule.didPutListener) { - PluginModule.didPutListener(id, registrationName, listener); + PluginModule.didPutListener(inst, registrationName, listener); } }, /** - * @param {string} id ID of the DOM element. + * @param {object} inst The instance, which is the source of events. * @param {string} registrationName Name of listener (e.g. `onClick`). * @return {?function} The stored callback. */ - getListener: function (id, registrationName) { + getListener: function (inst, registrationName) { var bankForRegistrationName = listenerBank[registrationName]; - return bankForRegistrationName && bankForRegistrationName[id]; + return bankForRegistrationName && bankForRegistrationName[inst._rootNodeID]; }, /** * Deletes a listener from the registration bank. * - * @param {string} id ID of the DOM element. + * @param {object} inst The instance, which is the source of events. * @param {string} registrationName Name of listener (e.g. `onClick`). */ - deleteListener: function (id, registrationName) { + deleteListener: function (inst, registrationName) { var PluginModule = EventPluginRegistry.registrationNameModules[registrationName]; if (PluginModule && PluginModule.willDeleteListener) { - PluginModule.willDeleteListener(id, registrationName); + PluginModule.willDeleteListener(inst, registrationName); } var bankForRegistrationName = listenerBank[registrationName]; // TODO: This should never be null -- when is it? if (bankForRegistrationName) { - delete bankForRegistrationName[id]; + delete bankForRegistrationName[inst._rootNodeID]; } }, /** * Deletes all listeners for the DOM element with the supplied ID. * - * @param {string} id ID of the DOM element. + * @param {object} inst The instance, which is the source of events. */ - deleteAllListeners: function (id) { + deleteAllListeners: function (inst) { for (var registrationName in listenerBank) { - if (!listenerBank[registrationName][id]) { + if (!listenerBank[registrationName][inst._rootNodeID]) { continue; } var PluginModule = EventPluginRegistry.registrationNameModules[registrationName]; if (PluginModule && PluginModule.willDeleteListener) { - PluginModule.willDeleteListener(id, registrationName); + PluginModule.willDeleteListener(inst, registrationName); } - delete listenerBank[registrationName][id]; + delete listenerBank[registrationName][inst._rootNodeID]; } }, @@ -2497,21 +2560,17 @@ var EventPluginHub = { * Allows registered plugins an opportunity to extract events from top-level * native browser events. * - * @param {string} topLevelType Record from `EventConstants`. - * @param {DOMEventTarget} topLevelTarget The listening component root node. - * @param {string} topLevelTargetID ID of `topLevelTarget`. - * @param {object} nativeEvent Native browser event. * @return {*} An accumulation of synthetic events. * @internal */ - extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) { + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { var events; var plugins = EventPluginRegistry.plugins; for (var i = 0; i < plugins.length; i++) { // Not every plugin in the ordering may be loaded at runtime. var possiblePlugin = plugins[i]; if (possiblePlugin) { - var extractedEvents = possiblePlugin.extractEvents(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget); + var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); if (extractedEvents) { events = accumulateInto(events, extractedEvents); } @@ -2548,7 +2607,7 @@ var EventPluginHub = { } else { forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); } - !!eventQueue ? process.env.NODE_ENV !== 'production' ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing ' + 'an event queue. Support for this has not yet been implemented.') : invariant(false) : undefined; + !!eventQueue ? process.env.NODE_ENV !== 'production' ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing ' + 'an event queue. Support for this has not yet been implemented.') : invariant(false) : void 0; // This would be a good time to rethrow if any of the event handlers threw. ReactErrorUtils.rethrowCaughtError(); }, @@ -2568,11 +2627,10 @@ var EventPluginHub = { module.exports = EventPluginHub; }).call(this,require('_process')) - -},{"./EventPluginRegistry":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginRegistry.js","./EventPluginUtils":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginUtils.js","./ReactErrorUtils":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactErrorUtils.js","./accumulateInto":"/Users/yuanyan/React/halogen/node_modules/react/lib/accumulateInto.js","./forEachAccumulated":"/Users/yuanyan/React/halogen/node_modules/react/lib/forEachAccumulated.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js","fbjs/lib/warning":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/warning.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginRegistry.js":[function(require,module,exports){ +},{"./EventPluginRegistry":18,"./EventPluginUtils":19,"./ReactErrorUtils":63,"./accumulateInto":108,"./forEachAccumulated":116,"_process":1,"fbjs/lib/invariant":152}],18:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -2580,7 +2638,6 @@ module.exports = EventPluginHub; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule EventPluginRegistry - * @typechecks static-only */ 'use strict'; @@ -2610,15 +2667,15 @@ function recomputePluginOrdering() { for (var pluginName in namesToPlugins) { var PluginModule = namesToPlugins[pluginName]; var pluginIndex = EventPluginOrder.indexOf(pluginName); - !(pluginIndex > -1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + 'the plugin ordering, `%s`.', pluginName) : invariant(false) : undefined; + !(pluginIndex > -1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + 'the plugin ordering, `%s`.', pluginName) : invariant(false) : void 0; if (EventPluginRegistry.plugins[pluginIndex]) { continue; } - !PluginModule.extractEvents ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + 'method, but `%s` does not.', pluginName) : invariant(false) : undefined; + !PluginModule.extractEvents ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + 'method, but `%s` does not.', pluginName) : invariant(false) : void 0; EventPluginRegistry.plugins[pluginIndex] = PluginModule; var publishedEvents = PluginModule.eventTypes; for (var eventName in publishedEvents) { - !publishEventForPlugin(publishedEvents[eventName], PluginModule, eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : invariant(false) : undefined; + !publishEventForPlugin(publishedEvents[eventName], PluginModule, eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : invariant(false) : void 0; } } } @@ -2632,7 +2689,7 @@ function recomputePluginOrdering() { * @private */ function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { - !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same ' + 'event name, `%s`.', eventName) : invariant(false) : undefined; + !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same ' + 'event name, `%s`.', eventName) : invariant(false) : void 0; EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig; var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; @@ -2660,9 +2717,14 @@ function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { * @private */ function publishRegistrationName(registrationName, PluginModule, eventName) { - !!EventPluginRegistry.registrationNameModules[registrationName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', registrationName) : invariant(false) : undefined; + !!EventPluginRegistry.registrationNameModules[registrationName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', registrationName) : invariant(false) : void 0; EventPluginRegistry.registrationNameModules[registrationName] = PluginModule; EventPluginRegistry.registrationNameDependencies[registrationName] = PluginModule.eventTypes[eventName].dependencies; + + if (process.env.NODE_ENV !== 'production') { + var lowerCasedName = registrationName.toLowerCase(); + EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName; + } } /** @@ -2692,6 +2754,14 @@ var EventPluginRegistry = { */ registrationNameDependencies: {}, + /** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in __DEV__. + * @type {Object} + */ + possibleRegistrationNames: process.env.NODE_ENV !== 'production' ? {} : null, + /** * Injects an ordering of plugins (by plugin name). This allows the ordering * to be decoupled from injection of the actual plugins so that ordering is @@ -2702,7 +2772,7 @@ var EventPluginRegistry = { * @see {EventPluginHub.injection.injectEventPluginOrder} */ injectEventPluginOrder: function (InjectedEventPluginOrder) { - !!EventPluginOrder ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than ' + 'once. You are likely trying to load more than one copy of React.') : invariant(false) : undefined; + !!EventPluginOrder ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than ' + 'once. You are likely trying to load more than one copy of React.') : invariant(false) : void 0; // Clone the ordering so it cannot be dynamically mutated. EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder); recomputePluginOrdering(); @@ -2726,7 +2796,7 @@ var EventPluginRegistry = { } var PluginModule = injectedNamesToPlugins[pluginName]; if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== PluginModule) { - !!namesToPlugins[pluginName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins ' + 'using the same name, `%s`.', pluginName) : invariant(false) : undefined; + !!namesToPlugins[pluginName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins ' + 'using the same name, `%s`.', pluginName) : invariant(false) : void 0; namesToPlugins[pluginName] = PluginModule; isOrderingDirty = true; } @@ -2786,17 +2856,25 @@ var EventPluginRegistry = { delete registrationNameModules[registrationName]; } } + + if (process.env.NODE_ENV !== 'production') { + var possibleRegistrationNames = EventPluginRegistry.possibleRegistrationNames; + for (var lowerCasedName in possibleRegistrationNames) { + if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) { + delete possibleRegistrationNames[lowerCasedName]; + } + } + } } }; module.exports = EventPluginRegistry; }).call(this,require('_process')) - -},{"_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginUtils.js":[function(require,module,exports){ +},{"_process":1,"fbjs/lib/invariant":152}],19:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -2819,15 +2897,22 @@ var warning = require('fbjs/lib/warning'); */ /** - * - `Mount`: [required] Module that can convert between React dom IDs and - * actual node references. + * - `ComponentTree`: [required] Module that can convert between React instances + * and actual node references. */ +var ComponentTree; +var TreeTraversal; var injection = { - Mount: null, - injectMount: function (InjectedMount) { - injection.Mount = InjectedMount; + injectComponentTree: function (Injected) { + ComponentTree = Injected; if (process.env.NODE_ENV !== 'production') { - process.env.NODE_ENV !== 'production' ? warning(InjectedMount && InjectedMount.getNode && InjectedMount.getID, 'EventPluginUtils.injection.injectMount(...): Injected Mount ' + 'module is missing getNode or getID.') : undefined; + process.env.NODE_ENV !== 'production' ? warning(Injected && Injected.getNodeFromInstance && Injected.getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.') : void 0; + } + }, + injectTreeTraversal: function (Injected) { + TreeTraversal = Injected; + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning(Injected && Injected.isAncestor && Injected.getLowestCommonAncestor, 'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' + 'module is missing isAncestor or getLowestCommonAncestor.') : void 0; } } }; @@ -2849,14 +2934,15 @@ var validateEventDispatches; if (process.env.NODE_ENV !== 'production') { validateEventDispatches = function (event) { var dispatchListeners = event._dispatchListeners; - var dispatchIDs = event._dispatchIDs; + var dispatchInstances = event._dispatchInstances; var listenersIsArr = Array.isArray(dispatchListeners); - var idsIsArr = Array.isArray(dispatchIDs); - var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; - process.env.NODE_ENV !== 'production' ? warning(idsIsArr === listenersIsArr && IDsLen === listenersLen, 'EventPluginUtils: Invalid `event`.') : undefined; + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; + + process.env.NODE_ENV !== 'production' ? warning(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.') : void 0; }; } @@ -2865,15 +2951,15 @@ if (process.env.NODE_ENV !== 'production') { * @param {SyntheticEvent} event SyntheticEvent to handle * @param {boolean} simulated If the event is simulated (changes exn behavior) * @param {function} listener Application-level callback - * @param {string} domID DOM id to pass to the callback. + * @param {*} inst Internal component instance */ -function executeDispatch(event, simulated, listener, domID) { +function executeDispatch(event, simulated, listener, inst) { var type = event.type || 'unknown-event'; - event.currentTarget = injection.Mount.getNode(domID); + event.currentTarget = EventPluginUtils.getNodeFromInstance(inst); if (simulated) { - ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event, domID); + ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event); } else { - ReactErrorUtils.invokeGuardedCallback(type, listener, event, domID); + ReactErrorUtils.invokeGuardedCallback(type, listener, event); } event.currentTarget = null; } @@ -2883,7 +2969,7 @@ function executeDispatch(event, simulated, listener, domID) { */ function executeDispatchesInOrder(event, simulated) { var dispatchListeners = event._dispatchListeners; - var dispatchIDs = event._dispatchIDs; + var dispatchInstances = event._dispatchInstances; if (process.env.NODE_ENV !== 'production') { validateEventDispatches(event); } @@ -2892,14 +2978,14 @@ function executeDispatchesInOrder(event, simulated) { if (event.isPropagationStopped()) { break; } - // Listeners and IDs are two parallel arrays that are always in sync. - executeDispatch(event, simulated, dispatchListeners[i], dispatchIDs[i]); + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); } } else if (dispatchListeners) { - executeDispatch(event, simulated, dispatchListeners, dispatchIDs); + executeDispatch(event, simulated, dispatchListeners, dispatchInstances); } event._dispatchListeners = null; - event._dispatchIDs = null; + event._dispatchInstances = null; } /** @@ -2911,7 +2997,7 @@ function executeDispatchesInOrder(event, simulated) { */ function executeDispatchesInOrderStopAtTrueImpl(event) { var dispatchListeners = event._dispatchListeners; - var dispatchIDs = event._dispatchIDs; + var dispatchInstances = event._dispatchInstances; if (process.env.NODE_ENV !== 'production') { validateEventDispatches(event); } @@ -2920,14 +3006,14 @@ function executeDispatchesInOrderStopAtTrueImpl(event) { if (event.isPropagationStopped()) { break; } - // Listeners and IDs are two parallel arrays that are always in sync. - if (dispatchListeners[i](event, dispatchIDs[i])) { - return dispatchIDs[i]; + // Listeners and Instances are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; } } } else if (dispatchListeners) { - if (dispatchListeners(event, dispatchIDs)) { - return dispatchIDs; + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; } } return null; @@ -2938,7 +3024,7 @@ function executeDispatchesInOrderStopAtTrueImpl(event) { */ function executeDispatchesInOrderStopAtTrue(event) { var ret = executeDispatchesInOrderStopAtTrueImpl(event); - event._dispatchIDs = null; + event._dispatchInstances = null; event._dispatchListeners = null; return ret; } @@ -2957,11 +3043,13 @@ function executeDirectDispatch(event) { validateEventDispatches(event); } var dispatchListener = event._dispatchListeners; - var dispatchID = event._dispatchIDs; - !!Array.isArray(dispatchListener) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : invariant(false) : undefined; - var res = dispatchListener ? dispatchListener(event, dispatchID) : null; + var dispatchInstance = event._dispatchInstances; + !!Array.isArray(dispatchListener) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : invariant(false) : void 0; + event.currentTarget = EventPluginUtils.getNodeFromInstance(dispatchInstance); + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; event._dispatchListeners = null; - event._dispatchIDs = null; + event._dispatchInstances = null; return res; } @@ -2986,11 +3074,26 @@ var EventPluginUtils = { executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, hasDispatches: hasDispatches, - getNode: function (id) { - return injection.Mount.getNode(id); + getInstanceFromNode: function (node) { + return ComponentTree.getInstanceFromNode(node); + }, + getNodeFromInstance: function (node) { + return ComponentTree.getNodeFromInstance(node); + }, + isAncestor: function (a, b) { + return TreeTraversal.isAncestor(a, b); + }, + getLowestCommonAncestor: function (a, b) { + return TreeTraversal.getLowestCommonAncestor(a, b); }, - getID: function (node) { - return injection.Mount.getID(node); + getParentInstance: function (inst) { + return TreeTraversal.getParentInstance(inst); + }, + traverseTwoPhase: function (target, fn, arg) { + return TreeTraversal.traverseTwoPhase(target, fn, arg); + }, + traverseEnterLeave: function (from, to, fn, argFrom, argTo) { + return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo); }, injection: injection @@ -2998,11 +3101,10 @@ var EventPluginUtils = { module.exports = EventPluginUtils; }).call(this,require('_process')) - -},{"./EventConstants":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventConstants.js","./ReactErrorUtils":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactErrorUtils.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js","fbjs/lib/warning":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/warning.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPropagators.js":[function(require,module,exports){ +},{"./EventConstants":16,"./ReactErrorUtils":63,"_process":1,"fbjs/lib/invariant":152,"fbjs/lib/warning":162}],20:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -3016,11 +3118,11 @@ module.exports = EventPluginUtils; var EventConstants = require('./EventConstants'); var EventPluginHub = require('./EventPluginHub'); - -var warning = require('fbjs/lib/warning'); +var EventPluginUtils = require('./EventPluginUtils'); var accumulateInto = require('./accumulateInto'); var forEachAccumulated = require('./forEachAccumulated'); +var warning = require('fbjs/lib/warning'); var PropagationPhases = EventConstants.PropagationPhases; var getListener = EventPluginHub.getListener; @@ -3029,9 +3131,9 @@ var getListener = EventPluginHub.getListener; * Some event types have a notion of different registration names for different * "phases" of propagation. This finds listeners by a given phase. */ -function listenerAtPhase(id, event, propagationPhase) { +function listenerAtPhase(inst, event, propagationPhase) { var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener(id, registrationName); + return getListener(inst, registrationName); } /** @@ -3040,15 +3142,15 @@ function listenerAtPhase(id, event, propagationPhase) { * Mutating the event's members allows us to not have to create a wrapping * "dispatch" object that pairs the event with the listener. */ -function accumulateDirectionalDispatches(domID, upwards, event) { +function accumulateDirectionalDispatches(inst, upwards, event) { if (process.env.NODE_ENV !== 'production') { - process.env.NODE_ENV !== 'production' ? warning(domID, 'Dispatching id must not be null') : undefined; + process.env.NODE_ENV !== 'production' ? warning(inst, 'Dispatching inst must not be null') : void 0; } var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; - var listener = listenerAtPhase(domID, event, phase); + var listener = listenerAtPhase(inst, event, phase); if (listener) { event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); - event._dispatchIDs = accumulateInto(event._dispatchIDs, domID); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); } } @@ -3061,7 +3163,7 @@ function accumulateDirectionalDispatches(domID, upwards, event) { */ function accumulateTwoPhaseDispatchesSingle(event) { if (event && event.dispatchConfig.phasedRegistrationNames) { - EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(event.dispatchMarker, accumulateDirectionalDispatches, event); + EventPluginUtils.traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); } } @@ -3070,7 +3172,9 @@ function accumulateTwoPhaseDispatchesSingle(event) { */ function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { if (event && event.dispatchConfig.phasedRegistrationNames) { - EventPluginHub.injection.getInstanceHandle().traverseTwoPhaseSkipTarget(event.dispatchMarker, accumulateDirectionalDispatches, event); + var targetInst = event._targetInst; + var parentInst = targetInst ? EventPluginUtils.getParentInstance(targetInst) : null; + EventPluginUtils.traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); } } @@ -3079,13 +3183,13 @@ function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { * registration names. Same as `accumulateDirectDispatchesSingle` but without * requiring that the `dispatchMarker` be the same as the dispatched ID. */ -function accumulateDispatches(id, ignoredDirection, event) { +function accumulateDispatches(inst, ignoredDirection, event) { if (event && event.dispatchConfig.registrationName) { var registrationName = event.dispatchConfig.registrationName; - var listener = getListener(id, registrationName); + var listener = getListener(inst, registrationName); if (listener) { event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); - event._dispatchIDs = accumulateInto(event._dispatchIDs, id); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); } } } @@ -3097,7 +3201,7 @@ function accumulateDispatches(id, ignoredDirection, event) { */ function accumulateDirectDispatchesSingle(event) { if (event && event.dispatchConfig.registrationName) { - accumulateDispatches(event.dispatchMarker, null, event); + accumulateDispatches(event._targetInst, null, event); } } @@ -3109,8 +3213,8 @@ function accumulateTwoPhaseDispatchesSkipTarget(events) { forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); } -function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { - EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(fromID, toID, accumulateDispatches, leave, enter); +function accumulateEnterLeaveDispatches(leave, enter, from, to) { + EventPluginUtils.traverseEnterLeave(from, to, accumulateDispatches, leave, enter); } function accumulateDirectDispatches(events) { @@ -3137,10 +3241,9 @@ var EventPropagators = { module.exports = EventPropagators; }).call(this,require('_process')) - -},{"./EventConstants":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventConstants.js","./EventPluginHub":"/Users/yuanyan/React/halogen/node_modules/react/lib/EventPluginHub.js","./accumulateInto":"/Users/yuanyan/React/halogen/node_modules/react/lib/accumulateInto.js","./forEachAccumulated":"/Users/yuanyan/React/halogen/node_modules/react/lib/forEachAccumulated.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/warning":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/warning.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/FallbackCompositionState.js":[function(require,module,exports){ +},{"./EventConstants":16,"./EventPluginHub":17,"./EventPluginUtils":19,"./accumulateInto":108,"./forEachAccumulated":116,"_process":1,"fbjs/lib/warning":162}],21:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -3148,14 +3251,14 @@ module.exports = EventPropagators; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule FallbackCompositionState - * @typechecks static-only */ 'use strict'; +var _assign = require('object-assign'); + var PooledClass = require('./PooledClass'); -var assign = require('./Object.assign'); var getTextContentAccessor = require('./getTextContentAccessor'); /** @@ -3175,7 +3278,7 @@ function FallbackCompositionState(root) { this._fallbackText = null; } -assign(FallbackCompositionState.prototype, { +_assign(FallbackCompositionState.prototype, { destructor: function () { this._root = null; this._startText = null; @@ -3234,9 +3337,9 @@ assign(FallbackCompositionState.prototype, { PooledClass.addPoolingTo(FallbackCompositionState); module.exports = FallbackCompositionState; -},{"./Object.assign":"/Users/yuanyan/React/halogen/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/yuanyan/React/halogen/node_modules/react/lib/PooledClass.js","./getTextContentAccessor":"/Users/yuanyan/React/halogen/node_modules/react/lib/getTextContentAccessor.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/HTMLDOMPropertyConfig.js":[function(require,module,exports){ +},{"./PooledClass":24,"./getTextContentAccessor":124,"object-assign":163}],22:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -3249,9 +3352,7 @@ module.exports = FallbackCompositionState; 'use strict'; var DOMProperty = require('./DOMProperty'); -var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); -var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE; var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY; var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE; var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS; @@ -3259,188 +3360,182 @@ var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE; var HAS_POSITIVE_NUMERIC_VALUE = DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE; var HAS_OVERLOADED_BOOLEAN_VALUE = DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE; -var hasSVG; -if (ExecutionEnvironment.canUseDOM) { - var implementation = document.implementation; - hasSVG = implementation && implementation.hasFeature && implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1'); -} - var HTMLDOMPropertyConfig = { - isCustomAttribute: RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/), + isCustomAttribute: RegExp.prototype.test.bind(new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')), Properties: { /** * Standard Properties */ - accept: null, - acceptCharset: null, - accessKey: null, - action: null, - allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, - allowTransparency: MUST_USE_ATTRIBUTE, - alt: null, + accept: 0, + acceptCharset: 0, + accessKey: 0, + action: 0, + allowFullScreen: HAS_BOOLEAN_VALUE, + allowTransparency: 0, + alt: 0, async: HAS_BOOLEAN_VALUE, - autoComplete: null, + autoComplete: 0, // autoFocus is polyfilled/normalized by AutoFocusUtils // autoFocus: HAS_BOOLEAN_VALUE, autoPlay: HAS_BOOLEAN_VALUE, - capture: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, - cellPadding: null, - cellSpacing: null, - charSet: MUST_USE_ATTRIBUTE, - challenge: MUST_USE_ATTRIBUTE, + capture: HAS_BOOLEAN_VALUE, + cellPadding: 0, + cellSpacing: 0, + charSet: 0, + challenge: 0, checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - classID: MUST_USE_ATTRIBUTE, - // To set className on SVG elements, it's necessary to use .setAttribute; - // this works on HTML elements too in all browsers except IE8. Conveniently, - // IE8 doesn't support SVG and so we can simply use the attribute in - // browsers that support SVG and the property in browsers that don't, - // regardless of whether the element is HTML or SVG. - className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY, - cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, - colSpan: null, - content: null, - contentEditable: null, - contextMenu: MUST_USE_ATTRIBUTE, - controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - coords: null, - crossOrigin: null, - data: null, // For `` acts as `src`. - dateTime: MUST_USE_ATTRIBUTE, + cite: 0, + classID: 0, + className: 0, + cols: HAS_POSITIVE_NUMERIC_VALUE, + colSpan: 0, + content: 0, + contentEditable: 0, + contextMenu: 0, + controls: HAS_BOOLEAN_VALUE, + coords: 0, + crossOrigin: 0, + data: 0, // For `` acts as `src`. + dateTime: 0, 'default': HAS_BOOLEAN_VALUE, defer: HAS_BOOLEAN_VALUE, - dir: null, - disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + dir: 0, + disabled: HAS_BOOLEAN_VALUE, download: HAS_OVERLOADED_BOOLEAN_VALUE, - draggable: null, - encType: null, - form: MUST_USE_ATTRIBUTE, - formAction: MUST_USE_ATTRIBUTE, - formEncType: MUST_USE_ATTRIBUTE, - formMethod: MUST_USE_ATTRIBUTE, + draggable: 0, + encType: 0, + form: 0, + formAction: 0, + formEncType: 0, + formMethod: 0, formNoValidate: HAS_BOOLEAN_VALUE, - formTarget: MUST_USE_ATTRIBUTE, - frameBorder: MUST_USE_ATTRIBUTE, - headers: null, - height: MUST_USE_ATTRIBUTE, - hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, - high: null, - href: null, - hrefLang: null, - htmlFor: null, - httpEquiv: null, - icon: null, - id: MUST_USE_PROPERTY, - inputMode: MUST_USE_ATTRIBUTE, - integrity: null, - is: MUST_USE_ATTRIBUTE, - keyParams: MUST_USE_ATTRIBUTE, - keyType: MUST_USE_ATTRIBUTE, - kind: null, - label: null, - lang: null, - list: MUST_USE_ATTRIBUTE, - loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - low: null, - manifest: MUST_USE_ATTRIBUTE, - marginHeight: null, - marginWidth: null, - max: null, - maxLength: MUST_USE_ATTRIBUTE, - media: MUST_USE_ATTRIBUTE, - mediaGroup: null, - method: null, - min: null, - minLength: MUST_USE_ATTRIBUTE, + formTarget: 0, + frameBorder: 0, + headers: 0, + height: 0, + hidden: HAS_BOOLEAN_VALUE, + high: 0, + href: 0, + hrefLang: 0, + htmlFor: 0, + httpEquiv: 0, + icon: 0, + id: 0, + inputMode: 0, + integrity: 0, + is: 0, + keyParams: 0, + keyType: 0, + kind: 0, + label: 0, + lang: 0, + list: 0, + loop: HAS_BOOLEAN_VALUE, + low: 0, + manifest: 0, + marginHeight: 0, + marginWidth: 0, + max: 0, + maxLength: 0, + media: 0, + mediaGroup: 0, + method: 0, + min: 0, + minLength: 0, + // Caution; `option.selected` is not updated if `select.multiple` is + // disabled with `removeAttribute`. multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - name: null, - nonce: MUST_USE_ATTRIBUTE, + name: 0, + nonce: 0, noValidate: HAS_BOOLEAN_VALUE, open: HAS_BOOLEAN_VALUE, - optimum: null, - pattern: null, - placeholder: null, - poster: null, - preload: null, - radioGroup: null, - readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - rel: null, + optimum: 0, + pattern: 0, + placeholder: 0, + poster: 0, + preload: 0, + profile: 0, + radioGroup: 0, + readOnly: HAS_BOOLEAN_VALUE, + rel: 0, required: HAS_BOOLEAN_VALUE, reversed: HAS_BOOLEAN_VALUE, - role: MUST_USE_ATTRIBUTE, - rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, - rowSpan: null, - sandbox: null, - scope: null, + role: 0, + rows: HAS_POSITIVE_NUMERIC_VALUE, + rowSpan: HAS_NUMERIC_VALUE, + sandbox: 0, + scope: 0, scoped: HAS_BOOLEAN_VALUE, - scrolling: null, - seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + scrolling: 0, + seamless: HAS_BOOLEAN_VALUE, selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - shape: null, - size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, - sizes: MUST_USE_ATTRIBUTE, + shape: 0, + size: HAS_POSITIVE_NUMERIC_VALUE, + sizes: 0, span: HAS_POSITIVE_NUMERIC_VALUE, - spellCheck: null, - src: null, - srcDoc: MUST_USE_PROPERTY, - srcLang: null, - srcSet: MUST_USE_ATTRIBUTE, + spellCheck: 0, + src: 0, + srcDoc: 0, + srcLang: 0, + srcSet: 0, start: HAS_NUMERIC_VALUE, - step: null, - style: null, - summary: null, - tabIndex: null, - target: null, - title: null, - type: null, - useMap: null, + step: 0, + style: 0, + summary: 0, + tabIndex: 0, + target: 0, + title: 0, + // Setting .type throws on non-') : undefined; + 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: ' + '') : void 0; 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]; + 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]; 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'); + process.env.NODE_ENV !== 'production' ? warning(false, 'One or more ES5 shims expected by React are not available: ' + 'https://fb.me/react-warning-polyfills') : void 0; break; } } @@ -6311,10 +6401,9 @@ if (process.env.NODE_ENV !== 'production') { module.exports = React; }).call(this,require('_process')) - -},{"./ReactCurrentOwner":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactCurrentOwner.js","./ReactDOMTextComponent":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactDOMTextComponent.js","./ReactDefaultInjection":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactDefaultInjection.js","./ReactInstanceHandles":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactInstanceHandles.js","./ReactMount":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactMount.js","./ReactPerf":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactPerf.js","./ReactReconciler":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactReconciler.js","./ReactUpdates":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactUpdates.js","./ReactVersion":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactVersion.js","./findDOMNode":"/Users/yuanyan/React/halogen/node_modules/react/lib/findDOMNode.js","./renderSubtreeIntoContainer":"/Users/yuanyan/React/halogen/node_modules/react/lib/renderSubtreeIntoContainer.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/ExecutionEnvironment":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/ExecutionEnvironment.js","fbjs/lib/warning":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/warning.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactDOMButton.js":[function(require,module,exports){ +},{"./ReactDOMComponentTree":39,"./ReactDefaultInjection":57,"./ReactMount":73,"./ReactPerf":80,"./ReactReconciler":85,"./ReactUpdates":88,"./ReactVersion":89,"./findDOMNode":114,"./getNativeComponentFromComposite":122,"./renderSubtreeIntoContainer":131,"_process":1,"fbjs/lib/ExecutionEnvironment":138,"fbjs/lib/warning":162}],36:[function(require,module,exports){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -6345,7 +6434,7 @@ var mouseListenerNames = { * when `disabled` is set. */ var ReactDOMButton = { - getNativeProps: function (inst, props, context) { + getNativeProps: function (inst, props) { if (!props.disabled) { return props; } @@ -6363,10 +6452,10 @@ var ReactDOMButton = { }; module.exports = ReactDOMButton; -},{}],"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactDOMComponent.js":[function(require,module,exports){ +},{}],37:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -6374,54 +6463,59 @@ module.exports = ReactDOMButton; * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ReactDOMComponent - * @typechecks static-only */ /* global hasOwnProperty:true */ 'use strict'; +var _assign = require('object-assign'); + var AutoFocusUtils = require('./AutoFocusUtils'); var CSSPropertyOperations = require('./CSSPropertyOperations'); +var DOMLazyTree = require('./DOMLazyTree'); +var DOMNamespaces = require('./DOMNamespaces'); var DOMProperty = require('./DOMProperty'); var DOMPropertyOperations = require('./DOMPropertyOperations'); var EventConstants = require('./EventConstants'); +var EventPluginHub = require('./EventPluginHub'); +var EventPluginRegistry = require('./EventPluginRegistry'); var ReactBrowserEventEmitter = require('./ReactBrowserEventEmitter'); var ReactComponentBrowserEnvironment = require('./ReactComponentBrowserEnvironment'); var ReactDOMButton = require('./ReactDOMButton'); +var ReactDOMComponentFlags = require('./ReactDOMComponentFlags'); +var ReactDOMComponentTree = require('./ReactDOMComponentTree'); var ReactDOMInput = require('./ReactDOMInput'); var ReactDOMOption = require('./ReactDOMOption'); var ReactDOMSelect = require('./ReactDOMSelect'); var ReactDOMTextarea = require('./ReactDOMTextarea'); -var ReactMount = require('./ReactMount'); var ReactMultiChild = require('./ReactMultiChild'); var ReactPerf = require('./ReactPerf'); -var ReactUpdateQueue = require('./ReactUpdateQueue'); -var assign = require('./Object.assign'); -var canDefineProperty = require('./canDefineProperty'); var escapeTextContentForBrowser = require('./escapeTextContentForBrowser'); var invariant = require('fbjs/lib/invariant'); var isEventSupported = require('./isEventSupported'); var keyOf = require('fbjs/lib/keyOf'); -var setInnerHTML = require('./setInnerHTML'); -var setTextContent = require('./setTextContent'); var shallowEqual = require('fbjs/lib/shallowEqual'); var validateDOMNesting = require('./validateDOMNesting'); var warning = require('fbjs/lib/warning'); -var deleteListener = ReactBrowserEventEmitter.deleteListener; +var Flags = ReactDOMComponentFlags; +var deleteListener = EventPluginHub.deleteListener; +var getNode = ReactDOMComponentTree.getNodeFromInstance; var listenTo = ReactBrowserEventEmitter.listenTo; -var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules; +var registrationNameModules = EventPluginRegistry.registrationNameModules; // For quickly matching children type, to test if can be treated as content. var CONTENT_TYPES = { 'string': true, 'number': true }; -var CHILDREN = keyOf({ children: null }); var STYLE = keyOf({ style: null }); var HTML = keyOf({ __html: null }); - -var ELEMENT_NODE_TYPE = 1; +var RESERVED_PROPS = { + children: null, + dangerouslySetInnerHTML: null, + suppressContentEditableWarning: null +}; function getDeclarationErrorAddendum(internalInstance) { if (internalInstance) { @@ -6436,71 +6530,6 @@ function getDeclarationErrorAddendum(internalInstance) { return ''; } -var legacyPropsDescriptor; -if (process.env.NODE_ENV !== 'production') { - legacyPropsDescriptor = { - props: { - enumerable: false, - get: function () { - var component = this._reactInternalComponent; - process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .props of a DOM node; instead, ' + 'recreate the props as `render` did originally or read the DOM ' + 'properties/attributes directly from this node (e.g., ' + 'this.refs.box.className).%s', getDeclarationErrorAddendum(component)) : undefined; - return component._currentElement.props; - } - } - }; -} - -function legacyGetDOMNode() { - if (process.env.NODE_ENV !== 'production') { - var component = this._reactInternalComponent; - process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .getDOMNode() of a DOM node; ' + 'instead, use the node directly.%s', getDeclarationErrorAddendum(component)) : undefined; - } - return this; -} - -function legacyIsMounted() { - var component = this._reactInternalComponent; - if (process.env.NODE_ENV !== 'production') { - process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .isMounted() of a DOM node.%s', getDeclarationErrorAddendum(component)) : undefined; - } - return !!component; -} - -function legacySetStateEtc() { - if (process.env.NODE_ENV !== 'production') { - var component = this._reactInternalComponent; - process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .setState(), .replaceState(), or ' + '.forceUpdate() of a DOM node. This is a no-op.%s', getDeclarationErrorAddendum(component)) : undefined; - } -} - -function legacySetProps(partialProps, callback) { - var component = this._reactInternalComponent; - if (process.env.NODE_ENV !== 'production') { - process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .setProps() of a DOM node. ' + 'Instead, call ReactDOM.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined; - } - if (!component) { - return; - } - ReactUpdateQueue.enqueueSetPropsInternal(component, partialProps); - if (callback) { - ReactUpdateQueue.enqueueCallbackInternal(component, callback); - } -} - -function legacyReplaceProps(partialProps, callback) { - var component = this._reactInternalComponent; - if (process.env.NODE_ENV !== 'production') { - process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .replaceProps() of a DOM node. ' + 'Instead, call ReactDOM.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined; - } - if (!component) { - return; - } - ReactUpdateQueue.enqueueReplacePropsInternal(component, partialProps); - if (callback) { - ReactUpdateQueue.enqueueCallbackInternal(component, callback); - } -} - function friendlyStringify(obj) { if (typeof obj === 'object') { if (Array.isArray(obj)) { @@ -6520,7 +6549,7 @@ function friendlyStringify(obj) { } else if (typeof obj === 'function') { return '[function object]'; } - // Differs from JSON.stringify in that undefined becauses undefined and that + // Differs from JSON.stringify in that undefined because undefined and that // inf and nan don't become null return String(obj); } @@ -6550,7 +6579,7 @@ function checkAndWarnForMutatedStyle(style1, style2, component) { styleMutationWarning[hash] = true; - process.env.NODE_ENV !== 'production' ? warning(false, '`%s` was passed a style object that has previously been mutated. ' + 'Mutating `style` is deprecated. Consider cloning it beforehand. Check ' + 'the `render` %s. Previous style: %s. Mutated style: %s.', componentName, owner ? 'of `' + ownerName + '`' : 'using <' + componentName + '>', friendlyStringify(style1), friendlyStringify(style2)) : undefined; + process.env.NODE_ENV !== 'production' ? warning(false, '`%s` was passed a style object that has previously been mutated. ' + 'Mutating `style` is deprecated. Consider cloning it beforehand. Check ' + 'the `render` %s. Previous style: %s. Mutated style: %s.', componentName, owner ? 'of `' + ownerName + '`' : 'using <' + componentName + '>', friendlyStringify(style1), friendlyStringify(style2)) : void 0; } /** @@ -6562,35 +6591,36 @@ function assertValidProps(component, props) { return; } // Note the use of `==` which checks for null or undefined. - if (process.env.NODE_ENV !== 'production') { - if (voidElementTags[component._tag]) { - process.env.NODE_ENV !== 'production' ? warning(props.children == null && props.dangerouslySetInnerHTML == null, '%s is a void element tag and must not have `children` or ' + 'use `props.dangerouslySetInnerHTML`.%s', component._tag, component._currentElement._owner ? ' Check the render method of ' + component._currentElement._owner.getName() + '.' : '') : undefined; - } + if (voidElementTags[component._tag]) { + !(props.children == null && props.dangerouslySetInnerHTML == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s is a void element tag and must not have `children` or ' + 'use `props.dangerouslySetInnerHTML`.%s', component._tag, component._currentElement._owner ? ' Check the render method of ' + component._currentElement._owner.getName() + '.' : '') : invariant(false) : void 0; } if (props.dangerouslySetInnerHTML != null) { - !(props.children == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : invariant(false) : undefined; - !(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ? process.env.NODE_ENV !== 'production' ? invariant(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' + 'for more information.') : invariant(false) : undefined; + !(props.children == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : invariant(false) : void 0; + !(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ? process.env.NODE_ENV !== 'production' ? invariant(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' + 'for more information.') : invariant(false) : void 0; } if (process.env.NODE_ENV !== 'production') { - process.env.NODE_ENV !== 'production' ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : undefined; - process.env.NODE_ENV !== 'production' ? warning(!props.contentEditable || props.children == null, 'A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.') : undefined; + process.env.NODE_ENV !== 'production' ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : void 0; + process.env.NODE_ENV !== 'production' ? warning(props.suppressContentEditableWarning || !props.contentEditable || props.children == null, 'A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.') : void 0; + process.env.NODE_ENV !== 'production' ? warning(props.onFocusIn == null && props.onFocusOut == null, 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.') : void 0; } - !(props.style == null || typeof props.style === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'The `style` prop expects a mapping from style properties to values, ' + 'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' + 'using JSX.%s', getDeclarationErrorAddendum(component)) : invariant(false) : undefined; + !(props.style == null || typeof props.style === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'The `style` prop expects a mapping from style properties to values, ' + 'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' + 'using JSX.%s', getDeclarationErrorAddendum(component)) : invariant(false) : void 0; } -function enqueuePutListener(id, registrationName, listener, transaction) { +function enqueuePutListener(inst, registrationName, listener, transaction) { if (process.env.NODE_ENV !== 'production') { // IE8 has no API for event capturing and the `onScroll` event doesn't // bubble. - process.env.NODE_ENV !== 'production' ? warning(registrationName !== 'onScroll' || isEventSupported('scroll', true), 'This browser doesn\'t support the `onScroll` event') : undefined; + process.env.NODE_ENV !== 'production' ? warning(registrationName !== 'onScroll' || isEventSupported('scroll', true), 'This browser doesn\'t support the `onScroll` event') : void 0; } - var container = ReactMount.findReactContainerForID(id); - if (container) { - var doc = container.nodeType === ELEMENT_NODE_TYPE ? container.ownerDocument : container; - listenTo(registrationName, doc); + var containerInfo = inst._nativeContainerInfo; + var doc = containerInfo._ownerDocument; + if (!doc) { + // Server rendering. + return; } + listenTo(registrationName, doc); transaction.getReactMountReady().enqueue(putListener, { - id: id, + inst: inst, registrationName: registrationName, listener: listener }); @@ -6598,7 +6628,12 @@ function enqueuePutListener(id, registrationName, listener, transaction) { function putListener() { var listenerToPut = this; - ReactBrowserEventEmitter.putListener(listenerToPut.id, listenerToPut.registrationName, listenerToPut.listener); + EventPluginHub.putListener(listenerToPut.inst, listenerToPut.registrationName, listenerToPut.listener); +} + +function optionPostMount() { + var inst = this; + ReactDOMOption.postMountWrapper(inst); } // There are so many media events, it makes sense to just @@ -6633,19 +6668,20 @@ function trapBubbledEventsLocal() { var inst = this; // If a component renders to null or if another component fatals and causes // the state of the tree to be corrupted, `node` here can be null. - !inst._rootNodeID ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Must be mounted to trap events') : invariant(false) : undefined; - var node = ReactMount.getNode(inst._rootNodeID); - !node ? process.env.NODE_ENV !== 'production' ? invariant(false, 'trapBubbledEvent(...): Requires node to be rendered.') : invariant(false) : undefined; + !inst._rootNodeID ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Must be mounted to trap events') : invariant(false) : void 0; + var node = getNode(inst); + !node ? process.env.NODE_ENV !== 'production' ? invariant(false, 'trapBubbledEvent(...): Requires node to be rendered.') : invariant(false) : void 0; switch (inst._tag) { case 'iframe': + case 'object': inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load', node)]; break; case 'video': case 'audio': inst._wrapperState.listeners = []; - // create listener for each media event + // Create listener for each media event for (var event in mediaEvents) { if (mediaEvents.hasOwnProperty(event)) { inst._wrapperState.listeners.push(ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes[event], mediaEvents[event], node)); @@ -6659,19 +6695,20 @@ function trapBubbledEventsLocal() { case 'form': inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset', node), ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit', node)]; break; + case 'input': + case 'select': + case 'textarea': + inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topInvalid, 'invalid', node)]; + break; } } -function mountReadyInputWrapper() { - ReactDOMInput.mountReadyWrapper(this); -} - function postUpdateSelectWrapper() { ReactDOMSelect.postUpdateWrapper(this); } // For HTML, certain tags should omit their close tag. We keep a whitelist for -// those special cased tags. +// those special-case tags. var omittedCloseTags = { 'area': true, @@ -6701,7 +6738,7 @@ var newlineEatingTags = { // For HTML, certain tags cannot have children. This has the same purpose as // `omittedCloseTags` except that `menuitem` should still have its closing tag. -var voidElementTags = assign({ +var voidElementTags = _assign({ 'menuitem': true }, omittedCloseTags); @@ -6711,27 +6748,21 @@ var voidElementTags = assign({ var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset var validatedTagCache = {}; -var hasOwnProperty = ({}).hasOwnProperty; +var hasOwnProperty = {}.hasOwnProperty; function validateDangerousTag(tag) { if (!hasOwnProperty.call(validatedTagCache, tag)) { - !VALID_TAG_REGEX.test(tag) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Invalid tag: %s', tag) : invariant(false) : undefined; + !VALID_TAG_REGEX.test(tag) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Invalid tag: %s', tag) : invariant(false) : void 0; validatedTagCache[tag] = true; } } -function processChildContextDev(context, inst) { - // Pass down our tag name to child components for validation purposes - context = assign({}, context); - var info = context[validateDOMNesting.ancestorInfoContextKey]; - context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst); - return context; -} - function isCustomComponent(tagName, props) { return tagName.indexOf('-') >= 0 || props.is != null; } +var globalIdCounter = 1; + /** * Creates a new React class that is idempotent and capable of containing other * React components. It accepts event listeners and DOM properties that are @@ -6746,19 +6777,25 @@ function isCustomComponent(tagName, props) { * @constructor ReactDOMComponent * @extends ReactMultiChild */ -function ReactDOMComponent(tag) { +function ReactDOMComponent(element) { + var tag = element.type; validateDangerousTag(tag); + this._currentElement = element; this._tag = tag.toLowerCase(); + this._namespaceURI = null; this._renderedChildren = null; this._previousStyle = null; this._previousStyleCopy = null; + this._nativeNode = null; + this._nativeParent = null; this._rootNodeID = null; + this._domID = null; + this._nativeContainerInfo = null; this._wrapperState = null; this._topLevelWrapper = null; - this._nodeWithLegacyProperties = null; + this._flags = 0; if (process.env.NODE_ENV !== 'production') { - this._unprocessedContextDev = null; - this._processedContextDev = null; + this._ancestorInfo = null; } } @@ -6766,27 +6803,28 @@ ReactDOMComponent.displayName = 'ReactDOMComponent'; ReactDOMComponent.Mixin = { - construct: function (element) { - this._currentElement = element; - }, - /** * Generates root tag markup then recurses. This method has side effects and * is not idempotent. * * @internal - * @param {string} rootID The root DOM ID for this node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @param {?ReactDOMComponent} the containing DOM component instance + * @param {?object} info about the native container * @param {object} context * @return {string} The computed markup. */ - mountComponent: function (rootID, transaction, context) { - this._rootNodeID = rootID; + mountComponent: function (transaction, nativeParent, nativeContainerInfo, context) { + this._rootNodeID = globalIdCounter++; + this._domID = nativeContainerInfo._idCounter++; + this._nativeParent = nativeParent; + this._nativeContainerInfo = nativeContainerInfo; var props = this._currentElement.props; switch (this._tag) { case 'iframe': + case 'object': case 'img': case 'form': case 'video': @@ -6797,50 +6835,96 @@ ReactDOMComponent.Mixin = { transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'button': - props = ReactDOMButton.getNativeProps(this, props, context); + props = ReactDOMButton.getNativeProps(this, props, nativeParent); break; case 'input': - ReactDOMInput.mountWrapper(this, props, context); - props = ReactDOMInput.getNativeProps(this, props, context); + ReactDOMInput.mountWrapper(this, props, nativeParent); + props = ReactDOMInput.getNativeProps(this, props); + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'option': - ReactDOMOption.mountWrapper(this, props, context); - props = ReactDOMOption.getNativeProps(this, props, context); + ReactDOMOption.mountWrapper(this, props, nativeParent); + props = ReactDOMOption.getNativeProps(this, props); break; case 'select': - ReactDOMSelect.mountWrapper(this, props, context); - props = ReactDOMSelect.getNativeProps(this, props, context); - context = ReactDOMSelect.processChildContext(this, props, context); + ReactDOMSelect.mountWrapper(this, props, nativeParent); + props = ReactDOMSelect.getNativeProps(this, props); + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'textarea': - ReactDOMTextarea.mountWrapper(this, props, context); - props = ReactDOMTextarea.getNativeProps(this, props, context); + ReactDOMTextarea.mountWrapper(this, props, nativeParent); + props = ReactDOMTextarea.getNativeProps(this, props); + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; } assertValidProps(this, props); - if (process.env.NODE_ENV !== 'production') { - if (context[validateDOMNesting.ancestorInfoContextKey]) { - validateDOMNesting(this._tag, this, context[validateDOMNesting.ancestorInfoContextKey]); + + // We create tags in the namespace of their parent container, except HTML + // tags get no namespace. + var namespaceURI; + var parentTag; + if (nativeParent != null) { + namespaceURI = nativeParent._namespaceURI; + parentTag = nativeParent._tag; + } else if (nativeContainerInfo._tag) { + namespaceURI = nativeContainerInfo._namespaceURI; + parentTag = nativeContainerInfo._tag; + } + if (namespaceURI == null || namespaceURI === DOMNamespaces.svg && parentTag === 'foreignobject') { + namespaceURI = DOMNamespaces.html; + } + if (namespaceURI === DOMNamespaces.html) { + if (this._tag === 'svg') { + namespaceURI = DOMNamespaces.svg; + } else if (this._tag === 'math') { + namespaceURI = DOMNamespaces.mathml; } } + this._namespaceURI = namespaceURI; if (process.env.NODE_ENV !== 'production') { - this._unprocessedContextDev = context; - this._processedContextDev = processChildContextDev(context, this); - context = this._processedContextDev; + var parentInfo; + if (nativeParent != null) { + parentInfo = nativeParent._ancestorInfo; + } else if (nativeContainerInfo._tag) { + parentInfo = nativeContainerInfo._ancestorInfo; + } + if (parentInfo) { + // parentInfo should always be present except for the top-level + // component when server rendering + validateDOMNesting(this._tag, this, parentInfo); + } + this._ancestorInfo = validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this); } var mountImage; if (transaction.useCreateElement) { - var ownerDocument = context[ReactMount.ownerDocumentContextKey]; - var el = ownerDocument.createElement(this._currentElement.type); - DOMPropertyOperations.setAttributeForID(el, this._rootNodeID); - // Populate node cache - ReactMount.getID(el); - this._updateDOMProperties({}, props, transaction, el); - this._createInitialChildren(transaction, props, context, el); - mountImage = el; + var ownerDocument = nativeContainerInfo._ownerDocument; + var el; + if (namespaceURI === DOMNamespaces.html) { + if (this._tag === 'script') { + // Create the script via .innerHTML so its "parser-inserted" flag is + // set to true and it does not execute + var div = ownerDocument.createElement('div'); + var type = this._currentElement.type; + div.innerHTML = '<' + type + '>'; + el = div.removeChild(div.firstChild); + } else { + el = ownerDocument.createElement(this._currentElement.type); + } + } else { + el = ownerDocument.createElementNS(namespaceURI, this._currentElement.type); + } + ReactDOMComponentTree.precacheNode(this, el); + this._flags |= Flags.hasCachedChildNodes; + if (!this._nativeParent) { + DOMPropertyOperations.setAttributeForRoot(el); + } + this._updateDOMProperties(null, props, transaction); + var lazyTree = DOMLazyTree(el); + this._createInitialChildren(transaction, props, context, lazyTree); + mountImage = lazyTree; } else { var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props); var tagContent = this._createContentMarkup(transaction, props, context); @@ -6852,16 +6936,16 @@ ReactDOMComponent.Mixin = { } switch (this._tag) { - case 'input': - transaction.getReactMountReady().enqueue(mountReadyInputWrapper, this); - // falls through case 'button': + case 'input': case 'select': case 'textarea': if (props.autoFocus) { transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this); } break; + case 'option': + transaction.getReactMountReady().enqueue(optionPostMount, this); } return mountImage; @@ -6893,7 +6977,7 @@ ReactDOMComponent.Mixin = { } if (registrationNameModules.hasOwnProperty(propKey)) { if (propValue) { - enqueuePutListener(this._rootNodeID, propKey, propValue, transaction); + enqueuePutListener(this, propKey, propValue, transaction); } } else { if (propKey === STYLE) { @@ -6902,13 +6986,13 @@ ReactDOMComponent.Mixin = { // See `_updateDOMProperties`. style block this._previousStyle = propValue; } - propValue = this._previousStyleCopy = assign({}, props.style); + propValue = this._previousStyleCopy = _assign({}, props.style); } - propValue = CSSPropertyOperations.createMarkupForStyles(propValue); + propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this); } var markup = null; if (this._tag != null && isCustomComponent(this._tag, props)) { - if (propKey !== CHILDREN) { + if (!RESERVED_PROPS.hasOwnProperty(propKey)) { markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue); } } else { @@ -6926,8 +7010,11 @@ ReactDOMComponent.Mixin = { return ret; } - var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID); - return ret + ' ' + markupForID; + if (!this._nativeParent) { + ret += ' ' + DOMPropertyOperations.createMarkupForRoot(); + } + ret += ' ' + DOMPropertyOperations.createMarkupForID(this._domID); + return ret; }, /** @@ -6976,23 +7063,23 @@ ReactDOMComponent.Mixin = { } }, - _createInitialChildren: function (transaction, props, context, el) { + _createInitialChildren: function (transaction, props, context, lazyTree) { // Intentional use of != to avoid catching zero/false. var innerHTML = props.dangerouslySetInnerHTML; if (innerHTML != null) { if (innerHTML.__html != null) { - setInnerHTML(el, innerHTML.__html); + DOMLazyTree.queueHTML(lazyTree, innerHTML.__html); } } else { var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null; var childrenToUse = contentToUse != null ? null : props.children; if (contentToUse != null) { // TODO: Validate that text is allowed as a child of this node - setTextContent(el, contentToUse); + DOMLazyTree.queueText(lazyTree, contentToUse); } else if (childrenToUse != null) { var mountImages = this.mountChildren(childrenToUse, transaction, context); for (var i = 0; i < mountImages.length; i++) { - el.appendChild(mountImages[i]); + DOMLazyTree.queueChild(lazyTree, mountImages[i]); } } } @@ -7051,25 +7138,10 @@ ReactDOMComponent.Mixin = { break; } - if (process.env.NODE_ENV !== 'production') { - // If the context is reference-equal to the old one, pass down the same - // processed object so the update bailout in ReactReconciler behaves - // correctly (and identically in dev and prod). See #5005. - if (this._unprocessedContextDev !== context) { - this._unprocessedContextDev = context; - this._processedContextDev = processChildContextDev(context, this); - } - context = this._processedContextDev; - } - assertValidProps(this, nextProps); - this._updateDOMProperties(lastProps, nextProps, transaction, null); + this._updateDOMProperties(lastProps, nextProps, transaction); this._updateDOMChildren(lastProps, nextProps, transaction, context); - if (!canDefineProperty && this._nodeWithLegacyProperties) { - this._nodeWithLegacyProperties.props = nextProps; - } - if (this._tag === 'select') { // native component that allows setting these optional * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. @@ -7676,11 +8031,15 @@ function forceUpdateIfMounted() { * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html */ var ReactDOMInput = { - getNativeProps: function (inst, props, context) { + getNativeProps: function (inst, props) { var value = LinkedValueUtils.getValue(props); var checked = LinkedValueUtils.getChecked(props); - var nativeProps = assign({}, props, { + var nativeProps = _assign({ + // Make sure we set .type before any other properties (setting .value + // before .type means .value is lost in IE11 and below) + type: undefined + }, props, { defaultChecked: undefined, defaultValue: undefined, value: value != null ? value : inst._wrapperState.initialValue, @@ -7694,39 +8053,71 @@ var ReactDOMInput = { mountWrapper: function (inst, props) { if (process.env.NODE_ENV !== 'production') { LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner); + + if (props.valueLink !== undefined && !didWarnValueLink) { + process.env.NODE_ENV !== 'production' ? warning(false, '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : void 0; + didWarnValueLink = true; + } + if (props.checkedLink !== undefined && !didWarnCheckedLink) { + process.env.NODE_ENV !== 'production' ? warning(false, '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : void 0; + didWarnCheckedLink = true; + } + if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { + process.env.NODE_ENV !== 'production' ? warning(false, 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : void 0; + didWarnCheckedDefaultChecked = true; + } + if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { + process.env.NODE_ENV !== 'production' ? warning(false, 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : void 0; + didWarnValueDefaultValue = true; + } + warnIfValueIsNull(props); } var defaultValue = props.defaultValue; inst._wrapperState = { initialChecked: props.defaultChecked || false, initialValue: defaultValue != null ? defaultValue : null, + listeners: null, onChange: _handleChange.bind(inst) }; - }, - - mountReadyWrapper: function (inst) { - // Can't be in mountWrapper or else server rendering leaks. - instancesByReactID[inst._rootNodeID] = inst; - }, - unmountWrapper: function (inst) { - delete instancesByReactID[inst._rootNodeID]; + if (process.env.NODE_ENV !== 'production') { + inst._wrapperState.controlled = props.checked !== undefined || props.value !== undefined; + } }, updateWrapper: function (inst) { var props = inst._currentElement.props; + if (process.env.NODE_ENV !== 'production') { + warnIfValueIsNull(props); + + var initialValue = inst._wrapperState.initialChecked || inst._wrapperState.initialValue; + var defaultValue = props.defaultChecked || props.defaultValue; + var controlled = props.checked !== undefined || props.value !== undefined; + var owner = inst._currentElement._owner; + + if ((initialValue || !inst._wrapperState.controlled) && controlled && !didWarnUncontrolledToControlled) { + process.env.NODE_ENV !== 'production' ? warning(false, '%s is changing a uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0; + didWarnUncontrolledToControlled = true; + } + if (inst._wrapperState.controlled && (defaultValue || !controlled) && !didWarnControlledToUncontrolled) { + process.env.NODE_ENV !== 'production' ? warning(false, '%s is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0; + didWarnControlledToUncontrolled = true; + } + } + // TODO: Shouldn't this be getChecked(props)? var checked = props.checked; if (checked != null) { - ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'checked', checked || false); + DOMPropertyOperations.setValueForProperty(ReactDOMComponentTree.getNodeFromInstance(inst), 'checked', checked || false); } var value = LinkedValueUtils.getValue(props); if (value != null) { // Cast `value` to a string to ensure the value is set correctly. While // browsers typically do this as necessary, jsdom doesn't. - ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'value', '' + value); + DOMPropertyOperations.setValueForProperty(ReactDOMComponentTree.getNodeFromInstance(inst), 'value', '' + value); } } }; @@ -7743,7 +8134,7 @@ function _handleChange(event) { var name = props.name; if (props.type === 'radio' && name != null) { - var rootNode = ReactMount.getNode(this._rootNodeID); + var rootNode = ReactDOMComponentTree.getNodeFromInstance(this); var queryRoot = rootNode; while (queryRoot.parentNode) { @@ -7766,11 +8157,9 @@ function _handleChange(event) { // This will throw if radio buttons rendered by different copies of React // and the same name are rendered into the same form (same as #1939). // That's probably okay; we don't support it just as we don't support - // mixing React with non-React. - var otherID = ReactMount.getID(otherNode); - !otherID ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(false) : undefined; - var otherInstance = instancesByReactID[otherID]; - !otherInstance ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOMInput: Unknown radio button ID %s.', otherID) : invariant(false) : undefined; + // mixing React radio buttons with non-React ones. + var otherInstance = ReactDOMComponentTree.getInstanceFromNode(otherNode); + !otherInstance ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(false) : void 0; // If this is a controlled radio button group, forcing the input that // was previously checked to update will cause it to be come re-checked // as appropriate. @@ -7783,11 +8172,27 @@ function _handleChange(event) { module.exports = ReactDOMInput; }).call(this,require('_process')) +},{"./DOMPropertyOperations":12,"./LinkedValueUtils":23,"./ReactDOMComponentTree":39,"./ReactUpdates":88,"_process":1,"fbjs/lib/invariant":152,"fbjs/lib/warning":162,"object-assign":163}],47:[function(require,module,exports){ +/** + * Copyright 2013-present, 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 ReactDOMInstrumentation + */ + +'use strict'; + +var ReactDOMDebugTool = require('./ReactDOMDebugTool'); -},{"./LinkedValueUtils":"/Users/yuanyan/React/halogen/node_modules/react/lib/LinkedValueUtils.js","./Object.assign":"/Users/yuanyan/React/halogen/node_modules/react/lib/Object.assign.js","./ReactDOMIDOperations":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactDOMIDOperations.js","./ReactMount":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactMount.js","./ReactUpdates":"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactUpdates.js","_process":"/Users/yuanyan/React/halogen/node_modules/browserify/node_modules/process/browser.js","fbjs/lib/invariant":"/Users/yuanyan/React/halogen/node_modules/react/node_modules/fbjs/lib/invariant.js"}],"/Users/yuanyan/React/halogen/node_modules/react/lib/ReactDOMOption.js":[function(require,module,exports){ +module.exports = { debugTool: ReactDOMDebugTool }; +},{"./ReactDOMDebugTool":41}],48:[function(require,module,exports){ (function (process){ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -7799,28 +8204,31 @@ module.exports = ReactDOMInput; 'use strict'; +var _assign = require('object-assign'); + var ReactChildren = require('./ReactChildren'); +var ReactDOMComponentTree = require('./ReactDOMComponentTree'); var ReactDOMSelect = require('./ReactDOMSelect'); -var assign = require('./Object.assign'); var warning = require('fbjs/lib/warning'); -var valueContextKey = ReactDOMSelect.valueContextKey; - /** * Implements an