mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-13 23:38:34 +01:00
Quicksand - make things work correctly with global drag and drop upload
Summary: Fixes T7685. This required making the global drag and drop behavior able to "uninstall" itself so to speak, and then it re-installs it self as necessary. Test Plan: Did the following all successfully - uploaded a file to homepage - homepage -> differential -- no way to upload via drag and drop - homepage -> differential -> homepage -- uploaded a file - homepage -> differential -> browser back button to homepage -- uploaded a file Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T7685 Differential Revision: https://secure.phabricator.com/D12534
This commit is contained in:
parent
cf154ae9f4
commit
e40aa8f782
9 changed files with 179 additions and 87 deletions
|
@ -8,10 +8,10 @@
|
|||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => '9a9b59ca',
|
||||
'core.pkg.js' => '348d5193',
|
||||
'core.pkg.js' => '493cc6e6',
|
||||
'darkconsole.pkg.js' => '8ab24e01',
|
||||
'differential.pkg.css' => '3500921f',
|
||||
'differential.pkg.js' => 'c0506961',
|
||||
'differential.pkg.js' => '890046d3',
|
||||
'diffusion.pkg.css' => '591664fa',
|
||||
'diffusion.pkg.js' => '0115b37c',
|
||||
'maniphest.pkg.css' => '68d4dd3d',
|
||||
|
@ -442,7 +442,7 @@ return array(
|
|||
'rsrc/js/application/uiexample/gesture-example.js' => '558829c2',
|
||||
'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5',
|
||||
'rsrc/js/core/Busy.js' => '59a7976a',
|
||||
'rsrc/js/core/DragAndDropFileUpload.js' => '7fa4b248',
|
||||
'rsrc/js/core/DragAndDropFileUpload.js' => '07de8873',
|
||||
'rsrc/js/core/DraggableList.js' => 'a16ec1c6',
|
||||
'rsrc/js/core/FileUpload.js' => '477359c8',
|
||||
'rsrc/js/core/Hovercard.js' => '7e8468ae',
|
||||
|
@ -468,7 +468,7 @@ return array(
|
|||
'rsrc/js/core/behavior-file-tree.js' => '88236f00',
|
||||
'rsrc/js/core/behavior-form.js' => '5c54cbf3',
|
||||
'rsrc/js/core/behavior-gesture.js' => '3ab51e2c',
|
||||
'rsrc/js/core/behavior-global-drag-and-drop.js' => 'bbdf75ca',
|
||||
'rsrc/js/core/behavior-global-drag-and-drop.js' => '3f6075ff',
|
||||
'rsrc/js/core/behavior-high-security-warning.js' => '8fc1c918',
|
||||
'rsrc/js/core/behavior-history-install.js' => '7ee2b591',
|
||||
'rsrc/js/core/behavior-hovercard.js' => 'f36e01af',
|
||||
|
@ -593,7 +593,7 @@ return array(
|
|||
'javelin-behavior-durable-column' => '657c2b50',
|
||||
'javelin-behavior-error-log' => '6882e80a',
|
||||
'javelin-behavior-fancy-datepicker' => 'c51ae228',
|
||||
'javelin-behavior-global-drag-and-drop' => 'bbdf75ca',
|
||||
'javelin-behavior-global-drag-and-drop' => '3f6075ff',
|
||||
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
|
||||
'javelin-behavior-high-security-warning' => '8fc1c918',
|
||||
'javelin-behavior-history-install' => '7ee2b591',
|
||||
|
@ -726,7 +726,7 @@ return array(
|
|||
'phabricator-core-css' => '76e8ee93',
|
||||
'phabricator-countdown-css' => '86b7b0a0',
|
||||
'phabricator-dashboard-css' => '17937d22',
|
||||
'phabricator-drag-and-drop-file-upload' => '7fa4b248',
|
||||
'phabricator-drag-and-drop-file-upload' => '07de8873',
|
||||
'phabricator-draggable-list' => 'a16ec1c6',
|
||||
'phabricator-fatal-config-template-css' => '8e6c6fcd',
|
||||
'phabricator-feed-css' => 'b513b5f4',
|
||||
|
@ -869,6 +869,14 @@ return array(
|
|||
'phabricator-shaped-request',
|
||||
'conpherence-thread-manager',
|
||||
),
|
||||
'07de8873' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-request',
|
||||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
'phabricator-file-upload',
|
||||
),
|
||||
'08883e8b' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1080,6 +1088,13 @@ return array(
|
|||
'javelin-dom',
|
||||
'phortune-credit-card-form',
|
||||
),
|
||||
'3f6075ff' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
'javelin-mask',
|
||||
'phabricator-drag-and-drop-file-upload',
|
||||
),
|
||||
'40a6a403' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1413,14 +1428,6 @@ return array(
|
|||
'javelin-behavior',
|
||||
'javelin-history',
|
||||
),
|
||||
'7fa4b248' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-request',
|
||||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
'phabricator-file-upload',
|
||||
),
|
||||
82439934 => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1722,13 +1729,6 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
),
|
||||
'bbdf75ca' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
'javelin-mask',
|
||||
'phabricator-drag-and-drop-file-upload',
|
||||
),
|
||||
'bd4c8dca' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
|
|
@ -57,6 +57,10 @@ abstract class PhabricatorController extends AphrontController {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function isGlobalDragAndDropUploadEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function willBeginExecution() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
|
|
|
@ -2,19 +2,17 @@
|
|||
|
||||
final class PhabricatorFileListController extends PhabricatorFileController {
|
||||
|
||||
private $key;
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->key = idx($data, 'key');
|
||||
public function isGlobalDragAndDropUploadEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$controller = id(new PhabricatorApplicationSearchController())
|
||||
->setQueryKey($this->key)
|
||||
->setQueryKey($request->getURIData('key'))
|
||||
->setSearchEngine(new PhabricatorFileSearchEngine())
|
||||
->setNavigation($this->buildSideNavView());
|
||||
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
final class PhabricatorFileUploadController extends PhabricatorFileController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
public function isGlobalDragAndDropUploadEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$file = PhabricatorFile::initializeNewFile();
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* IMPORTANT: If you use this, make sure to implement
|
||||
*
|
||||
* public function isGlobalDragAndDropUploadEnabled() {
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* on the controller(s) that render this class...! This is necessary
|
||||
* to make sure Quicksand works properly with the javascript in this
|
||||
* UI.
|
||||
*/
|
||||
final class PhabricatorGlobalUploadTargetView extends AphrontView {
|
||||
|
||||
private $showIfSupportedID;
|
||||
|
@ -19,7 +30,7 @@ final class PhabricatorGlobalUploadTargetView extends AphrontView {
|
|||
return null;
|
||||
}
|
||||
|
||||
$instructions_id = celerity_generate_unique_node_id();
|
||||
$instructions_id = 'phabricator-global-drag-and-drop-upload-instructions';
|
||||
|
||||
require_celerity_resource('global-drag-and-drop-css');
|
||||
|
||||
|
|
|
@ -2,19 +2,18 @@
|
|||
|
||||
final class PhabricatorHomeMainController extends PhabricatorHomeController {
|
||||
|
||||
private $only;
|
||||
private $minipanels = array();
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->only = idx($data, 'only');
|
||||
public function isGlobalDragAndDropUploadEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$user = $this->getRequest()->getUser();
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
|
||||
$dashboard = PhabricatorDashboardInstall::getDashboard(
|
||||
$user,
|
||||
|
@ -42,7 +41,7 @@ final class PhabricatorHomeMainController extends PhabricatorHomeController {
|
|||
$content = $this->buildMainResponse($projects);
|
||||
}
|
||||
|
||||
if (!$this->only) {
|
||||
if (!$request->getURIData('only')) {
|
||||
$nav = $this->buildNav();
|
||||
$nav->appendChild(
|
||||
array(
|
||||
|
|
|
@ -605,6 +605,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
|
||||
private function buildQuicksandConfig() {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
$controller = $this->getController();
|
||||
|
||||
$dropdown_query = id(new AphlictDropdownDataQuery())
|
||||
->setViewer($viewer);
|
||||
|
@ -624,7 +625,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
$rendered_dropdowns[$application_class] =
|
||||
$application->buildMainMenuExtraNodes(
|
||||
$viewer,
|
||||
$this->getController());
|
||||
$controller);
|
||||
}
|
||||
|
||||
$console_config = null;
|
||||
|
@ -638,6 +639,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
$dropdown_query->getNotificationData(),
|
||||
$dropdown_query->getConpherenceData(),
|
||||
),
|
||||
'globalDragAndDrop' => $controller->isGlobalDragAndDropUploadEnabled(),
|
||||
'aphlictDropdowns' => $rendered_dropdowns,
|
||||
'consoleConfig' => $console_config,
|
||||
) + $this->buildAphlictListenConfigData();
|
||||
|
|
|
@ -40,6 +40,17 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
members : {
|
||||
_node : null,
|
||||
_depth : 0,
|
||||
_isEnabled: false,
|
||||
|
||||
setIsEnabled: function(bool) {
|
||||
this._isEnabled = bool;
|
||||
return this;
|
||||
},
|
||||
|
||||
getIsEnabled: function() {
|
||||
return this._isEnabled;
|
||||
},
|
||||
|
||||
_updateDepth : function(delta) {
|
||||
if (this._depth === 0 && delta > 0) {
|
||||
this.invoke('didBeginDrag');
|
||||
|
@ -54,6 +65,7 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
|
||||
start : function() {
|
||||
|
||||
|
||||
// TODO: move this to JX.DOM.contains()?
|
||||
function contains(container, child) {
|
||||
do {
|
||||
|
@ -73,6 +85,9 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
'click',
|
||||
null,
|
||||
JX.bind(this, function (e) {
|
||||
if (!this.getIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (this._depth) {
|
||||
e.kill();
|
||||
// Force depth to 0.
|
||||
|
@ -87,6 +102,10 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
'dragenter',
|
||||
null,
|
||||
JX.bind(this, function(e) {
|
||||
if (!this.getIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contains(this._node, e.getTarget())) {
|
||||
this._updateDepth(1);
|
||||
}
|
||||
|
@ -97,6 +116,10 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
'dragleave',
|
||||
null,
|
||||
JX.bind(this, function(e) {
|
||||
if (!this.getIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contains(this._node, e.getTarget())) {
|
||||
this._updateDepth(-1);
|
||||
}
|
||||
|
@ -106,18 +129,26 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
this._node,
|
||||
'dragover',
|
||||
null,
|
||||
function(e) {
|
||||
JX.bind(this, function(e) {
|
||||
if (!this.getIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: We must set this, or Chrome refuses to drop files from the
|
||||
// download shelf.
|
||||
e.getRawEvent().dataTransfer.dropEffect = 'copy';
|
||||
e.kill();
|
||||
});
|
||||
}));
|
||||
|
||||
JX.DOM.listen(
|
||||
this._node,
|
||||
'drop',
|
||||
null,
|
||||
JX.bind(this, function(e) {
|
||||
if (!this.getIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.kill();
|
||||
|
||||
var files = e.getRawEvent().dataTransfer.files;
|
||||
|
@ -135,6 +166,10 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
'paste',
|
||||
null,
|
||||
JX.bind(this, function(e) {
|
||||
if (!this.getIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var clipboard = e.getRawEvent().clipboardData;
|
||||
if (!clipboard) {
|
||||
return;
|
||||
|
@ -168,6 +203,8 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
|||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this.setIsEnabled(true);
|
||||
},
|
||||
|
||||
_sendRequest : function(spec) {
|
||||
|
|
|
@ -7,64 +7,102 @@
|
|||
* phabricator-drag-and-drop-file-upload
|
||||
*/
|
||||
|
||||
JX.behavior('global-drag-and-drop', function(config) {
|
||||
JX.behavior('global-drag-and-drop', function(config, statics) {
|
||||
if (!JX.PhabricatorDragAndDropFileUpload.isSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pending = 0;
|
||||
var files = [];
|
||||
var errors = false;
|
||||
function init() {
|
||||
statics.pending = 0;
|
||||
statics.files = [];
|
||||
statics.errors = false;
|
||||
statics.enabled = true;
|
||||
|
||||
if (config.ifSupported) {
|
||||
JX.$(config.ifSupported).style.display = '';
|
||||
if (config.ifSupported) {
|
||||
JX.$(config.ifSupported).style.display = '';
|
||||
}
|
||||
|
||||
var page = JX.$('phabricator-standard-page');
|
||||
statics.drop = new JX.PhabricatorDragAndDropFileUpload(page)
|
||||
.setURI(config.uploadURI)
|
||||
.setViewPolicy(config.viewPolicy)
|
||||
.setChunkThreshold(config.chunkThreshold);
|
||||
|
||||
install_extra_listeners();
|
||||
|
||||
statics.drop.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var page = JX.$('phabricator-standard-page');
|
||||
var drop = new JX.PhabricatorDragAndDropFileUpload(page)
|
||||
.setURI(config.uploadURI)
|
||||
.setViewPolicy(config.viewPolicy)
|
||||
.setChunkThreshold(config.chunkThreshold);
|
||||
|
||||
drop.listen('didBeginDrag', function() {
|
||||
JX.Mask.show('global-upload-mask');
|
||||
JX.DOM.show(JX.$(config.instructions));
|
||||
});
|
||||
|
||||
drop.listen('didEndDrag', function() {
|
||||
JX.Mask.hide('global-upload-mask');
|
||||
JX.DOM.hide(JX.$(config.instructions));
|
||||
});
|
||||
|
||||
drop.listen('willUpload', function() {
|
||||
pending++;
|
||||
});
|
||||
|
||||
drop.listen('didUpload', function(f) {
|
||||
files.push(f);
|
||||
|
||||
pending--;
|
||||
if (pending === 0 && !errors) {
|
||||
// If whatever the user dropped in has finished uploading, send them to
|
||||
// their uploads.
|
||||
var uri;
|
||||
uri = JX.$U(config.browseURI);
|
||||
var ids = [];
|
||||
for (var ii = 0; ii < files.length; ii++) {
|
||||
ids.push(files[ii].getID());
|
||||
function install_extra_listeners() {
|
||||
statics.drop.listen('didBeginDrag', function() {
|
||||
if (!statics.enabled) {
|
||||
return;
|
||||
}
|
||||
uri.setQueryParam('h', ids.join(','));
|
||||
JX.Mask.show('global-upload-mask');
|
||||
JX.DOM.show(JX.$(config.instructions));
|
||||
});
|
||||
|
||||
files = [];
|
||||
statics.drop.listen('didEndDrag', function() {
|
||||
if (!statics.enabled) {
|
||||
return;
|
||||
}
|
||||
JX.Mask.hide('global-upload-mask');
|
||||
JX.DOM.hide(JX.$(config.instructions));
|
||||
});
|
||||
|
||||
uri.go();
|
||||
}
|
||||
});
|
||||
statics.drop.listen('willUpload', function() {
|
||||
if (!statics.enabled) {
|
||||
return;
|
||||
}
|
||||
statics.pending++;
|
||||
});
|
||||
|
||||
drop.listen('didError', function() {
|
||||
pending--;
|
||||
errors = true;
|
||||
});
|
||||
statics.drop.listen('didUpload', function(f) {
|
||||
if (!statics.enabled) {
|
||||
return;
|
||||
}
|
||||
statics.files.push(f);
|
||||
|
||||
drop.start();
|
||||
statics.pending--;
|
||||
if (statics.pending === 0 && !statics.errors) {
|
||||
// If whatever the user dropped in has finished uploading, send them to
|
||||
// their uploads.
|
||||
var uri;
|
||||
uri = JX.$U(config.browseURI);
|
||||
var ids = [];
|
||||
for (var ii = 0; ii < statics.files.length; ii++) {
|
||||
ids.push(statics.files[ii].getID());
|
||||
}
|
||||
uri.setQueryParam('h', ids.join(','));
|
||||
|
||||
statics.files = [];
|
||||
|
||||
uri.go();
|
||||
}
|
||||
});
|
||||
|
||||
statics.drop.listen('didError', function() {
|
||||
if (!statics.enabled) {
|
||||
return;
|
||||
}
|
||||
statics.pending--;
|
||||
statics.errors = true;
|
||||
});
|
||||
}
|
||||
|
||||
statics.init = statics.init || init();
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'quicksand-redraw',
|
||||
null,
|
||||
function (e) {
|
||||
e.kill();
|
||||
|
||||
var data = e.getData();
|
||||
var toggle = data.newResponse.globalDragAndDrop;
|
||||
statics.enabled = toggle;
|
||||
statics.drop.setIsEnabled(toggle);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue