{"action":"created","comment":{"url":"https://api.github.com/repos/Automattic/wp-calypso/pulls/comments/61264207","id":61264207,"diff_hunk":"@@ -107,18 +144,67 @@ export default React.createClass( {\n \t\tif ( isSingleImage && ! MediaValidationStore.hasErrors( site.ID ) ) {\n \t\t\t// For single image upload, insert into post content, blocking save\n \t\t\t// until the image has finished upload\n-\t\t\tif ( selectedItems[ 0 ].transient ) {\n+\t\t\tlet selectedItem = selectedItems[ 0 ]","path":"client/components/tinymce/plugins/media/drop-zone.jsx","position":77,"original_position":77,"commit_id":"a0f6c079ebef4154ba319272325ed0f4ad34b841","original_commit_id":"a0f6c079ebef4154ba319272325ed0f4ad34b841","user":{"login":"aduth","id":1779930,"avatar_url":"https://avatars.githubusercontent.com/u/1779930?v=3","gravatar_id":"","url":"https://api.github.com/users/aduth","html_url":"https://github.com/aduth","followers_url":"https://api.github.com/users/aduth/followers","following_url":"https://api.github.com/users/aduth/following{/other_user}","gists_url":"https://api.github.com/users/aduth/gists{/gist_id}","starred_url":"https://api.github.com/users/aduth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aduth/subscriptions","organizations_url":"https://api.github.com/users/aduth/orgs","repos_url":"https://api.github.com/users/aduth/repos","events_url":"https://api.github.com/users/aduth/events{/privacy}","received_events_url":"https://api.github.com/users/aduth/received_events","type":"User","site_admin":false},"body":"If you're not reassigning `selectedItem`, should be declared with `const` ([reference](https://github.com/Automattic/wp-calypso/blob/master/docs/coding-guidelines/javascript.md#variable-declarations)).","created_at":"2016-04-27T14:14:38Z","updated_at":"2016-04-27T14:14:38Z","html_url":"https://github.com/Automattic/wp-calypso/pull/5020#discussion_r61264207","pull_request_url":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020","_links":{"self":{"href":"https://api.github.com/repos/Automattic/wp-calypso/pulls/comments/61264207"},"html":{"href":"https://github.com/Automattic/wp-calypso/pull/5020#discussion_r61264207"},"pull_request":{"href":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020"}}},"pull_request":{"url":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020","id":67927906,"html_url":"https://github.com/Automattic/wp-calypso/pull/5020","diff_url":"https://github.com/Automattic/wp-calypso/pull/5020.diff","patch_url":"https://github.com/Automattic/wp-calypso/pull/5020.patch","issue_url":"https://api.github.com/repos/Automattic/wp-calypso/issues/5020","number":5020,"state":"open","locked":false,"title":"Fix drag-n-drop image orientation of preview","user":{"login":"krisk","id":565580,"avatar_url":"https://avatars.githubusercontent.com/u/565580?v=3","gravatar_id":"","url":"https://api.github.com/users/krisk","html_url":"https://github.com/krisk","followers_url":"https://api.github.com/users/krisk/followers","following_url":"https://api.github.com/users/krisk/following{/other_user}","gists_url":"https://api.github.com/users/krisk/gists{/gist_id}","starred_url":"https://api.github.com/users/krisk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/krisk/subscriptions","organizations_url":"https://api.github.com/users/krisk/orgs","repos_url":"https://api.github.com/users/krisk/repos","events_url":"https://api.github.com/users/krisk/events{/privacy}","received_events_url":"https://api.github.com/users/krisk/received_events","type":"User","site_admin":false},"body":"Fixes #318\r\n\r\nThis PR addresses the issue of incorrect image preview orientation when drag-n-dropping in the editor.\r\n\r\n## Problem\r\n\r\nAs specified in the issue, the problem is that **exif** image orientation isn't respected.\r\n\r\n## Initial investigation\r\n\r\nAfter toying with the initial idea of handling image orientation via CSS transforms, it soon became apparent that there would be several unintended consequences and edge cases to cover. When an image is rotated (via CSS `transform`) its dimensions remain unchanged (i.e, _width_ and _height_ do not automatically flip). This presents problems if, while an image is being uploaded, it is then also edited (such as resized, or captions are added, etc...). These problems are compounded when the transient image is replaced with the persisted copy.\r\n\r\n## Solution\r\n\r\nInstead, I went the route of re-orienting the actual image, by drawing it into the canvas and applying the appropriate rotation, utilizing the library [JavaScript-Load-Image](https://github.com/blueimp/JavaScript-Load-Image).\r\n\r\nAt a glance, the following steps are taken:\r\n\r\n1. Check image orientation (i.e. read Exif data)\r\n2. If the image orientation needs to be changed, use [JavaScript-Load-Image](https://github.com/blueimp/JavaScript-Load-Image) to draw the re-oriented image.\r\n - When redrawing, limit the maximum width of the image to be the width of TinyMCE's body. This will result in the constructed image to be of a _reasonable_ file size, otherwise large images will have debilitatingly large data URIs, which _may_ adversely affect UX. Additionally, this helps reduce the probability of stack size limit errors.\r\n3. Retrieve the Data URI, and assign it to the media item URL\r\n4. Build the markup (an image tag) with the Data URI\r\n\r\nAdditionally, if the image requires re-orientation, then we need to do the following:\r\n\r\n1. Block saving from happening as well as the entire auto-save routine. This is because data URIs can quickly exceed length limitations, as well as take up space in `localStorage`.\r\n2. Block the updating of transient images within TinyMCE's editor (i.e, replacing transient images with the persisted ones). This is because when an image is dragged in the drop-zone, if it needs re-orientation then it is **not** actually inserted into the DOM **until** re-orientation finishes.\r\n\r\nOnce re-orientation completes, we can unblock saving.\r\n\r\nTo handle the above workflow, I introduced the functions `onBeforeAddMedia` and `onAfterAddMedia`, which are executed as chained promises.\r\n\r\n1. Execute `onBeforeAddMedia`: if there's an image which needs re-orientation, block all savings.\r\n2. Then, execute `onAddMedia`: deal with re-orientation, if necessary.\r\n3. Then, execute `onAfterAddMedia`: unblock saving.\r\n\r\n## Problems\r\n\r\n### Mirrored Images\r\n\r\nAll orientations are now supported, and the preview correctly shows a properly oriented image. However, I noticed that for all mirrored orientations, while the preview does indeed show the correct re-oriented image, the persisted image is oriented **incorrectly**:\r\n\r\n- Orientation 2 (up/mirrored)\r\n- Orientation 4 (down/mirrored)\r\n- Orientation 5 (left/mirrored)\r\n- Orientation 7 (right/mirrored)\r\n\r\nI believe this may need to be addressed at the API layer. Otherwise, we'd need to check orientation of the persisted image on the client-side, which may not be the most optimal solution.\r\n\r\n### Safari\r\n\r\nSafari is still a little finicky with images containing large data-URIs. I'm exploring a fix for this.\r\n\r\n## Testing\r\n\r\nExif images are hard to come by, so you can utilize [these](https://github.com/recurser/exif-orientation-examples), and [these](http://www.galloway.me.uk/media/other/EXIF_Orientation_Samples.zip).\r\n\r\nI put the entirety of the code behind the feature flag `post-editor/image-reorientation`.\r\n\r\nCC: @mdawaffe, @aduth ","created_at":"2016-04-26T17:42:22Z","updated_at":"2016-04-27T14:14:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d9a78498af4d4901891493ff410ad2f022c5f213","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020/commits","review_comments_url":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020/comments","review_comment_url":"https://api.github.com/repos/Automattic/wp-calypso/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Automattic/wp-calypso/issues/5020/comments","statuses_url":"https://api.github.com/repos/Automattic/wp-calypso/statuses/a0f6c079ebef4154ba319272325ed0f4ad34b841","head":{"label":"krisk:fix/editor/318-drag-n-drop-orientation","ref":"fix/editor/318-drag-n-drop-orientation","sha":"a0f6c079ebef4154ba319272325ed0f4ad34b841","user":{"login":"krisk","id":565580,"avatar_url":"https://avatars.githubusercontent.com/u/565580?v=3","gravatar_id":"","url":"https://api.github.com/users/krisk","html_url":"https://github.com/krisk","followers_url":"https://api.github.com/users/krisk/followers","following_url":"https://api.github.com/users/krisk/following{/other_user}","gists_url":"https://api.github.com/users/krisk/gists{/gist_id}","starred_url":"https://api.github.com/users/krisk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/krisk/subscriptions","organizations_url":"https://api.github.com/users/krisk/orgs","repos_url":"https://api.github.com/users/krisk/repos","events_url":"https://api.github.com/users/krisk/events{/privacy}","received_events_url":"https://api.github.com/users/krisk/received_events","type":"User","site_admin":false},"repo":{"id":57140186,"name":"wp-calypso","full_name":"krisk/wp-calypso","owner":{"login":"krisk","id":565580,"avatar_url":"https://avatars.githubusercontent.com/u/565580?v=3","gravatar_id":"","url":"https://api.github.com/users/krisk","html_url":"https://github.com/krisk","followers_url":"https://api.github.com/users/krisk/followers","following_url":"https://api.github.com/users/krisk/following{/other_user}","gists_url":"https://api.github.com/users/krisk/gists{/gist_id}","starred_url":"https://api.github.com/users/krisk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/krisk/subscriptions","organizations_url":"https://api.github.com/users/krisk/orgs","repos_url":"https://api.github.com/users/krisk/repos","events_url":"https://api.github.com/users/krisk/events{/privacy}","received_events_url":"https://api.github.com/users/krisk/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/krisk/wp-calypso","description":"The new JavaScript- and API-powered WordPress.com","fork":true,"url":"https://api.github.com/repos/krisk/wp-calypso","forks_url":"https://api.github.com/repos/krisk/wp-calypso/forks","keys_url":"https://api.github.com/repos/krisk/wp-calypso/keys{/key_id}","collaborators_url":"https://api.github.com/repos/krisk/wp-calypso/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/krisk/wp-calypso/teams","hooks_url":"https://api.github.com/repos/krisk/wp-calypso/hooks","issue_events_url":"https://api.github.com/repos/krisk/wp-calypso/issues/events{/number}","events_url":"https://api.github.com/repos/krisk/wp-calypso/events","assignees_url":"https://api.github.com/repos/krisk/wp-calypso/assignees{/user}","branches_url":"https://api.github.com/repos/krisk/wp-calypso/branches{/branch}","tags_url":"https://api.github.com/repos/krisk/wp-calypso/tags","blobs_url":"https://api.github.com/repos/krisk/wp-calypso/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/krisk/wp-calypso/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/krisk/wp-calypso/git/refs{/sha}","trees_url":"https://api.github.com/repos/krisk/wp-calypso/git/trees{/sha}","statuses_url":"https://api.github.com/repos/krisk/wp-calypso/statuses/{sha}","languages_url":"https://api.github.com/repos/krisk/wp-calypso/languages","stargazers_url":"https://api.github.com/repos/krisk/wp-calypso/stargazers","contributors_url":"https://api.github.com/repos/krisk/wp-calypso/contributors","subscribers_url":"https://api.github.com/repos/krisk/wp-calypso/subscribers","subscription_url":"https://api.github.com/repos/krisk/wp-calypso/subscription","commits_url":"https://api.github.com/repos/krisk/wp-calypso/commits{/sha}","git_commits_url":"https://api.github.com/repos/krisk/wp-calypso/git/commits{/sha}","comments_url":"https://api.github.com/repos/krisk/wp-calypso/comments{/number}","issue_comment_url":"https://api.github.com/repos/krisk/wp-calypso/issues/comments{/number}","contents_url":"https://api.github.com/repos/krisk/wp-calypso/contents/{+path}","compare_url":"https://api.github.com/repos/krisk/wp-calypso/compare/{base}...{head}","merges_url":"https://api.github.com/repos/krisk/wp-calypso/merges","archive_url":"https://api.github.com/repos/krisk/wp-calypso/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/krisk/wp-calypso/downloads","issues_url":"https://api.github.com/repos/krisk/wp-calypso/issues{/number}","pulls_url":"https://api.github.com/repos/krisk/wp-calypso/pulls{/number}","milestones_url":"https://api.github.com/repos/krisk/wp-calypso/milestones{/number}","notifications_url":"https://api.github.com/repos/krisk/wp-calypso/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/krisk/wp-calypso/labels{/name}","releases_url":"https://api.github.com/repos/krisk/wp-calypso/releases{/id}","deployments_url":"https://api.github.com/repos/krisk/wp-calypso/deployments","created_at":"2016-04-26T15:33:17Z","updated_at":"2016-04-26T15:33:23Z","pushed_at":"2016-04-27T13:33:07Z","git_url":"git://github.com/krisk/wp-calypso.git","ssh_url":"git@github.com:krisk/wp-calypso.git","clone_url":"https://github.com/krisk/wp-calypso.git","svn_url":"https://github.com/krisk/wp-calypso","homepage":"https://developer.wordpress.com/calypso/","size":18001,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Automattic:master","ref":"master","sha":"3d2c01eda9e897f7732c1418da80ea40ac879a21","user":{"login":"Automattic","id":887802,"avatar_url":"https://avatars.githubusercontent.com/u/887802?v=3","gravatar_id":"","url":"https://api.github.com/users/Automattic","html_url":"https://github.com/Automattic","followers_url":"https://api.github.com/users/Automattic/followers","following_url":"https://api.github.com/users/Automattic/following{/other_user}","gists_url":"https://api.github.com/users/Automattic/gists{/gist_id}","starred_url":"https://api.github.com/users/Automattic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Automattic/subscriptions","organizations_url":"https://api.github.com/users/Automattic/orgs","repos_url":"https://api.github.com/users/Automattic/repos","events_url":"https://api.github.com/users/Automattic/events{/privacy}","received_events_url":"https://api.github.com/users/Automattic/received_events","type":"Organization","site_admin":false},"repo":{"id":45936895,"name":"wp-calypso","full_name":"Automattic/wp-calypso","owner":{"login":"Automattic","id":887802,"avatar_url":"https://avatars.githubusercontent.com/u/887802?v=3","gravatar_id":"","url":"https://api.github.com/users/Automattic","html_url":"https://github.com/Automattic","followers_url":"https://api.github.com/users/Automattic/followers","following_url":"https://api.github.com/users/Automattic/following{/other_user}","gists_url":"https://api.github.com/users/Automattic/gists{/gist_id}","starred_url":"https://api.github.com/users/Automattic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Automattic/subscriptions","organizations_url":"https://api.github.com/users/Automattic/orgs","repos_url":"https://api.github.com/users/Automattic/repos","events_url":"https://api.github.com/users/Automattic/events{/privacy}","received_events_url":"https://api.github.com/users/Automattic/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Automattic/wp-calypso","description":"The new JavaScript- and API-powered WordPress.com","fork":false,"url":"https://api.github.com/repos/Automattic/wp-calypso","forks_url":"https://api.github.com/repos/Automattic/wp-calypso/forks","keys_url":"https://api.github.com/repos/Automattic/wp-calypso/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Automattic/wp-calypso/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Automattic/wp-calypso/teams","hooks_url":"https://api.github.com/repos/Automattic/wp-calypso/hooks","issue_events_url":"https://api.github.com/repos/Automattic/wp-calypso/issues/events{/number}","events_url":"https://api.github.com/repos/Automattic/wp-calypso/events","assignees_url":"https://api.github.com/repos/Automattic/wp-calypso/assignees{/user}","branches_url":"https://api.github.com/repos/Automattic/wp-calypso/branches{/branch}","tags_url":"https://api.github.com/repos/Automattic/wp-calypso/tags","blobs_url":"https://api.github.com/repos/Automattic/wp-calypso/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Automattic/wp-calypso/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Automattic/wp-calypso/git/refs{/sha}","trees_url":"https://api.github.com/repos/Automattic/wp-calypso/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Automattic/wp-calypso/statuses/{sha}","languages_url":"https://api.github.com/repos/Automattic/wp-calypso/languages","stargazers_url":"https://api.github.com/repos/Automattic/wp-calypso/stargazers","contributors_url":"https://api.github.com/repos/Automattic/wp-calypso/contributors","subscribers_url":"https://api.github.com/repos/Automattic/wp-calypso/subscribers","subscription_url":"https://api.github.com/repos/Automattic/wp-calypso/subscription","commits_url":"https://api.github.com/repos/Automattic/wp-calypso/commits{/sha}","git_commits_url":"https://api.github.com/repos/Automattic/wp-calypso/git/commits{/sha}","comments_url":"https://api.github.com/repos/Automattic/wp-calypso/comments{/number}","issue_comment_url":"https://api.github.com/repos/Automattic/wp-calypso/issues/comments{/number}","contents_url":"https://api.github.com/repos/Automattic/wp-calypso/contents/{+path}","compare_url":"https://api.github.com/repos/Automattic/wp-calypso/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Automattic/wp-calypso/merges","archive_url":"https://api.github.com/repos/Automattic/wp-calypso/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Automattic/wp-calypso/downloads","issues_url":"https://api.github.com/repos/Automattic/wp-calypso/issues{/number}","pulls_url":"https://api.github.com/repos/Automattic/wp-calypso/pulls{/number}","milestones_url":"https://api.github.com/repos/Automattic/wp-calypso/milestones{/number}","notifications_url":"https://api.github.com/repos/Automattic/wp-calypso/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Automattic/wp-calypso/labels{/name}","releases_url":"https://api.github.com/repos/Automattic/wp-calypso/releases{/id}","deployments_url":"https://api.github.com/repos/Automattic/wp-calypso/deployments","created_at":"2015-11-10T20:00:16Z","updated_at":"2016-04-27T12:28:51Z","pushed_at":"2016-04-27T14:13:03Z","git_url":"git://github.com/Automattic/wp-calypso.git","ssh_url":"git@github.com:Automattic/wp-calypso.git","clone_url":"https://github.com/Automattic/wp-calypso.git","svn_url":"https://github.com/Automattic/wp-calypso","homepage":"https://developer.wordpress.com/calypso/","size":74835,"stargazers_count":7209,"watchers_count":7209,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":872,"mirror_url":null,"open_issues_count":1314,"forks":872,"open_issues":1314,"watchers":7209,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020"},"html":{"href":"https://github.com/Automattic/wp-calypso/pull/5020"},"issue":{"href":"https://api.github.com/repos/Automattic/wp-calypso/issues/5020"},"comments":{"href":"https://api.github.com/repos/Automattic/wp-calypso/issues/5020/comments"},"review_comments":{"href":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020/comments"},"review_comment":{"href":"https://api.github.com/repos/Automattic/wp-calypso/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Automattic/wp-calypso/pulls/5020/commits"},"statuses":{"href":"https://api.github.com/repos/Automattic/wp-calypso/statuses/a0f6c079ebef4154ba319272325ed0f4ad34b841"}}}}