2011-05-22 11:55:10 -07:00
|
|
|
/**
|
|
|
|
|
* @requires javelin-install
|
|
|
|
|
* javelin-util
|
|
|
|
|
* javelin-request
|
|
|
|
|
* javelin-dom
|
|
|
|
|
* javelin-uri
|
2012-10-08 15:23:05 -07:00
|
|
|
* phabricator-file-upload
|
2011-05-22 11:55:10 -07:00
|
|
|
* @provides phabricator-drag-and-drop-file-upload
|
|
|
|
|
* @javelin
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
JX.install('PhabricatorDragAndDropFileUpload', {
|
|
|
|
|
|
|
|
|
|
construct : function(node) {
|
|
|
|
|
this._node = node;
|
|
|
|
|
},
|
|
|
|
|
|
Modernize file uploads
Summary:
Modernizes file uploads. In particular:
- Adds a mobile menu, with an "Upload File" item.
- Adds crumbs to the list view, detail view and upload view.
- Adds "Upload File" action to crumbs.
- Moves upload file to a separate page.
- Removes the combined upload file + recent files page.
- Makes upload file use a normal file control by default (works on mobile).
- Home page, file list and file upload page are now global drop targets which accept files dropped anywhere on them. Dragging a file into the window shows a mask and an instructional message.
- User education on this is a little weak but I think that's a big can of worms?
- Fixes a bug where dropping multiple files into a Remarkup text area produced bad results (resolves T2190).
T879 is related, although it's specifically about Maniphest. I've declined to make global drop targets yet there because there are multiple drop targets on the page with different meanings. That UI needs updating in general.
@chad, do we have an "upload" icon (counterpart to "download")?
Test Plan: Uploaded files in Maniphest, Differential, Files, and from Home. Dragged and dropped multiple files into Differential. Used crumbs, mobile.
Reviewers: chad, btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2190
Differential Revision: https://secure.phabricator.com/D4200
2012-12-16 16:34:01 -08:00
|
|
|
events : [
|
|
|
|
|
'didBeginDrag',
|
|
|
|
|
'didEndDrag',
|
|
|
|
|
'willUpload',
|
|
|
|
|
'progress',
|
|
|
|
|
'didUpload',
|
|
|
|
|
'didError'],
|
2011-05-22 11:55:10 -07:00
|
|
|
|
Improve drag-and-drop uploader
Summary:
Make it discoverable, show uploading progress, show file thumbnails, allow you
to remove files, make it a generic form component.
Test Plan:
Uploaded ducks
Reviewed By: tomo
Reviewers: aran, tomo, jungejason, tuomaspelkonen
CC: anjali, aran, epriestley, tomo
Differential Revision: 334
2011-05-22 16:11:41 -07:00
|
|
|
statics : {
|
|
|
|
|
isSupported : function() {
|
|
|
|
|
// TODO: Is there a better capability test for this? This seems okay in
|
|
|
|
|
// Safari, Firefox and Chrome.
|
Modernize file uploads
Summary:
Modernizes file uploads. In particular:
- Adds a mobile menu, with an "Upload File" item.
- Adds crumbs to the list view, detail view and upload view.
- Adds "Upload File" action to crumbs.
- Moves upload file to a separate page.
- Removes the combined upload file + recent files page.
- Makes upload file use a normal file control by default (works on mobile).
- Home page, file list and file upload page are now global drop targets which accept files dropped anywhere on them. Dragging a file into the window shows a mask and an instructional message.
- User education on this is a little weak but I think that's a big can of worms?
- Fixes a bug where dropping multiple files into a Remarkup text area produced bad results (resolves T2190).
T879 is related, although it's specifically about Maniphest. I've declined to make global drop targets yet there because there are multiple drop targets on the page with different meanings. That UI needs updating in general.
@chad, do we have an "upload" icon (counterpart to "download")?
Test Plan: Uploaded files in Maniphest, Differential, Files, and from Home. Dragged and dropped multiple files into Differential. Used crumbs, mobile.
Reviewers: chad, btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2190
Differential Revision: https://secure.phabricator.com/D4200
2012-12-16 16:34:01 -08:00
|
|
|
|
2013-04-02 09:52:31 -07:00
|
|
|
return !!window.FileList;
|
|
|
|
|
},
|
|
|
|
|
isPasteSupported : function() {
|
|
|
|
|
// TODO: Needs to check if event.clipboardData is available.
|
|
|
|
|
// Works in Chrome, doesn't work in Firefox 10.
|
Improve drag-and-drop uploader
Summary:
Make it discoverable, show uploading progress, show file thumbnails, allow you
to remove files, make it a generic form component.
Test Plan:
Uploaded ducks
Reviewed By: tomo
Reviewers: aran, tomo, jungejason, tuomaspelkonen
CC: anjali, aran, epriestley, tomo
Differential Revision: 334
2011-05-22 16:11:41 -07:00
|
|
|
return !!window.FileList;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
members : {
|
|
|
|
|
_node : null,
|
|
|
|
|
_depth : 0,
|
2015-04-23 15:08:35 -07:00
|
|
|
_isEnabled: false,
|
|
|
|
|
|
|
|
|
|
setIsEnabled: function(bool) {
|
|
|
|
|
this._isEnabled = bool;
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getIsEnabled: function() {
|
|
|
|
|
return this._isEnabled;
|
|
|
|
|
},
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
_updateDepth : function(delta) {
|
2013-05-18 17:04:22 -07:00
|
|
|
if (this._depth === 0 && delta > 0) {
|
Modernize file uploads
Summary:
Modernizes file uploads. In particular:
- Adds a mobile menu, with an "Upload File" item.
- Adds crumbs to the list view, detail view and upload view.
- Adds "Upload File" action to crumbs.
- Moves upload file to a separate page.
- Removes the combined upload file + recent files page.
- Makes upload file use a normal file control by default (works on mobile).
- Home page, file list and file upload page are now global drop targets which accept files dropped anywhere on them. Dragging a file into the window shows a mask and an instructional message.
- User education on this is a little weak but I think that's a big can of worms?
- Fixes a bug where dropping multiple files into a Remarkup text area produced bad results (resolves T2190).
T879 is related, although it's specifically about Maniphest. I've declined to make global drop targets yet there because there are multiple drop targets on the page with different meanings. That UI needs updating in general.
@chad, do we have an "upload" icon (counterpart to "download")?
Test Plan: Uploaded files in Maniphest, Differential, Files, and from Home. Dragged and dropped multiple files into Differential. Used crumbs, mobile.
Reviewers: chad, btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2190
Differential Revision: https://secure.phabricator.com/D4200
2012-12-16 16:34:01 -08:00
|
|
|
this.invoke('didBeginDrag');
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
this._depth += delta;
|
Modernize file uploads
Summary:
Modernizes file uploads. In particular:
- Adds a mobile menu, with an "Upload File" item.
- Adds crumbs to the list view, detail view and upload view.
- Adds "Upload File" action to crumbs.
- Moves upload file to a separate page.
- Removes the combined upload file + recent files page.
- Makes upload file use a normal file control by default (works on mobile).
- Home page, file list and file upload page are now global drop targets which accept files dropped anywhere on them. Dragging a file into the window shows a mask and an instructional message.
- User education on this is a little weak but I think that's a big can of worms?
- Fixes a bug where dropping multiple files into a Remarkup text area produced bad results (resolves T2190).
T879 is related, although it's specifically about Maniphest. I've declined to make global drop targets yet there because there are multiple drop targets on the page with different meanings. That UI needs updating in general.
@chad, do we have an "upload" icon (counterpart to "download")?
Test Plan: Uploaded files in Maniphest, Differential, Files, and from Home. Dragged and dropped multiple files into Differential. Used crumbs, mobile.
Reviewers: chad, btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2190
Differential Revision: https://secure.phabricator.com/D4200
2012-12-16 16:34:01 -08:00
|
|
|
|
2013-05-18 17:04:22 -07:00
|
|
|
if (this._depth === 0 && delta < 0) {
|
Modernize file uploads
Summary:
Modernizes file uploads. In particular:
- Adds a mobile menu, with an "Upload File" item.
- Adds crumbs to the list view, detail view and upload view.
- Adds "Upload File" action to crumbs.
- Moves upload file to a separate page.
- Removes the combined upload file + recent files page.
- Makes upload file use a normal file control by default (works on mobile).
- Home page, file list and file upload page are now global drop targets which accept files dropped anywhere on them. Dragging a file into the window shows a mask and an instructional message.
- User education on this is a little weak but I think that's a big can of worms?
- Fixes a bug where dropping multiple files into a Remarkup text area produced bad results (resolves T2190).
T879 is related, although it's specifically about Maniphest. I've declined to make global drop targets yet there because there are multiple drop targets on the page with different meanings. That UI needs updating in general.
@chad, do we have an "upload" icon (counterpart to "download")?
Test Plan: Uploaded files in Maniphest, Differential, Files, and from Home. Dragged and dropped multiple files into Differential. Used crumbs, mobile.
Reviewers: chad, btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2190
Differential Revision: https://secure.phabricator.com/D4200
2012-12-16 16:34:01 -08:00
|
|
|
this.invoke('didEndDrag');
|
|
|
|
|
}
|
2011-05-22 11:55:10 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
start : function() {
|
|
|
|
|
|
2015-04-23 15:08:35 -07:00
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
// TODO: move this to JX.DOM.contains()?
|
|
|
|
|
function contains(container, child) {
|
|
|
|
|
do {
|
|
|
|
|
if (child === container) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
child = child.parentNode;
|
|
|
|
|
} while (child);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-01 11:16:02 -07:00
|
|
|
// Firefox has some issues sometimes; implement this click handler so
|
|
|
|
|
// the user can recover. See T5188.
|
|
|
|
|
JX.DOM.listen(
|
|
|
|
|
this._node,
|
|
|
|
|
'click',
|
|
|
|
|
null,
|
|
|
|
|
JX.bind(this, function (e) {
|
2015-04-23 15:08:35 -07:00
|
|
|
if (!this.getIsEnabled()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-08-01 11:16:02 -07:00
|
|
|
if (this._depth) {
|
|
|
|
|
e.kill();
|
|
|
|
|
// Force depth to 0.
|
|
|
|
|
this._updateDepth(-this._depth);
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
// We track depth so that the _node may have children inside of it and
|
|
|
|
|
// not become unselected when they are dragged over.
|
|
|
|
|
JX.DOM.listen(
|
|
|
|
|
this._node,
|
|
|
|
|
'dragenter',
|
|
|
|
|
null,
|
|
|
|
|
JX.bind(this, function(e) {
|
2015-04-23 15:08:35 -07:00
|
|
|
if (!this.getIsEnabled()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
if (contains(this._node, e.getTarget())) {
|
|
|
|
|
this._updateDepth(1);
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
JX.DOM.listen(
|
|
|
|
|
this._node,
|
|
|
|
|
'dragleave',
|
|
|
|
|
null,
|
|
|
|
|
JX.bind(this, function(e) {
|
2015-04-23 15:08:35 -07:00
|
|
|
if (!this.getIsEnabled()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
if (contains(this._node, e.getTarget())) {
|
|
|
|
|
this._updateDepth(-1);
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
JX.DOM.listen(
|
|
|
|
|
this._node,
|
|
|
|
|
'dragover',
|
|
|
|
|
null,
|
2015-04-23 15:08:35 -07:00
|
|
|
JX.bind(this, function(e) {
|
|
|
|
|
if (!this.getIsEnabled()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-02 06:45:20 -07:00
|
|
|
// NOTE: We must set this, or Chrome refuses to drop files from the
|
|
|
|
|
// download shelf.
|
|
|
|
|
e.getRawEvent().dataTransfer.dropEffect = 'copy';
|
2011-05-22 11:55:10 -07:00
|
|
|
e.kill();
|
2015-04-23 15:08:35 -07:00
|
|
|
}));
|
2011-05-22 11:55:10 -07:00
|
|
|
|
|
|
|
|
JX.DOM.listen(
|
|
|
|
|
this._node,
|
|
|
|
|
'drop',
|
|
|
|
|
null,
|
|
|
|
|
JX.bind(this, function(e) {
|
2015-04-23 15:08:35 -07:00
|
|
|
if (!this.getIsEnabled()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
e.kill();
|
|
|
|
|
|
|
|
|
|
var files = e.getRawEvent().dataTransfer.files;
|
|
|
|
|
for (var ii = 0; ii < files.length; ii++) {
|
2012-10-08 15:23:05 -07:00
|
|
|
this._sendRequest(files[ii]);
|
2011-05-22 11:55:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Force depth to 0.
|
|
|
|
|
this._updateDepth(-this._depth);
|
|
|
|
|
}));
|
2013-04-02 09:52:31 -07:00
|
|
|
|
|
|
|
|
if (JX.PhabricatorDragAndDropFileUpload.isPasteSupported()) {
|
|
|
|
|
JX.DOM.listen(
|
|
|
|
|
this._node,
|
|
|
|
|
'paste',
|
|
|
|
|
null,
|
|
|
|
|
JX.bind(this, function(e) {
|
2015-04-23 15:08:35 -07:00
|
|
|
if (!this.getIsEnabled()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-21 10:04:46 -07:00
|
|
|
var clipboard = e.getRawEvent().clipboardData;
|
|
|
|
|
if (!clipboard) {
|
2013-04-02 09:52:31 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-21 10:04:46 -07:00
|
|
|
// If there's any text on the clipboard, just let the event fire
|
|
|
|
|
// normally, choosing the text over any images. See T5437 / D9647.
|
|
|
|
|
var text = clipboard.getData('text/plain').toString();
|
|
|
|
|
if (text.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Safari and Firefox have clipboardData, but no items. They
|
|
|
|
|
// don't seem to provide a way to get image data directly yet.
|
|
|
|
|
if (!clipboard.items) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (var ii = 0; ii < clipboard.items.length; ii++) {
|
|
|
|
|
var item = clipboard.items[ii];
|
2013-04-02 09:52:31 -07:00
|
|
|
if (!/^image\//.test(item.type)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2014-08-20 16:21:50 -07:00
|
|
|
var spec = item.getAsFile();
|
|
|
|
|
// pasted files don't have a name; see
|
|
|
|
|
// https://code.google.com/p/chromium/issues/detail?id=361145
|
|
|
|
|
if (!spec.name) {
|
|
|
|
|
spec.name = 'pasted_file';
|
|
|
|
|
}
|
|
|
|
|
this._sendRequest(spec);
|
2013-04-02 09:52:31 -07:00
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
}
|
2015-04-23 15:08:35 -07:00
|
|
|
|
|
|
|
|
this.setIsEnabled(true);
|
2012-10-08 15:23:05 -07:00
|
|
|
},
|
2015-03-13 11:30:36 -07:00
|
|
|
|
2012-10-08 15:23:05 -07:00
|
|
|
_sendRequest : function(spec) {
|
|
|
|
|
var file = new JX.PhabricatorFileUpload()
|
2015-03-13 11:30:36 -07:00
|
|
|
.setRawFileObject(spec)
|
2012-10-08 15:23:05 -07:00
|
|
|
.setName(spec.name)
|
2015-03-13 11:30:36 -07:00
|
|
|
.setTotalBytes(spec.size);
|
|
|
|
|
|
|
|
|
|
var threshold = this.getChunkThreshold();
|
|
|
|
|
if (threshold && (file.getTotalBytes() > threshold)) {
|
|
|
|
|
// This is a large file, so we'll go through allocation so we can
|
|
|
|
|
// pick up support for resume and chunking.
|
|
|
|
|
this._allocateFile(file);
|
|
|
|
|
} else {
|
|
|
|
|
// If this file is smaller than the chunk threshold, skip the round
|
|
|
|
|
// trip for allocation and just upload it directly.
|
|
|
|
|
this._sendDataRequest(file);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_allocateFile: function(file) {
|
|
|
|
|
file
|
|
|
|
|
.setStatus('allocate')
|
2012-10-08 15:23:05 -07:00
|
|
|
.update();
|
|
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
var alloc_uri = this._getUploadURI(file)
|
|
|
|
|
.setQueryParam('allocate', 1);
|
|
|
|
|
|
|
|
|
|
new JX.Workflow(alloc_uri)
|
|
|
|
|
.setHandler(JX.bind(this, this._didAllocateFile, file))
|
|
|
|
|
.start();
|
|
|
|
|
},
|
2012-10-08 15:23:05 -07:00
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
_getUploadURI: function(file) {
|
|
|
|
|
var uri = JX.$U(this.getURI())
|
2012-10-08 15:23:05 -07:00
|
|
|
.setQueryParam('name', file.getName())
|
2015-03-13 11:30:36 -07:00
|
|
|
.setQueryParam('length', file.getTotalBytes());
|
Give files uploaded to objects a very restrictive view policy
Summary:
Fixes T4589. This implements much better policy behavior for files that aligns with user expectations.
Currently, all files have permissive visibility.
The new behavior is:
- Files uploaded via drag-and-drop to the home page or file upload page get permissive visibility, for ease of quickly sharing things like screenshots.
- Files uploaded via the manual file upload control get permissive visibility by default, but the user can select the policy they want at upload time in an explicit/obvious way.
- Files uploaded via drag-and-drop anywhere else (e.g., comments or Pholio) get restricted visibility (only the uploader).
- When the user applies a transaction to the object which uses the file, we attach the file to the object and punch a hole through the policies: if you can see the object, you can see the file.
- This rule requires things to use ApplicationTransactions, which is why this took so long to fix.
- The "attach stuff to the object" code has been in place for a long time and works correctly.
I'll land D8498 after this lands, too.
Test Plan:
- Uploaded via global homepage upload and file drag-and-drop upload, saw permissive visibility.
- Uploaded via comment area, saw restricted visibility.
- After commenting, verified links were established and the file became visible to users who could see the attached object.
- Verified Pholio (which is a bit of a special case) correctly attaches images.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T4589
Differential Revision: https://secure.phabricator.com/D10131
2014-08-02 14:46:13 -07:00
|
|
|
|
|
|
|
|
if (this.getViewPolicy()) {
|
2015-03-13 11:30:36 -07:00
|
|
|
uri.setQueryParam('viewPolicy', this.getViewPolicy());
|
Give files uploaded to objects a very restrictive view policy
Summary:
Fixes T4589. This implements much better policy behavior for files that aligns with user expectations.
Currently, all files have permissive visibility.
The new behavior is:
- Files uploaded via drag-and-drop to the home page or file upload page get permissive visibility, for ease of quickly sharing things like screenshots.
- Files uploaded via the manual file upload control get permissive visibility by default, but the user can select the policy they want at upload time in an explicit/obvious way.
- Files uploaded via drag-and-drop anywhere else (e.g., comments or Pholio) get restricted visibility (only the uploader).
- When the user applies a transaction to the object which uses the file, we attach the file to the object and punch a hole through the policies: if you can see the object, you can see the file.
- This rule requires things to use ApplicationTransactions, which is why this took so long to fix.
- The "attach stuff to the object" code has been in place for a long time and works correctly.
I'll land D8498 after this lands, too.
Test Plan:
- Uploaded via global homepage upload and file drag-and-drop upload, saw permissive visibility.
- Uploaded via comment area, saw restricted visibility.
- After commenting, verified links were established and the file became visible to users who could see the attached object.
- Verified Pholio (which is a bit of a special case) correctly attaches images.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T4589
Differential Revision: https://secure.phabricator.com/D10131
2014-08-02 14:46:13 -07:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
if (file.getAllocatedPHID()) {
|
|
|
|
|
uri.setQueryParam('phid', file.getAllocatedPHID());
|
|
|
|
|
}
|
2012-10-08 15:23:05 -07:00
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
return uri;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_didAllocateFile: function(file, r) {
|
|
|
|
|
var phid = r.phid;
|
|
|
|
|
var upload = r.upload;
|
2012-10-08 15:23:05 -07:00
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
if (!upload) {
|
|
|
|
|
if (phid) {
|
|
|
|
|
this._completeUpload(file, r);
|
|
|
|
|
} else {
|
|
|
|
|
this._failUpload(file, r);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
if (phid) {
|
|
|
|
|
// Start or resume a chunked upload.
|
|
|
|
|
file.setAllocatedPHID(phid);
|
|
|
|
|
this._loadChunks(file);
|
2012-10-08 15:23:05 -07:00
|
|
|
} else {
|
2015-03-13 11:30:36 -07:00
|
|
|
// Proceed with non-chunked upload.
|
|
|
|
|
this._sendDataRequest(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_loadChunks: function(file) {
|
|
|
|
|
file
|
|
|
|
|
.setStatus('chunks')
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
var chunks_uri = this._getUploadURI(file)
|
|
|
|
|
.setQueryParam('querychunks', 1);
|
|
|
|
|
|
|
|
|
|
new JX.Workflow(chunks_uri)
|
|
|
|
|
.setHandler(JX.bind(this, this._didLoadChunks, file))
|
|
|
|
|
.start();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_didLoadChunks: function(file, r) {
|
|
|
|
|
file.setChunks(r);
|
|
|
|
|
this._uploadNextChunk(file);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_uploadNextChunk: function(file) {
|
|
|
|
|
var chunks = file.getChunks();
|
|
|
|
|
var chunk;
|
|
|
|
|
for (var ii = 0; ii < chunks.length; ii++) {
|
|
|
|
|
chunk = chunks[ii];
|
|
|
|
|
if (!chunk.complete) {
|
2015-03-15 11:37:05 -07:00
|
|
|
this._uploadChunk(file, chunk);
|
2015-03-13 11:30:36 -07:00
|
|
|
break;
|
2012-10-08 15:23:05 -07:00
|
|
|
}
|
2015-03-13 11:30:36 -07:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2015-03-15 11:37:05 -07:00
|
|
|
_uploadChunk: function(file, chunk, callback) {
|
2015-03-13 11:30:36 -07:00
|
|
|
file
|
|
|
|
|
.setStatus('upload')
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
var chunkup_uri = this._getUploadURI(file)
|
|
|
|
|
.setQueryParam('uploadchunk', 1)
|
|
|
|
|
.setQueryParam('__upload__', 1)
|
|
|
|
|
.setQueryParam('byteStart', chunk.byteStart)
|
|
|
|
|
.toString();
|
|
|
|
|
|
|
|
|
|
var callback = JX.bind(this, this._didUploadChunk, file, chunk);
|
|
|
|
|
|
|
|
|
|
var req = new JX.Request(chunkup_uri, callback);
|
|
|
|
|
|
|
|
|
|
var seen_bytes = 0;
|
|
|
|
|
var onprogress = JX.bind(this, function(progress) {
|
|
|
|
|
file
|
|
|
|
|
.addUploadedBytes(progress.loaded - seen_bytes)
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
seen_bytes = progress.loaded;
|
|
|
|
|
this.invoke('progress', file);
|
2012-10-08 15:23:05 -07:00
|
|
|
});
|
|
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
req.listen('error', JX.bind(this, this._onUploadError, req, file));
|
|
|
|
|
req.listen('uploadprogress', onprogress);
|
|
|
|
|
|
2015-03-15 11:37:05 -07:00
|
|
|
var blob = file.getRawFileObject().slice(chunk.byteStart, chunk.byteEnd);
|
|
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
req
|
2015-03-15 11:37:05 -07:00
|
|
|
.setRawData(blob)
|
2015-03-13 11:30:36 -07:00
|
|
|
.send();
|
|
|
|
|
},
|
2012-10-08 15:23:05 -07:00
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
_didUploadChunk: function(file, chunk, r) {
|
|
|
|
|
file.didCompleteChunk(chunk);
|
2012-10-08 15:23:05 -07:00
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
if (r.complete) {
|
|
|
|
|
this._completeUpload(file, r);
|
|
|
|
|
} else {
|
|
|
|
|
this._uploadNextChunk(file);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_sendDataRequest: function(file) {
|
|
|
|
|
file
|
|
|
|
|
.setStatus('uploading')
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
this.invoke('willUpload', file);
|
|
|
|
|
|
|
|
|
|
var up_uri = this._getUploadURI(file)
|
|
|
|
|
.setQueryParam('__upload__', 1)
|
|
|
|
|
.toString();
|
|
|
|
|
|
|
|
|
|
var onupload = JX.bind(this, function(r) {
|
|
|
|
|
if (r.error) {
|
|
|
|
|
this._failUpload(file, r);
|
2012-10-08 15:23:05 -07:00
|
|
|
} else {
|
2015-03-13 11:30:36 -07:00
|
|
|
this._completeUpload(file, r);
|
2012-10-08 15:23:05 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
var req = new JX.Request(up_uri, onupload);
|
|
|
|
|
|
2012-10-08 15:23:05 -07:00
|
|
|
var onprogress = JX.bind(this, function(progress) {
|
|
|
|
|
file
|
|
|
|
|
.setTotalBytes(progress.total)
|
|
|
|
|
.setUploadedBytes(progress.loaded)
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
this.invoke('progress', file);
|
|
|
|
|
});
|
|
|
|
|
|
2015-03-13 11:30:36 -07:00
|
|
|
req.listen('error', JX.bind(this, this._onUploadError, req, file));
|
2012-10-08 15:23:05 -07:00
|
|
|
req.listen('uploadprogress', onprogress);
|
|
|
|
|
|
|
|
|
|
req
|
2015-03-13 11:30:36 -07:00
|
|
|
.setRawData(file.getRawFileObject())
|
2012-10-08 15:23:05 -07:00
|
|
|
.send();
|
2015-03-13 11:30:36 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_completeUpload: function(file, r) {
|
|
|
|
|
file
|
|
|
|
|
.setID(r.id)
|
|
|
|
|
.setPHID(r.phid)
|
|
|
|
|
.setURI(r.uri)
|
|
|
|
|
.setMarkup(r.html)
|
|
|
|
|
.setStatus('done')
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
this.invoke('didUpload', file);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_failUpload: function(file, r) {
|
|
|
|
|
file
|
|
|
|
|
.setStatus('error')
|
|
|
|
|
.setError(r.error)
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
|
|
this.invoke('didError', file);
|
|
|
|
|
},
|
|
|
|
|
|
2015-03-15 11:37:05 -07:00
|
|
|
_onUploadError: function(req, file, error) {
|
2015-03-13 11:30:36 -07:00
|
|
|
file.setStatus('error');
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
file.setError(error.code + ': ' + error.info);
|
|
|
|
|
} else {
|
|
|
|
|
var xhr = req.getTransport();
|
|
|
|
|
if (xhr.responseText) {
|
|
|
|
|
file.setError('Server responded: ' + xhr.responseText);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file.update();
|
|
|
|
|
this.invoke('didError', file);
|
2011-05-22 11:55:10 -07:00
|
|
|
}
|
2015-03-13 11:30:36 -07:00
|
|
|
|
2011-05-22 11:55:10 -07:00
|
|
|
},
|
|
|
|
|
properties: {
|
2015-03-13 11:30:36 -07:00
|
|
|
URI: null,
|
|
|
|
|
activatedClass: null,
|
|
|
|
|
viewPolicy: null,
|
|
|
|
|
chunkThreshold: null
|
2011-05-22 11:55:10 -07:00
|
|
|
}
|
|
|
|
|
});
|