1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-30 13:41:57 +02:00

Merged in AD-917-show-progress-when-uploading (pull request #54)

Ad 917 show progress when uploading
This commit is contained in:
TimDaubenschuetz 2015-09-15 13:15:52 +02:00
commit e025de878b
18 changed files with 362 additions and 163 deletions

View File

@ -45,7 +45,6 @@ requests.defaults({
class AppGateway {
start() {
let settings;
let subdomain = window.location.host.split('.')[0];

View File

@ -208,7 +208,8 @@ let MediaPlayer = React.createClass({
<br />You can leave this page and check back on the status later.</em>
</p>
<ProgressBar now={this.props.encodingStatus}
label='%(percent)s%' />
label="%(percent)s%"
className="ascribe-progress-bar" />
</div>
);
} else {

View File

@ -1,7 +1,7 @@
'use strict';
import React from 'react';
import ProgressBar from 'react-progressbar';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import FileDragAndDropDialog from './file_drag_and_drop_dialog';
import FileDragAndDropPreviewIterator from './file_drag_and_drop_preview_iterator';
@ -169,12 +169,16 @@ let FileDragAndDrop = React.createClass({
if(this.props.hashingProgress !== -2) {
return (
<div className={className}>
<p>{getLangText('Computing hash(es)... This may take a few minutes.')}</p>
<p>
<span>{Math.ceil(this.props.hashingProgress)}%</span>
<a onClick={this.props.handleCancelHashing}> {getLangText('Cancel hashing')}</a>
</p>
<ProgressBar completed={this.props.hashingProgress} color="#48DACB"/>
<div className="file-drag-and-drop-hashing-dialog">
<p>{getLangText('Computing hash(es)... This may take a few minutes.')}</p>
<p>
<a onClick={this.props.handleCancelHashing}> {getLangText('Cancel hashing')}</a>
</p>
<ProgressBar
now={Math.ceil(this.props.hashingProgress)}
label="%(percent)s%"
className="ascribe-progress-bar"/>
</div>
</div>
);
} else {

View File

@ -32,7 +32,7 @@ let FileDragAndDropDialog = React.createClass({
queryParamsUpload.method = 'upload';
return (
<span className="file-drag-and-drop-dialog present-options">
<div className="file-drag-and-drop-dialog present-options">
<p>{getLangText('Would you rather')}</p>
<Link
to={this.getPath()}
@ -51,12 +51,12 @@ let FileDragAndDropDialog = React.createClass({
{getLangText('Upload and hash your work')}
</span>
</Link>
</span>
</div>
);
} else {
if(this.props.multipleFiles) {
return (
<span className="file-drag-and-drop-dialog">
<div className="file-drag-and-drop-dialog">
<p>{getLangText('Drag files here')}</p>
<p>{getLangText('or')}</p>
<span
@ -64,13 +64,13 @@ let FileDragAndDropDialog = React.createClass({
onClick={this.props.onClick}>
{getLangText('choose files to upload')}
</span>
</span>
</div>
);
} else {
let dialog = queryParams.method === 'hash' ? getLangText('choose a file to hash') : getLangText('choose a file to upload');
return (
<span className="file-drag-and-drop-dialog">
<div className="file-drag-and-drop-dialog">
<p>{getLangText('Drag a file here')}</p>
<p>{getLangText('or')}</p>
<span
@ -78,7 +78,7 @@ let FileDragAndDropDialog = React.createClass({
onClick={this.props.onClick}>
{dialog}
</span>
</span>
</div>
);
}
}

View File

@ -72,7 +72,7 @@ let FileDragAndDropPreview = React.createClass({
if(this.props.areAssetsEditable) {
removeBtn = (<div className="delete-file">
<span
<span
className="glyphicon glyphicon-remove text-center"
aria-hidden="true"
title={getLangText('Remove file')}

View File

@ -1,7 +1,7 @@
'use strict';
import React from 'react';
import ProgressBar from 'react-progressbar';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import AppConstants from '../../constants/application_constants';
import { getLangText } from '../../utils/lang_utils.js';
@ -60,7 +60,9 @@ let FileDragAndDropPreviewImage = React.createClass({
<div
className="file-drag-and-drop-preview-image"
style={imageStyle}>
<ProgressBar completed={this.props.progress} color="black"/>
<ProgressBar
now={Math.ceil(this.props.progress)}
className="ascribe-progress-bar ascribe-progress-bar-xs"/>
{actionSymbol}
</div>
);

View File

@ -3,6 +3,10 @@
import React from 'react';
import FileDragAndDropPreview from './file_drag_and_drop_preview';
import FileDragAndDropPreviewProgress from './file_drag_and_drop_preview_progress';
import { displayValidFilesFilter } from './react_s3_fine_uploader_utils';
let FileDragAndDropPreviewIterator = React.createClass({
propTypes: {
@ -16,26 +20,37 @@ let FileDragAndDropPreviewIterator = React.createClass({
},
render() {
if(this.props.files) {
let {
files,
handleDeleteFile,
handleCancelFile,
handlePauseFile,
handleResumeFile,
areAssetsDownloadable,
areAssetsEditable
} = this.props;
files = files.filter(displayValidFilesFilter);
if(files && files.length > 0) {
return (
<div>
{this.props.files.map((file, i) => {
if(file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1) {
<div className="file-drag-and-drop-preview-iterator">
<div className="file-drag-and-drop-preview-iterator-spacing">
{files.map((file, i) => {
return (
<FileDragAndDropPreview
key={i}
file={file}
handleDeleteFile={this.props.handleDeleteFile}
handleCancelFile={this.props.handleCancelFile}
handlePauseFile={this.props.handlePauseFile}
handleResumeFile={this.props.handleResumeFile}
areAssetsDownloadable={this.props.areAssetsDownloadable}
areAssetsEditable={this.props.areAssetsEditable}/>
handleDeleteFile={handleDeleteFile}
handleCancelFile={handleCancelFile}
handlePauseFile={handlePauseFile}
handleResumeFile={handleResumeFile}
areAssetsDownloadable={areAssetsDownloadable}
areAssetsEditable={areAssetsEditable}/>
);
} else {
return null;
}
})}
})}
</div>
<FileDragAndDropPreviewProgress files={files} />
</div>
);
} else {

View File

@ -1,7 +1,7 @@
'use strict';
import React from 'react';
import ProgressBar from 'react-progressbar';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import AppConstants from '../../constants/application_constants';
import { getLangText } from '../../utils/lang_utils.js';
@ -55,7 +55,9 @@ let FileDragAndDropPreviewOther = React.createClass({
return (
<div
className="file-drag-and-drop-preview">
<ProgressBar completed={this.props.progress} color="black"/>
<ProgressBar
now={Math.ceil(this.props.progress)}
className="ascribe-progress-bar ascribe-progress-bar-xs"/>
<div className="file-drag-and-drop-preview-table-wrapper">
<div className="file-drag-and-drop-preview-other">
{actionSymbol}

View File

@ -0,0 +1,64 @@
'use strict';
import React from 'react';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import { displayValidProgressFilesFilter } from './react_s3_fine_uploader_utils';
let FileDragAndDropPreviewProgress = React.createClass({
propTypes: {
files: React.PropTypes.array
},
calcOverallFileSize() {
let overallFileSize = 0;
let files = this.props.files.filter(displayValidProgressFilesFilter);
// We just sum up all files' sizes
for(let i = 0; i < files.length; i++) {
overallFileSize += files[i].size;
}
return overallFileSize;
},
calcOverallProgress() {
let overallProgress = 0;
let overallFileSize = this.calcOverallFileSize();
let files = this.props.files.filter(displayValidProgressFilesFilter);
// We calculate the overall progress by summing the individuals
// files' progresses in relation to their size
for(let i = 0; i < files.length; i++) {
overallProgress += files[i].size / overallFileSize * files[i].progress;
}
return overallProgress;
},
render() {
let overallProgress = this.calcOverallProgress();
let overallFileSize = this.calcOverallFileSize();
let style = {
visibility: 'hidden'
};
// only visible if overallProgress is over zero
// or the overallFileSize is greater than 10MB
if(overallProgress !== 0 && overallFileSize > 10000000) {
style.visibility = 'visible';
}
return (
<ProgressBar
now={Math.ceil(overallProgress)}
label="Overall progress: %(percent)s%"
className="ascribe-progress-bar"
style={style} />
);
}
});
export default FileDragAndDropPreviewProgress;

View File

@ -17,7 +17,7 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import AppConstants from '../../constants/application_constants';
import { computeHashOfFile } from '../../utils/file_utils';
import { computeHashOfFile, displayValidFilesFilter } from '../../utils/file_utils';
var ReactS3FineUploader = React.createClass({
propTypes: {
@ -340,11 +340,9 @@ var ReactS3FineUploader = React.createClass({
completed: false
};
let newState = React.addons.update(this.state, {
startedChunks: { $set: chunks }
});
let startedChunks = React.addons.update(this.state.startedChunks, { $set: chunks });
this.setState(newState);
this.setState({ startedChunks });
},
onUploadChunkSuccess(id, chunkData, responseJson, xhr) {
@ -357,11 +355,9 @@ var ReactS3FineUploader = React.createClass({
chunks[chunkKey].responseJson = responseJson;
chunks[chunkKey].xhr = xhr;
let newState = React.addons.update(this.state, {
startedChunks: { $set: chunks }
});
let startedChunks = React.addons.update(this.state.startedChunks, { $set: chunks });
this.setState(newState);
this.setState({ startedChunks });
}
},
@ -381,11 +377,8 @@ var ReactS3FineUploader = React.createClass({
files[id].status = 'upload successful';
files[id].key = this.state.uploader.getKey(id);
let newState = React.addons.update(this.state, {
filesToUpload: { $set: files }
});
this.setState(newState);
let filesToUpload = React.addons.update(this.state.filesToUpload, { $set: files });
this.setState({ filesToUpload });
// Only after the blob has been created server-side, we can make the form submittable.
this.createBlob(files[id])
@ -467,15 +460,17 @@ var ReactS3FineUploader = React.createClass({
} else {
console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader');
}
return true;
},
onProgress(id, name, uploadedBytes, totalBytes) {
let newState = React.addons.update(this.state, {
filesToUpload: { [id]: {
progress: { $set: (uploadedBytes / totalBytes) * 100} }
let filesToUpload = React.addons.update(this.state.filesToUpload, {
[id]: {
progress: { $set: (uploadedBytes / totalBytes) * 100}
}
});
this.setState(newState);
this.setState({ filesToUpload });
},
onSessionRequestComplete(response, success) {
@ -497,8 +492,9 @@ var ReactS3FineUploader = React.createClass({
return file;
});
let newState = React.addons.update(this.state, {filesToUpload: {$set: updatedFilesToUpload}});
this.setState(newState);
let filesToUpload = React.addons.update(this.state.filesToUpload, {$set: updatedFilesToUpload});
this.setState({filesToUpload });
} else {
// server has to respond with 204
//let notification = new GlobalNotificationModel('Could not load attached files (Further data)', 'danger', 10000);
@ -510,13 +506,11 @@ var ReactS3FineUploader = React.createClass({
onDeleteComplete(id, xhr, isError) {
if(isError) {
let notification = new GlobalNotificationModel(getLangText('Couldn\'t delete file'), 'danger', 10000);
this.setStatusOfFile(id, 'online');
let notification = new GlobalNotificationModel(getLangText('There was an error deleting your file.'), 'danger', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
} else {
// To hide the file in this component, we need to set it's status to "deleted"
this.setStatusOfFile(id, 'deleted');
let notification = new GlobalNotificationModel(getLangText('File deleted'), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
}
@ -538,6 +532,13 @@ var ReactS3FineUploader = React.createClass({
},
handleDeleteFile(fileId) {
// We set the files state to 'deleted' immediately, so that the user is not confused with
// the unresponsiveness of the UI
//
// If there is an error during the deletion, we will just change the status back to 'online'
// and display an error message
this.setStatusOfFile(fileId, 'deleted');
// In some instances (when the file was already uploaded and is just displayed to the user
// - for example in the loan contract or additional files dialog)
// fineuploader does not register an id on the file (we do, don't be confused by this!).
@ -555,8 +556,6 @@ var ReactS3FineUploader = React.createClass({
// promise
} else {
let fileToDelete = this.state.filesToUpload[fileId];
fileToDelete.status = 'deleted';
S3Fetcher
.deleteFile(fileToDelete.s3Key, fileToDelete.s3Bucket)
.then(() => this.onDeleteComplete(fileToDelete.id, null, false))
@ -588,7 +587,7 @@ var ReactS3FineUploader = React.createClass({
handleUploadFile(files) {
// If multiple set and user already uploaded its work,
// cancel upload
if(!this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled').length > 0) {
if(!this.props.multiple && this.state.filesToUpload.filter(displayValidFilesFilter).length > 0) {
return;
}
@ -744,6 +743,7 @@ var ReactS3FineUploader = React.createClass({
synchronizeFileLists(files) {
let oldFiles = this.state.filesToUpload;
let oldAndNewFiles = this.state.uploader.getUploads();
// Add fineuploader specific information to new files
for(let i = 0; i < oldAndNewFiles.length; i++) {
for(let j = 0; j < files.length; j++) {
@ -758,6 +758,22 @@ var ReactS3FineUploader = React.createClass({
// and re-add fineuploader specific information for old files as well
for(let i = 0; i < oldAndNewFiles.length; i++) {
for(let j = 0; j < oldFiles.length; j++) {
// EXCEPTION:
//
// Files do not necessarily come from the user's hard drive but can also be fetched
// from Amazon S3. This is handled in onSessionRequestComplete.
//
// If the user deletes one of those files, then fineuploader will still keep it in his
// files array but with key, progress undefined and size === -1 but
// status === 'upload successful'.
// This poses a problem as we depend on the amount of files that have
// status === 'upload successful', therefore once the file is synced,
// we need to tag its status as 'deleted' (which basically happens here)
if(oldAndNewFiles[i].size === -1 && (!oldAndNewFiles[i].progress || oldAndNewFiles[i].progress === 0)) {
oldAndNewFiles[i].status = 'deleted';
}
if(oldAndNewFiles[i].originalName === oldFiles[j].name) {
oldAndNewFiles[i].progress = oldFiles[j].progress;
oldAndNewFiles[i].type = oldFiles[j].type;
@ -768,30 +784,23 @@ var ReactS3FineUploader = React.createClass({
}
// set the new file array
let newState = React.addons.update(this.state, {
filesToUpload: { $set: oldAndNewFiles }
});
this.setState(newState);
let filesToUpload = React.addons.update(this.state.filesToUpload, { $set: oldAndNewFiles });
this.setState({ filesToUpload });
},
setStatusOfFile(fileId, status) {
// also, sync files from state with the ones from fineuploader
let filesToUpload = JSON.parse(JSON.stringify(this.state.filesToUpload));
let changeSet = {};
filesToUpload[fileId].status = status;
// is status is set to deleted or canceled, we also need to reset the progress
// back to zero
if(status === 'deleted' || status === 'canceled') {
filesToUpload[fileId].progress = 0;
changeSet.progress = { $set: 0 };
}
// set state
let newState = React.addons.update(this.state, {
filesToUpload: { $set: filesToUpload }
});
changeSet.status = { $set: status };
this.setState(newState);
let filesToUpload = React.addons.update(this.state.filesToUpload, { [fileId]: changeSet });
this.setState({ filesToUpload });
},
isDropzoneInactive() {

View File

@ -1,5 +1,14 @@
'use strict';
/**
* Filter function for filtering all deleted and canceled files
* @param {object} file A file from filesToUpload that has status as a prop.
* @return {boolean}
*/
export function displayValidFilesFilter(file) {
return file.status !== 'deleted' && file.status !== 'canceled';
}
/**
* Returns a boolean if there has been at least one file uploaded
* successfully without it being deleted or canceled.
@ -7,10 +16,19 @@
* @return {Boolean}
*/
export function isReadyForFormSubmission(files) {
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
files = files.filter(displayValidFilesFilter);
if (files.length > 0 && files[0].status === 'upload successful') {
return true;
} else {
return false;
}
}
}
/**
* Filter function for which files to integrate in the progress process
* @param {object} file A file from filesToUpload, that has a status as a prop.
* @return {boolean}
*/
export function displayValidProgressFilesFilter(file) {
return file.status !== 'deleted' && file.status !== 'canceled' && file.status !== 'online';
}

View File

@ -3,7 +3,7 @@
*
* Copyright 2015, Widen Enterprises, Inc. info@fineuploader.com
*
* Version: 5.2.2
* Version: 5.3.0
*
* Homepage: http://fineuploader.com
*
@ -894,7 +894,7 @@ var qq = function(element) {
}());
/*global qq */
qq.version = "5.2.2";
qq.version = "5.3.0";
/* globals qq */
qq.supportedFeatures = (function() {
@ -1928,6 +1928,10 @@ qq.status = {
this._endpointStore.set(endpoint, id);
},
setForm: function(elementOrId) {
this._updateFormSupportAndParams(elementOrId);
},
setItemLimit: function(newItemLimit) {
this._currentItemLimit = newItemLimit;
},
@ -1945,16 +1949,11 @@ qq.status = {
},
uploadStoredFiles: function() {
var idToUpload;
if (this._storedIds.length === 0) {
this._itemError("noFilesError");
}
else {
while (this._storedIds.length) {
idToUpload = this._storedIds.shift();
this._uploadFile(idToUpload);
}
this._uploadStoredFiles();
}
}
};
@ -2038,10 +2037,11 @@ qq.status = {
});
},
_createStore: function(initialValue, readOnlyValues) {
_createStore: function(initialValue, _readOnlyValues_) {
var store = {},
catchall = initialValue,
perIdReadOnlyValues = {},
readOnlyValues = _readOnlyValues_,
copy = function(orig) {
if (qq.isObject(orig)) {
return qq.extend({}, orig);
@ -2095,8 +2095,20 @@ qq.status = {
addReadOnly: function(id, values) {
// Only applicable to Object stores
if (qq.isObject(store)) {
perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
qq.extend(perIdReadOnlyValues[id], values);
// If null ID, apply readonly values to all files
if (id === null) {
if (qq.isFunction(values)) {
readOnlyValues = values;
}
else {
readOnlyValues = readOnlyValues || {};
qq.extend(readOnlyValues, values);
}
}
else {
perIdReadOnlyValues[id] = perIdReadOnlyValues[id] || {};
qq.extend(perIdReadOnlyValues[id], values);
}
}
},
@ -2882,7 +2894,7 @@ qq.status = {
_onBeforeManualRetry: function(id) {
var itemLimit = this._currentItemLimit,
fileName;
console.log(this._handler.isValid(id));
if (this._preventRetries[id]) {
this.log("Retries are forbidden for id " + id, "warn");
return false;
@ -3005,13 +3017,14 @@ qq.status = {
this._onSubmit.apply(this, arguments);
this._uploadData.setStatus(id, qq.status.SUBMITTED);
this._onSubmitted.apply(this, arguments);
this._options.callbacks.onSubmitted.apply(this, arguments);
if (this._options.autoUpload) {
this._options.callbacks.onSubmitted.apply(this, arguments);
this._uploadFile(id);
}
else {
this._storeForLater(id);
this._options.callbacks.onSubmitted.apply(this, arguments);
}
},
@ -3238,6 +3251,23 @@ qq.status = {
}
},
_updateFormSupportAndParams: function(formElementOrId) {
this._options.form.element = formElementOrId;
this._formSupport = qq.FormSupport && new qq.FormSupport(
this._options.form, qq.bind(this.uploadStoredFiles, this), qq.bind(this.log, this)
);
if (this._formSupport && this._formSupport.attachedToForm) {
this._paramsStore.addReadOnly(null, this._formSupport.getFormInputsAsObject);
this._options.autoUpload = this._formSupport.newAutoUpload;
if (this._formSupport.newEndpoint) {
this.setEndpoint(this._formSupport.newEndpoint);
}
}
},
_upload: function(id, params, endpoint) {
var name = this.getName(id);
@ -3264,6 +3294,25 @@ qq.status = {
}
},
_uploadStoredFiles: function() {
var idToUpload, stillSubmitting,
self = this;
while (this._storedIds.length) {
idToUpload = this._storedIds.shift();
this._uploadFile(idToUpload);
}
// If we are still waiting for some files to clear validation, attempt to upload these again in a bit
stillSubmitting = this.getUploads({status: qq.status.SUBMITTING}).length;
if (stillSubmitting) {
qq.log("Still waiting for " + stillSubmitting + " files to clear submit queue. Will re-parse stored IDs array shortly.");
setTimeout(function() {
self._uploadStoredFiles();
}, 1000);
}
},
/**
* Performs some internal validation checks on an item, defined in the `validation` option.
*
@ -5271,6 +5320,7 @@ qq.XhrUploadHandler = function(spec) {
*/
getResumableFilesData: function() {
var resumableFilesData = [];
handler._iterateResumeRecords(function(key, uploadData) {
handler.moveInProgressToRemaining(null, uploadData.chunking.inProgress, uploadData.chunking.remaining);
@ -5461,7 +5511,7 @@ qq.XhrUploadHandler = function(spec) {
_iterateResumeRecords: function(callback) {
if (resumeEnabled) {
qq.each(localStorage, function(key, item) {
if (key.indexOf(qq.format("qq{}resume-", namespace)) === 0) {
if (key.indexOf(qq.format("qq{}resume", namespace)) === 0) {
var uploadData = JSON.parse(item);
callback(key, uploadData);
}
@ -5728,7 +5778,9 @@ qq.WindowReceiveMessage = function(o) {
},
getItemByFileId: function(id) {
return this._templating.getFileContainer(id);
if (!this._templating.isHiddenForever(id)) {
return this._templating.getFileContainer(id);
}
},
reset: function() {
@ -6238,11 +6290,6 @@ qq.WindowReceiveMessage = function(o) {
dontDisplay = this._handler.isProxied(id) && this._options.scaling.hideScaled,
record;
// If we don't want this file to appear in the UI, skip all of this UI-related logic.
if (dontDisplay) {
return;
}
if (this._options.display.prependFiles) {
if (this._totalFilesInBatch > 1 && this._filesInBatchAddedToUi > 0) {
prependIndex = this._filesInBatchAddedToUi - 1;
@ -6274,7 +6321,7 @@ qq.WindowReceiveMessage = function(o) {
}
}
this._templating.addFile(id, this._options.formatFileName(name), prependData);
this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);
if (canned) {
this._thumbnailUrls[id] && this._templating.updateThumbnail(id, this._thumbnailUrls[id], true);
@ -6638,6 +6685,7 @@ qq.Templating = function(spec) {
HIDE_DROPZONE_ATTR = "qq-hide-dropzone",
DROPZPONE_TEXT_ATTR = "qq-drop-area-text",
IN_PROGRESS_CLASS = "qq-in-progress",
HIDDEN_FOREVER_CLASS = "qq-hidden-forever",
isCancelDisabled = false,
generatedThumbnails = 0,
thumbnailQueueMonitorRunning = false,
@ -7273,7 +7321,7 @@ qq.Templating = function(spec) {
isCancelDisabled = true;
},
addFile: function(id, name, prependInfo) {
addFile: function(id, name, prependInfo, hideForever) {
var fileEl = qq.toElement(templateHtml.fileTemplate),
fileNameEl = getTemplateEl(fileEl, selectorClasses.file),
uploaderEl = getTemplateEl(container, selectorClasses.uploader),
@ -7296,30 +7344,36 @@ qq.Templating = function(spec) {
fileList.appendChild(fileEl);
}
hide(getProgress(id));
hide(getSize(id));
hide(getDelete(id));
hide(getRetry(id));
hide(getPause(id));
hide(getContinue(id));
if (isCancelDisabled) {
this.hideCancel(id);
if (hideForever) {
fileEl.style.display = "none";
qq(fileEl).addClass(HIDDEN_FOREVER_CLASS);
}
else {
hide(getProgress(id));
hide(getSize(id));
hide(getDelete(id));
hide(getRetry(id));
hide(getPause(id));
hide(getContinue(id));
thumb = getThumbnail(id);
if (thumb && !thumb.src) {
cachedWaitingForThumbnailImg.then(function(waitingImg) {
thumb.src = waitingImg.src;
if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {
qq(thumb).css({
maxHeight: waitingImg.style.maxHeight,
maxWidth: waitingImg.style.maxWidth
});
}
if (isCancelDisabled) {
this.hideCancel(id);
}
show(thumb);
});
thumb = getThumbnail(id);
if (thumb && !thumb.src) {
cachedWaitingForThumbnailImg.then(function(waitingImg) {
thumb.src = waitingImg.src;
if (waitingImg.style.maxHeight && waitingImg.style.maxWidth) {
qq(thumb).css({
maxHeight: waitingImg.style.maxHeight,
maxWidth: waitingImg.style.maxWidth
});
}
show(thumb);
});
}
}
},
@ -7413,6 +7467,10 @@ qq.Templating = function(spec) {
icon && qq(icon).addClass(options.classes.editable);
},
isHiddenForever: function(id) {
return qq(getFile(id)).hasClass(HIDDEN_FOREVER_CLASS);
},
hideEditIcon: function(id) {
var icon = getEditIcon(id);
@ -7572,13 +7630,17 @@ qq.Templating = function(spec) {
},
generatePreview: function(id, optFileOrBlob) {
thumbGenerationQueue.push({id: id, optFileOrBlob: optFileOrBlob});
!thumbnailQueueMonitorRunning && generateNextQueuedPreview();
if (!this.isHiddenForever(id)) {
thumbGenerationQueue.push({id: id, optFileOrBlob: optFileOrBlob});
!thumbnailQueueMonitorRunning && generateNextQueuedPreview();
}
},
updateThumbnail: function(id, thumbnailUrl, showWaitingImg) {
thumbGenerationQueue.push({update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});
!thumbnailQueueMonitorRunning && generateNextQueuedPreview();
if (!this.isHiddenForever(id)) {
thumbGenerationQueue.push({update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});
!thumbnailQueueMonitorRunning && generateNextQueuedPreview();
}
},
hasDialog: function(type) {
@ -9489,12 +9551,6 @@ qq.s3.XhrUploadHandler = function(spec, proxy) {
result.success,
function failure(reason, xhr) {
console.logGlobal(reason + 'in chunked.combine', false, {
uploadId,
etagMap,
result
});
result.failure(upload.done(id, xhr).response, xhr);
}
);
@ -12335,7 +12391,7 @@ qq.Scaler = function(spec, log) {
"use strict";
var self = this,
includeReference = spec.sendOriginal,
includeOriginal = spec.sendOriginal,
orient = spec.orient,
defaultType = spec.defaultType,
defaultQuality = spec.defaultQuality / 100,
@ -12385,16 +12441,18 @@ qq.Scaler = function(spec, log) {
});
});
includeReference && records.push({
records.push({
uuid: originalFileUuid,
name: originalFileName,
blob: originalBlob
size: originalBlob.size,
blob: includeOriginal ? originalBlob : null
});
}
else {
records.push({
uuid: originalFileUuid,
name: originalFileName,
size: originalBlob.size,
blob: originalBlob
});
}
@ -12413,19 +12471,17 @@ qq.Scaler = function(spec, log) {
proxyGroupId = qq.getUniqueId();
qq.each(self.getFileRecords(uuid, name, file), function(idx, record) {
var relatedBlob = file,
relatedSize = size,
var blobSize = record.size,
id;
if (record.blob instanceof qq.BlobProxy) {
relatedBlob = record.blob;
relatedSize = -1;
blobSize = -1;
}
id = uploadData.addFile({
uuid: record.uuid,
name: record.name,
size: relatedSize,
size: blobSize,
batchId: batchId,
proxyGroupId: proxyGroupId
});
@ -12437,10 +12493,13 @@ qq.Scaler = function(spec, log) {
originalId = id;
}
addFileToHandler(id, relatedBlob);
fileList.push({id: id, file: relatedBlob});
if (record.blob) {
addFileToHandler(id, record.blob);
fileList.push({id: id, file: record.blob});
}
else {
uploadData.setStatus(id, qq.status.REJECTED);
}
});
// If we are potentially uploading an original file and some scaled versions,
@ -12453,8 +12512,8 @@ qq.Scaler = function(spec, log) {
qqparentsize: uploadData.retrieve({id: originalId}).size
};
// Make SURE the UUID for each scaled image is sent with the upload request,
// to be consistent (since we need to ensure it is sent for the original file as well).
// Make sure the UUID for each scaled image is sent with the upload request,
// to be consistent (since we may need to ensure it is sent for the original file as well).
params[uuidParamName] = uploadData.retrieve({id: scaledId}).uuid;
uploadData.setParentId(scaledId, originalId);
@ -14411,4 +14470,4 @@ code.google.com/p/crypto-js/wiki/License
C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
}());
/*! 2015-06-09 */
/*! 2015-08-26 */

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,6 @@
'use strict';
import React from 'react';
import Router from 'react-router';
import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece';
@ -17,8 +16,6 @@ import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button';
import AclProxy from '../../../../../acl_proxy';
import AclButton from '../../../../../ascribe_buttons/acl_button';
import { getLangText } from '../../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../../utils/general_utils';

View File

@ -3,7 +3,6 @@
import alt from '../alt';
import EventActions from '../actions/event_actions';
class GoogleAnalyticsHandler {
constructor() {
this.bindActions(EventActions);

View File

@ -73,9 +73,8 @@
"q": "^1.4.1",
"raven-js": "^1.1.19",
"react": "^0.13.2",
"react-bootstrap": "^0.24.3",
"react-bootstrap": "^0.25.1",
"react-datepicker": "^0.12.0",
"react-progressbar": "^1.1.0",
"react-router": "^0.13.3",
"react-router-bootstrap": "~0.16.0",
"react-star-rating": "~1.3.2",

View File

@ -10,7 +10,6 @@
cursor: default !important;
padding: 1.5em 0 1.5em 0;
}
.inactive-dropzone {
@ -29,6 +28,27 @@
}
}
.file-drag-and-drop-preview-iterator {
margin: 2.5em 0 0 0;
text-align: right;
> div:first-child {
text-align: center;
}
}
.file-drag-and-drop-preview-iterator-spacing {
margin-bottom: 1em;
}
.file-drag-and-drop-dialog {
margin: 1.5em 0 1.5em 0;
}
.file-drag-and-drop-hashing-dialog {
margin: 1.5em 0 0 0;
}
.file-drag-and-drop .file-drag-and-drop-dialog > p:first-child {
font-size: 1.5em !important;

View File

@ -413,3 +413,14 @@ hr {
padding-bottom: 30%;
text-align: center;
}
.ascribe-progress-bar {
margin-bottom: 0;
> .progress-bar {
background-color: $ascribe-color-green;
}
}
.ascribe-progress-bar-xs {
height: 12px;
}