react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / browser / ui / dom / Danger.js
81159 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule Danger9* @typechecks static-only10*/1112/*jslint evil: true, sub: true */1314"use strict";1516var ExecutionEnvironment = require('ExecutionEnvironment');1718var createNodesFromMarkup = require('createNodesFromMarkup');19var emptyFunction = require('emptyFunction');20var getMarkupWrap = require('getMarkupWrap');21var invariant = require('invariant');2223var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;24var RESULT_INDEX_ATTR = 'data-danger-index';2526/**27* Extracts the `nodeName` from a string of markup.28*29* NOTE: Extracting the `nodeName` does not require a regular expression match30* because we make assumptions about React-generated markup (i.e. there are no31* spaces surrounding the opening tag and there is at least one attribute).32*33* @param {string} markup String of markup.34* @return {string} Node name of the supplied markup.35* @see http://jsperf.com/extract-nodename36*/37function getNodeName(markup) {38return markup.substring(1, markup.indexOf(' '));39}4041var Danger = {4243/**44* Renders markup into an array of nodes. The markup is expected to render45* into a list of root nodes. Also, the length of `resultList` and46* `markupList` should be the same.47*48* @param {array<string>} markupList List of markup strings to render.49* @return {array<DOMElement>} List of rendered nodes.50* @internal51*/52dangerouslyRenderMarkup: function(markupList) {53invariant(54ExecutionEnvironment.canUseDOM,55'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' +56'thread. Make sure `window` and `document` are available globally ' +57'before requiring React when unit testing or use ' +58'React.renderToString for server rendering.'59);60var nodeName;61var markupByNodeName = {};62// Group markup by `nodeName` if a wrap is necessary, else by '*'.63for (var i = 0; i < markupList.length; i++) {64invariant(65markupList[i],66'dangerouslyRenderMarkup(...): Missing markup.'67);68nodeName = getNodeName(markupList[i]);69nodeName = getMarkupWrap(nodeName) ? nodeName : '*';70markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];71markupByNodeName[nodeName][i] = markupList[i];72}73var resultList = [];74var resultListAssignmentCount = 0;75for (nodeName in markupByNodeName) {76if (!markupByNodeName.hasOwnProperty(nodeName)) {77continue;78}79var markupListByNodeName = markupByNodeName[nodeName];8081// This for-in loop skips the holes of the sparse array. The order of82// iteration should follow the order of assignment, which happens to match83// numerical index order, but we don't rely on that.84for (var resultIndex in markupListByNodeName) {85if (markupListByNodeName.hasOwnProperty(resultIndex)) {86var markup = markupListByNodeName[resultIndex];8788// Push the requested markup with an additional RESULT_INDEX_ATTR89// attribute. If the markup does not start with a < character, it90// will be discarded below (with an appropriate console.error).91markupListByNodeName[resultIndex] = markup.replace(92OPEN_TAG_NAME_EXP,93// This index will be parsed back out below.94'$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '95);96}97}9899// Render each group of markup with similar wrapping `nodeName`.100var renderNodes = createNodesFromMarkup(101markupListByNodeName.join(''),102emptyFunction // Do nothing special with <script> tags.103);104105for (i = 0; i < renderNodes.length; ++i) {106var renderNode = renderNodes[i];107if (renderNode.hasAttribute &&108renderNode.hasAttribute(RESULT_INDEX_ATTR)) {109110resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);111renderNode.removeAttribute(RESULT_INDEX_ATTR);112113invariant(114!resultList.hasOwnProperty(resultIndex),115'Danger: Assigning to an already-occupied result index.'116);117118resultList[resultIndex] = renderNode;119120// This should match resultList.length and markupList.length when121// we're done.122resultListAssignmentCount += 1;123124} else if (__DEV__) {125console.error(126"Danger: Discarding unexpected node:",127renderNode128);129}130}131}132133// Although resultList was populated out of order, it should now be a dense134// array.135invariant(136resultListAssignmentCount === resultList.length,137'Danger: Did not assign to every index of resultList.'138);139140invariant(141resultList.length === markupList.length,142'Danger: Expected markup to render %s nodes, but rendered %s.',143markupList.length,144resultList.length145);146147return resultList;148},149150/**151* Replaces a node with a string of markup at its current position within its152* parent. The markup must render into a single root node.153*154* @param {DOMElement} oldChild Child node to replace.155* @param {string} markup Markup to render in place of the child node.156* @internal157*/158dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) {159invariant(160ExecutionEnvironment.canUseDOM,161'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' +162'worker thread. Make sure `window` and `document` are available ' +163'globally before requiring React when unit testing or use ' +164'React.renderToString for server rendering.'165);166invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.');167invariant(168oldChild.tagName.toLowerCase() !== 'html',169'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +170'<html> node. This is because browser quirks make this unreliable ' +171'and/or slow. If you want to render to the root you must use ' +172'server rendering. See renderComponentToString().'173);174175var newChild = createNodesFromMarkup(markup, emptyFunction)[0];176oldChild.parentNode.replaceChild(newChild, oldChild);177}178179};180181module.exports = Danger;182183184