mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-28 00:10:57 +01:00
Provide an <input type="file">
control in Remarkup for mobile and users with esoteric windowing systems
Summary: Ref T5187. This definitely feels a bit flimsy and I'm going to hold it until I cut the release since it changes a couple of things about Workflow in general, but it seems to work OK and most of it is fine. The intent is described in T5187#176236. In practice, most of that works like I describe, then the `phui-file-upload` behavior gets some weird glue to figure out if the input is part of the form. Not the most elegant system, but I think it'll hold until we come up with many reasons to write a lot more Javascript. Test Plan: Used both drag-and-drop and the upload dialog to upload files in Safari, Firefox and Chrome. {F1653716} Reviewers: chad Reviewed By: chad Maniphest Tasks: T5187 Differential Revision: https://secure.phabricator.com/D15953
This commit is contained in:
parent
804a5db41a
commit
f2c36a934e
11 changed files with 287 additions and 38 deletions
|
@ -1594,6 +1594,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
||||||
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
||||||
'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php',
|
'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php',
|
||||||
|
'PHUIFormFileControl' => 'view/form/control/PHUIFormFileControl.php',
|
||||||
'PHUIFormFreeformDateControl' => 'view/form/control/PHUIFormFreeformDateControl.php',
|
'PHUIFormFreeformDateControl' => 'view/form/control/PHUIFormFreeformDateControl.php',
|
||||||
'PHUIFormIconSetControl' => 'view/form/control/PHUIFormIconSetControl.php',
|
'PHUIFormIconSetControl' => 'view/form/control/PHUIFormIconSetControl.php',
|
||||||
'PHUIFormInsetView' => 'view/form/PHUIFormInsetView.php',
|
'PHUIFormInsetView' => 'view/form/PHUIFormInsetView.php',
|
||||||
|
@ -5996,6 +5997,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
||||||
'PHUIFeedStoryView' => 'AphrontView',
|
'PHUIFeedStoryView' => 'AphrontView',
|
||||||
'PHUIFormDividerControl' => 'AphrontFormControl',
|
'PHUIFormDividerControl' => 'AphrontFormControl',
|
||||||
|
'PHUIFormFileControl' => 'AphrontFormControl',
|
||||||
'PHUIFormFreeformDateControl' => 'AphrontFormControl',
|
'PHUIFormFreeformDateControl' => 'AphrontFormControl',
|
||||||
'PHUIFormIconSetControl' => 'AphrontFormControl',
|
'PHUIFormIconSetControl' => 'AphrontFormControl',
|
||||||
'PHUIFormInsetView' => 'AphrontView',
|
'PHUIFormInsetView' => 'AphrontView',
|
||||||
|
|
|
@ -56,7 +56,7 @@ final class PhabricatorFileDropUploadController
|
||||||
$file_phid = $result['filePHID'];
|
$file_phid = $result['filePHID'];
|
||||||
if ($file_phid) {
|
if ($file_phid) {
|
||||||
$file = $this->loadFile($file_phid);
|
$file = $this->loadFile($file_phid);
|
||||||
$result += $this->getFileDictionary($file);
|
$result += $file->getDragAndDropDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
return id(new AphrontAjaxResponse())->setContent($result);
|
return id(new AphrontAjaxResponse())->setContent($result);
|
||||||
|
@ -84,7 +84,7 @@ final class PhabricatorFileDropUploadController
|
||||||
} else {
|
} else {
|
||||||
$result = array(
|
$result = array(
|
||||||
'complete' => true,
|
'complete' => true,
|
||||||
) + $this->getFileDictionary($file);
|
) + $file->getDragAndDropDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
return id(new AphrontAjaxResponse())->setContent($result);
|
return id(new AphrontAjaxResponse())->setContent($result);
|
||||||
|
@ -99,18 +99,10 @@ final class PhabricatorFileDropUploadController
|
||||||
'isExplicitUpload' => true,
|
'isExplicitUpload' => true,
|
||||||
));
|
));
|
||||||
|
|
||||||
$result = $this->getFileDictionary($file);
|
$result = $file->getDragAndDropDictionary();
|
||||||
return id(new AphrontAjaxResponse())->setContent($result);
|
return id(new AphrontAjaxResponse())->setContent($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getFileDictionary(PhabricatorFile $file) {
|
|
||||||
return array(
|
|
||||||
'id' => $file->getID(),
|
|
||||||
'phid' => $file->getPHID(),
|
|
||||||
'uri' => $file->getBestURI(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadFile($file_phid) {
|
private function loadFile($file_phid) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,51 @@ final class PhabricatorFileUploadDialogController
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $request->getViewer();
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
return $this->newDialog()
|
$e_file = true;
|
||||||
->setTitle(pht('Upload File'))
|
$errors = array();
|
||||||
->appendChild(pht(
|
if ($request->isDialogFormPost()) {
|
||||||
'To add files, drag and drop them into the comment text area.'))
|
$file_phids = $request->getStrList('filePHIDs');
|
||||||
->addCancelButton('/', pht('Close'));
|
if ($file_phids) {
|
||||||
|
$files = id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs($file_phids)
|
||||||
|
->setRaisePolicyExceptions(true)
|
||||||
|
->execute();
|
||||||
|
} else {
|
||||||
|
$files = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($files) {
|
||||||
|
$results = array();
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$results[] = $file->getDragAndDropDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = array(
|
||||||
|
'files' => $results,
|
||||||
|
);
|
||||||
|
|
||||||
|
return id(new AphrontAjaxResponse())->setContent($content);
|
||||||
|
} else {
|
||||||
|
$e_file = pht('Required');
|
||||||
|
$errors[] = pht('You must choose a file to upload.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->appendChild(
|
||||||
|
id(new PHUIFormFileControl())
|
||||||
|
->setName('filePHIDs')
|
||||||
|
->setLabel(pht('Upload File'))
|
||||||
|
->setAllowMultiple(true)
|
||||||
|
->setError($e_file));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('File'))
|
||||||
|
->setErrors($errors)
|
||||||
|
->appendForm($form)
|
||||||
|
->addSubmitButton(pht('Upload'))
|
||||||
|
->addCancelButton('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -851,6 +851,14 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
return $supported;
|
return $supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDragAndDropDictionary() {
|
||||||
|
return array(
|
||||||
|
'id' => $this->getID(),
|
||||||
|
'phid' => $this->getPHID(),
|
||||||
|
'uri' => $this->getBestURI(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function instantiateStorageEngine() {
|
public function instantiateStorageEngine() {
|
||||||
return self::buildEngine($this->getStorageEngine());
|
return self::buildEngine($this->getStorageEngine());
|
||||||
}
|
}
|
||||||
|
|
44
src/view/form/control/PHUIFormFileControl.php
Normal file
44
src/view/form/control/PHUIFormFileControl.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PHUIFormFileControl
|
||||||
|
extends AphrontFormControl {
|
||||||
|
|
||||||
|
private $allowMultiple;
|
||||||
|
|
||||||
|
protected function getCustomControlClass() {
|
||||||
|
return 'phui-form-file-upload';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAllowMultiple($allow_multiple) {
|
||||||
|
$this->allowMultiple = $allow_multiple;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowMultiple() {
|
||||||
|
return $this->allowMultiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderInput() {
|
||||||
|
$file_id = $this->getID();
|
||||||
|
|
||||||
|
Javelin::initBehavior(
|
||||||
|
'phui-file-upload',
|
||||||
|
array(
|
||||||
|
'fileInputID' => $file_id,
|
||||||
|
'inputName' => $this->getName(),
|
||||||
|
'uploadURI' => '/file/dropupload/',
|
||||||
|
'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(),
|
||||||
|
));
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'input',
|
||||||
|
array(
|
||||||
|
'type' => 'file',
|
||||||
|
'multiple' => $this->getAllowMultiple() ? 'multiple' : null,
|
||||||
|
'name' => $this->getName().'.raw',
|
||||||
|
'id' => $file_id,
|
||||||
|
'disabled' => $this->getDisabled() ? 'disabled' : null,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
63
webroot/rsrc/externals/javelin/lib/Workflow.js
vendored
63
webroot/rsrc/externals/javelin/lib/Workflow.js
vendored
|
@ -25,7 +25,7 @@ JX.install('Workflow', {
|
||||||
this.setData(data || {});
|
this.setData(data || {});
|
||||||
},
|
},
|
||||||
|
|
||||||
events : ['error', 'finally', 'submit'],
|
events : ['error', 'finally', 'submit', 'start'],
|
||||||
|
|
||||||
statics : {
|
statics : {
|
||||||
_stack : [],
|
_stack : [],
|
||||||
|
@ -54,6 +54,9 @@ JX.install('Workflow', {
|
||||||
}
|
}
|
||||||
|
|
||||||
var workflow = new JX.Workflow(form.getAttribute('action'), {});
|
var workflow = new JX.Workflow(form.getAttribute('action'), {});
|
||||||
|
|
||||||
|
workflow._form = form;
|
||||||
|
|
||||||
workflow.setDataWithListOfPairs(pairs);
|
workflow.setDataWithListOfPairs(pairs);
|
||||||
workflow.setMethod(form.getAttribute('method'));
|
workflow.setMethod(form.getAttribute('method'));
|
||||||
workflow.listen('finally', function() {
|
workflow.listen('finally', function() {
|
||||||
|
@ -137,9 +140,14 @@ JX.install('Workflow', {
|
||||||
data.push([button.name, button.value || true]);
|
data.push([button.name, button.value || true]);
|
||||||
|
|
||||||
var active = JX.Workflow._getActiveWorkflow();
|
var active = JX.Workflow._getActiveWorkflow();
|
||||||
|
|
||||||
|
active._form = form;
|
||||||
|
|
||||||
var e = active.invoke('submit', {form: form, data: data});
|
var e = active.invoke('submit', {form: form, data: data});
|
||||||
if (!e.getStopped()) {
|
if (!e.getStopped()) {
|
||||||
active._destroy();
|
// NOTE: Don't remove the current dialog yet because additional
|
||||||
|
// handlers may still want to access the nodes.
|
||||||
|
|
||||||
active
|
active
|
||||||
.setURI(form.getAttribute('action') || active.getURI())
|
.setURI(form.getAttribute('action') || active.getURI())
|
||||||
.setDataWithListOfPairs(data)
|
.setDataWithListOfPairs(data)
|
||||||
|
@ -156,7 +164,41 @@ JX.install('Workflow', {
|
||||||
_root : null,
|
_root : null,
|
||||||
_pushed : false,
|
_pushed : false,
|
||||||
_data : null,
|
_data : null,
|
||||||
|
|
||||||
|
_form: null,
|
||||||
|
_paused: 0,
|
||||||
|
_nextCallback: null,
|
||||||
|
|
||||||
|
getSourceForm: function() {
|
||||||
|
return this._form;
|
||||||
|
},
|
||||||
|
|
||||||
|
pause: function() {
|
||||||
|
this._paused++;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
resume: function() {
|
||||||
|
if (!this._paused) {
|
||||||
|
JX.$E('Resuming a workflow which is not paused!');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._paused--;
|
||||||
|
|
||||||
|
if (!this._paused) {
|
||||||
|
var next = this._nextCallback;
|
||||||
|
this._nextCallback = null;
|
||||||
|
if (next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
_onload : function(r) {
|
_onload : function(r) {
|
||||||
|
this._destroy();
|
||||||
|
|
||||||
// It is permissible to send back a falsey redirect to force a page
|
// It is permissible to send back a falsey redirect to force a page
|
||||||
// reload, so we need to take this branch if the key is present.
|
// reload, so we need to take this branch if the key is present.
|
||||||
if (r && (typeof r.redirect != 'undefined')) {
|
if (r && (typeof r.redirect != 'undefined')) {
|
||||||
|
@ -247,7 +289,19 @@ JX.install('Workflow', {
|
||||||
this._root = null;
|
this._root = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
start : function() {
|
start : function() {
|
||||||
|
var next = JX.bind(this, this._send);
|
||||||
|
|
||||||
|
this.pause();
|
||||||
|
this._nextCallback = next;
|
||||||
|
|
||||||
|
this.invoke('start', this);
|
||||||
|
|
||||||
|
this.resume();
|
||||||
|
},
|
||||||
|
|
||||||
|
_send: function() {
|
||||||
var uri = this.getURI();
|
var uri = this.getURI();
|
||||||
var method = this.getMethod();
|
var method = this.getMethod();
|
||||||
var r = new JX.Request(uri, JX.bind(this, this._onload));
|
var r = new JX.Request(uri, JX.bind(this, this._onload));
|
||||||
|
@ -291,6 +345,11 @@ JX.install('Workflow', {
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addData: function(key, value) {
|
||||||
|
this._data.push([key, value]);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
setDataWithListOfPairs : function(list_of_pairs) {
|
setDataWithListOfPairs : function(list_of_pairs) {
|
||||||
this._data = list_of_pairs;
|
this._data = list_of_pairs;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -155,7 +155,7 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
||||||
|
|
||||||
var files = e.getRawEvent().dataTransfer.files;
|
var files = e.getRawEvent().dataTransfer.files;
|
||||||
for (var ii = 0; ii < files.length; ii++) {
|
for (var ii = 0; ii < files.length; ii++) {
|
||||||
this._sendRequest(files[ii]);
|
this.sendRequest(files[ii]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force depth to 0.
|
// Force depth to 0.
|
||||||
|
@ -216,7 +216,7 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
||||||
if (!spec.name) {
|
if (!spec.name) {
|
||||||
spec.name = 'pasted_file';
|
spec.name = 'pasted_file';
|
||||||
}
|
}
|
||||||
this._sendRequest(spec);
|
this.sendRequest(spec);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ JX.install('PhabricatorDragAndDropFileUpload', {
|
||||||
this.setIsEnabled(true);
|
this.setIsEnabled(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_sendRequest : function(spec) {
|
sendRequest : function(spec) {
|
||||||
var file = new JX.PhabricatorFileUpload()
|
var file = new JX.PhabricatorFileUpload()
|
||||||
.setRawFileObject(spec)
|
.setRawFileObject(spec)
|
||||||
.setName(spec.name)
|
.setName(spec.name)
|
||||||
|
|
|
@ -62,6 +62,26 @@ JX.install('TextAreaUtils', {
|
||||||
JX.TextAreaUtils.setSelectionRange(area, start, end);
|
JX.TextAreaUtils.setSelectionRange(area, start, end);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a reference to a given uploaded file into a textarea.
|
||||||
|
*/
|
||||||
|
insertFileReference: function(area, file) {
|
||||||
|
var ref = '{F' + file.getID() + '}';
|
||||||
|
|
||||||
|
// If we're inserting immediately after a "}" (usually, another file
|
||||||
|
// reference), put some newlines before our token so that multiple file
|
||||||
|
// uploads get laid out more nicely.
|
||||||
|
var range = JX.TextAreaUtils.getSelectionRange(area);
|
||||||
|
var before = area.value.substring(0, range.start);
|
||||||
|
if (before.match(/\}$/)) {
|
||||||
|
ref = '\n\n' + ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
JX.TextAreaUtils.setSelectionText(area, ref, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the document pixel positions of the beginning and end of a character
|
* Get the document pixel positions of the beginning and end of a character
|
||||||
* range in a textarea.
|
* range in a textarea.
|
||||||
|
|
|
@ -10,32 +10,23 @@ JX.behavior('aphront-drag-and-drop-textarea', function(config) {
|
||||||
|
|
||||||
var target = JX.$(config.target);
|
var target = JX.$(config.target);
|
||||||
|
|
||||||
function onupload(f) {
|
|
||||||
var ref = '{F' + f.getID() + '}';
|
|
||||||
|
|
||||||
// If we're inserting immediately after a "}" (usually, another file
|
|
||||||
// reference), put some newlines before our token so that multiple file
|
|
||||||
// uploads get laid out more nicely.
|
|
||||||
var range = JX.TextAreaUtils.getSelectionRange(target);
|
|
||||||
var before = target.value.substring(0, range.start);
|
|
||||||
if (before.match(/\}$/)) {
|
|
||||||
ref = '\n\n' + ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
JX.TextAreaUtils.setSelectionText(target, ref, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JX.PhabricatorDragAndDropFileUpload.isSupported()) {
|
if (JX.PhabricatorDragAndDropFileUpload.isSupported()) {
|
||||||
var drop = new JX.PhabricatorDragAndDropFileUpload(target)
|
var drop = new JX.PhabricatorDragAndDropFileUpload(target)
|
||||||
.setURI(config.uri)
|
.setURI(config.uri)
|
||||||
.setChunkThreshold(config.chunkThreshold);
|
.setChunkThreshold(config.chunkThreshold);
|
||||||
|
|
||||||
drop.listen('didBeginDrag', function() {
|
drop.listen('didBeginDrag', function() {
|
||||||
JX.DOM.alterClass(target, config.activatedClass, true);
|
JX.DOM.alterClass(target, config.activatedClass, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
drop.listen('didEndDrag', function() {
|
drop.listen('didEndDrag', function() {
|
||||||
JX.DOM.alterClass(target, config.activatedClass, false);
|
JX.DOM.alterClass(target, config.activatedClass, false);
|
||||||
});
|
});
|
||||||
drop.listen('didUpload', onupload);
|
|
||||||
|
drop.listen('didUpload', function(file) {
|
||||||
|
JX.TextAreaUtils.insertFileReference(target, file);
|
||||||
|
});
|
||||||
|
|
||||||
drop.start();
|
drop.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,21 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
|
||||||
.start();
|
.start();
|
||||||
break;
|
break;
|
||||||
case 'fa-cloud-upload':
|
case 'fa-cloud-upload':
|
||||||
new JX.Workflow('/file/uploaddialog/').start();
|
new JX.Workflow('/file/uploaddialog/')
|
||||||
|
.setHandler(function(response) {
|
||||||
|
var files = response.files;
|
||||||
|
for (var ii = 0; ii < files.length; ii++) {
|
||||||
|
var file = files[ii];
|
||||||
|
|
||||||
|
var upload = new JX.PhabricatorFileUpload()
|
||||||
|
.setID(file.id)
|
||||||
|
.setPHID(file.phid)
|
||||||
|
.setURI(file.uri);
|
||||||
|
|
||||||
|
JX.TextAreaUtils.insertFileReference(area, upload);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.start();
|
||||||
break;
|
break;
|
||||||
case 'fa-arrows-alt':
|
case 'fa-arrows-alt':
|
||||||
if (edit_mode == 'fa-arrows-alt') {
|
if (edit_mode == 'fa-arrows-alt') {
|
||||||
|
|
80
webroot/rsrc/js/phui/behavior-phui-file-upload.js
Normal file
80
webroot/rsrc/js/phui/behavior-phui-file-upload.js
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* @provides javelin-behavior-phui-file-upload
|
||||||
|
* @requires javelin-behavior
|
||||||
|
* javelin-stratcom
|
||||||
|
* javelin-dom
|
||||||
|
* phuix-dropdown-menu
|
||||||
|
*/
|
||||||
|
|
||||||
|
JX.behavior('phui-file-upload', function(config) {
|
||||||
|
|
||||||
|
function startUpload(workflow, input) {
|
||||||
|
var files = input.files;
|
||||||
|
|
||||||
|
if (!files || !files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var state = {
|
||||||
|
workflow: workflow,
|
||||||
|
input: input,
|
||||||
|
waiting: 0,
|
||||||
|
phids: []
|
||||||
|
};
|
||||||
|
|
||||||
|
var callback = JX.bind(null, didUpload, state);
|
||||||
|
|
||||||
|
var dummy = input;
|
||||||
|
var uploader = new JX.PhabricatorDragAndDropFileUpload(dummy)
|
||||||
|
.setURI(config.uploadURI)
|
||||||
|
.setChunkThreshold(config.chunkThreshold);
|
||||||
|
|
||||||
|
uploader.listen('didUpload', callback);
|
||||||
|
uploader.start();
|
||||||
|
|
||||||
|
workflow.pause();
|
||||||
|
for (var ii = 0; ii < files.length; ii++) {
|
||||||
|
state.waiting++;
|
||||||
|
uploader.sendRequest(files[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function didUpload(state, file) {
|
||||||
|
state.phids.push(file.getPHID());
|
||||||
|
state.waiting--;
|
||||||
|
|
||||||
|
if (state.waiting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.workflow
|
||||||
|
.addData(config.inputName, state.phids.join(', '))
|
||||||
|
.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
JX.Workflow.listen('start', function(workflow) {
|
||||||
|
var form = workflow.getSourceForm();
|
||||||
|
if (!form) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var input;
|
||||||
|
try {
|
||||||
|
input = JX.$(config.fileInputID);
|
||||||
|
} catch (ex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var local_form = JX.DOM.findAbove(input, 'form');
|
||||||
|
if (!local_form) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_form !== form) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startUpload(workflow, input);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in a new issue