diff --git a/externals/javelin b/externals/javelin index 45fa775fea..14f4218c5b 160000 --- a/externals/javelin +++ b/externals/javelin @@ -1 +1 @@ -Subproject commit 45fa775fea5cc7fa1d834a04b9d25a08bcfa4812 +Subproject commit 14f4218c5b7d50bb0f4144d937e482cdb98f6cdb diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 3e42ddd866..b66e75c4d1 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -361,13 +361,14 @@ celerity_register_resource_map(array( ), 'javelin-behavior-aphront-drag-and-drop-textarea' => array( - 'uri' => '/res/fa7527f9/rsrc/js/application/core/behavior-drag-and-drop-textarea.js', + 'uri' => '/res/65980508/rsrc/js/application/core/behavior-drag-and-drop-textarea.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'phabricator-drag-and-drop-file-upload', + 3 => 'phabricator-paste-file-upload', ), 'disk' => '/rsrc/js/application/core/behavior-drag-and-drop-textarea.js', ), @@ -954,7 +955,7 @@ celerity_register_resource_map(array( ), 'javelin-magical-init' => array( - 'uri' => '/res/d6832060/rsrc/js/javelin/core/init.js', + 'uri' => '/res/caa86a45/rsrc/js/javelin/core/init.js', 'type' => 'js', 'requires' => array( @@ -1426,24 +1427,6 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/DropdownMenu.js', ), - 'phabricator-feed-css' => - array( - 'uri' => '/res/e4bf27b5/rsrc/css/application/feed/feed.css', - 'type' => 'css', - 'requires' => - array( - ), - 'disk' => '/rsrc/css/application/feed/feed.css', - ), - 'phabricator-jump-nav' => - array( - 'uri' => '/res/69238d2f/rsrc/css/application/directory/phabricator-jump-nav.css', - 'type' => 'css', - 'requires' => - array( - ), - 'disk' => '/rsrc/css/application/directory/phabricator-jump-nav.css', - ), 'phabricator-keyboard-shortcut' => array( 'uri' => '/res/beed38cd/rsrc/js/application/core/KeyboardShortcut.js', @@ -1503,6 +1486,49 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/Prefab.js', ), + 0 => + array( + 'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-uri', + 1 => 'javelin-php-serializer', + ), + 'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js', + ), + 'phabricator-feed-css' => + array( + 'uri' => '/res/e4bf27b5/rsrc/css/application/feed/feed.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/feed/feed.css', + ), + 'phabricator-jump-nav' => + array( + 'uri' => '/res/69238d2f/rsrc/css/application/directory/phabricator-jump-nav.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/directory/phabricator-jump-nav.css', + ), + 'phabricator-paste-file-upload' => + array( + 'uri' => '/res/cdc939bd/rsrc/js/application/core/PasteFileUpload.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-request', + 3 => 'javelin-dom', + 4 => 'javelin-uri', + ), + 'disk' => '/rsrc/js/application/core/PasteFileUpload.js', + ), 'phabricator-profile-css' => array( 'uri' => '/res/9869d10b/rsrc/css/application/profile/profile-view.css', @@ -1551,17 +1577,6 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/ShapedRequest.js', ), - 0 => - array( - 'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js', - 'type' => 'js', - 'requires' => - array( - 0 => 'javelin-uri', - 1 => 'javelin-php-serializer', - ), - 'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js', - ), 'phabricator-slowvote-css' => array( 'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css', @@ -1896,7 +1911,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/6a6def05/core.pkg.css', 'type' => 'css', ), - 'ef420ead' => + 'c8aaade8' => array( 'name' => 'differential.pkg.js', 'symbols' => @@ -1917,7 +1932,7 @@ celerity_register_resource_map(array( 13 => 'javelin-behavior-phabricator-object-selector', 14 => 'differential-inline-comment-editor', ), - 'uri' => '/res/pkg/ef420ead/differential.pkg.js', + 'uri' => '/res/pkg/c8aaade8/differential.pkg.js', 'type' => 'js', ), ), @@ -1935,7 +1950,7 @@ celerity_register_resource_map(array( 'aphront-typeahead-control-css' => '6a6def05', 'differential-changeset-view-css' => '4c3b1b11', 'differential-core-view-css' => '4c3b1b11', - 'differential-inline-comment-editor' => 'ef420ead', + 'differential-inline-comment-editor' => 'c8aaade8', 'differential-local-commits-view-css' => '4c3b1b11', 'differential-revision-add-comment-css' => '4c3b1b11', 'differential-revision-comment-css' => '4c3b1b11', @@ -1946,20 +1961,20 @@ celerity_register_resource_map(array( 'diffusion-commit-view-css' => '03ef179e', 'javelin-behavior' => '4fbae2af', 'javelin-behavior-aphront-basic-tokenizer' => '080edee4', - 'javelin-behavior-aphront-drag-and-drop' => 'ef420ead', - 'javelin-behavior-aphront-drag-and-drop-textarea' => 'ef420ead', + 'javelin-behavior-aphront-drag-and-drop' => 'c8aaade8', + 'javelin-behavior-aphront-drag-and-drop-textarea' => 'c8aaade8', 'javelin-behavior-aphront-form-disable-on-submit' => '46547a92', - 'javelin-behavior-differential-accept-with-errors' => 'ef420ead', - 'javelin-behavior-differential-add-reviewers-and-ccs' => 'ef420ead', - 'javelin-behavior-differential-comment-jump' => 'ef420ead', - 'javelin-behavior-differential-diff-radios' => 'ef420ead', - 'javelin-behavior-differential-edit-inline-comments' => 'ef420ead', - 'javelin-behavior-differential-feedback-preview' => 'ef420ead', - 'javelin-behavior-differential-keyboard-navigation' => 'ef420ead', - 'javelin-behavior-differential-populate' => 'ef420ead', - 'javelin-behavior-differential-show-more' => 'ef420ead', + 'javelin-behavior-differential-accept-with-errors' => 'c8aaade8', + 'javelin-behavior-differential-add-reviewers-and-ccs' => 'c8aaade8', + 'javelin-behavior-differential-comment-jump' => 'c8aaade8', + 'javelin-behavior-differential-diff-radios' => 'c8aaade8', + 'javelin-behavior-differential-edit-inline-comments' => 'c8aaade8', + 'javelin-behavior-differential-feedback-preview' => 'c8aaade8', + 'javelin-behavior-differential-keyboard-navigation' => 'c8aaade8', + 'javelin-behavior-differential-populate' => 'c8aaade8', + 'javelin-behavior-differential-show-more' => 'c8aaade8', 'javelin-behavior-phabricator-keyboard-shortcuts' => '46547a92', - 'javelin-behavior-phabricator-object-selector' => 'ef420ead', + 'javelin-behavior-phabricator-object-selector' => 'c8aaade8', 'javelin-behavior-phabricator-watch-anchor' => '46547a92', 'javelin-behavior-refresh-csrf' => '46547a92', 'javelin-behavior-workflow' => '46547a92', @@ -1984,12 +1999,12 @@ celerity_register_resource_map(array( 'phabricator-core-buttons-css' => '6a6def05', 'phabricator-core-css' => '6a6def05', 'phabricator-directory-css' => '6a6def05', - 'phabricator-drag-and-drop-file-upload' => 'ef420ead', + 'phabricator-drag-and-drop-file-upload' => 'c8aaade8', 'phabricator-keyboard-shortcut' => '46547a92', 'phabricator-keyboard-shortcut-manager' => '46547a92', 'phabricator-object-selector-css' => '4c3b1b11', 'phabricator-remarkup-css' => '6a6def05', - 'phabricator-shaped-request' => 'ef420ead', + 'phabricator-shaped-request' => 'c8aaade8', 'phabricator-standard-page-view' => '6a6def05', 'syntax-highlighting-css' => '6a6def05', ), diff --git a/src/docs/userguide/remarkup.diviner b/src/docs/userguide/remarkup.diviner index 0c62fcefd0..9c0b59632f 100644 --- a/src/docs/userguide/remarkup.diviner +++ b/src/docs/userguide/remarkup.diviner @@ -285,6 +285,9 @@ You can embed an image by using braces to refer to it: In most interfaces, you can drag-and-drop an image from your computer into the text area to upload and reference it. +Some browsers (e.g. Chrome) support uploading an image data just by pasting them +from clipboard into the text area. + You can set file display options like this: {F123, layout=left, float, size=full} diff --git a/webroot/rsrc/js/application/core/PasteFileUpload.js b/webroot/rsrc/js/application/core/PasteFileUpload.js new file mode 100644 index 0000000000..73d4bdc1f0 --- /dev/null +++ b/webroot/rsrc/js/application/core/PasteFileUpload.js @@ -0,0 +1,68 @@ +/** + * @requires javelin-install + * javelin-util + * javelin-request + * javelin-dom + * javelin-uri + * @provides phabricator-paste-file-upload + * @javelin + */ + +JX.install('PhabricatorPasteFileUpload', { + + construct : function(node) { + this._node = node; + }, + + events : ['willUpload', 'didUpload'], + + statics : { + isSupported : function() { + // TODO: Needs to check if event.clipboardData is available. + // Works in Chrome, doesn't work in Firefox 10. + return !!window.FileList; + } + }, + + members : { + _node : null, + + start : function() { + JX.DOM.listen( + this._node, + 'paste', + null, + JX.bind(this, function(e) { + var clipboardData = e.getRawEvent().clipboardData; + if (!clipboardData) { + return; + } + for (var ii = 0; ii < clipboardData.types.length; ii++) { + if (/^image\//.test(clipboardData.types[ii])) { + var file = clipboardData.items[ii].getAsFile(); + + this.invoke('willUpload', file); + + var up_uri = JX.$U(this.getURI()) + .setQueryParam('name', 'clipboard.png') + .toString(); + + new JX.Request(up_uri, JX.bind(this, function(r) { + this.invoke('didUpload', r); + })) + .setFile(file) + .send(); + + e.kill(); + break; + } + } + + })); + } + }, + + properties: { + URI : null + } +}); diff --git a/webroot/rsrc/js/application/core/behavior-drag-and-drop-textarea.js b/webroot/rsrc/js/application/core/behavior-drag-and-drop-textarea.js index 73d33c27b8..ea54391413 100644 --- a/webroot/rsrc/js/application/core/behavior-drag-and-drop-textarea.js +++ b/webroot/rsrc/js/application/core/behavior-drag-and-drop-textarea.js @@ -3,25 +3,38 @@ * @requires javelin-behavior * javelin-dom * phabricator-drag-and-drop-file-upload + * phabricator-paste-file-upload */ JX.behavior('aphront-drag-and-drop-textarea', function(config) { - if (!JX.PhabricatorDragAndDropFileUpload.isSupported()) { - return; + if (JX.PhabricatorDragAndDropFileUpload.isSupported()) { + var target = JX.$(config.target); + var drop = new JX.PhabricatorDragAndDropFileUpload(target) + .setActivatedClass(config.activatedClass) + .setURI(config.uri); + + drop.listen('didUpload', function(f) { + // TODO: Implement some fancy cursor position stuff in Javelin so we + // can drop it in wherever the cursor is. + target.value = target.value + "\n{F" + f.id + "}"; + }); + + drop.start(); } - var target = JX.$(config.target); - var drop = new JX.PhabricatorDragAndDropFileUpload(target) - .setActivatedClass(config.activatedClass) - .setURI(config.uri); + if (JX.PhabricatorPasteFileUpload.isSupported()) { + var target = JX.$(config.target); + var paste = new JX.PhabricatorPasteFileUpload(target).setURI(config.uri); - drop.listen('didUpload', function(f) { - // TODO: Implement some fancy cursor position stuff in Javelin so we - // can drop it in wherever the cursor is. - target.value = target.value + "\n{F" + f.id + "}"; - }); + paste.listen('didUpload', function(f) { + // TODO: Implement some fancy cursor position stuff in Javelin so we + // can drop it in wherever the cursor is. + target.value = target.value + '{F' + f.id + '}'; + }); + + paste.start(); + } - drop.start(); });