{"action":"created","issue":{"url":"https://api.github.com/repos/dekujs/deku/issues/198","labels_url":"https://api.github.com/repos/dekujs/deku/issues/198/labels{/name}","comments_url":"https://api.github.com/repos/dekujs/deku/issues/198/comments","events_url":"https://api.github.com/repos/dekujs/deku/issues/198/events","html_url":"https://github.com/dekujs/deku/pull/198","id":95006809,"number":198,"title":"added ability to cancel events","user":{"login":"lancejpollard","id":28718,"avatar_url":"https://avatars.githubusercontent.com/u/28718?v=3","gravatar_id":"","url":"https://api.github.com/users/lancejpollard","html_url":"https://github.com/lancejpollard","followers_url":"https://api.github.com/users/lancejpollard/followers","following_url":"https://api.github.com/users/lancejpollard/following{/other_user}","gists_url":"https://api.github.com/users/lancejpollard/gists{/gist_id}","starred_url":"https://api.github.com/users/lancejpollard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lancejpollard/subscriptions","organizations_url":"https://api.github.com/users/lancejpollard/orgs","repos_url":"https://api.github.com/users/lancejpollard/repos","events_url":"https://api.github.com/users/lancejpollard/events{/privacy}","received_events_url":"https://api.github.com/users/lancejpollard/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-07-14T18:24:59Z","updated_at":"2015-07-14T20:46:48Z","closed_at":"2015-07-14T20:45:21Z","pull_request":{"url":"https://api.github.com/repos/dekujs/deku/pulls/198","html_url":"https://github.com/dekujs/deku/pull/198","diff_url":"https://github.com/dekujs/deku/pull/198.diff","patch_url":"https://github.com/dekujs/deku/pull/198.patch"},"body":"cc @anthonyshort This makes it so you can cancel events. The use case is this:\r\n\r\n```html\r\n<div class='App' onClick={closePopup}>\r\n  <div class='Item' onClick={openModal}>\r\n    <div class='Item-settings' onClick={openPopup}>\r\n    </div>\r\n  </div>\r\n</div>\r\n```\r\n\r\nIf you click `Item-settings`, imagine it opens a popup. Then if you click anywhere _except_ the opened popup, it closes the popup. However, if you click on the `Item`, it both closes the popup and opens some modal window let's say. That's at least how it seems like it should work.\r\n\r\nWhat _shouldn't_ happen are the following:\r\n\r\n1. If you click `Item-settings` when everything is closed, it both opens the popup _and_ opens the modal.\r\n2. If the popup is open, and you click `Item` outside of `Item-settings`, it leaves the popup open and also opens the modal.\r\n\r\nThe current implementation of Deku has the problem of (2). The reason is because it exits on the first found event handler in the tree.\r\n\r\nhttps://github.com/dekujs/deku/blob/master/lib/render.js#L1229\r\n\r\nThis means that if the popup is open, and you click `Item`, then the `App` handler never gets executed (so the popup never gets closed).\r\n\r\nSo first try was removing `break`. But that causes problem (1): when you click `Item-settings` when nothing is open, it will both open the popup and the modal, because the event is handled by all handlers. So to fix this, I added:\r\n\r\n```js\r\nif (false === fn(event)) break;\r\n```\r\n\r\nThis makes it so you can return `false` in an event handler, and it will stop propagation. I tried using `event.stopPropagation()` or `event.stopImmediatePropagation()` but there's [no indication that they have been called](http://stackoverflow.com/questions/7259753/in-a-javascript-event-how-to-determine-stoppropagation-has-been-called) (they are natively handled, which sucks here). So a common workaround is to `return false`. This is similar to how `array.forEach` works when you want to cancel, and I feel like I've seen this many times in event handling systems in the past.\r\n\r\nThis PR solves the problem of allowing you to have nested virtual elements handle the same event in a controllable way.\r\n\r\n_Time spent figuring out: 2 hours_"},"comment":{"url":"https://api.github.com/repos/dekujs/deku/issues/comments/121379680","html_url":"https://github.com/dekujs/deku/pull/198#issuecomment-121379680","issue_url":"https://api.github.com/repos/dekujs/deku/issues/198","id":121379680,"user":{"login":"anthonyshort","id":36125,"avatar_url":"https://avatars.githubusercontent.com/u/36125?v=3","gravatar_id":"","url":"https://api.github.com/users/anthonyshort","html_url":"https://github.com/anthonyshort","followers_url":"https://api.github.com/users/anthonyshort/followers","following_url":"https://api.github.com/users/anthonyshort/following{/other_user}","gists_url":"https://api.github.com/users/anthonyshort/gists{/gist_id}","starred_url":"https://api.github.com/users/anthonyshort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anthonyshort/subscriptions","organizations_url":"https://api.github.com/users/anthonyshort/orgs","repos_url":"https://api.github.com/users/anthonyshort/repos","events_url":"https://api.github.com/users/anthonyshort/events{/privacy}","received_events_url":"https://api.github.com/users/anthonyshort/received_events","type":"User","site_admin":false},"created_at":"2015-07-14T20:46:47Z","updated_at":"2015-07-14T20:46:47Z","body":"Cool looks ok. This could probably be a problem with the way we bubble events manually and wouldn't be a problem if we could just rely on bubbling for every event.\r\n\r\nWe could potentially send through a wrapped version of `event.stopPropagation()` that would stop it from going up higher."}}