Question: COMMANDS_TO_RUN+=('./scripts/circleci/build.sh') COMMANDS_TO_RUN+=('yarn test-build --runInBand') COMMANDS_TO_RUN+=('yarn test-build-prod --runInBand') <ins> COMMANDS_TO_RUN+=('./scripts/circleci/upload_build.sh') </ins> fi if [ $((3 % CIRCLE_NODE_TOTAL)) -eq "$CIRCLE_NODE_INDEX" ]; then

It looks like this: It happened two times on random commits, and I don't see a pattern. Probably caused by me changing how tasks are distributed between parallel nodes in I don't understand why would try to run before a build exists though (if that's what's happening?)
I think this one would require some experience with CircleCI. I don't have any pointers as to where to start: I don't understand why it's failing myself. So it's not a very beginner-friendly issue (I marked the difficulty as medium for that reason).
Another example:
I want to work on this. After doing some research on circleci document, I didn't find the document said about parallel test and deployment sequence. I'm curious about how circleci deal with parallel test and deployment sequence. I think there are two situations: all parallel test finishes, run deployment sequence. If this is true, I think it won't cause current test error. container runs deployment after the container's test finished. I guess it is more likely in this case. Sometimes it passed, it's because node 2 already built file. Sometimes it failed because node 2 didn't build file yet. So I think maybe that's because each container will run deployment after that node test finished. If the situation is as above, I come up with two solutions. we want to keep current test flow, we can try to keep each node builds time balance. this test at first, then run other test parallel. reference link:
Only node 2 does a full build. So I don't understand how deployment on other nodes could work at all.
Or do nodes share the file system?
I think nodes share the file system. Otherwise, it should fail every time. It will be easier to debug if we can add more log, like current build time and .
Would it make sense to change the upload script to only run on the second node?
Yep, I think so, because in the document I can't ensure whether deployment stage is triggered after all parallel test finished.
Can we just put the deployment command right into the test command? Is there any benefit to separating them?
I think it's also workable, but may lead misunderstanding. Cause we put build process to test stage. Or we can try to use stage. Run at compile stage, so we can promise and stages have needed file.


Question: COMMANDS_TO_RUN+=('./scripts/circleci/build.sh') COMMANDS_TO_RUN+=('yarn test-build --runInBand') COMMANDS_TO_RUN+=('yarn test-build-prod --runInBand') <ins> COMMANDS_TO_RUN+=('./scripts/circleci/upload_build.sh') </ins> fi if [ $((3 % CIRCLE_NODE_TOTAL)) -eq "$CIRCLE_NODE_INDEX" ]; then

The interesting part is our regular tests don't need compilation. If "compile" stage has to run before any other stages then we'll wait unnecessarily. I'd prefer to have a single script that does everything than to buy into CircleCI specific terminology unless it buys us something real good (e.g. parallelism was very useful). Maybe can try this:
OK, I understand your consideration. I think this fix will work. Just tell me if anything can help.


Question: } } while (nextEffect !== null) { <ins> if (__DEV__) { setCurrentFiber(nextEffect); } </ins> const effectTag = nextEffect.effectTag; if (effectTag & (Update | Callback)) {

I've noticed a strange bug with the react redux opt-in. If i use it with a connected class component, everything is ok: If i use it with a connected functional component that use with , i obtain a strange error: in method. I create a codepen to reproduce the issue: PS: Sorry for the cors error, but i don't find the way to add as cdn
I believe the issue here is that expects the second argument to be a function that returns the reference: See: for more information about the API of the hook. Maybe the error thrown could be more clear?
You're right, accept a function as second argument. A warning on wrong argument type could be a good idea.
Ill take this issue on
Sure
i get TypeError: React.useImperativeMethods is not a function in 16.8.0-alpha.1 but when back to 16.7.0-alpha.2 not get this error
The hook was renamed in this PR: Most likely between the 16.7 alpha and 16.8 alpha
Yeah, it was renamed.
yes it work good after rename it where i can get changes between alpha version ?
Commit log. We don't write changelogs for alphas.
I'm taking this in since we want to get Hooks out sooner.
alright np


Question: const MAX_SIZE = 500; const PAGE_SIZE = 50; <del> function createRecord<K, V>(key: K): EmptyRecord<K, V> { </del> <ins> function createRecord<K>(key: K): EmptyRecord<K> { </ins> return { status: Empty, suspender: null,

In we landed a change to the Flow types in , making the types for the various types recursive with their and properties. On that PR we may have been running an older version of Flow - I'm not having luck finding the record of when Flow ran for that PR, so not sure. In any case, that PR was merged even though it had the recursive Flow type definitions, plus one or more Flow errors which were unrelated and not detected. The problem with the recursive type definitions is that recent versions of Flow will go into an infinite loop if they try to infer types which are recursive. The solution may be to add more detail to those types, but to unblock things we temporarily made them looser type definitions.


Question: return newHead; } <del> function load<V>(emptyRecord: EmptyRecord, suspender: Promise<V>) { const pendingRecord: PendingRecord<V> = (emptyRecord: any); </del> <ins> function load<K, V>(emptyRecord: EmptyRecord<K>, suspender: Promise<V>) { const pendingRecord: PendingRecord<K, V> = (emptyRecord: any); </ins> pendingRecord.status = Pending; pendingRecord.suspender = suspender; suspender.then( value => { // Resource loaded successfully. <del> const resolvedRecord: ResolvedRecord<V> = (pendingRecord: any); </del> <ins> const resolvedRecord: ResolvedRecord<K, V> = (pendingRecord: any); </ins> resolvedRecord.status = Resolved; resolvedRecord.suspender = null; resolvedRecord.value = value;


Question: 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. <del> // Must set `value` property if it is not null and not yet set. </del> if (!propertyInfo.hasSideEffects || <del> ('' + node[propName]) !== ('' + value) || !node.hasAttribute(propertyInfo.attributeName)) { </del> <ins> ('' + node[propName]) !== ('' + value)) { </ins> // Contrary to `setAttribute`, object properties are properly // `toString`ed by IE8/9. node[propName] = value;

Appears to be working in Firefox but at least Chrome & Safari are broken. Should be a really recent regression so very few possible changes to blame... Easiest repo: the todo list on our homepage.
Just a heads up but this still seems to be an issue even on 15.4.1. I've been struggling to reproduce this because it seems to be some sort of ninja bug. Nevertheless, I was wondering if anyone is still dealing with this problem?
I haven't seen anything.
I'm still seeing this issue.
Please open a new issue with a simplified repro case if you're still seeing this!


Question: {isEditable ? ( <EditableValue  dataType={dataType}   initialValue={value}  overrideValueFn={((overrideValueFn: any): OverrideValueFn)} path={path}  initialValue={value}  /> ) : ( {displayValue}

Do you want to request a feature or report a bug? Report a bug What is the current behavior? The hook's value is shown as in React DevTools if the value is a string or a number. Clicking on the bug icon prints the correct values to console. ! If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. CodeSandbox: Direct link to page so you can see the DevTools: What is the expected behavior? The DevTools should show the correct value of the hook. Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React? React 16.9.0. Google Chrome [Version 77.0.3865.90 (Official Build) (64-bit)] running on Linux x64. This issue appeared after version 4.1.0 (9/19/2019) of the DevTools Chrome extension. Might be same bug as but this one appears without any complicated reproduction steps.
Looks like the issue also appears with boolean values.
Having the same problem. The extension worked fine after I downgraded React to version 16.8.6
I think the only significant difference between React v16.8 and v16.9 is that v16.9 injects the function DevTools uses to support editable hooks (in other words, DevTools is using a different code path when you run v16.8 vs v16.9). I think that means this bug is probably related to somehow. Will dig in more.
Should be fixed by
This fix will be released with 4.1.1 (sometime soon)
This fix has just been published to NPM and posted to Chrome/Firefox as v4.1.1


Question: do { lastID = internalGetID(current); current = current.parentNode; <del> invariant( current != null, 'findFirstReactDOMImpl(...): Unexpected detached subtree found when ' + 'traversing DOM from node `%s`.', nodeID ); </del> <ins> if (current == null) { // The passed-in node has been detached from the container it was // originally rendered into. return null; } </ins> } while (lastID !== reactRootID); if (current === containersByReactRootID[reactRootID]) {

Since upgrading from beta3 to rc1 I've seen this error a few times in production. Haven't been able to trace the source yet though. cc
I was unmounting a root during a keyboard event which caused this to happen. I think this has always been a problem? Perhaps we've only been lucky... leaving open just to be sure. EDIT: Could it make sense to have something along the lines of ? Allowing you to schedule things to occur as soon as the current transaction ends.
This invariant was new in this release. We also hit one case at FB that I haven't yet investigated. Probably need to change something for the final release.
I have seen this on RC1 can't find a sequence of actions to repeat it.
I'm running into this issue as well when conditionally rendering based on state. Not sure how to boil it down to a simple reproducible bug report yet.
My issue only happens when I am leveraging FastClick. Didn't happen before 0.14.
I've found it is because the events are handled in a different order with fastclick, so the batching gets weird...
e.g. click gets fired before touchEnd, so click handler setState to remove subtree, and then react tries to do something with it in touch end perhaps?


Question: do { lastID = internalGetID(current); current = current.parentNode; <del> invariant( current != null, 'findFirstReactDOMImpl(...): Unexpected detached subtree found when ' + 'traversing DOM from node `%s`.', nodeID ); </del> <ins> if (current == null) { // The passed-in node has been detached from the container it was // originally rendered into. return null; } </ins> } while (lastID !== reactRootID); if (current === containersByReactRootID[reactRootID]) {

In this repro, I created 2 buttons and only one is rendered at a time. One button's click handler is hooked up to React's synthetic "click" event while the other is hooked up to the native "click" event. Even though only one button is rendered at a time, a single click is triggering both click events. This bug can be hit by apps that mix React components with non-React controls (e.g. jQuery UI). I reproed this in Chrome with React 0.13.2. to the button labeled "One" Expected: There's a button rendered labeled "Two" Actual: The rendered button still has the label "One" If you open the console, you'll see "goToTwo" and "goToOne" which indicates that the "One" button's click handler ran and then the "Two" button's click handler ran (even though we never saw button "Two"").
I experimented more and came up with another repro: In this one, you click on a button with a native "click" handler which causes the button to go away and an input field to be rendered. It results in this exception: From these 2 repros, it seems something strange is going on when calling from within a native "click" handler.
It works if you add to the event handler.
Thanks for the workaround. Is the behavior without the by design? It looks like the bad behavior is being caused by the rerender happening synchronously within the native "click" handler.
This looks bad. We don't do a great job interacting with native events. Sebastian wrote a post about this once-upon-a-time, how native and synthetic event systems are, by and large, not interoperable. Even so, I can't see a reason we should fatal like this. Do you understand what's going wrong here? What a fix might look like?
This happens when we handle a click event from a node that's been removed in between when the event is triggered and when React receives it. How should we deal with the case that events fire on detached elements? Should we ignore events for nodes that aren't in the document? I don't think the bug is easily fixable otherwise because we don't have the old event handler after the reconcile that removes that node.
Here are some additional details about the impact of the bug.


Question: do { lastID = internalGetID(current); current = current.parentNode; <del> invariant( current != null, 'findFirstReactDOMImpl(...): Unexpected detached subtree found when ' + 'traversing DOM from node `%s`.', nodeID ); </del> <ins> if (current == null) { // The passed-in node has been detached from the container it was // originally rendered into. return null; } </ins> } while (lastID !== reactRootID); if (current === containersByReactRootID[reactRootID]) {

It sounds like this bug is likely to trigger when you use a non-React component (e.g. jQuery UI) in a React single page application and the non-React component triggers a navigation within the app.
Thanks for an excellent bug report and good repro case! I think this happens because we use the "root id" to determine which element was clicked. In the repro case there is no "key" as part of the root ID for two reasons: 1) It is not a child of a container (multichild) so it doesn't get a key to the root ID. 2) It doesn't have a unique key and doesn't need one because it the button is of a different type. If I make sure that a key is used as part of the root ID the problem is solved: So the problem in the repro isn't that we're firing on a removed node, it is that we're firing the event on the new node. This would be solved if we used a unique ID per instance to identify event handlers instead of a generate root that is non-unique. Which I think we wanted to do anyway. Is there another repro that shows a different issue?


Question: Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized. <del> First, add the third-party **Showdown** library to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground): </del> <ins> First, add the third-party library **marked** to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground): </ins> ```html{7} <!-- index.html -->

Since copy+pasting our code makes it too easy for people to XSS themselves, lets just add a comment in there about it.
PR at - let me know if that's what you had in mind!
My intuition is that it makes more sense to fix the example (call a sanitization library) or to change the example completely (demonstrate something else that is safer). It looks really bad to have a security warning on the homepage of the react site. Makes it seem like our framework encourages unsafe operations, rather than a safe-by-default way of doing things.
Should switch the demo to use a different library like markdown-js that escapes everything and doesn't support HTML:
markdown-js looks good. First attempt: ,output Code licensed if someone wants to turn this into a coherent example; I've signed the CLA.
That's a good suggestion too :) - what are your thoughts? I'm happy to change the example to use like people have suggested above. nice usage example :+1:
Uh yea, that sounds fine to me. This behavior is definitely non-standard markdown but it's an example so not a big deal. We should probably do the same for the tutorial while we're here. And it's on cdnjs so that's all pretty easy:
Just going to use marked instead, which I'm already familiar with and has an option to sanitize input.


Question: ); } break; <ins> case 'option': transaction.getReactMountReady().enqueue( optionPostMount, this ); </ins> } return mountImage;


Question: "private": true, "scripts": { "build": "cross-env NODE_ENV=production yarn run build:chrome && yarn run build:firefox && yarn run build:edge", <del> "build:dev": "cross-env NODE_ENV=development yarn run build:chrome && yarn run build:firefox && yarn run build:edge", </del> <ins> "build:dev": "cross-env NODE_ENV=development yarn run build:chrome:dev && yarn run build:firefox:dev && yarn run build:edge:dev", </ins> "build:chrome": "cross-env NODE_ENV=production node ./chrome/build", "build:chrome:crx": "cross-env NODE_ENV=production node ./chrome/build --crx", "build:chrome:dev": "cross-env NODE_ENV=development node ./chrome/build",

<!-- Please provide a clear and concise description of what the bug is. Include screenshots if needed. Please test using the latest version of the relevant React packages to make sure your issue has not already been fixed. --React Dev Tools version: 4.6.0 I'm not sure there is a problem with within package, or it's just my misunderstand how it works, but script create production build. Command above runs a each script (per browser) in which is set to . run in creates minified version of files. where has set to . Each step in should be replaced from to
Send a PR? This does look odd.
Sure, I'll take a look at it tomorrow, it's looks odd and incorrectly but need to check there isn't any trap with that


Question: return markup; }, <ins> _constructComponent: function(publicProps, publicContext) { if (__DEV__) { ReactCurrentOwner.current = this; try { return this._constructComponentWithoutOwner(publicProps, publicContext); } finally { ReactCurrentOwner.current = null; } } else { return this._constructComponentWithoutOwner(publicProps, publicContext); } }, _constructComponentWithoutOwner: function(publicProps, publicContext) { var Component = this._currentElement.type; if (shouldConstruct(Component)) { return new Component(publicProps, publicContext, ReactUpdateQueue); } else { return Component(publicProps, publicContext, ReactUpdateQueue); } }, </ins> performInitialMountWithErrorHandling: function( renderedElement, nativeParent,

There appears to have been a change in how is generated between 0.13 and 0.14 which is causing a number of our shallow rendered tests to fail when upgrading because the deepEquals fails on the property. Here is a simple example component which exhibits the issue.
I've been seeing some similar issues with shallow rendering. My current (messy - sorry!) workaround is this: Let me know if that helps! My version currently breaks some of the Jest tests, but I'm happy to work on this some more and submit a PR.
Thank you very much for this, it's been a tremendous help! While this solved the problem for my test case above it still failed on a large number of our more complex tests. I've been iterating on it and once I have all of our tests passing I'll add the updated version.
Here is the updated workaround, it works for our 238 tests of varying complexity but I'd be interested to see if it passes all of your tests as well.
Awesome! If you don't mind trying, what happens if you do and then use the earlier ?
Much cleaner thanks, I guess I was in my head too much :)
I prefer applying a monkey patch, until we have this fixed in react by wrapping TestUtils in my own module:
This should be fixed by .


Question: <script type="text/javascript" src="/react/js/react.js"></script> <script type="text/javascript" src="/react/js/JSXTransformer.js"></script> <script type="text/javascript" src="/react/js/live_editor.js"></script> <del> <script type="text/javascript" src="/react/js/showdown.js"></script> </del> </head> <body>


Question: const elementType = getElementTypeForFiber(fiber); const {_debugOwner} = fiber; <del> const ownerID = _debugOwner != null ? getFiberIDThrows(_debugOwner) : 0; </del> <ins> // Ideally we should call getFiberIDThrows() for _debugOwner, // since owners are almost always higher in the tree (and so have already been processed), // but in some (rare) instances reported in open source, a descendant mounts before an owner. // Since this is a DEV only field it's probably okay to also just lazily generate and ID here if needed. // See https://github.com/facebook/react/issues/21445 const ownerID = _debugOwner != null ? getOrGenerateFiberID(_debugOwner) : 0; </ins> const parentID = parentFiber ? getFiberIDThrows(parentFiber) : 0; const displayNameStringID = getStringID(displayName);

<!-- Please answer both questions below before submitting this issue. --Please provide a link to the URL of the website (if it is public), a CodeSandbox () example that reproduces the bug, or a project on GitHub that we can checkout and run locally. If possible, please describe how to reproduce this bug on the website or app mentioned above: <!-- FILL THIS IN --<!-- FILL THIS IN --<!-- FILL THIS IN --<!---------------------------------------------------<!-- Please do not remove the text below this line --<!---------------------------------------------------DevTools version: 4.13.1- Call stack: at chrome- at (chrome-) at chrome- at listener (chrome-) Component stack: (none) GitHub URL search query:
Hi I'm sorry you ran into this problem Unfortunately, it doesn't look like this issue has enough info for one of us to reproduce it though. This means that it's going to be very hard for us to fix. Please help us by providing a link to a CodeSandbox (), a repository on GitHub, or a minimal code example that reproduces the problem. (Screenshots or videos can also be helpful if they help provide context on how to repro the bug.) Here are some tips for providing a minimal example:
I am also having this bug
See the comment above please :) Repro is needed.
This happened to me, the node wasn't appearing in the Components tree and I was getting this error. The problem was that my attribute was way too long
! suddenly having this issue right now. I thought it was because of my commits, but changing to another old branch just give the same errors. it was working just fine yesterday, don't know why. maybe due to the devtools update or something? btw I'm on react 16.8.6, react devtools 4.13.3 (5/19/2021)
Try updating to the latest release (4.13.4) just to rule anything out. But if you're still seeing the issue, then we still need a repro case.
at first the bug still persists. with same error log. then I retried close the devtools and opened it again (I think I actually have done this as well before) then somehow it works now. the error log still shows up but at least now all components are showing on the devtools, and that's all I need.


Question: const elementType = getElementTypeForFiber(fiber); const {_debugOwner} = fiber; <del> const ownerID = _debugOwner != null ? getFiberIDThrows(_debugOwner) : 0; </del> <ins> // Ideally we should call getFiberIDThrows() for _debugOwner, // since owners are almost always higher in the tree (and so have already been processed), // but in some (rare) instances reported in open source, a descendant mounts before an owner. // Since this is a DEV only field it's probably okay to also just lazily generate and ID here if needed. // See https://github.com/facebook/react/issues/21445 const ownerID = _debugOwner != null ? getOrGenerateFiberID(_debugOwner) : 0; </ins> const parentID = parentFiber ? getFiberIDThrows(parentFiber) : 0; const displayNameStringID = getStringID(displayName);

in addition, I found this ! and I was trying to hide that component (which has no recent changes on it) to see whether it has any impact. or any component that last showing on the devtools. but for now, that'll be all. thank you for responding
I appreciate the extra information, but this isn't a description that I can use to reproduce (and fix) the bug. I need an actual website (or code) that I can run along with instructions (like "do this, then this") so I can see the bug.
There are some simple code could help reproduce. You could try following code sandbox link. The reproduce steps are: "Do not" open develop panel. to develop panel and go to react dev tab. Errors was shown. I guess it's kind of race condition. When I change the component order such as It will work perfect. Ps: brief explain what component do. The PageLoadProgressHandler will dispatch float element to PopupPool.
Excellent! Thank you, Super interesting that this bug only occurs if you wait to open DevTools until after the page has loaded.
I think it is because only have two components, I have two sites, one it will always happen, another will random happen. or maybe code-sandbox do some strange things.
This is interesting. The reason DevTools throws is that the Fiber's owner (the attribute) points to a Fiber that hasn't been mounted yet. That seems unexpected. This repro is just a wrapper around two NPM packages. Where's the source code for these packages? :D Edit I found it, although there's a lot of indirection here_. Tracing one package which imports another which imports another. Would be helpful if it were flattened but I guess I can always step through the bundled source.
PopupPool: PageLoadProgressHandler: Good luck... XD.
Interestingly, if I copy the , , and source files into the sandbox (and only change the import statement in ) the bug goes away. That's surprising.
I wonder if I'm running slightly different code? The debug log shows a slightly different tree structure.


Question: const elementType = getElementTypeForFiber(fiber); const {_debugOwner} = fiber; <del> const ownerID = _debugOwner != null ? getFiberIDThrows(_debugOwner) : 0; </del> <ins> // Ideally we should call getFiberIDThrows() for _debugOwner, // since owners are almost always higher in the tree (and so have already been processed), // but in some (rare) instances reported in open source, a descendant mounts before an owner. // Since this is a DEV only field it's probably okay to also just lazily generate and ID here if needed. // See https://github.com/facebook/react/issues/21445 const ownerID = _debugOwner != null ? getOrGenerateFiberID(_debugOwner) : 0; </ins> const parentID = parentFiber ? getFiberIDThrows(parentFiber) : 0; const displayNameStringID = getStringID(displayName);

Is the version of the source you linked me to the same as the one the Sandbox points to in NPM, Edit Looks like the repro is using 0.18.8 (released a couple of months ago) but the latest NPM release is 0.11.1. That being said, it doesn't look like the files that are being imported have changed (at least not in source) so I'm still not sure what's up.
I change two main components to hook style then get better performance, it reduce the error happen, but I still could get error. Some error is happen after component render done and open the panel same behavior with pervious. I'll log my changes in following issue ticket.
Would be nice to get a smaller reproduction of this issue (all of the code in one project, rather than spread across many NPM packages). That's what I was trying to do with moving the source but then the bug goes away b'c the code seems to be different. I noticed one potential difference being the indirection but I'm not sure how likely that is to be related.
Looking at the error while debugging, it looks like the , then either renders it or dispatches a popup event to show it. I'm not sure why (too sleepy to think it through maybe) but sometimes seems to be mounting before_ has, which goes against an assumption in DevTools. Will dig back in tomorrow.
I really appreciate the repro case, but there are so many layers of indirection between the various NPM packages being used to dynamically create the components. It's difficult to trace through. I'm going to hand this issue to you and ask for a smaller repro case. (Without 10+ NPM projects that each require each other.) Is this something you can help with? Edit I fixed this () but the test case I is not great since it relies on unsupported side effects to trigger the problem case. I'd still love to get a smaller repro so I can (1) be sure I fully fixed the problem and (2) add a regression case so it doesn't get re-introduced.
Bugfix released as
thank you fixed on version 4.13.5
Thanks your effort. Your fixed also be success from my side.


Question:
 // // showdown.js -- A javascript port of Markdown. // // Copyright (c) 2007 John Fraser. // // Original Markdown Copyright (c) 2004-2005 John Gruber //   <http://daringfireball.net/projects/markdown/> // // Redistributable under a BSD-style open source license. // See license.txt for more information. // // The full source distribution is at: // //				A A L //				T C A //				T K B // //   <http://www.attacklab.net/> // // // Wherever possible, Showdown is a straight, line-by-line port // of the Perl version of Markdown. // // This is not a normal parser design; it's basically just a // series of string substitutions.  It's hard to read and // maintain this way,  but keeping Showdown close to the original // design makes it easier to port new features. // // More importantly, Showdown behaves like markdown.pl in most // edge cases.  So web applications can do client-side preview // in Javascript, and then build identical HTML on the server. // // This port needs the new RegExp functionality of ECMA 262, // 3rd Edition (i.e. Javascript 1.5).  Most modern web browsers // should do fine.  Even with the new regular expression features, // We do a lot of work to emulate Perl's regex functionality. // The tricky changes in this file mostly have the "attacklab:" // label.  Major or self-explanatory changes don't. // // Smart diff tools like Araxis Merge will be able to match up // this file with markdown.pl in a useful way.  A little tweaking // helps: in a copy of markdown.pl, replace "#" with "//" and // replace "$text" with "text".  Be sure to ignore whitespace // and line endings. // // // Showdown usage: // //   var text = "Markdown *rocks*."; // //   var converter = new Showdown.converter(); //   var html = converter.makeHtml(text); // //   alert(html); // // Note: move the sample code to the bottom of this // file before uncommenting it. // // // Showdown namespace // var Showdown = {}; // // converter // // Wraps all "globals" so that the only thing // exposed is makeHtml(). // Showdown.converter = function() { // // Globals: // // Global hashes, used by various utility routines var g_urls; var g_titles; var g_html_blocks; // Used to track when we're inside an ordered or unordered list // (see _ProcessListItems() for details): var g_list_level = 0; this.makeHtml = function(text) { // // Main function. The order in which other subs are called here is // essential. Link and image substitutions need to happen before // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the  // and  tags get encoded. // // Clear the global hashes. If we don't clear these, you get conflicts // from other articles when generating a page which contains more than // one article (e.g. an index page that shows the N most recent // articles): g_urls = new Array(); g_titles = new Array(); g_html_blocks = new Array(); // attacklab: Replace ~ with ~T // This lets us use tilde as an escape char to avoid md5 hashes // The choice of character is arbitray; anything that isn't // magic in Markdown will work. text = text.replace(/~/g,"~T"); // attacklab: Replace $ with ~D // RegExp interprets $ as a special character // when it's in a replacement string text = text.replace(/$/g,"~D"); // Standardize line endings text = text.replace(/rn/g,"n"); // DOS to Unix text = text.replace(/r/g,"n"); // Mac to Unix // Make sure text begins and ends with a couple of newlines: text = "nn" + text + "nn"; // Convert all tabs to spaces. text = _Detab(text); // Strip any lines consisting only of spaces and tabs. // This makes subsequent regexen easier to write, because we can // match consecutive blank lines with /n+/ instead of something // contorted like /[ t]*n+/ . text = text.replace(/^[ t]+$/mg,""); // Turn block-level HTML blocks into hash entries text = _HashHTMLBlocks(text); // Strip link definitions, store in hashes. text = _StripLinkDefinitions(text); text = _RunBlockGamut(text); text = _UnescapeSpecialChars(text); // attacklab: Restore dollar signs text = text.replace(/~D/g,"$$"); // attacklab: Restore tildes text = text.replace(/~T/g,"~"); return text; } var _StripLinkDefinitions = function(text) { // // Strips link definitions from text, stores the URLs and titles in // hash references. // // Link defs are in the form: ^[id]: url "optional title" /* var text = text.replace(/ ^[ ]{0,3}[(.+)]:  // id = $1  attacklab: g_tab_width - 1 [ t]* n?				// maybe *one* newline [ t]* <?(S+?)>?			// url = $2 [ t]* n?				// maybe one newline [ t]* (?: (n*)				// any lines skipped = $3 attacklab: lookbehind removed ["(] (.+?)				// title = $4 [")] [ t]* )?					// title is optional (?:n+|$) /gm, function(){...}); */ var text = text.replace(/^[ ]{0,3}[(.+)]:[ t]*n?[ t]*<?(S+?)>?[ t]*n?[ t]*(?:(n*)["(](.+?)[")][ t]*)?(?:n+|Z)/gm, function (wholeMatch,m1,m2,m3,m4) { m1 = m1.toLowerCase(); g_urls[m1] = _EncodeAmpsAndAngles(m2);  // Link IDs are case-insensitive if (m3) { // Oops, found blank lines, so it's not a title. // Put back the parenthetical statement we stole. return m3+m4; } else if (m4) { g_titles[m1] = m4.replace(/"/g,"""); } // Completely remove the definition from the text return ""; } ); return text; } var _HashHTMLBlocks = function(text) { // attacklab: Double up blank lines to reduce lookaround text = text.replace(/n/g,"nn"); // Hashify HTML blocks: // We only want to do this for block-level HTML tags, such as headers, // lists, and tables. That's because we still want to wrap
s around // "paragraphs" that are wrapped in non-block-level tags, such as anchors, // phrase emphasis, and spans. The list of tags we're looking for is // hard-coded: var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del" var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" // First, look for nested blocks, e.g.: //
 //
 //     tags for inner block must be indented. //
 //
 // // The outermost tags must start at the left margin for this to match, and // the inner nested divs must be indented. // We need to do this before the next, more liberal match, because the next // match will start at the first `<div>` and stop at the first `</div>`. // attacklab: This regex can be expensive when it fails. /* var text = text.replace(/ (						// save in $1 ^					// start of line  (with /m) <($block_tags_a)	// start tag = $2 b					// word break // attacklab: hack around khtml/pcre bug... [^r]*?n			// any number of lines, minimally matching </2>				// the matching end tag [ t]*				// trailing spaces/tabs (?=n+)				// followed by a newline )						// attacklab: there are sentinel newlines at end of document /gm,function(){...}}; */ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)b[^r]*?n</2>[ t]*(?=n+))/gm,hashElement); // // Now match more liberally, simply from `n<tag>` to `</tag>n` // /* var text = text.replace(/ (						// save in $1 ^					// start of line  (with /m) <($block_tags_b)	// start tag = $2 b					// word break // attacklab: hack around khtml/pcre bug... [^r]*?				// any number of lines, minimally matching .*</2>				// the matching end tag [ t]*				// trailing spaces/tabs (?=n+)				// followed by a newline )						// attacklab: there are sentinel newlines at end of document /gm,function(){...}}; */ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)b[^r]*?.*</2>[ t]*(?=n+)n)/gm,hashElement); // Special case just for
. It was easier to make a special case than // to make the other regex more complicated. /* text = text.replace(/ (						// save in $1 nn				// Starting after a blank line [ ]{0,3} (<(hr)				// start tag = $2 b					// word break ([^<>])*?			// /?>)				// the matching end tag [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(n[ ]{0,3}(<(hr)b([^<>])*?/?>)[ t]*(?=n{2,}))/g,hashElement); // Special case for standalone HTML comments: /* text = text.replace(/ (						// save in $1 nn				// Starting after a blank line [ ]{0,3}			// attacklab: g_tab_width - 1 <! (--[^r]*?--s*)+ > [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(nn[ ]{0,3}<!(--[^r]*?--s*)+>[ t]*(?=n{2,}))/g,hashElement); // PHP and ASP-style processor instructions (<?...?> and <%...%>) /* text = text.replace(/ (?: nn				// Starting after a blank line ) (						// save in $1 [ ]{0,3}			// attacklab: g_tab_width - 1 (?: <([?%])			// $2 [^r]*? 2> ) [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(?:nn)([ ]{0,3}(?:<([?%])[^r]*?2>)[ t]*(?=n{2,}))/g,hashElement); // attacklab: Undo double lines (see comment at top of this function) text = text.replace(/nn/g,"n"); return text; } var hashElement = function(wholeMatch,m1) { var blockText = m1; // Undo double lines blockText = blockText.replace(/nn/g,"n"); blockText = blockText.replace(/^n/,""); // strip trailing blank lines blockText = blockText.replace(/n+$/g,""); // Replace the element text with a marker ("~KxK" where x is its key) blockText = "nn~K" + (g_html_blocks.push(blockText)-1) + "Knn"; return blockText; }; var _RunBlockGamut = function(text) { // // These are all the transformations that form block-level // tags like paragraphs, headers, and list items. // text = _DoHeaders(text); // Do Horizontal Rules: var key = hashBlock("
"); text = text.replace(/^[ ]{0,2}([ ]?*[ ]?){3,}[ t]*$/gm,key); text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ t]*$/gm,key); text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ t]*$/gm,key); text = _DoLists(text); text = _DoCodeBlocks(text); text = _DoBlockQuotes(text); // We already ran _HashHTMLBlocks() before, in Markdown(), but that // was to escape raw HTML in the original Markdown source. This time, // we're escaping the markup we've just created, so that we don't wrap //
 tags around block-level tags. text = _HashHTMLBlocks(text); text = _FormParagraphs(text); return text; } var _RunSpanGamut = function(text) { // // These are all the transformations that occur *within* block-level // tags like paragraphs, headers, and list items. // text = _DoCodeSpans(text); text = _EscapeSpecialCharsWithinTagAttributes(text); text = _EncodeBackslashEscapes(text); // Process anchor and image tags. Images must come first, // because ![foo][f] looks like an anchor. text = _DoImages(text); text = _DoAnchors(text); // Make links out of things like `<http://example.com/>` // Must come after _DoAnchors(), because you can use < and > // delimiters in inline links like [this](<url>). text = _DoAutoLinks(text); text = _EncodeAmpsAndAngles(text); text = _DoItalicsAndBold(text); // Do hard breaks: text = text.replace(/  +n/g,"
n"); return text; } var _EscapeSpecialCharsWithinTagAttributes = function(text) { // // Within tags -- meaning between < and > -- encode [ ` * _] so they // don't conflict with their use in Markdown for code, italics and strong. // // Build a regex to find HTML tags and comments.  See Friedl's // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. var regex = /(<[a-z/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--s*)+>)/gi; text = text.replace(regex, function(wholeMatch) { var tag = wholeMatch.replace(/(.)</?code>(?=.)/g,"$1`"); tag = escapeCharacters(tag,"`*_"); return tag; }); return text; } var _DoAnchors = function(text) { // // Turn Markdown link shortcuts into XHTML  tags. // // // First, handle reference-style links: [link text] [id] // /* text = text.replace(/ (							// wrap whole match in $1 [ ( (?: [[^]]*]		// allow brackets nested one level | [^[]			// or anything else )* ) ] [ ]?					// one optional space (?:n[ ]*)?				// one optional newline followed by spaces [ (.*?)					// id = $3 ] )()()()()					// pad remaining backreferences /g,_DoAnchors_callback); */ text = text.replace(/([((?:[[^]]*]|[^[]])*)][ ]?(?:n[ ]*)?[(.*?)])()()()()/g,writeAnchorTag); // // Next, inline-style links: [link text](url "optional title") // /* text = text.replace(/ (						// wrap whole match in $1 [ ( (?: [[^]]*]	// allow brackets nested one level | [^[]]			// or anything else ) ) ] (						// literal paren [ t]* ()						// no id, so leave $3 empty <?(.*?)>?				// href = $4 [ t]* (						// $5 (['"])				// quote char = $6 (.*?)				// Title = $7 6					// matching quote [ t]*				// ignore any spaces/tabs between closing quote and ) )?						// title is optional ) ) /g,writeAnchorTag); */ text = text.replace(/([((?:[[^]]*]|[^[]])*)]([ t]*()<?(.*?)>?[ t]*((['"])(.*?)6[ t]*)?))/g,writeAnchorTag); // // Last, handle reference-style shortcuts: [link text] // These must come last in case you've also got [link test][1] // or [link test](/foo) // /* text = text.replace(/ (		 					// wrap whole match in $1 [ ([^[]]+)				// link text = $2; can't contain '[' or ']' ] )()()()()()					// pad rest of backreferences /g, writeAnchorTag); */ text = text.replace(/([([^[]]+)])()()()()()/g, writeAnchorTag); return text; } var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { if (m7 == undefined) m7 = ""; var whole_match = m1; var link_text   = m2; var link_id	 = m3.toLowerCase(); var url		= m4; var title	= m7; if (url == "") { if (link_id == "") { // lower-case and turn embedded newlines into spaces link_id = link_text.toLowerCase().replace(/ ?n/g," "); } url = "#"+link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } } else { if (whole_match.search(/(s*)$/m)>-1) { // Special case for explicit empty url url = ""; } else { return whole_match; } } } url = escapeCharacters(url,"*_"); var result = "" + link_text + ""; return result; } var _DoImages = function(text) { // // Turn Markdown image shortcuts into  tags. // // // First, handle reference-style labeled images: ![alt text][id] // /* text = text.replace(/ (						// wrap whole match in $1 ![ (.*?)				// alt text = $2 ] [ ]?				// one optional space (?:n[ ]*)?			// one optional newline followed by spaces [ (.*?)				// id = $3 ] )()()()()				// pad rest of backreferences /g,writeImageTag); */ text = text.replace(/(![(.*?)][ ]?(?:n[ ]*)?[(.*?)])()()()()/g,writeImageTag); // // Next, handle inline images:  ![alt text](url "optional title") // Don't forget: encode * and _ /* text = text.replace(/ (						// wrap whole match in $1 ![ (.*?)				// alt text = $2 ] s?					// One optional whitespace character (					// literal paren [ t]* ()					// no id, so leave $3 empty <?(S+?)>?			// src url = $4 [ t]* (					// $5 (['"])			// quote char = $6 (.*?)			// title = $7 6				// matching quote [ t]* )?					// title is optional ) ) /g,writeImageTag); */ text = text.replace(/(![(.*?)]s?([ t]*()<?(S+?)>?[ t]*((['"])(.*?)6[ t]*)?))/g,writeImageTag); return text; } var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { var whole_match = m1; var alt_text   = m2; var link_id	 = m3.toLowerCase(); var url		= m4; var title	= m7; if (!title) title = ""; if (url == "") { if (link_id == "") { // lower-case and turn embedded newlines into spaces link_id = alt_text.toLowerCase().replace(/ ?n/g," "); } url = "#"+link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } } else { return whole_match; } } alt_text = alt_text.replace(/"/g,"""); url = escapeCharacters(url,"*_"); var result = ""; return result; } var _DoHeaders = function(text) { // Setext-style headers: //	Header 1 //	======== // //	Header 2 //	-------- // text = text.replace(/^(.+)[ t]*n=+[ t]*n+/gm, function(wholeMatch,m1){return hashBlock('
' + _RunSpanGamut(m1) + "
");}); text = text.replace(/^(.+)[ t]*n-+[ t]*n+/gm, function(matchFound,m1){return hashBlock('
' + _RunSpanGamut(m1) + "
");}); // atx-style headers: //  # Header 1 //  ## Header 2 //  ## Header 2 with closing hashes ## //  ... //  ###### Header 6 // /* text = text.replace(/ ^(#{1,6})				// $1 = string of #'s [ t]* (.+?)					// $2 = Header text [ t]* #*						// optional closing #'s (not counted) n+ /gm, function() {...}); */ text = text.replace(/^(#{1,6})[ t]*(.+?)[ t]*#*n+/gm, function(wholeMatch,m1,m2) { var h_level = m1.length; return hashBlock("<h" + h_level + ' id="' + headerId(m2) + '">' + _RunSpanGamut(m2) + "</h" + h_level + ">"); }); function headerId(m) { return m.replace(/[^w]/g, '').toLowerCase(); } return text; } // This declaration keeps Dojo compressor from outputting garbage: var _ProcessListItems; var _DoLists = function(text) { // // Form HTML ordered (numbered) and unordered (bulleted) lists. // // attacklab: add sentinel to hack around khtml/safari bug: // http://bugs.webkit.org/show_bug.cgi?id=11231 text += "~0"; // Re-usable pattern to match any entirel ul or ol list: /* var whole_list = / (									// $1 = whole list (								// $2 [ ]{0,3}					// attacklab: g_tab_width - 1 ([*+-]|d+[.])				// $3 = first list item marker [ t]+ ) [^r]+? (								// $4 ~0							// sentinel for workaround; should be $ | n{2,} (?=S) (?!							// Negative lookahead for another list item marker [ t]* (?:[*+-]|d+[.])[ t]+ ) ) )/g */ var whole_list = /^(([ ]{0,3}([*+-]|d+[.])[ t]+)[^r]+?(~0|n{2,}(?=S)(?![ t]*(?:[*+-]|d+[.])[ t]+)))/gm; if (g_list_level) { text = text.replace(whole_list,function(wholeMatch,m1,m2) { var list = m1; var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol"; // Turn double returns into triple returns, so that we can make a // paragraph for the last item in a list, if necessary: list = list.replace(/n{2,}/g,"nnn");; var result = _ProcessListItems(list); // Trim any trailing whitespace, to put the closing `</$list_type>` // up on the preceding line, to get it past the current stupid // HTML block parser. This is a hack to work around the terrible // hack that is the HTML block parser. result = result.replace(/s+$/,""); result = "<"+list_type+">" + result + "</"+list_type+">n"; return result; }); } else { whole_list = /(nn|^n?)(([ ]{0,3}([*+-]|d+[.])[ t]+)[^r]+?(~0|n{2,}(?=S)(?![ t]*(?:[*+-]|d+[.])[ t]+)))/g; text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) { var runup = m1; var list = m2; var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol"; // Turn double returns into triple returns, so that we can make a // paragraph for the last item in a list, if necessary: var list = list.replace(/n{2,}/g,"nnn");; var result = _ProcessListItems(list); result = runup + "<"+list_type+">n" + result + "</"+list_type+">n"; return result; }); } // attacklab: strip sentinel text = text.replace(/~0/,""); return text; } _ProcessListItems = function(list_str) { // //  Process the contents of a single ordered or unordered list, splitting it //  into individual list items. // // The $g_list_level global keeps track of when we're inside a list. // Each time we enter a list, we increment it; when we leave a list, // we decrement. If it's zero, we're not in a list anymore. // // We do this because when we're not inside a list, we want to treat // something like this: // //    I recommend upgrading to version //    8. Oops, now this line is treated //    as a sub-list. // // As a single paragraph, despite the fact that the second line starts // with a digit-period-space sequence. // // Whereas when we're inside a list (or sub-list), that line will be // treated as the start of a sub-list. What a kludge, huh? This is // an aspect of Markdown's syntax that's hard to parse perfectly // without resorting to mind-reading. Perhaps the solution is to // change the syntax rules such that sub-lists must start with a // starting cardinal number; e.g. "1." or "a.". g_list_level++; // trim trailing blank lines: list_str = list_str.replace(/n{2,}$/,"n"); // attacklab: add sentinel to emulate z list_str += "~0"; /* list_str = list_str.replace(/ (n)?							// leading line = $1 (^[ t]*)						// leading whitespace = $2 ([*+-]|d+[.]) [ t]+			// list marker = $3 ([^r]+?						// list item text   = $4 (n{1,2})) (?= n* (~0 | 2 ([*+-]|d+[.]) [ t]+)) /gm, function(){...}); */ list_str = list_str.replace(/(n)?(^[ t]*)([*+-]|d+[.])[ t]+([^r]+?(n{1,2}))(?=n*(~0|2([*+-]|d+[.])[ t]+))/gm, function(wholeMatch,m1,m2,m3,m4){ var item = m4; var leading_line = m1; var leading_space = m2; if (leading_line || (item.search(/n{2,}/)>-1)) { item = _RunBlockGamut(_Outdent(item)); } else { // Recursion for sub-lists: item = _DoLists(_Outdent(item)); item = item.replace(/n$/,""); // chomp(item) item = _RunSpanGamut(item); } return  "
" + item + "
n"; } ); // attacklab: strip sentinel list_str = list_str.replace(/~0/g,""); g_list_level--; return list_str; } var _DoCodeBlocks = function(text) { // //  Process Markdown `<pre><code>` blocks. // /* text = text.replace(text, /(?:nn|^) (								// $1 = the code block -- one or more lines, starting with a space/tab (?: (?:[ ]{4}|t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width .*n+ )+ ) (n*[ ]{0,3}[^ tn]|(?=~0))	// attacklab: g_tab_width /g,function(){...}); */ // attacklab: sentinel workarounds for lack of A and Z, safarikhtml bug text += "~0"; text = text.replace(/(?:nn|^)((?:(?:[ ]{4}|t).*n+)+)(n*[ ]{0,3}[^ tn]|(?=~0))/g, function(wholeMatch,m1,m2) { var codeblock = m1; var nextChar = m2; codeblock = _EncodeCode( _Outdent(codeblock)); codeblock = _Detab(codeblock); codeblock = codeblock.replace(/^n+/g,""); // trim leading newlines codeblock = codeblock.replace(/n+$/g,""); // trim trailing whitespace codeblock = "
" + codeblock + "n
"; return hashBlock(codeblock) + nextChar; } ); // attacklab: strip sentinel text = text.replace(/~0/,""); return text; } var hashBlock = function(text) { text = text.replace(/(^n+|n+$)/g,""); return "nn~K" + (g_html_blocks.push(text)-1) + "Knn"; } var _DoCodeSpans = function(text) { // //   *  Backtick quotes are used for  spans. // //   *  You can use multiple backticks as the delimiters if you want to //	 include literal backticks in the code span. So, this input: // //		 Just type ``foo `bar` baz`` at the prompt. // //	   Will translate to: // //
Just type foo `bar` baz at the prompt.
 // //	There's no arbitrary limit to the number of backticks you //	can use as delimters. If you need three consecutive backticks //	in your code, use four for delimiters, etc. // //  *  You can use spaces to get literal backticks at the edges: // //		 ... type `` `bar` `` ... // //	   Turns to: // //		 ... type `bar` ... // /* text = text.replace(/ (^|[^])					// Character before opening ` can't be a backslash (`+)						// $2 = Opening run of ` (							// $3 = The code block [^r]*? [^`]					// attacklab: work around lack of lookbehind ) 2							// Matching closer (?!`) /gm, function(){...}); */ text = text.replace(/(^|[^])(`+)([^r]*?[^`])2(?!`)/gm, function(wholeMatch,m1,m2,m3,m4) { var c = m3; c = c.replace(/^([ t]*)/g,"");	// leading whitespace c = c.replace(/[ t]*$/g,"");	// trailing whitespace c = _EncodeCode(c); return m1+""+c+""; }); return text; } var _EncodeCode = function(text) { // // Encode/escape certain characters inside Markdown code runs. // The point is that in code, these characters are literals, // and lose their special Markdown meanings. // // Encode all ampersands; HTML entities are not // entities within a Markdown code span. text = text.replace(/&/g,"&"); // Do the angle bracket song and dance: text = text.replace(/</g,"<"); text = text.replace(/>/g,">"); // Now, escape characters that are magic in Markdown: text = escapeCharacters(text,"*_{}[]",false); // jj the line above breaks this: //--- //* Item //   1. Subitem //            special char: * //--- return text; } var _DoItalicsAndBold = function(text) { //  must go first: text = text.replace(/(**|__)(?=S)([^r]*?S[*_]*)1/g, "$2"); text = text.replace(/(*|_)(?=S)([^r]*?S)1/g, "$2"); return text; } var _DoBlockQuotes = function(text) { /* text = text.replace(/ (								// Wrap whole match in $1 ( ^[ t]*>[ t]?			// '>' at the start of a line .+n					// rest of the first line (.+n)*					// subsequent consecutive lines n*						// blanks )+ ) /gm, function(){...}); */ text = text.replace(/((^[ t]*>[ t]?.+n(.+n)*n*)+)/gm, function(wholeMatch,m1) { var bq = m1; // attacklab: hack around Konqueror 3.5.4 bug: // "----------bug".replace(/^-/g,"") == "bug" bq = bq.replace(/^[ t]*>[ t]?/gm,"~0");	// trim one level of quoting // attacklab: clean up hack bq = bq.replace(/~0/g,""); bq = bq.replace(/^[ t]+$/gm,"");		// trim whitespace-only lines bq = _RunBlockGamut(bq);				// recurse bq = bq.replace(/(^|n)/g,"$1  "); // These leading spaces screw with
 content, so we need to fix that: bq = bq.replace( /(s*
[^r]+?
)/gm, function(wholeMatch,m1) { var pre = m1; // attacklab: hack around Konqueror 3.5.4 bug: pre = pre.replace(/^  /mg,"~0"); pre = pre.replace(/~0/g,""); return pre; }); return hashBlock("
n" + bq + "n
"); }); return text; } var _FormParagraphs = function(text) { // //  Params: //    $text - string to process with html
 tags // // Strip leading and trailing lines: text = text.replace(/^n+/g,""); text = text.replace(/n+$/g,""); var grafs = text.split(/n{2,}/g); var grafsOut = new Array(); // // Wrap
 tags. // var end = grafs.length; for (var i=0; i<end; i++) { var str = grafs[i]; // if this is an HTML marker, copy it if (str.search(/~K(d+)K/g) >= 0) { grafsOut.push(str); } else if (str.search(/S/) >= 0) { str = _RunSpanGamut(str); str = str.replace(/^([ t]*)/g,"
"); str += "
" grafsOut.push(str); } } // // Unhashify HTML blocks // end = grafsOut.length; for (var i=0; i<end; i++) { // if this is a marker for an html block... while (grafsOut[i].search(/~K(d+)K/) >= 0) { var blockText = g_html_blocks[RegExp.$1]; blockText = blockText.replace(/$/g,"$$$$"); // Escape any dollar signs grafsOut[i] = grafsOut[i].replace(/~Kd+K/,blockText); } } return grafsOut.join("nn"); } var _EncodeAmpsAndAngles = function(text) { // Smart processing for ampersands and angle brackets that need to be encoded. // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: //   http://bumppo.net/projects/amputator/ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|w+);)/g,"&"); // Encode naked <'s text = text.replace(/<(?![a-z/?$!])/gi,"<"); return text; } var _EncodeBackslashEscapes = function(text) { // //   Parameter:  String. //   Returns:	The string, with after processing the following backslash //			   escape sequences. // // attacklab: The polite way to do this is with the new // escapeCharacters() function: // // 	text = escapeCharacters(text,"",true); // 	text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); // // ...but we're sidestepping its use of the (slow) RegExp constructor // as an optimization for Firefox.  This function gets called a LOT. text = text.replace(/()/g,escapeCharacters_callback); text = text.replace(/([`*_{}[]()>#+-.!])/g,escapeCharacters_callback); return text; } var _DoAutoLinks = function(text) { text = text.replace(/<((https?|ftp|dict):[^'">s]+)>/gi,"$1"); // Email addresses: <address@domain.foo> /* text = text.replace(/ < (?:mailto:)? ( [-.w]+ @ [-a-z0-9]+(.[-a-z0-9]+)*.[a-z]+ ) > /gi, _DoAutoLinks_callback()); */ text = text.replace(/<(?:mailto:)?([-.w]+@[-a-z0-9]+(.[-a-z0-9]+)*.[a-z]+)>/gi, function(wholeMatch,m1) { return _EncodeEmailAddress( _UnescapeSpecialChars(m1) ); } ); return text; } var _EncodeEmailAddress = function(addr) { // //  Input: an email address, e.g. "foo@example.com" // //  Output: the email address as a mailto link, with each character //	of the address encoded as either a decimal or hex entity, in //	the hopes of foiling most address harvesting spam bots. E.g.: // //	foo //	   @example.com // //  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk //  mailing list: <http://tinyurl.com/yu7ue> // // attacklab: why can't javascript speak hex? function char2hex(ch) { var hexDigits = '0123456789ABCDEF'; var dec = ch.charCodeAt(0); return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15)); } var encode = [ function(ch){return "&#"+ch.charCodeAt(0)+";";}, function(ch){return "&#x"+char2hex(ch)+";";}, function(ch){return ch;} ]; addr = "mailto:" + addr; addr = addr.replace(/./g, function(ch) { if (ch == "@") { // this *must* be encoded. I insist. ch = encode[Math.floor(Math.random()*2)](ch); } else if (ch !=":") { // leave ':' alone (to spot mailto: later) var r = Math.random(); // roughly 10% raw, 45% hex, 45% dec ch =  ( r > .9  ?	encode[2](ch)   : r > .45 ?	encode[1](ch)   : encode[0](ch) ); } return ch; }); addr = "" + addr + ""; addr = addr.replace(/">.+:/g,"">"); // strip the mailto: from the visible part return addr; } var _UnescapeSpecialChars = function(text) { // // Swap back in all the special characters we've hidden. // text = text.replace(/~E(d+)E/g, function(wholeMatch,m1) { var charCodeToReplace = parseInt(m1); return String.fromCharCode(charCodeToReplace); } ); return text; } var _Outdent = function(text) { // // Remove one level of line-leading tabs or spaces // // attacklab: hack around Konqueror 3.5.4 bug: // "----------bug".replace(/^-/g,"") == "bug" text = text.replace(/^(t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width // attacklab: clean up hack text = text.replace(/~0/g,"") return text; } var _Detab = function(text) { // attacklab: Detab's completely rewritten for speed. // In perl we could fix it by anchoring the regexp with G. // In javascript we're less fortunate. // expand first n-1 tabs text = text.replace(/t(?=t)/g,"    "); // attacklab: g_tab_width // replace the nth with two sentinels text = text.replace(/t/g,"~A~B"); // use the sentinel to anchor our regex so it doesn't explode text = text.replace(/~B(.+?)~A/g, function(wholeMatch,m1,m2) { var leadingText = m1; var numSpaces = 4 - leadingText.length % 4;  // attacklab: g_tab_width // there *must* be a better way to do this: for (var i=0; i<numSpaces; i++) leadingText+=" "; return leadingText; } ); // clean up sentinels text = text.replace(/~A/g,"    ");  // attacklab: g_tab_width text = text.replace(/~B/g,""); return text; } // //  attacklab: Utility functions // var escapeCharacters = function(text, charsToEscape, afterBackslash) { // First we have to escape the escape characters so that // we can build a character class out of them var regexString = "([" + charsToEscape.replace(/([[]])/g,"$1") + "])"; if (afterBackslash) { regexString = "" + regexString; } var regex = new RegExp(regexString,"g"); text = text.replace(regex,escapeCharacters_callback); return text; } var escapeCharacters_callback = function(wholeMatch,m1) { var charCodeToEscape = m1.charCodeAt(0); return "~E"+charCodeToEscape+"E"; } } // end of Showdown.converter // export if (typeof exports != 'undefined') exports.Showdown = Showdown;   No newline at end of file


Question: : emptyObject; const instance = new ctor(props, context); adoptClassInstance(workInProgress, instance); <del> checkClassInstance(workInProgress); </del> // Cache unmasked context so we can avoid recreating masked context unless necessary. // ReactFiberContext usually updates this cache but can't for newly-created instances.

Follow up from Here's one I found. These two invariants: are in a function that's behind a DEV block: I don't think this is intentional, but need to verify. There may be more. I'll use this issue to track while preserves existing behavior.
Here’s another difference: in development, putting a string ref on a functional component throws with: Stateless function components cannot have refs. but in production gives you: Element ref was specified as a string but no owner was set.


Question: that support `*.tmLanguage`. * Linting provides accurate line numbers after compiling without sourcemaps. * Elements use standard scoping so linters can find usage of out-of-scope components. <ins> ### Debugging [React Developer Tools](https://github.com/facebook/react-devtools) is a [Chrome extension](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) that allows you to inspect the React component hierarchy in the Chrome Developer Tools. </ins>

I don't know where the right place to link to them is. Maybe "Getting started", "Tutorial" and "Tooling integration"?


Question: } export function createLaneMap<T>(initial: T): LaneMap<T> { <del> return new Array(TotalLanes).fill(initial); </del> <ins> // Intentionally pushing one by one. // https://v8.dev/blog/elements-kinds#avoid-creating-holes const laneMap = []; for (let i = 0; i < TotalLanes; i++) { laneMap.push(initial); } return laneMap; </ins> } export function markRootUpdated(

After updating react-dom to version 17 the build now includes () which isn't supported by ie11 without polyfilling. Coming from this line. Tested with just the default cra production build to make sure it wasn't a problem with my webpack config and the same issue. Tested using CRA on version 16.9.8 of react and react-dom which works with the production build for ie11.
Confirmed with https://csb-hznfc- (built from ) which errors with "SCRIPT438: Object doesn't support property or method 'fill'".
Any chance you could confirm the fix on a real IE
Gonna wait to see if a few more bugs get reported in the next few hours. Then will cut a patch.
Should be fixed in 17.0.1.


Question: echo "Only docs were updated, stopping build process." exit fi <del> npm install -g npm </del> <ins> npm install -g npm@latest-2 </ins> script: - | if [ "$TEST_TYPE" = build_website ]; then


Question: echo "Only docs were updated, stopping build process." exit fi <del> npm install -g npm </del> <ins> npm install -g npm@latest-2 </ins> script: - | if [ "$TEST_TYPE" = build_website ]; then


Question: echo "Only docs were updated, stopping build process." exit fi <del> npm install -g npm </del> <ins> npm install -g npm@latest-2 </ins> script: - | if [ "$TEST_TYPE" = build_website ]; then


Question: var Component = this._currentElement.type; // Initialize the public class <del> var inst; </del> <ins> var inst = this._constructComponent(publicProps, publicContext); </ins> var renderedElement; <del> if (Component.prototype && Component.prototype.isReactComponent) { if (__DEV__) { ReactCurrentOwner.current = this; try { inst = new Component(publicProps, publicContext, ReactUpdateQueue); } finally { ReactCurrentOwner.current = null; } } else { inst = new Component(publicProps, publicContext, ReactUpdateQueue); } } else { if (__DEV__) { ReactCurrentOwner.current = this; try { inst = Component(publicProps, publicContext, ReactUpdateQueue); } finally { ReactCurrentOwner.current = null; } } else { inst = Component(publicProps, publicContext, ReactUpdateQueue); } if (inst == null || inst.render == null) { renderedElement = inst; warnIfInvalidElement(Component, renderedElement); invariant( inst === null || inst === false || ReactElement.isValidElement(inst), '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component' ); inst = new StatelessComponent(Component); } </del> <ins> // Support functional components if (!shouldConstruct(Component) && (inst == null || inst.render == null)) { renderedElement = inst; warnIfInvalidElement(Component, renderedElement); invariant( inst === null || inst === false || ReactElement.isValidElement(inst), '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component' ); inst = new StatelessComponent(Component); </ins> } if (__DEV__) {


Question: items: - id: flux-overview title: Flux Overview <ins> href: http://facebook.github.io/flux/docs/overview.html </ins> - id: flux-todo-list title: Flux TodoMVC Tutorial <ins> href: http://facebook.github.io/flux/docs/todo-list.html </ins>

We're basically keeping 2 copies of documentation in sync and failing. We should just point at and We should maybe make the permalinks on our site redirect or just link offsite. We should also look for links in our docs pointing to those pages and update.
cc
also cc
Definitively agreed, we should link all the traffic to the dedicated website. See the Complementary section on Flux website


Question: const Resolved = 2; const Rejected = 3; <del> type EmptyRecord<K, V> = {| </del> <ins> type EmptyRecord<K> = {| </ins> status: 0, suspender: null, key: K, value: null, error: null, <del> next: Record<K, V> | null, previous: Record<K, V> | null, </del> <ins> next: any, // TODO: (issue #12941) previous: any, // TODO: (issue #12941) /** * Proper types would be something like this: * next: Record<K, V> | null, * previous: Record<K, V> | null, */ </ins> |}; type PendingRecord<K, V> = {| status: 1, <del> suspender: Promise<K, V>, </del> <ins> suspender: Promise<V>, </ins> key: K, value: null, error: null, <del> next: Record<K, V> | null, previous: Record<K, V> | null, </del> <ins> next: any, // TODO: (issue #12941) previous: any, // TODO: (issue #12941) /** * Proper types would be something like this: * next: Record<K, V> | null, * previous: Record<K, V> | null, */ </ins> |}; type ResolvedRecord<K, V> = {|


Question: export const enableSelectiveHydration = false; export const enableChunksAPI = false; export const exposeConcurrentModeAPIs = __EXPERIMENTAL__; <del> export const warnAboutShorthandPropertyCollision = false; </del> <ins> export const warnAboutShorthandPropertyCollision = true; </ins> export const enableSchedulerDebugging = false; export const debugRenderPhaseSideEffectsForStrictMode = true; export const disableJavaScriptURLs = false;

I a "bug" today that made me spent 1h figuring out what was going on: I'm using an external component that accepts a prop in order to set the of the root element, but this same component also accepts a prop which I wasn't passing, and by default, it was set to . The result: React didn't throw an error nor a warning, however, the resulting element in the DOM didn't contain either or , and since the element had a default coming from a CSS class, it took me a while to figure out why the color that I was passing wasn't being applied, and instead it was using the one from the CSS class. See: What I reported above was the case. I other cases as a bonus, as when I was playing with this they also seemed weird to me. On I define the same properties, but because I change the order, it works. On the toggleable ones, initially I can see the background, but after changing it never appears anymore. I'm not sure if I created those extra "test cases" correctly. My main concern is really around static1 not outputting anything on the console as a warning. Related issues: I wonder if ( should have covered this?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution.
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!
it seems that the bot automatically closed the issue, but this still needs action. I took a time to investigate it, and I realized that the work Sophie has done covers this case, but there's just one problem: it's disabled under a . I built it locally and flipped the flag, and it works: I can see the helpful warning. It was flagged in , and as per the PR, the original intention was to unflag it on the next minor. Since then we had at least 4 new minor versions, but it is still flagged. Is there a special reason for that or was it just forgotten? tagging you since you this flag, so I'm hoping you can give context here.
Can we unflag this?
This was released.


Question: --- id: flux-todo-list title: Flux TodoMVC Tutorial <del> prev: flux-overview.html </del> --- <del> To demonstrate the Flux architecture with some example code, let's take on the classic TodoMVC application. The entire application is available in the Flux GitHub repo within the [flux-todomvc](https://github.com/facebook/flux/tree/master/examples/flux-todomvc) example directory, but let's walk through the development of it a step at a time. To begin, we'll need some boilerplate and get up and running with a module system. Node's module system, based on CommonJS, will fit the bill very nicely and we can build off of [react-boilerplate](https://github.com/petehunt/react-boilerplate) to get up and running quickly. Assuming you have npm installed, simply clone the react-boilerplate code from GitHub, and navigate into the resulting directory in Terminal (or whatever CLI application you like). Next run the npm scripts to get up and running: `npm install`, then `npm run build`, and lastly `npm start` to continuously build using Browserify. The TodoMVC example has all this built into it as well, but if you're starting with react-boilerplate make sure you edit your package.json file to match the file structure and dependencies described in the TodoMVC example's [package.json](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/package.json), or else your code won't match up with the explanations below. Source Code Structure --------------------- The resulting index.js file may be used as the entry point into our app, but we'll put most of our code in a 'js' directory. Let's let Browserify do its thing, and now we'll open a new tab in Terminal (or a GUI file browser) to look at the directory. It should look something like this: ``` myapp | + ... + js | + app.js + bundle.js // generated by Browserify whenever we make changes. + index.html + ... ``` Next we'll dive into the js directory, and layout our application's primary directory structure: ``` myapp | + ... + js | + actions + components // all React components, both views and controller-views + constants + dispatcher + stores + app.js + bundle.js + index.html + ... ``` Using the Dispatcher -------------------- We'll use the dispatcher from the [Flux GitHub repository](https://github.com/facebook/flux), but let's go over how to get it into our project, how it works and how we'll use it. The dispatcher's source code is written in [ECMAScript 6](https://github.com/lukehoban/es6features), the future version of JavaScript.  To use the future of JS in today's browser's we need to transpile it back to a version of JS that browsers can use.  We perform this build step, transpiling from ES6 into common JavaScript, using npm. You can get up and running with the dispatcher in a variety of ways, but perhaps the simplest is to use [Michael Jackson](https://twitter.com/mjackson)'s npm module version of the Flux project, called [react-dispatcher](https://www.npmjs.org/package/react-dispatcher): ``` npm install react-dispatcher ``` Afterward, you can require the dispatcher in your project's modules like so: ```javascript var Dispatcher = require('Flux').Dispatcher; ``` Alternatively, you can clone the Flux repo, run the Gulp-based build script with `npm install`, and then simply copy the dispatcher and invariant modules located inside flux/lib/ to the dispatcher directory for your project.  This the what we did in the [example code](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/js/dispatcher). The two most important methods that the dispatcher exposes publically are register() and dispatch().  We'll use register() within our stores to register each store's callback. We'll use dispatch() within our action creators to trigger the invocation of the callbacks. ```javascript class Dispatcher { constructor() { this._callbacks = {}; this._isPending = {}; this._isHandled = {}; this._isDispatching = false; this._pendingPayload = null; } /** * Registers a callback to be invoked with every dispatched payload. * * @param {function} callback * @return {string} */ register(callback) { var id = _prefix + _lastID++; this._callbacks[id] = callback; return id; } // ... /** * Dispatches a payload to all registered callbacks. * * @param {object} payload */ dispatch(payload) { invariant( !this._isDispatching, 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.' ); this._startDispatching(payload); try { for (var id in this._callbacks) { if (this._isPending[id]) { continue; } this._invokeCallback(id); } } finally { this._stopDispatching(); } } // ... _invokeCallback(id) { this._isPending[id] = true; this._callbacks[id](this._pendingPayload); this._isHandled[id] = true; } _startDispatching(payload) { for (var id in this._callbacks) { this._isPending[id] = false; this._isHandled[id] = false; } this._pendingPayload = payload; this._isDispatching = true; } _stopDispatching() { this._pendingPayload = null; this._isDispatching = false; } } ``` Now we are all set to create a dispatcher that is more specific to our app, which we'll call AppDispatcher. ```javascript var Dispatcher = require('./Dispatcher'); var merge = require('react/lib/merge'); var AppDispatcher = merge(Dispatcher.prototype, { /** * A bridge function between the views and the dispatcher, marking the action * as a view action.  Another variant here could be handleServerAction. * @param {object} action The data coming from the view. */ handleViewAction: function(action) { this.dispatch({ source: 'VIEW_ACTION', action: action }); } }); module.exports = AppDispatcher; ``` Now we've created an implementation that is a bit more specific to our needs, with a helper function we can use when we create actions. We might expand on this later to provide a separate helper for server updates, but for now this is all we need. You don't actually need to create an AppDispatcher in every application, but we wanted to show it here as an example.  The creation of the AppDispatcher allows us to extend the functionality of the Dispatcher.  In this application, for example, we have provided metadata about the source of the action outside of the action itself. Creating Stores ---------------- We can use Node's EventEmitter to get started with a store. We need EventEmitter to broadcast the 'change' event to our controller-views. So let's take a look at what that looks like. I've omitted some of the code for the sake of brevity, but for the full version see [TodoStore.js](https://github.com/Facebook/flux/blob/master/examples/flux-todomvc/js/stores/TodoStore.js) in the TodoMVC example code. ```javascript var AppDispatcher = require('../dispatcher/AppDispatcher'); var EventEmitter = require('events').EventEmitter; var TodoConstants = require('../constants/TodoConstants'); var merge = require('react/lib/merge'); var CHANGE_EVENT = 'change'; var _todos = {}; // collection of todo items /** * Create a TODO item. * @param {string} text The content of the TODO */ function create(text) { // Using the current timestamp in place of a real id. var id = Date.now(); _todos[id] = { id: id, complete: false, text: text }; } /** * Delete a TODO item. * @param {string} id */ function destroy(id) { delete _todos[id]; } var TodoStore = merge(EventEmitter.prototype, { /** * Get the entire collection of TODOs. * @return {object} */ getAll: function() { return _todos; }, emitChange: function() { this.emit(CHANGE_EVENT); }, /** * @param {function} callback */ addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, /** * @param {function} callback */ removeChangeListener: function(callback) { this.removeListener(CHANGE_EVENT, callback); }, dispatcherIndex: AppDispatcher.register(function(payload) { var action = payload.action; var text; switch(action.actionType) { case TodoConstants.TODO_CREATE: text = action.text.trim(); if (text !== '') { create(text); TodoStore.emitChange(); } break; case TodoConstants.TODO_DESTROY: destroy(action.id); TodoStore.emitChange(); break; // add more cases for other actionTypes, like TODO_UPDATE, etc. } return true; // No errors. Needed by promise in Dispatcher. }) }); module.exports = TodoStore; ``` There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from the outside. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action. Another important part is the registration of the store's callback with the dispatcher. We pass in our payload handling callback to the dispatcher and preserve the index that this store has in the dispatcher's registry. The callback function currently only handles two actionTypes, but later we can add as many as we need. Listening to Changes with a Controller-View ------------------------------------------- We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook's Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface. Here's one for our TodoMVC example. Again, this is slightly abbreviated, but for the full code you can take a look at the TodoMVC example's [TodoApp.react.js](https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/components/TodoApp.react.js) ```javascript /** @jsx React.DOM */ var Footer = require('./Footer.react'); var Header = require('./Header.react'); var MainSection = require('./MainSection.react'); var React = require('react'); var TodoStore = require('../stores/TodoStore'); function getTodoState() { return { allTodos: TodoStore.getAll() }; } var TodoApp = React.createClass({ getInitialState: function() { return getTodoState(); }, componentDidMount: function() { TodoStore.addChangeListener(this._onChange); }, componentWillUnmount: function() { TodoStore.removeChangeListener(this._onChange); }, /** * @return {object} */ render: function() { return ( <div> <Header /> <MainSection allTodos={this.state.allTodos} areAllComplete={this.state.areAllComplete} /> <Footer allTodos={this.state.allTodos} /> </div> ); }, _onChange: function() { this.setState(getTodoState()); } }); module.exports = TodoApp; ``` Now we're in our familiar React territory, utilizing React's lifecycle methods. We set up the initial state of this controller-view in getInitialState(), register an event listener in componentDidMount(), and then clean up after ourselves within componentWillUnmount(). We render a containing div and pass down the collection of states we got from the TodoStore. The Header component contains the primary text input for the application, but it does not need to know the state of the store. The MainSection and Footer do need this data, so we pass it down to them. More Views ---------- At a high level, the React component hierarchy of the app looks like this: ```javascript <TodoApp> <Header> <TodoTextInput /> <MainSection> <ul> <TodoItem /> </ul> </MainSection> </Header> </TodoApp> ``` If a TodoItem is in edit mode, it will also render a TodoTextInput as a child. Let's take a look at how some of these components display the data they receive as props, and how they communicate through actions with the dispatcher. The MainSection needs to iterate over the collection of to-do items it received from TodoApp to create the list of TodoItems. In the component's render() method, we can do that iteration like so: ```javascript var allTodos = this.props.allTodos; for (var key in allTodos) { todos.push(<TodoItem key={key} todo={allTodos[key]} />); } return ( <section id="main"> <ul id="todo-list">{todos}</ul> </section> ); ``` Now each TodoItem can display its own text, and perform actions utilizing its own ID. Explaining all the different actions that a TodoItem can invoke in the TodoMVC example goes beyond the scope of this article, but let's just take a look at the action that deletes one of the to-do items. Here is an abbreviated version of the TodoItem: ```javascript /** @jsx React.DOM */ var React = require('react'); var TodoActions = require('../actions/TodoActions'); var TodoTextInput = require('./TodoTextInput.react'); var TodoItem = React.createClass({ propTypes: { todo: React.PropTypes.object.isRequired }, render: function() { var todo = this.props.todo; return ( <li key={todo.id}> <label> {todo.text} </label> <button className="destroy" onClick={this._onDestroyClick} /> </li> ); }, _onDestroyClick: function() { TodoActions.destroy(this.props.todo.id); } }); module.exports = TodoItem; ``` With a destroy action available in our library of TodoActions, and a store ready to handle it, connecting the user's interaction with application state changes could not be simpler. We just wrap our onClick handler around the destroy action, provide it with the id, and we're done. Now the user can click the destroy button and kick off the Flux cycle to update the rest of the application. Text input, on the other hand, is just a bit more complicated because we need to hang on to the state of the text input within the React component itself. Let's take a look at how TodoTextInput works. As you'll see below, with every change to the input, React expects us to update the state of the component. So when we are finally ready to save the text inside the input, we will put the value held in the component's state in the action's payload. This is UI state, rather than application state, and keeping that distinction in mind is a good guide for where state should live. All application state should live in the store, while components occasionally hold on to UI state. Ideally, React components preserve as little state as possible. Because TodoTextInput is being used in multiple places within our application, with different behaviors, we'll need to pass the onSave method in as a prop from the component's parent. This allows onSave to invoke different action creator methods depending on where it is used. ```javascript /** @jsx React.DOM */ var React = require('react'); var ReactPropTypes = React.PropTypes; var ENTER_KEY_CODE = 13; var TodoTextInput = React.createClass({ propTypes: { className: ReactPropTypes.string, id: ReactPropTypes.string, placeholder: ReactPropTypes.string, onSave: ReactPropTypes.func.isRequired, value: ReactPropTypes.string }, getInitialState: function() { return { value: this.props.value || '' }; }, /** * @return {object} */ render: function() /*object*/ { return ( <input className={this.props.className} id={this.props.id} placeholder={this.props.placeholder} onBlur={this._save} onChange={this._onChange} onKeyDown={this._onKeyDown} value={this.state.value} autoFocus={true} /> ); }, /** * Invokes the callback passed in as onSave, allowing this component to be * used in different ways. */ _save: function() { this.props.onSave(this.state.value); this.setState({ value: '' }); }, /** * @param {object} event */ _onChange: function(/*object*/ event) { this.setState({ value: event.target.value }); }, /** * @param {object} event */ _onKeyDown: function(event) { if (event.keyCode === ENTER_KEY_CODE) { this._save(); } } }); module.exports = TodoTextInput; ``` The Header passes in the onSave method as a prop to allow the TodoTextInput to create new to-do items: ```javascript /** @jsx React.DOM */ var React = require('react'); var TodoActions = require('../actions/TodoActions'); var TodoTextInput = require('./TodoTextInput.react'); var Header = React.createClass({ /** * @return {object} */ render: function() { return ( <header id="header"> <h1>todos</h1> <TodoTextInput id="new-todo" placeholder="What needs to be done?" onSave={this._onSave} /> </header> ); }, /** * Event handler called within TodoTextInput. * Defining this here allows TodoTextInput to be used in multiple places * in different ways. * @param {string} text */ _onSave: function(text) { TodoActions.create(text); } }); module.exports = Header; ``` In a different context, such as in editing mode for an existing to-do item, we might pass an onSave callback that invokes `TodoActions.update(text)` instead. Creating Actions with Semantic Methods -------------------------------------- Here is the basic code for the two action creator methods we used above in our views: ```javascript /** * TodoActions */ var AppDispatcher = require('../dispatcher/AppDispatcher'); var TodoConstants = require('../constants/TodoConstants'); var TodoActions = { /** * @param {string} text */ create: function(text) { AppDispatcher.handleViewAction({ actionType: TodoConstants.TODO_CREATE, text: text }); }, /** * @param {string} id */ destroy: function(id) { AppDispatcher.handleViewAction({ actionType: TodoConstants.TODO_DESTROY, id: id }); }, }; module.exports = TodoActions; ``` As you can see, we really would not need to have the helpers AppDispatcher.handleViewAction() or TodoActions.create(). We could, in theory, call AppDispatcher.dispatch() directly and provide a payload. But as our application grows, having these helpers keeps the code clean and semantic. It's just a lot cleaner to write TodoActions.destroy(id) instead of writing a whole lot of things that our TodoItem shouldn't have to know about. The payload produced by the TodoActions.create() will look like: ```javascript { source: 'VIEW_ACTION', action: { type: 'TODO_CREATE', text: 'Write blog post about Flux' } } ``` This payload is provided to the TodoStore through its registered callback. The TodoStore then broadcasts the 'change' event, and the MainSection responds by fetching the new collection of to-do items from the TodoStore and changing its state. This change in state causes the TodoApp component to call its own render() method, and the render() method of all of its descendents. Start Me Up ----------- The bootstrap file of our application is app.js. It simply takes the TodoApp component and renders it in the root element of the application. ```javascript /** @jsx React.DOM */ var React = require('react'); var TodoApp = require('./components/TodoApp.react'); React.renderComponent( <TodoApp />, document.getElementById('todoapp') ); ``` Dependency Management in the Dispatcher ---------------------------------------------- As our application grows beyond this simple application to contain multiple stores, we'll need a way to be able to manage dependencies between them. That is, Store A might need to derive data based on Store B's data, so Store A would need Store B to update itself first.  This functionality is available with the Dispatcher's waitFor() method. We would call waitFor() within the store's registered callback like so: ```javascript Dispatcher.waitFor([StoreB.dispatcherIndex, StoreC.dispatcherIndex]); // now do things, knowing that both StoreB and StoreC have updated ``` In the source code, you can see that we are interupting the synchronous iteration over the callbacks and starting a new iteration of callbacks based on the array of dispatcherIndexes passed into waitFor(). ```javascript /** * Waits for the callbacks specified to be invoked before continuing execution * of the current callback. This method should only be used by a callback in * response to a dispatched payload. * * @param {array<string>} ids */ waitFor(ids) { invariant( this._isDispatching, 'Dispatcher.waitFor(...): Must be invoked while dispatching.' ); for (var ii = 0; ii < ids.length; ii++) { var id = ids[ii]; if (this._isPending[id]) { invariant( this._isHandled[id], 'Dispatcher.waitFor(...): Circular dependency detected while ' + 'waiting for `%s`.', id ); continue; } invariant( this._callbacks[id], 'Dispatcher.waitFor(...): `%s` does not map to a registered callback.', id ); this._invokeCallback(id); } } ``` Now within the store's callback we can explicitly wait for any dependencies to first update before moving forward.  However, if Store A waits for Store B, and B waits for A, then a circular dependency will occur. To help prevent this situation, the dispatcher will throw an error in the browser console if we accidentally have two stores that are waiting for each other. The Future of Flux ------------------ A lot of people ask if Facebook will release Flux as an open source framework. Really, Flux is just an architecture, not a framework.  But perhaps a Flux boilerplate project might make sense, if there is enough interest. Please let us know if you'd like to see us do this. Thanks for taking the time to read about how we build client-side applications at Facebook. We hope Flux proves as useful to you as it has to us. </del> <ins> This page has been moved to the Flux website. [View it there](http://facebook.github.io/flux/docs/todo-list.html). </ins>


Question: * `Object.create` – Provided by `es5-sham.js` from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim). * `console.*` – Only needed when using the unminified build. If you need to polyfill this, try [paulmillr's console-polyfill](https://github.com/paulmillr/console-polyfill). <ins> ### Cross-browser Issues Although React is pretty good at abstracting browser differences, some browsers are limited or present quirky behaviors that we couldn't find a workaround. #### onScroll event on IE8 On IE8 the `onScroll` event doesn't bubbles and IE8 doesn't have an API to define handlers to the capturing phase of an event, meaning there is no way for React to listen to these events. Currently a handler to this event is ignored on IE8. See the [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) GitHub issue for more information. </ins>

Here's an example: (no jsfiddle because that's broken in IE8)
I tried to fix this bug yesterday but had a bad time trying to find a fix for a similar cases. I looked at current well maintained libraries and didn't find a way to make scroll bubble or capture it on IE8. Seems like trying to fix it would be a waste of time and would make code much complex, for a browser that is slowly dying. My suggestion is to point that out on the documentation.
Seems like this isn't so easy. Let's do what says and document it.
do you think that we should do a everytime someone uses onScroll on any browser or would that be annoying? I would say it would be annoying but it would also be very frustrating to figure that it's a React limitation after some hours of debugging on IE8 (ugh!)
+1 on the warning -- would be super helpful.
reopening so we can add a warning
Warning was in
Now that events are listened on demand, maybe the warning should be moved to method, where support is already checked?
It also prints the warning if you render on the server, its annoying :/
That's odd, I wouldn't expect that code to run at all when using server rendering.
I see this warning when I'm doing with . Any chance to disable it?
I also see this error when using ssr
This is happening to me with JSDOM as well and in my case our team project standards aren't going to accommodate leaving these errors in the console when tests are run. How can I suppress or stub this out. It's not just obnoxious it is preventing me from getting my work merged in our project.
/ - I am now seeing this error after upgrading my version of Enzyme to . Did you find a way to suppress these warnings for JSDOM?
If you're having problems please file a new issue. Nobody actively reads old issues, and requests for help here will get lost.


Question: <div className="content" dangerouslySetInnerHTML={{  __html: converter.makeHtml(this.state.value)   __html: marked(this.state.value, {sanitize: true})  }} />


Question: listeners: null, onChange: _handleChange.bind(inst), }; <ins> if (__DEV__) { inst._wrapperState.controlled = props.checked !== undefined || props.value !== undefined; } </ins> }, updateWrapper: function(inst) {

A component should either be using uncontrolled inputs or controlled inputs, but not both (they should pick a single paradigm, for the lifetime of the component). As a result, an instance of an input should never switch from controlled to uncontrolled (or vice versa). We should warn when an input that was previously controlled becomes uncontrolled, or vice versa.
Could you provide some code as to how a controlled input becomes uncontrolled and vice versa?
I just got this warning, can anyone point me to an explanation with a bit more detail? ty
put your code in a stackoverflow question, and link it here.
newswim Read about controlled components and uncontrolled components. Choose one (preferably controlled components), and don't ever use uncontrolled components. If you are using controlled components, make sure you never pass a or to React. And yes, is correct, this is better addressed on StackOverflow.
I don't consider an input's value being null or undefined as a qualifying factor in determining if an input is controlled or uncontrolled. Controlled forms are a paradigm that may share some qualities with uncontrolled forms. It's about listening to changes and updating the state of the value, but React shouldn't stipulate that the value can't be undefined. It's an additional burden to those following good practice in using controlled forms. This warning should occur if both defaultValue and value props are used throughout the input's lifecycle.
I agree, but in the sense that they shouldn't be a single component at all, they should be two separate. Regardless I would say that actually providing the correct string value to an interactive component that expects a string value seems like a rather good practice. Otherwise you will have two distinct value states and , but both being intended to mean the exact same thing. No, because being or makes it uncontrolled by definition and you shouldn't switch between controlled and uncontrolled.


Question: ): void { if (__DEV__) { currentHookNameInDev = 'useImperativeHandle'; <ins> warning( typeof create === 'function', 'Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: %s.', create !== null ? typeof create : 'null', ); </ins> } // TODO: If deps are provided, should we skip comparing the ref itself? const nextDeps =

I've noticed a strange bug with the react redux opt-in. If i use it with a connected class component, everything is ok: If i use it with a connected functional component that use with , i obtain a strange error: in method. I create a codepen to reproduce the issue: PS: Sorry for the cors error, but i don't find the way to add as cdn
I believe the issue here is that expects the second argument to be a function that returns the reference: See: for more information about the API of the hook. Maybe the error thrown could be more clear?
You're right, accept a function as second argument. A warning on wrong argument type could be a good idea.
Ill take this issue on
Sure
i get TypeError: React.useImperativeMethods is not a function in 16.8.0-alpha.1 but when back to 16.7.0-alpha.2 not get this error
The hook was renamed in this PR: Most likely between the 16.7 alpha and 16.8 alpha
Yeah, it was renamed.
yes it work good after rename it where i can get changes between alpha version ?
Commit log. We don't write changelogs for alphas.
I'm taking this in since we want to get Hooks out sooner.
alright np


Question: }); ``` <del> This is a special API that intentionally makes it difficult to insert raw HTML, but for Showdown we'll take advantage of this backdoor. </del> <ins> This is a special API that intentionally makes it difficult to insert raw HTML, but for marked we'll take advantage of this backdoor. </ins> <del> **Remember:** by using this feature you're relying on Showdown to be secure. </del> <ins> **Remember:** by using this feature you're relying on marked to be secure. In this case, we pass `sanitize: true` which tells marked to escape any HTML markup in the source instead of passing it through unchanged. </ins> ### Hook up the data model


Question: } } <ins> function shouldConstruct(Component) { return Component.prototype && Component.prototype.isReactComponent; } </ins> /** * ------------------ The Life-Cycle of a Composite Component ------------------ *


Question: ); } <ins> function optionPostMount() { var inst = this; ReactDOMOption.postMountWrapper(inst); } </ins> // There are so many media events, it makes sense to just // maintain a list rather than create a `trapBubbledEvent` for each var mediaEvents = {

Appears to be working in Firefox but at least Chrome & Safari are broken. Should be a really recent regression so very few possible changes to blame... Easiest repo: the todo list on our homepage.
Just a heads up but this still seems to be an issue even on 15.4.1. I've been struggling to reproduce this because it seems to be some sort of ninja bug. Nevertheless, I was wondering if anyone is still dealing with this problem?
I haven't seen anything.
I'm still seeing this issue.
Please open a new issue with a simplified repro case if you're still seeing this!