Summary:
Ref T5240.
- Add proper class when dropping cards.
- Add proper class when creating new cards.
- Make X-drag explicit so that it works if there's only one column.
- Stop tootips when dragging, resume them after dropping.
- Move CSS rule for consistency.
- Allow user to hit "Escape" to cancel an in-progress drag.
Test Plan:
- Dropped cards.
- Created new cards.
- X-dragged on a workboard with one column and a dashboard.
- Dragged over a tooltip (no tip), dropped, moused over tooltip (tip).
- Hit escape during a drag.
Reviewers: chad
Reviewed By: chad
Subscribers: cspeckmim
Maniphest Tasks: T5240
Differential Revision: https://secure.phabricator.com/D15163
Summary:
Ref T5240. Currently, when dragging nodes, we leave them where they are in the document and apply "position: relative;" so we can move them around on screen.
- Pros: All the CSS still works.
- Cons: Can't drag them outside the nearest containing element with "overflow: hidden;", many subtle positioning bugs with scrollable containers.
Instead, this diff leaves the thing we're dragging exactly where it is, clones it, and drags the clone instead.
- Pros: You can drag it anywhere. Seems to fix all the scrolling container problems.
- Cons: CSS which depends on a container class no longer works.
The CSS thing is bad, but doesn't seem too unreasonable to fix. Basically, we just need to put some `phui-this-is-a-workboard-card` class on the cards, and use that to style them instead of `phui-workboard-view`, and then do something similar for draggable lists.
Although we no longer need to drag cards to tabs with the current design, I think there's a reasonable chance we'll revisit that later. The current design also calls for scrollable columns, but there would be no way to drag cards outside of their current column with the current approach.
NOTE: This does not attempt to fix the CSS, so dragging is pretty rough, since the "clone" loses a number of container classes and thus a number of rules. I'll clean up the CSS in the next change.
Test Plan:
- Dragged stuff around on task lists, workboards, and sort lists (e.g., pinned applications) in Safari, Firefox and Chrome.
- Scrolled window and containers (workboards) during drag.
- Dragged stuff out of the workboard.
- Dragged stuff offscreen.
- CSS is funky, but I can no longer find any positioning or layout issues in any browser.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T5240
Differential Revision: https://secure.phabricator.com/D15160
Summary: Ref T5240. This property does nothing.
Test Plan: Search, drag a card around.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T5240
Differential Revision: https://secure.phabricator.com/D15159
Summary:
Ref T5240. Currently, we calculate drag positions assuming the "ghost" element is not present (it isn't, usually), then adjust them while dragging to account for the ghost.
However, this fails after scrolling: we dirty the cache, but the ghost //is// present. We continue adjusting for it, but essentially double-adjust. This leads to scroll positions being about 80-ish px off from where they should be.
Test Plan:
- Begin dragging a task in a long task list.
- While dragging, use mousewheel to scroll to the bottom of the list.
- Drag task downward through the list.
- Before fix: ghost is off by, like, an inch or so.
- After fix: ghost position is accurate to cursor position.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T5240
Differential Revision: https://secure.phabricator.com/D15157
Summary:
Fixes T10229. Broadly:
- When the user hovers over a line number or inline comment, we update the yellow reticle to highlight the relevant lines. Specifically, this is in response to a `mouseover` event.
- On touch devices, touches fire `mouseover` and if you mutate the DOM inside the event, the device aborts the touch.
To remedy this:
- Distingiush between mouse-originated and touch-originated cursor events.
- We do this, roughly, by setting a flag when we see "touchstart", and clearing it when we see the second copy of any unique cursor event.
- This method is complex, but should be robust to any implementation differences between devices (for example, it will work no matter which order the events are fired in).
- This method should also produce the correct results on weird devices that have both mouse-devices and touch-devices available for cursor input.
- When we see a touch-originated `mouseover` or `mouseout`, don't mutate the DOM.
- Put an extra DOM mutation into the `click` event to improve highlighting behavior on touch devices.
Test Plan:
- In iOS Simulator (4s, iOS 9.2), clicked various inline actions ("Reply", "Hide", "Done", "Cancel", line numbers, etc). Got responses after a single touch.
- Verified hover + click behavior on a desktop.
- Logged and examined a bunch of events as a general sanity check.
Reviewers: chad
Reviewed By: chad
Subscribers: aljungberg
Maniphest Tasks: T10229
Differential Revision: https://secure.phabricator.com/D15136
Summary: Ref T10229. Fixes T9969. We make a decision about 1up vs 2up pretty early, and sometimes the viewport size reads as larger than the device, so we incorrectly select 2up when the proper setting would be 1up.
Test Plan:
I can reproduce this by, e.g., reloading a lot on an iPhone 4s in iOS Simulator running iOS 9.2. Sometimes it picks 2-up. I added logging to show that the viewport dimension read was the issue.
After this change, it always selects 1-up (`window.screen.availWidth` is defined and sensible on the device).
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9969, T10229
Differential Revision: https://secure.phabricator.com/D15135
Summary:
Ref T10163.
- If you click a result, we get a blur before your click hits, and deactivate before the click can work. Instead, wait before responding to blur.
- Use the standard sort handler which puts unixnames over human names. Also use the standard filter which deals with disabled users not matching unless they're the only match.
Test Plan:
- Clicked a result, got a replacement.
- Named myself "dog dog", typed "@dog", user "@dog" was now first match despite me being "@admin".
- Used normal typeaheads to make sure I didn't break sort handler.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10163
Differential Revision: https://secure.phabricator.com/D15031
Summary: Ref T3725. This probably has 900,000 bugs. This will need updates for subprojects/milestones.
Test Plan:
- Tested very gently in Safari, Firefox and Chrome.
- Reasonable inputs appear to work.
- Clicking, escape, tab, return, arrow keys work OK?
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T3725
Differential Revision: https://secure.phabricator.com/D15029
Summary:
Ref T10010. Ref T5819. General alignment of the stars:
- There were some hacks in Conduit around stripping `fa-...` off icons when reading and writing that I wanted to get rid of.
- We probably have room for a subtitle in the new heavy nav, and using the icon name is a good starting point (and maybe good enough on its own?)
- The project list was real bad looking with redundant tag/names, now it is very slightly less bad looking with non-redundant types?
- Some installs will want to call Milestones something else, and this gets us a big part of the way there.
- This may slightly help to reinforce "tag" vs "policy" vs "group" stuff?
---
I'm letting installs have enough rope to shoot themselves in the foot (e.g., define 100 icons). It isn't the end of the world if they reuse icons, and is clearly their fault.
I think the cases where 100 icons will break down are:
- Icon selector dialog may get very unwieldy.
- Query UI will be pretty iffy/huge with 100 icons.
We could improve these fairly easily if an install comes up with a reasonable use case for having 100 icons.
---
The UI on the icon itself in the list views is a little iffy -- mostly, it's too saturated/bold.
I'd ideally like to try either:
- rendering a "shade" version (i.e. lighter, less-saturated color); or
- rendering a "shade" tag with just the icon in it.
However, there didn't seem to be a way to do the first one right now (`fa-example sh-blue` doesn't work) and the second one had weird margins/padding, so I left it like this for now. I figure we can clean it up once we build the thick nav, since that will probably also want an identical element.
(I don't want to render a full tag with the icon + name since I think that's confusing -- it looks like a project/object tag, but is not.)
Test Plan:
{F1049905}
{F1049906}
Reviewers: chad
Reviewed By: chad
Subscribers: 20after4, Luke081515.2
Maniphest Tasks: T5819, T10010
Differential Revision: https://secure.phabricator.com/D14918
Summary: Ref T10004. This control doesn't disable visually or behaviorally, e.g. when locked in an EditEngine configuration.
Test Plan:
- Locked field for Projects.
- Reviewed form in EditEngine.
- Created/edited a project.
- Swapped default.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10004
Differential Revision: https://secure.phabricator.com/D14911
Summary: Ref T10004. This primarily supports moving Phame to EditEngine.
Test Plan: {F1045166}
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10004
Differential Revision: https://secure.phabricator.com/D14887
Summary: Ref T8980. Previously, if you had like `T123T123T123` and waved your mouse over them, we wouldn't move the card. Now, move the card.
Test Plan: Waved mouse. Saw the card move.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T8980
Differential Revision: https://secure.phabricator.com/D14881
Summary: Ref T8980. This calculation was not quite right and you could sneak one off screen if you tried carefully.
Test Plan: Couldn't sneak one off screen anymore.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T8980
Differential Revision: https://secure.phabricator.com/D14880
Summary:
Ref T8980. Move away from events to EngineExtensions.
This also simplifies hovercards a bit:
- Removes tasks from revision cards.
- Removes blockers/blocked from task cards.
- Removes "Send Message" from user cards.
These mostly felt cluttery to me. Open to arguments to retain them. I think we can make better use of the space, though (e.g., flags, projects + board columns).
Test Plan:
- Viewed people, task, revision, commit and project hovercards.
{F1043256}
{F1043257}
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T8980
Differential Revision: https://secure.phabricator.com/D14878
Summary:
Ref T3967. This gives us a reasonable baseline for doing remarkup previews inline in all contexts, and works in weird/constrained context including:
- inline comments;
- conpherence; and
- custom fields.
It would be nicer to go beyond this in contexts like Phame posts, but this is a start, at least.
Test Plan:
{F1040877}
{F1040878}
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T3967
Differential Revision: https://secure.phabricator.com/D14855
Summary:
Fixes T10039. We add text to textareas in two cases:
- Users clicking assitance buttons in Remarkup text areas.
- Drag-and-drop file uploads.
In case (1), it makes sense to highlight the text (it shows the user what we inserted, and lets them undo the action easily if it isn't what they wanted).
In case (2), it does not. Users almost never want to delete or edit a file reference. It is slightly nice to have the reference as a visual callout, but I don't think this is a big deal.
Change the behavior so that we highlight only for remarkup buttons, not for drag-and-drop files.
Test Plan:
- Clicked an "isnert quote" button on remarkup assist area, got highlighted example text.
- Dragged and dropped a file, got text inserted with no highlight.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10039
Differential Revision: https://secure.phabricator.com/D14851
Summary: Fixes T9871. Ref T10004. These won't win any awards but it fixes them being incredibly weird and confusing.
Test Plan:
{F1029090}
- Tried to use controls, got reasonable behavior.
- Used normal controls to make sure I didn't break anything.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9871, T10004
Differential Revision: https://secure.phabricator.com/D14814
Summary:
Ref T10004. After a user logs in, we send them to the "next" URI cookie if there is one, but currently don't always do a very good job of selecting a "next" URI, especially if they tried to do something with a dialog before being asked to log in.
In particular, if a logged-out user clicks an action like "Edit Blocking Tasks" on a Maniphest task, the default behavior is to send them to the standalone page for that dialog after they log in. This can be pretty confusing.
See T2691 and D6416 for earlier efforts here. At that time, we added a mechanism to //manually// override the default behavior, and fixed the most common links. This worked, but I'd like to fix the //default// beahvior so we don't need to remember to `setObjectURI()` correctly all over the place.
ApplicationEditor has also introduced new cases which are more difficult to get right. While we could get them right by using the override and being careful about things, this also motivates fixing the default behavior.
Finally, we have better tools for fixing the default behavior now than we did in 2013.
Instead of using manual overrides, have JS include an "X-Phabricator-Via" header in Ajax requests. This is basically like a referrer header, and will contain the page the user's browser is on.
In essentially every case, this should be a very good place (and often the best place) to send them after login. For all pages currently using `setObjectURI()`, it should produce the same behavior by default.
I'll remove the `setObjectURI()` mechanism in the next diff.
Test Plan: Clicked various workflow actions while logged out, saw "next" get set to a reasonable value, was redirected to a sensible, non-confusing page after login (the page with whatever button I clicked on it).
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T10004
Differential Revision: https://secure.phabricator.com/D14804
Summary:
Ref T9992. This is a step on the path to getting EditEngine working in Badges, Projects and Calendar.
This doesn't add a new `EditField` for icons yet, just standardizes the old stuff. New stuff is more general and I saved 150 lines of code.
I put the endpoint in Files because the similar "choose a profile picture" endpoint will definitely go there, and this endpoint might eventually feature, like, "draw your own icon~~" or something.
Test Plan:
- Created events, projects and badges with custom icons.
- Edited events, projects and badges, changing their icons.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9992
Differential Revision: https://secure.phabricator.com/D14799
Summary:
Ref T9132. Fixes T4580. Thhat might actually have been fixed a while ago or something since it describes a buggy/bad interaction which doesn't reproduce for me at HEAD.
This saves and restores all the stacked actions (subscribers, projects, etc) so that you don't lose anything if you close a window by accident.
Test Plan:
Added a bunch of actions in various states, reloaded the page, draft stuck around.
Submitted form, actions didn't stick around anymore.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T4580, T9132
Differential Revision: https://secure.phabricator.com/D14675
Summary:
Ref T9132. This is kind of a mess because the tokenizer rewrite left rendering tokenizers in Javascript a little rough. This causes bugs like icons not showing up on tokens in the "Policy" dialog, which there's a task for somewhere I think.
I think I've fixed it enough that the beahavior is now correct (i.e., icons show up properly), but some of the code is a bit iffy. I'll eventually clean this up properly, but it's fairly well contained for now.
Test Plan:
- Reassigned a task.
- Put a task up for grabs.
- No reassign on closed tasks.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9132
Differential Revision: https://secure.phabricator.com/D14669
Summary:
Fixes T9675.
Fixes the calculation for the difference between the first day of the month and the first day of the week. It was previously possible for this to be negative, which caused the subsequent loop to hang the browser.
Test Plan:
- Set week to start on Sunday. Observed that the calendar still renders fine.
- Set week to start on Monday. Observed that the browser no longer hangs on November 2015.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: Korvin
Maniphest Tasks: T9675
Differential Revision: https://secure.phabricator.com/D14409
Summary:
Ref T9324. When you upload a normal file, we call `willUpload` and then `didUpload`.
When you upload a chunked file, we never call `willUpload`. This can get things out of sync. Make sure we invoke this event for both chunked and non-chunked uploads.
Test Plan: Got cleaner behavior (redirect after all uploads finish) in new Phacility file upload area.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9324
Differential Revision: https://secure.phabricator.com/D14083
Summary: Fixes T8605, Popup datepicker should respect user preferred week start day
Test Plan: Edit event, open datepicker, calendar weeks should start on Sunday by default, and another day, if specified in User Preferences.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T8605
Differential Revision: https://secure.phabricator.com/D13419
Summary:
Fixes T4139. Adds a "Desktop Notifications" panel to settings. For now, we start with "Send Desktop Notifications Too" functionality. We can try to be fancy later and only send desktop notifications if the web app doesn't have focus, etc.
Test Plan:
Made some comments as a test user on a task and got purdy desktop notifications using Chrome. Then did it again with Firefox.
Played around with permissions form with Chrome and got helpful information about what was up. Played around with Firefox and got similar results, except canceling the dialogue didn't invoke my handler code somehow. Oh Firefox!
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: rbalik, tycho.tatitscheff, joshuaspence, epriestley, Korvin
Maniphest Tasks: T4139
Differential Revision: https://secure.phabricator.com/D13219
Summary: Fixes T8565, Quoted text remarkup should be smart enough to know when to add a '>' and when to add '> '
Test Plan: Open an object with remarkup comments, add 'quote', select that text click the quote button in the remarkup menu, text should become '> quote'. Select and click again, text should become '>> quote'.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T8565
Differential Revision: https://secure.phabricator.com/D13334
Summary: Ref T8362, Date controls should respect user time preferences
Test Plan: Set user time preference to 24-hour format, create an event, type 23 in time input, 23:00 should be suggested. Saveing a 24-hour format time should save correctly.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T8362
Differential Revision: https://secure.phabricator.com/D13291
Summary: Ref T8362, Add date format preference and respect it in date selection controls
Test Plan: Set date format preference in the user settings panels, create new event, select new start date in the correct format.
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: jasonrumney, eadler, epriestley, Korvin
Maniphest Tasks: T8362
Differential Revision: https://secure.phabricator.com/D13262
Summary: Fixes T7696.
Test Plan: hit the quote button with no text - it worked. highlighted some text and hit the quote button - it worked. hit the list item button with no text - it worked. hit the list item button with text selected - it worked
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7696
Differential Revision: https://secure.phabricator.com/D13060
Summary: Ref T8099. We removed the background column, so this JS wasn't able to fire and make the filetree movable.
Test Plan: Set Filetree on, resize it. Scroll through a diff.
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D13048
Summary: Ref T8060, String inputs should be validated and replaced by "today" values.
Test Plan: Open Calendar advanced search, enter "tea time" in date input control, open datepicker, "today" should be selected.
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: Korvin, epriestley
Maniphest Tasks: T8060
Differential Revision: https://secure.phabricator.com/D13018
Summary: Ref T8060, Convert date control dropdowns to an input for date
Test Plan: Create new Calendar event, use US time format to enter a date or use datepicker, confirm dates are interpreted correctly.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8060
Differential Revision: https://secure.phabricator.com/D13010
Summary: Ref T8031, Calendar event datepicker should auto-complete end time to be an hour from start time unless end time has been edited
Test Plan: Create event, edit start time, end time should adjust to an hour from start time.
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: Korvin, epriestley
Maniphest Tasks: T8031
Differential Revision: https://secure.phabricator.com/D12960
Summary: Fixes T7524.
Test Plan:
- made a task with a comment including another task. resized window so still desktop size and task reference on edge of window. invoked hovercard by bovering over task reference and noted the hovercard was completely visible.
- opened the durable column and made a task reference. invoked hovercard by hovering over task reference and noted the hovercard was completely visible.
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7524
Differential Revision: https://secure.phabricator.com/D12759
Summary: noticed this while doing some other work. didn't really break anything before but no need to install this listener every time we load the global drag and drop behavior; just the once works fine.
Test Plan: home -> profile -> back to home and drag and drop still worked
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Differential Revision: https://secure.phabricator.com/D12740
Summary:
Fixes T7919. This is a pretty generic toggle behavior. Make it quicksand ready by making it install only once and swallow the regular "click" event so the quicksand "click" event doesn't get funky with it.
Also fixes a bug in Quicksand that I discovered developing / testing this feature. We have to update the internal member variable to be better than 0 similarly to how id works. So do that.
Test Plan: went to phriction, toggled menu open, clicked home, clicked phriction and toggled menu again. Went back in history and noted menu was left to toggle state I previously had it. (currently a feature, not a bug)
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7919
Differential Revision: https://secure.phabricator.com/D12708
Summary: Ref T8024. Allow `DateControlValue` to manage enabled/disabled state, so we can eventually delete the copy of this logic in `DateControl`.
Test Plan:
- Used Calendar ApplicationSearch queries to observe improved behaviors:
- Error for invalid start date, if enabled.
- Error for invalid end date, if enabled.
- Error for invalid date range, if both enabled.
- When submitting an invalid date (for example, with the time "Tea Time"), form retains invalid date verbatim instead of discarding information.
- Created an event, using existing date controls to check that I didn't break anything.
Reviewers: chad, lpriestley, btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T8024
Differential Revision: https://secure.phabricator.com/D12673
Summary: Fixes T7913. Collapse the separate board dropdown into the board projects behavior; we always need that anyway and now we can install the listener more granularly.
Test Plan:
- visted project board
- invoked create task, cancelled dialog
- visited project feed
- visited project board
- invoked create task, cancelled dialog (FAILED pre patch...!)
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7913
Differential Revision: https://secure.phabricator.com/D12599
Summary:
Fixes T7700.
This ends up being kind of tricky because
- the key for a given request is only correct at the time the dark console is rendered
- the dark console itself should contain every request made, as opposed to being drawn from scratch
- in the case of a quicksand request, the behavior gets invoked first with the correctly rendered console as part of the `quicksand-redraw` event and then again shortly after as an ajax request would, except this is incorrect relative to when the key should be calculated...
So...
- assume we can get away with concurrency between the `quicksand-redraw` event and ajax request invocation of the behavior
- cache the right data as part of the `quicksand-redraw` event and then use it in the subsequent ajax call
- make sure ajax config gets a 'quicksand' flag
...otherwise its somewhat standard make sure this behavior can be init'd a bunch stuff.
Test Plan: visited '/', visited '/differential/', visited '/DXXX' - observed correctly populating dark console with all sorts of good data stuff. navigated backwards and observed dark console staying the same as expected. navigated by clicking links and console updated again
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7700
Differential Revision: https://secure.phabricator.com/D12582
Summary:
Fixes T7900.
- Update the hidden form input so the current application is searched.
- Update the menu icon.
- Update the button icon, if "Search Current Application" is selected.
Test Plan:
- Navigated between applications with Quicksand.
- Observed button icon update.
- Observed menu icon update.
- Observed results being scoped to the correct application.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T7900
Differential Revision: https://secure.phabricator.com/D12540
Summary: Fixes T7064. We need to pass the quicksand magic request variable around and then instrument the javascript to handle quicksand page loads.
Test Plan:
Enabled two factor auth on my account and then
- visited password page
- filled out 2 factor auth request
- saw high security bubble
- clicked about still seeing high security bubble
- refreshed page and still saw security bubble
- dismissed bubble by following through workflow after clicking bubble
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7064
Differential Revision: https://secure.phabricator.com/D12536