1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Rough implementation of drag-and-drop file uploads

Summary:
This gets all the major pieces working. Allows you to drag-and-drop files in
Differential and Phriction, and embed files in remarkup with {Fxxx} references.
See also task.

I'm explicitly not documenting this yet since it's still pretty rough.

Test Plan: Dragged and dropped stuff into Differential and Phriction.
Reviewed By: jungejason
Reviewers: jungejason, tuomaspelkonen, aran, tomo
Commenters: tomo
CC: aran, tomo, jungejason
Differential Revision: 674
This commit is contained in:
epriestley 2011-07-15 14:17:55 -07:00
parent 35d03d36c7
commit 9d3f33a7a6
13 changed files with 198 additions and 53 deletions

View file

@ -54,7 +54,7 @@ celerity_register_resource_map(array(
),
'aphront-form-view-css' =>
array(
'uri' => '/res/8ee16aba/rsrc/css/aphront/form-view.css',
'uri' => '/res/c79fd668/rsrc/css/aphront/form-view.css',
'type' => 'css',
'requires' =>
array(
@ -117,7 +117,7 @@ celerity_register_resource_map(array(
),
'aphront-table-view-css' =>
array(
'uri' => '/res/3ac9ba50/rsrc/css/aphront/table-view.css',
'uri' => '/res/f4f39a2e/rsrc/css/aphront/table-view.css',
'type' => 'css',
'requires' =>
array(
@ -331,6 +331,18 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop.js',
),
'javelin-behavior-aphront-drag-and-drop-textarea' =>
array(
'uri' => '/res/fa7527f9/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',
),
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
),
'javelin-behavior-aphront-form-disable-on-submit' =>
array(
'uri' => '/res/6c659ede/rsrc/js/application/core/behavior-form.js',
@ -637,6 +649,37 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/js/application/core/behavior-keyboard-shortcuts.js',
),
'javelin-behavior-phriction-document-preview' =>
array(
'uri' => '/res/f1665ecd/rsrc/js/application/phriction/phriction-document-preview.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-util',
3 => 'phabricator-shaped-request',
),
'disk' => '/rsrc/js/application/phriction/phriction-document-preview.js',
),
'javelin-behavior-projects-resource-editor' =>
array(
'uri' => '/res/a54d5616/rsrc/js/application/projects/projects-resource-editor.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'phabricator-prefab',
2 => 'multirow-row-manager',
3 => 'javelin-tokenizer',
4 => 'javelin-typeahead-preloaded-source',
5 => 'javelin-typeahead',
6 => 'javelin-dom',
7 => 'javelin-json',
8 => 'javelin-util',
),
'disk' => '/rsrc/js/application/projects/projects-resource-editor.js',
),
0 =>
array(
'uri' => '/res/1da00bfe/rsrc/js/javelin/lib/__tests__/URI.js',
@ -675,37 +718,6 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/js/application/core/behavior-watch-anchor.js',
),
'javelin-behavior-phriction-document-preview' =>
array(
'uri' => '/res/f1665ecd/rsrc/js/application/phriction/phriction-document-preview.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-util',
3 => 'phabricator-shaped-request',
),
'disk' => '/rsrc/js/application/phriction/phriction-document-preview.js',
),
'javelin-behavior-projects-resource-editor' =>
array(
'uri' => '/res/a54d5616/rsrc/js/application/projects/projects-resource-editor.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'phabricator-prefab',
2 => 'multirow-row-manager',
3 => 'javelin-tokenizer',
4 => 'javelin-typeahead-preloaded-source',
5 => 'javelin-typeahead',
6 => 'javelin-dom',
7 => 'javelin-json',
8 => 'javelin-util',
),
'disk' => '/rsrc/js/application/projects/projects-resource-editor.js',
),
'javelin-behavior-refresh-csrf' =>
array(
'uri' => '/res/39aa51f7/rsrc/js/application/core/behavior-refresh-csrf.js',
@ -1305,7 +1317,7 @@ celerity_register_resource_map(array(
'uri' => '/res/pkg/95b66c1a/differential.pkg.css',
'type' => 'css',
),
'b3fd9e3f' =>
'a841d3be' =>
array (
'name' => 'core.pkg.css',
'symbols' =>
@ -1326,7 +1338,7 @@ celerity_register_resource_map(array(
13 => 'phabricator-remarkup-css',
14 => 'syntax-highlighting-css',
),
'uri' => '/res/pkg/b3fd9e3f/core.pkg.css',
'uri' => '/res/pkg/a841d3be/core.pkg.css',
'type' => 'css',
),
'd0713563' =>
@ -1362,15 +1374,15 @@ celerity_register_resource_map(array(
),
'reverse' =>
array (
'aphront-crumbs-view-css' => 'b3fd9e3f',
'aphront-dialog-view-css' => 'b3fd9e3f',
'aphront-form-view-css' => 'b3fd9e3f',
'aphront-list-filter-view-css' => 'b3fd9e3f',
'aphront-panel-view-css' => 'b3fd9e3f',
'aphront-side-nav-view-css' => 'b3fd9e3f',
'aphront-table-view-css' => 'b3fd9e3f',
'aphront-tokenizer-control-css' => 'b3fd9e3f',
'aphront-typeahead-control-css' => 'b3fd9e3f',
'aphront-crumbs-view-css' => 'a841d3be',
'aphront-dialog-view-css' => 'a841d3be',
'aphront-form-view-css' => 'a841d3be',
'aphront-list-filter-view-css' => 'a841d3be',
'aphront-panel-view-css' => 'a841d3be',
'aphront-side-nav-view-css' => 'a841d3be',
'aphront-table-view-css' => 'a841d3be',
'aphront-tokenizer-control-css' => 'a841d3be',
'aphront-typeahead-control-css' => 'a841d3be',
'differential-changeset-view-css' => '95b66c1a',
'differential-core-view-css' => '95b66c1a',
'differential-revision-add-comment-css' => '95b66c1a',
@ -1407,13 +1419,13 @@ celerity_register_resource_map(array(
'javelin-util' => '307df223',
'javelin-vector' => '307df223',
'javelin-workflow' => 'd0713563',
'phabricator-core-buttons-css' => 'b3fd9e3f',
'phabricator-core-css' => 'b3fd9e3f',
'phabricator-directory-css' => 'b3fd9e3f',
'phabricator-core-buttons-css' => 'a841d3be',
'phabricator-core-css' => 'a841d3be',
'phabricator-directory-css' => 'a841d3be',
'phabricator-keyboard-shortcut' => 'd0713563',
'phabricator-keyboard-shortcut-manager' => 'd0713563',
'phabricator-remarkup-css' => 'b3fd9e3f',
'phabricator-standard-page-view' => 'b3fd9e3f',
'syntax-highlighting-css' => 'b3fd9e3f',
'phabricator-remarkup-css' => 'a841d3be',
'phabricator-standard-page-view' => 'a841d3be',
'syntax-highlighting-css' => 'a841d3be',
),
));

View file

@ -477,6 +477,7 @@ phutil_register_library_map(array(
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/refresh',
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion',
'PhabricatorRemarkupRuleEmbedFile' => 'infrastructure/markup/remarkup/markuprule/embedobject',
'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro',
'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
'PhabricatorRemarkupRuleMention' => 'infrastructure/markup/remarkup/markuprule/mention',
@ -1013,6 +1014,7 @@ phutil_register_library_map(array(
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',
'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleEmbedFile' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleManiphest' => 'PhabricatorRemarkupRuleObjectName',
'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule',

View file

@ -106,6 +106,7 @@ final class DifferentialAddCommentView extends AphrontView {
->setName('comment')
->setID('comment-content')
->setLabel('Comment')
->setEnableDragAndDropFileUploads(true)
->setValue($this->draft))
->appendChild(
id(new AphrontFormSubmitControl())

View file

@ -100,6 +100,7 @@ class PhabricatorMarkupEngine {
$rules[] = new PhutilRemarkupRuleHyperlink();
$rules[] = new PhabricatorRemarkupRuleEmbedFile();
$rules[] = new PhabricatorRemarkupRuleDifferential();
$rules[] = new PhabricatorRemarkupRuleDiffusion();
$rules[] = new PhabricatorRemarkupRuleManiphest();

View file

@ -9,6 +9,7 @@
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/differential');
phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/diffusion');
phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/embedobject');
phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/imagemacro');
phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/maniphest');
phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/mention');

View file

@ -193,6 +193,7 @@ class PhrictionEditController
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
->setName('content')
->setID('document-textarea')
->setEnableDragAndDropFileUploads(true)
->setCaption($remarkup_reference))
->appendChild(
id(new AphrontFormSubmitControl())

View file

@ -0,0 +1,58 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group markup
*/
class PhabricatorRemarkupRuleEmbedFile
extends PhutilRemarkupRule {
public function apply($text) {
return preg_replace_callback(
"@{F(\d+)}@",
array($this, 'markupEmbedFile'),
$text);
}
public function markupEmbedFile($matches) {
$file = null;
if ($matches[1]) {
// TODO: This is pretty inefficient if there are a bunch of files.
$file = id(new PhabricatorFile())->load($matches[1]);
}
if ($file) {
return $this->getEngine()->storeText(
phutil_render_tag(
'a',
array(
'href' => $file->getViewURI(),
'target' => '_blank',
),
phutil_render_tag(
'img',
array(
'src' => $file->getThumb160x120URI(),
))));
} else {
return $matches[0];
}
}
}

View file

@ -0,0 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/files/storage/file');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'markup/engine/remarkup/markuprule/base');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorRemarkupRuleEmbedFile.php');

View file

@ -72,13 +72,12 @@ class PhabricatorRemarkupRuleMention
$username = strtolower($matches[1]);
$exists = isset($this->actualUsers[$username]);
$real = $this->actualUsers[$username]['realName'];
$class = $exists
? 'phabricator-remarkup-mention-exists'
: 'phabricator-remarkup-mention-unknown';
if ($exists) {
$real = $this->actualUsers[$username]['realName'];
$tag = phutil_render_tag(
'a',
array(

View file

@ -23,6 +23,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
const HEIGHT_VERY_TALL = 'very-tall';
private $height;
private $enableDragAndDropFileUploads;
public function setHeight($height) {
$this->height = $height;
@ -33,6 +34,11 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
return 'aphront-form-control-textarea';
}
public function setEnableDragAndDropFileUploads($enable) {
$this->enableDragAndDropFileUploads = $enable;
return $this;
}
protected function renderInput() {
$height_class = null;
@ -44,6 +50,20 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
break;
}
$id = $this->getID();
if ($this->enableDragAndDropFileUploads) {
if (!$id) {
$id = celerity_generate_unique_node_id();
}
Javelin::initBehavior(
'aphront-drag-and-drop-textarea',
array(
'target' => $id,
'activatedClass' => 'aphront-textarea-drag-and-drop',
'uri' => '/file/dropupload/',
));
}
return phutil_render_tag(
'textarea',
array(
@ -51,7 +71,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl {
'disabled' => $this->getDisabled() ? 'disabled' : null,
'class' => $height_class,
'style' => $this->getControlStyle(),
'id' => $this->getID(),
'id' => $id,
),
phutil_escape_html($this->getValue()));
}

View file

@ -6,6 +6,8 @@
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'infrastructure/javelin/api');
phutil_require_module('phabricator', 'view/form/control/base');
phutil_require_module('phutil', 'markup');

View file

@ -133,3 +133,8 @@ table.aphront-form-control-checkbox-layout th {
font-size: 11px;
padding: 6px 8px;
}
.aphront-textarea-drag-and-drop {
background: #99ff99;
border-color: #669966;
}

View file

@ -0,0 +1,27 @@
/**
* @provides javelin-behavior-aphront-drag-and-drop-textarea
* @requires javelin-behavior
* javelin-dom
* phabricator-drag-and-drop-file-upload
*/
JX.behavior('aphront-drag-and-drop-textarea', function(config) {
if (!JX.PhabricatorDragAndDropFileUpload.isSupported()) {
return;
}
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();
});