mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 21:02:41 +01:00
Support paste file uploads
Summary: This is so freaking cool that I will try to implement it also on Facebook. Idea is from http://strd6.com/2011/09/html5-javascript-pasting-image-data-in-chrome/. I don't know how to properly detect support but lying about it is not a big deal. Test Plan: Go to revision comment textarea. Paste some text data - works as usual. Paste some image data in Chrome - file is uploaded and a link to it is inserted. Reviewers: epriestley Reviewed By: epriestley CC: aran, epriestley Differential Revision: https://secure.phabricator.com/D1681
This commit is contained in:
parent
48ab6aa465
commit
97144c0932
5 changed files with 160 additions and 61 deletions
2
externals/javelin
vendored
2
externals/javelin
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 45fa775fea5cc7fa1d834a04b9d25a08bcfa4812
|
Subproject commit 14f4218c5b7d50bb0f4144d937e482cdb98f6cdb
|
|
@ -361,13 +361,14 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-behavior-aphront-drag-and-drop-textarea' =>
|
'javelin-behavior-aphront-drag-and-drop-textarea' =>
|
||||||
array(
|
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',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
0 => 'javelin-behavior',
|
0 => 'javelin-behavior',
|
||||||
1 => 'javelin-dom',
|
1 => 'javelin-dom',
|
||||||
2 => 'phabricator-drag-and-drop-file-upload',
|
2 => 'phabricator-drag-and-drop-file-upload',
|
||||||
|
3 => 'phabricator-paste-file-upload',
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
||||||
),
|
),
|
||||||
|
@ -954,7 +955,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-magical-init' =>
|
'javelin-magical-init' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/d6832060/rsrc/js/javelin/core/init.js',
|
'uri' => '/res/caa86a45/rsrc/js/javelin/core/init.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1426,24 +1427,6 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'disk' => '/rsrc/js/application/core/DropdownMenu.js',
|
'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' =>
|
'phabricator-keyboard-shortcut' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/beed38cd/rsrc/js/application/core/KeyboardShortcut.js',
|
'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',
|
'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' =>
|
'phabricator-profile-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/9869d10b/rsrc/css/application/profile/profile-view.css',
|
'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',
|
'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' =>
|
'phabricator-slowvote-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css',
|
'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',
|
'uri' => '/res/pkg/6a6def05/core.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'ef420ead' =>
|
'c8aaade8' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'differential.pkg.js',
|
'name' => 'differential.pkg.js',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -1917,7 +1932,7 @@ celerity_register_resource_map(array(
|
||||||
13 => 'javelin-behavior-phabricator-object-selector',
|
13 => 'javelin-behavior-phabricator-object-selector',
|
||||||
14 => 'differential-inline-comment-editor',
|
14 => 'differential-inline-comment-editor',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/ef420ead/differential.pkg.js',
|
'uri' => '/res/pkg/c8aaade8/differential.pkg.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1935,7 +1950,7 @@ celerity_register_resource_map(array(
|
||||||
'aphront-typeahead-control-css' => '6a6def05',
|
'aphront-typeahead-control-css' => '6a6def05',
|
||||||
'differential-changeset-view-css' => '4c3b1b11',
|
'differential-changeset-view-css' => '4c3b1b11',
|
||||||
'differential-core-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-local-commits-view-css' => '4c3b1b11',
|
||||||
'differential-revision-add-comment-css' => '4c3b1b11',
|
'differential-revision-add-comment-css' => '4c3b1b11',
|
||||||
'differential-revision-comment-css' => '4c3b1b11',
|
'differential-revision-comment-css' => '4c3b1b11',
|
||||||
|
@ -1946,20 +1961,20 @@ celerity_register_resource_map(array(
|
||||||
'diffusion-commit-view-css' => '03ef179e',
|
'diffusion-commit-view-css' => '03ef179e',
|
||||||
'javelin-behavior' => '4fbae2af',
|
'javelin-behavior' => '4fbae2af',
|
||||||
'javelin-behavior-aphront-basic-tokenizer' => '080edee4',
|
'javelin-behavior-aphront-basic-tokenizer' => '080edee4',
|
||||||
'javelin-behavior-aphront-drag-and-drop' => 'ef420ead',
|
'javelin-behavior-aphront-drag-and-drop' => 'c8aaade8',
|
||||||
'javelin-behavior-aphront-drag-and-drop-textarea' => 'ef420ead',
|
'javelin-behavior-aphront-drag-and-drop-textarea' => 'c8aaade8',
|
||||||
'javelin-behavior-aphront-form-disable-on-submit' => '46547a92',
|
'javelin-behavior-aphront-form-disable-on-submit' => '46547a92',
|
||||||
'javelin-behavior-differential-accept-with-errors' => 'ef420ead',
|
'javelin-behavior-differential-accept-with-errors' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'ef420ead',
|
'javelin-behavior-differential-add-reviewers-and-ccs' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-comment-jump' => 'ef420ead',
|
'javelin-behavior-differential-comment-jump' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-diff-radios' => 'ef420ead',
|
'javelin-behavior-differential-diff-radios' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-edit-inline-comments' => 'ef420ead',
|
'javelin-behavior-differential-edit-inline-comments' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-feedback-preview' => 'ef420ead',
|
'javelin-behavior-differential-feedback-preview' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-keyboard-navigation' => 'ef420ead',
|
'javelin-behavior-differential-keyboard-navigation' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-populate' => 'ef420ead',
|
'javelin-behavior-differential-populate' => 'c8aaade8',
|
||||||
'javelin-behavior-differential-show-more' => 'ef420ead',
|
'javelin-behavior-differential-show-more' => 'c8aaade8',
|
||||||
'javelin-behavior-phabricator-keyboard-shortcuts' => '46547a92',
|
'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-phabricator-watch-anchor' => '46547a92',
|
||||||
'javelin-behavior-refresh-csrf' => '46547a92',
|
'javelin-behavior-refresh-csrf' => '46547a92',
|
||||||
'javelin-behavior-workflow' => '46547a92',
|
'javelin-behavior-workflow' => '46547a92',
|
||||||
|
@ -1984,12 +1999,12 @@ celerity_register_resource_map(array(
|
||||||
'phabricator-core-buttons-css' => '6a6def05',
|
'phabricator-core-buttons-css' => '6a6def05',
|
||||||
'phabricator-core-css' => '6a6def05',
|
'phabricator-core-css' => '6a6def05',
|
||||||
'phabricator-directory-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' => '46547a92',
|
||||||
'phabricator-keyboard-shortcut-manager' => '46547a92',
|
'phabricator-keyboard-shortcut-manager' => '46547a92',
|
||||||
'phabricator-object-selector-css' => '4c3b1b11',
|
'phabricator-object-selector-css' => '4c3b1b11',
|
||||||
'phabricator-remarkup-css' => '6a6def05',
|
'phabricator-remarkup-css' => '6a6def05',
|
||||||
'phabricator-shaped-request' => 'ef420ead',
|
'phabricator-shaped-request' => 'c8aaade8',
|
||||||
'phabricator-standard-page-view' => '6a6def05',
|
'phabricator-standard-page-view' => '6a6def05',
|
||||||
'syntax-highlighting-css' => '6a6def05',
|
'syntax-highlighting-css' => '6a6def05',
|
||||||
),
|
),
|
||||||
|
|
|
@ -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
|
In most interfaces, you can drag-and-drop an image from your computer into the
|
||||||
text area to upload and reference it.
|
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:
|
You can set file display options like this:
|
||||||
|
|
||||||
{F123, layout=left, float, size=full}
|
{F123, layout=left, float, size=full}
|
||||||
|
|
68
webroot/rsrc/js/application/core/PasteFileUpload.js
Normal file
68
webroot/rsrc/js/application/core/PasteFileUpload.js
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
});
|
|
@ -3,14 +3,12 @@
|
||||||
* @requires javelin-behavior
|
* @requires javelin-behavior
|
||||||
* javelin-dom
|
* javelin-dom
|
||||||
* phabricator-drag-and-drop-file-upload
|
* phabricator-drag-and-drop-file-upload
|
||||||
|
* phabricator-paste-file-upload
|
||||||
*/
|
*/
|
||||||
|
|
||||||
JX.behavior('aphront-drag-and-drop-textarea', function(config) {
|
JX.behavior('aphront-drag-and-drop-textarea', function(config) {
|
||||||
|
|
||||||
if (!JX.PhabricatorDragAndDropFileUpload.isSupported()) {
|
if (JX.PhabricatorDragAndDropFileUpload.isSupported()) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var target = JX.$(config.target);
|
var target = JX.$(config.target);
|
||||||
var drop = new JX.PhabricatorDragAndDropFileUpload(target)
|
var drop = new JX.PhabricatorDragAndDropFileUpload(target)
|
||||||
.setActivatedClass(config.activatedClass)
|
.setActivatedClass(config.activatedClass)
|
||||||
|
@ -23,5 +21,20 @@ JX.behavior('aphront-drag-and-drop-textarea', function(config) {
|
||||||
});
|
});
|
||||||
|
|
||||||
drop.start();
|
drop.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JX.PhabricatorPasteFileUpload.isSupported()) {
|
||||||
|
var target = JX.$(config.target);
|
||||||
|
var paste = new JX.PhabricatorPasteFileUpload(target).setURI(config.uri);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue