04-29-2011 05:57 AM
05-04-2011 06:34 AM
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
/**
* FlashUpload component.
*
* Popups a YUI panel and displays a filelist and buttons to browse for files
* and upload them. Files can be removed and uploads can be cancelled.
* For single file uploads version input can be submitted.
*
* A multi file upload scenario could look like:
*
* var flashUpload = Alfresco.component.getFlashUploadInstance();
* var multiUploadConfig =
* {
* siteId: siteId,
* containerId: doclibContainerId,
* path: docLibUploadPath,
* filter: [],
* mode: flashUpload.MODE_MULTI_UPLOAD,
* }
* this.flashUpload.show(multiUploadConfig);
*
* @namespace Alfresco.module
* @class Alfresco.FlashUpload
* @extends Alfresco.component.Base
*/
(function()
{
/**
* YUI Library aliases
*/
var Dom = YAHOO.util.Dom,
Element = YAHOO.util.Element,
KeyListener = YAHOO.util.KeyListener;
/**
* FlashUpload constructor.
*
* FlashUpload is considered a singleton so constructor should be treated as private,
* please use Alfresco.component.getFlashUploadInstance() instead.
*
* @param htmlId {String} The HTML id of the parent element
* @return {Alfresco.component.FlashUpload} The new FlashUpload instance
* @constructor
* @private
*/
Alfresco.FlashUpload = function(htmlId)
{
Alfresco.FlashUpload.superclass.constructor.call(this, "Alfresco.FlashUpload", htmlId, ["button", "container", "datatable", "datasource", "cookie", "uploader"]);
this.swf = Alfresco.constants.URL_CONTEXT + "yui/uploader/assets/uploader.swf?dt=" + (new Date()).getTime();
this.hasRequiredFlashPlayer = Alfresco.util.hasRequiredFlashPlayer(9, 0, 45);
this.fileStore = {};
this.addedFiles = {};
this.defaultShowConfig =
{
siteId: null,
containerId: null,
uploadDirectory: null,
updateNodeRef: null,
updateFilename: null,
mode: this.MODE_SINGLE_UPLOAD,
filter: [],
onFileUploadComplete: null,
overwrite: false,
thumbnails: null,
uploadURL: null,
username: null
};
this.suppliedConfig = {};
this.showConfig = {};
this.fileItemTemplates = {};
return this;
};
YAHOO.extend(Alfresco.FlashUpload, Alfresco.component.Base,
{
/**
* The flash move will dispatch the contentReady event twice,
* make sure we only react on it twice.
*
* @property contentReady
* @type boolean
*/
contentReady: false,
/**
* The user is browsing and adding files to the file list
*
* @property STATE_BROWSING
* @type int
*/
STATE_BROWSING: 1,
/**
* File(s) is being uploaded to the server
*
* @property STATE_UPLOADING
* @type int
*/
STATE_UPLOADING: 2,
/**
* All files are processed and have either failed or been successfully
* uploaded to the server.
*
* @property STATE_FINISHED
* @type int
*/
STATE_FINISHED: 3,
/**
* File failed to upload.
*
* @property STATE_FAILURE
* @type int
*/
STATE_FAILURE: 4,
/**
* File was successfully STATE_SUCCESS.
*
* @property STATE_SUCCESS
* @type int
*/
STATE_SUCCESS: 5,
/**
* The state of which the uploader currently is, where the flow is.
* STATE_BROWSING > STATE_UPLOADING > STATE_FINISHED
*
* @property state
* @type int
*/
state: 1,
/**
* Stores references and state for each file that is in the file list.
* The fileId parameter from the YAHOO.widget.Uploader is used as the key
* and the value is an object that stores the state and references.
*
* @property fileStore
* @type object Used as a hash table with fileId as key and an object
* literal as the value.
* The object literal is of the form:
* {
* contentType: {HTMLElement}, // select that holds the chosen contentType for the file.
* fileButton: {YAHOO.widget.Button}, // Will be disabled on success or STATE_FAILURE
* state: {int}, // Keeps track if the individual file has been successfully uploaded or failed
* // (state flow: STATE_BROWSING > STATE_UPLOADING > STATE_SUCCESS or STATE_FAILURE)
* progress: {HTMLElement}, // span that is the "progress bar" which is moved during progress
* progressInfo: {HTMLElement}, // span that displays the filename and the state
* progressPercentage: {HTMLElement}, // span that displays the upload percentage for the individual file
* fileName: {string}, // filename
* nodeRef: {string} // nodeRef if the file has been uploaded successfully
* }
*/
fileStore: null,
/**
* The number of successful uploads since upload was clicked.
*
* @property noOfSuccessfulUploads
* @type int
*/
noOfSuccessfulUploads: 0,
/**
* The number of failed uploads since upload was clicked.
*
* @property noOfFailedUploads
* @type int
*/
noOfFailedUploads: 0,
/**
* Remembers what files that how been added to the file list since
* the show method was called.
*
* @property addedFiles
* @type object
*/
addedFiles: null,
/**
* Shows uploader in single upload mode.
*
* @property MODE_SINGLE_UPLOAD
* @static
* @type int
*/
MODE_SINGLE_UPLOAD: 1,
/**
* Shows uploader in single update mode.
*
* @property MODE_SINGLE_UPDATE
* @static
* @type int
*/
MODE_SINGLE_UPDATE: 2,
/**
* Shows uploader in multi upload mode.
*
* @property MODE_MULTI_UPLOAD
* @static
* @type int
*/
MODE_MULTI_UPLOAD: 3,
/**
* The default config for the gui state for the uploader.
* The user can override these properties in the show() method to use the
* uploader for both single & multi uploads and single updates.
*
* @property defaultShowConfig
* @type object
*/
defaultShowConfig: null,
/**
* The config passed in to the show method.
*
* @property suppliedConfig
* @type object
*/
suppliedConfig: null,
/**
* The merged result of the defaultShowConfig and the config passed in
* to the show method.
*
* @property showConfig
* @type object
*/
showConfig: null,
/**
* Contains the upload gui
*
* @property panel
* @type YAHOO.widget.Panel
*/
panel: null,
/**
* YUI class that controls the .swf to open the browser dialog window
* and transfers the files.
*
* @property uploader
* @type YAHOO.widget.Uploader
*/
uploader: null,
/**
* A property that is set to true after the loaded swf movie has dispatched its swfReady/contentReady event
*
* @property uploader Ready
* @type boolean
*/
uploaderReady: false,
/**
* Used to display the user selceted files and keep track of what files
* that are selected and should be STATE_FINISHED.
*
* @property uploader
* @type YAHOO.widget.DataTable
*/
dataTable: null,
/**
* HTMLElement of type span that displays the dialog title.
*
* @property titleText
* @type HTMLElement
*/
titleText: null,
/**
* HTMLElement of type span that displays help text for multi uploads.
*
* @property multiUploadTip
* @type HTMLElement
*/
multiUploadTip: null,
/**
* HTMLElement of type span that displays help text for single updates.
*
* @property singleUpdateTip
* @type HTMLElement
*/
singleUpdateTip: null,
/**
* HTMLElement of type span that displays the total upload status
*
* @property statusText
* @type HTMLElement
*/
statusText: null,
/**
* HTMLElement of type radio button for major or minor version
*
* @property description
* @type HTMLElement
*/
minorVersion: null,
/**
* HTMLElement of type textarea for version comment
*
* @property description
* @type HTMLElement
*/
description: null,
/**
* HTMLElement of type div that displays the version input form.
*
* @property versionSection
* @type HTMLElement
*/
versionSection: null,
/**
* HTMLElements of type div that is used to to display a column in a
* row in the file table list. It is loaded dynamically from the server
* and then cloned for each row and column in the file list.
* The fileItemTemplates has the following form:
* {
* left: HTMLElement to display the left column
* center: HTMLElement to display the center column
* right: HTMLElement to display the right column
* }
*
* @property fileItemTemplates
* @type HTMLElement
*/
fileItemTemplates: null,
/**
* Fired by YUI when parent element is available for scripting.
* Initial History Manager event registration
*
* @method onReady
*/
onReady: function FlashUpload_onReady()
{
// Tell the YUI class where the swf is
YAHOO.widget.Uploader.SWFURL = this.swf;
Dom.removeClass(this.id + "-dialog", "hidden");
// Create the panel
this.panel = Alfresco.util.createYUIPanel(this.id + "-dialog");
/**
* Mac Gecko bugfix for javascript losing connection to the flash uploader movie.
* To avoid a mac gecko bug where scrollbars are displayed even if the "scrolled"
* content isn't visible, YUI toggled the "overflow" style property between "hidden"
* and "visible", this unfortnately also caused the flash movie (which is a child
* of the toggled element) to get re-instantiated.
*
* (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
*/
if (this.panel.platform == "mac" && YAHOO.env.ua.gecko)
{
/**
* Remove the already added event listeners that toggles
* the "overflow" style property for the dialog wrapper.
*/
var Config = YAHOO.util.Config,
p = this.panel;
if (Config.alreadySubscribed(p.showEvent, p.showMacGeckoScrollbars, p))
{
p.showEvent.unsubscribe(p.showMacGeckoScrollbars, p);
}
if (Config.alreadySubscribed(p.showEvent, p.hideMacGeckoScrollbars, p))
{
p.showEvent.unsubscribe(p.hideMacGeckoScrollbars, p);
}
// Remove the toggling of the "overview" style property for the dialog itself.
p.showMacGeckoScrollbars = function(){};
p.hideMacGeckoScrollbars = function(){};
// Add a class for special bug fix css classes
Dom.addClass(p.element, "reinstantiated-fix");
}
// Save a reference to the file row template that is hidden inside the markup
this.fileItemTemplates.left = Dom.get(this.id + "-left-div");
this.fileItemTemplates.center = Dom.get(this.id + "-center-div");
this.fileItemTemplates.right = Dom.get(this.id + "-right-div");
// Create the YIU datatable object
this._createEmptyDataTable();
// Save a reference to the HTMLElement displaying texts so we can alter the texts later
this.titleText = Dom.get(this.id + "-title-span");
this.multiUploadTip = Dom.get(this.id + "-multiUploadTip-span");
this.singleUpdateTip = Dom.get(this.id + "-singleUpdateTip-span");
this.statusText = Dom.get(this.id + "-status-span");
this.description = Dom.get(this.id + "-description-textarea");
// Save reference to version radio so we can reset and get its value later
this.minorVersion = Dom.get(this.id + "-minorVersion-radioButton");
// Save a reference to the HTMLElement displaying version input so we can hide or show it
this.versionSection = Dom.get(this.id + "-versionSection-div");
// Create and save a reference to the uploadButton so we can alter it later
this.widgets.uploadButton = Alfresco.util.createYUIButton(this, "upload-button", this.onUploadButtonClick);
// Create and save a reference to the cancelOkButton so we can alter it later
this.widgets.cancelOkButton = Alfresco.util.createYUIButton(this, "cancelOk-button", this.onCancelOkButtonClick);
// Create and save a reference to the uploader so we can call it later
this.uploader = new YAHOO.widget.Uploader(this.id + "-flashuploader-div", Alfresco.constants.URL_CONTEXT + "themes/" + Alfresco.constants.THEME + "/images/upload-button-sprite.png", true);
this.uploader.subscribe("fileSelect", this.onFileSelect, this, true);
this.uploader.subscribe("uploadComplete",this.onUploadComplete, this, true);
this.uploader.subscribe("uploadProgress",this.onUploadProgress, this, true);
this.uploader.subscribe("uploadStart",this.onUploadStart, this, true);
this.uploader.subscribe("uploadCancel",this.onUploadCancel, this, true);
this.uploader.subscribe("uploadCompleteData",this.onUploadCompleteData, this, true);
this.uploader.subscribe("uploadError",this.onUploadError, this, true);
this.uploader.subscribe("contentReady", this.onContentReady, this, true);
// Register the ESC key to close the dialog
this.widgets.escapeListener = new KeyListener(document,
{
keys: KeyListener.KEY.ESCAPE
},
{
fn: this.onCancelOkButtonClick,
scope: this,
correctScope: true
});
},
/**
* Called when the "wrapping" SWFPlayer-flash movie is loaded
*
* @method onContentReady
*/
onContentReady: function FlashUpload_onContentReady(event)
{
this.uploader.enable();
this.uploader.setAllowMultipleFiles(this.showConfig.mode === this.MODE_MULTI_UPLOAD);
this.uploader.setFileFilters(this.showConfig.filter);
},
/**
* Show can be called multiple times and will display the uploader dialog
* in different ways depending on the config parameter.
*
* @method show
* @param config {object} describes how the upload dialog should be displayed
* The config object is in the form of:
* {
* siteId: {string}, // site to upload file(s) to
* containerId: {string}, // container to upload file(s) to (i.e. a doclib id)
* uploadPath: {string}, // directory path inside the component to where the uploaded file(s) should be save
* updateNodeRef: {string}, // nodeRef to the document that should be updated
* updateFilename: {string},// The name of the file that should be updated, used to display the tip
* mode: {int}, // MODE_SINGLE_UPLOAD, MODE_MULTI_UPLOAD or MODE_SINGLE_UPDATE
* filter: {array}, // limits what kind of files the user can select in the OS file selector
* onFileUploadComplete: null, // Callback after upload
* overwrite: false // If true and in mode MODE_XXX_UPLOAD it tells
* // the backend to overwrite a versionable file with the existing name
* // If false and in mode MODE_XXX_UPLOAD it tells
* // the backend to append a number to the versionable filename to avoid
* // an overwrite and a new version
* }
*/
show: function FlashUpload_show(config)
{
if (!this.hasRequiredFlashPlayer)
{
Alfresco.util.PopupManager.displayPrompt(
{
text: this.msg("label.noFlash")
});
}
// Merge the supplied config with default config and check mandatory properties
this.suppliedConfig = config;
this.showConfig = YAHOO.lang.merge(this.defaultShowConfig, config);
if (this.showConfig.uploadDirectory === undefined && this.showConfig.updateNodeRef === undefined)
{
throw new Error("An updateNodeRef OR uploadDirectory must be provided");
}
if (this.showConfig.uploadDirectory !== null && this.showConfig.uploadDirectory.length === 0)
{
this.showConfig.uploadDirectory = "/";
}
// Apply the config before it is shown
this._resetGUI();
// Apply the config before it is shown
this._applyConfig();
// Enable the Esc key listener
this.widgets.escapeListener.enable();
// Show the upload panel
this.panel.show();
// Need to resize FF in Ubuntu so the button appears
var swfWrapper = this.id + "-flashuploader-div";
if (navigator.userAgent && navigator.userAgent.indexOf("Ubuntu") != -1 &&
YAHOO.env.ua.gecko > 1 && !Dom.hasClass(swfWrapper, "button-fix"))
{
Dom.addClass(swfWrapper, "button-fix");
}
var swf = Dom.getChildrenBy(Dom.get(this.id + "-flashuploader-div"), function(node)
{
return node.tagName.toLowerCase() == "embed" || node.tagName.toLowerCase() == "object";
})[0];
swf.focus();
},
/**
* Reset GUI to start state
*
* @method _resetGUI
* @private
*/
_resetGUI: function FlashUpload__resetGUI()
{
// Reset references and the gui before showing it
this.state = this.STATE_BROWSING;
this.noOfFailedUploads = 0;
this.noOfSuccessfulUploads = 0;
this.statusText.innerHTML = " ";
this.description.value = "";
this.minorVersion.checked = true;
this.widgets.uploadButton.set("label", this.msg("button.upload"));
this.widgets.uploadButton.set("disabled", true);
this.widgets.cancelOkButton.set("label", this.msg("button.cancel"));
this.widgets.cancelOkButton.set("disabled", false);
},
/**
* Fired by YUI:s DataTable when the added row has been rendered to the data table list.
*
* @method onPostRenderEvent
*/
onPostRenderEvent: function FlashUpload_onPostRenderEvent()
{
// Display the upload button since all files are rendered
if (this.dataTable.getRecordSet().getLength() > 0)
{
this.widgets.uploadButton.set("disabled", false);
}
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
if (this.dataTable.getRecordSet().getLength() === 0)
{
this.uploader.enable();
}
else
{
this.uploader.disable();
}
}
},
/**
* Fired by YUI:s DataTable when a row has been added to the data table list.
* Keeps track of added files.
*
* @method onRowDeleteEvent
* @param event {object} a DataTable "rowDelete" event
*/
onRowDeleteEvent: function FlashUpload_onRowDeleteEvent(event)
{
},
/**
* Fired by YIUs Uploader when the user has selected one or more files
* from the OS:s file dialog window.
* Adds file that hasn't been selected before to the gui and adjusts the gui.
*
* @method onFileSelect
* @param event {object} an Uploader "fileSelect" event
*/
onFileSelect: function FlashUpload_onFileSelect(event)
{
// Disable upload button until all files have been rendered and added
this.widgets.uploadButton.set("disabled", true);
// For each time the user select new files, all the previous selected
// files also are included in the event.fileList. Make sure we only
// add files to the table that haven's been added before.
var newFiles = [],
data,
uniqueFileToken;
for (var i in event.fileList)
{
if (this.dataTable.get("renderLoopSize") === 0)
{
this.dataTable.set("renderLoopSize", 1);
}
data = YAHOO.widget.DataTable._cloneObject(event.fileList[i]);
uniqueFileToken = this._getUniqueFileToken(data);
if (!this.addedFiles[uniqueFileToken])
{
if (data.size === 0 && !this.addedFiles[uniqueFileToken])
{
Alfresco.util.PopupManager.displayMessage(
{
text: this.msg("message.zeroByteFileSelected", data.name)
});
}
else
{
// Add file to file table
newFiles.push(data);
}
// Since the flash movie allows the user to select one file several
// times we need to keep track of the selected files by our selves
this.addedFiles[uniqueFileToken] = uniqueFileToken;
}
}
// Add all files to table
this.dataTable.addRows(newFiles, 0);
},
/**
* Fired by YIU:s Uploader when transfer has been start for one of the files.
* Adjusts the gui.
*
* @method onUploadStart
* @param event {object} an Uploader "uploadStart" event
*/
onUploadStart: function FlashUpload_onUploadStart(event)
{
// Get the reference to the files gui components
var fileInfo = this.fileStore[event.id];
// Hide the contentType drop down if it wasn't hidden already
Dom.addClass(fileInfo.contentType, "hidden");
// Show the progress percentage if it wasn't visible already
fileInfo.progressPercentage.innerHTML = "0%";
Dom.removeClass(fileInfo.progressPercentage, "hidden");
// Make sure we know we are in upload state
fileInfo.state = this.STATE_UPLOADING;
},
/**
* Fired by YIU:s Uploader during the transfer for one of the files.
* Adjusts the gui and its progress bars.
*
* @method onUploadComplete
* @param event {object} an Uploader "uploadProgress" event
*/
onUploadProgress: function FlashUpload_onUploadProgress(event)
{
var flashId = event.id;
var fileInfo = this.fileStore[flashId];
// Set percentage
var percentage = event.bytesLoaded / event.bytesTotal;
fileInfo.progressPercentage.innerHTML = Math.round(percentage * 100) + "%";
// Set progress position
var left = (-400 + (percentage * 400));
Dom.setStyle(fileInfo.progress, "left", left + "px");
},
/**
* Fired by YIU:s Uploader when transfer is complete for one of the files.
*
* @method onUploadComplete
* @param event {object} an Uploader "uploadComplete" event
*/
onUploadComplete: function FlashUpload_onUploadComplete(event)
{
/**
* Actions taken on a completed upload is handled by the
* onUploadCompleteData() method instead.
*/
},
/**
* Fired by YIU:s Uploader when transfer is completed for a file.
* A difference compared to the onUploadComplete() method is that
* the response body is available in the event.
* Adjusts the gui and calls for another file to upload if the upload
* was succesful.
*
* @method onUploadCompleteData
* @param event {object} an Uploader "uploadCompleteData" event
*/
onUploadCompleteData: function FlashUpload_onUploadCompleteData(event)
{
// The individual file has been transfered completely
// Now adjust the gui for the individual file row
var fileInfo = this.fileStore[event.id];
fileInfo.state = this.STATE_SUCCESS;
fileInfo.fileButton.set("disabled", true);
// Extract the nodeRef and (possibly changed) fileName from the JSON response
var oldFileName = fileInfo.fileName;
var json = Alfresco.util.parseJSON(event.data);
if (json)
{
fileInfo.nodeRef = json.nodeRef;
fileInfo.fileName = json.fileName;
}
// Add the label "Successful" after the filename, updating the fileName from the response
fileInfo.progressInfo.innerHTML = fileInfo.progressInfo.innerHTML.replace(oldFileName, fileInfo.fileName) + " " + this.msg("label.success");
// Change the style of the progress bar
Dom.removeClass(fileInfo.progress, "fileupload-progressSuccess-span");
Dom.addClass(fileInfo.progress, "fileupload-progressFinished-span");
// Move the progress bar to "full" progress
Dom.setStyle(fileInfo.progress, "left", 0 + "px");
fileInfo.progressPercentage.innerHTML = "100%";
this.noOfSuccessfulUploads++;
// Adjust the rest of the gui
this._updateStatus();
this._uploadFromQueue(1);
this._adjustGuiIfFinished();
},
/**
* Fired by YIU:s Uploader when transfer has been cancelled for one of the files.
* Doesn't do anything.
*
* @method onUploadCancel
* @param event {object} an Uploader "uploadCancel" event
*/
onUploadCancel: function FlashUpload_onUploadCancel(event)
{
// The gui has already been adjusted in the function that caused the cancel
},
/**
* Fired by YIU:s Uploader when transfer failed for one of the files.
* Adjusts the gui and calls for another file to upload.
*
* @method onUploadError
* @param event {object} an Uploader "uploadError" event
*/
onUploadError: function FlashUpload_onUploadError(event)
{
var fileInfo = this.fileStore[event.id];
// This sometimes gets called twice, make sure we only adjust the gui once
if (fileInfo.state !== this.STATE_FAILURE)
{
fileInfo.state = this.STATE_FAILURE;
// Add the failure label to the filename & and as a title attribute
var key = "label.failure." + event.status,
msg = Alfresco.util.message(key, this.name);
if(msg == key)
{
msg = Alfresco.util.message("label.failure", this.name);
}
fileInfo.progressInfo["innerHTML"] = fileInfo.progressInfo["innerHTML"] + " " + msg;
fileInfo.progressInfoCell.setAttribute("title", msg);
// Change the style of the progress bar
Dom.removeClass(fileInfo.progress, "fileupload-progressSuccess-span");
Dom.addClass(fileInfo.progress, "fileupload-progressFailure-span");
// Set the progress bar to "full" progress
Dom.setStyle(fileInfo.progress, "left", 0 + "px");
// Disable the remove button
fileInfo.fileButton.set("disabled", true);
// Adjust the rest of the gui
this.noOfFailedUploads++;
this._updateStatus();
this._uploadFromQueue(1);
this._adjustGuiIfFinished();
}
},
/**
* Called by an anonymous function which that redirects the call to here
* when the user clicks the file remove button.
* Removes the file and cancels it if it was being uploaded
*
* @method _onFileButtonClickHandler
* @param flashId {string} an id matching the flash movies fileId
* @param recordId {int} an id matching a record in the data tables data source
*/
_onFileButtonClickHandler: function FlashUpload__onFileButtonClickHandler(flashId, recordId)
{
/**
* The file button has been clicked to remove a file.
* Remove the file from the datatable and all references to it.
*/
var r = this.dataTable.getRecordSet().getRecord(recordId);
this.addedFiles[this._getUniqueFileToken(r.getData())] = null;
this.fileStore[flashId] = null;
this.dataTable.deleteRow(r);
if (this.state === this.STATE_BROWSING)
{
// Remove the file from the flash movies memory
this.uploader.removeFile(flashId);
if (this.dataTable.getRecordSet().getLength() === 0)
{
// If it was the last file, disable the gui since no files exist.
this.widgets.uploadButton.set("disabled", true);
this.uploader.enable();
}
}
else if (this.state === this.STATE_UPLOADING)
{
// Cancel the ongoing upload for the file in the flash movie
this.uploader.cancel(flashId);
// Continue to upload documents from the queue
this._uploadFromQueue(1);
// Update the rest of the gui
this._updateStatus();
this._adjustGuiIfFinished();
}
},
/**
* Fired when the user clicks the cancel/ok button.
* The action taken depends on what state the uploader is in.
* In STATE_BROWSING - Closes the panel.
* In STATE_UPLOADING - Cancels current uploads,
* informs the user about how many that were uploaded,
* tells the documentlist to update itself
* and closes the panel.
* In STATE_FINISHED - Tells the documentlist to update itself
* and closes the panel.
*
* @method onBrowseButtonClick
* @param event {object} a Button "click" event
*/
onCancelOkButtonClick: function FlashUpload_onCancelOkButtonClick()
{
var message, i;
if (this.state === this.STATE_BROWSING)
{
// Do nothing (but close the panel, which happens below)
}
else if (this.state === this.STATE_UPLOADING)
{
this._cancelAllUploads();
// Inform the user if any files were uploaded before the rest was cancelled
var noOfUploadedFiles = 0;
for (i in this.fileStore)
{
if (this.fileStore[i] && this.fileStore[i].state === this.STATE_SUCCESS)
{
noOfUploadedFiles++;
}
}
if (noOfUploadedFiles > 0)
{
message = YAHOO.lang.substitute(this.msg("message.cancelStatus"),
{
"0": noOfUploadedFiles
});
}
// Tell the document list to refresh itself if present
YAHOO.Bubbling.fire("metadataRefresh",
{
currentPath: this.showConfig.path
});
}
else if (this.state === this.STATE_FINISHED)
{
// Tell the document list to refresh itself if present and to
// highlight the uploaded file (if multi upload was used display the first file)
var fileName = null, f;
for (i in this.fileStore)
{
f = this.fileStore[i];
if (f && f.state === this.STATE_SUCCESS)
{
fileName = f.fileName;
break;
}
}
if (fileName)
{
YAHOO.Bubbling.fire("metadataRefresh",
{
currentPath: this.showConfig.path,
highlightFile: fileName
});
}
else
{
YAHOO.Bubbling.fire("metadataRefresh",
{
currentPath: this.showConfig.path
});
}
}
// Hide the panel
this.panel.hide();
// Disable the Esc key listener
this.widgets.escapeListener.disable();
// Remove all files and references for this upload "session"
this._clear();
// Inform the user if any files were uploaded before the rest was cancelled
if (message)
{
Alfresco.util.PopupManager.displayPrompt(
{
text: message
});
}
},
/**
* Fired when the user clicks the upload button.
* Starts the uploading and adjusts the gui.
*
* @method onBrowseButtonClick
* @param event {object} a Button "click" event
*/
onUploadButtonClick: function FlashUpload_onUploadButtonClick()
{
if (this.state === this.STATE_BROWSING)
{
// Change the stat to uploading state and adjust the gui
var length = this.dataTable.getRecordSet().getLength();
if (length > 0)
{
this.state = this.STATE_UPLOADING;
this.widgets.uploadButton.set("disabled", true);
this.uploader.disable();
this._updateStatus();
}
// And start uploading from the queue
this._uploadFromQueue(2);
}
},
/**
* Adjust the gui according to the config passed into the show method.
*
* @method _applyConfig
* @private
*/
_applyConfig: function FlashUpload__applyConfig()
{
// Set the panel title
var title;
if (this.showConfig.mode === this.MODE_SINGLE_UPLOAD)
{
title = this.msg("header.singleUpload");
}
else if (this.showConfig.mode === this.MODE_MULTI_UPLOAD)
{
title = this.msg("header.multiUpload");
}
else if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
title = this.msg("header.singleUpdate");
}
this.titleText.innerHTML = title;
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
this.singleUpdateTip.innerHTML = YAHOO.lang.substitute(this.msg("label.singleUpdateTip"),
{
"0": this.showConfig.updateFilename
});
// Display the version input form
Dom.removeClass(this.versionSection, "hidden");
}
else
{
// Hide the version input form
Dom.addClass(this.versionSection, "hidden");
}
if (this.showConfig.mode === this.MODE_MULTI_UPLOAD)
{
// Show the upload status label, only interesting for multiple files
Dom.removeClass(this.statusText, "hidden");
// Show the help label for how to select multiple files
Dom.removeClass(this.multiUploadTip, "hidden");
// Hide the help label for other modes
Dom.addClass(this.singleUpdateTip, "hidden");
// Make the file list long
this.dataTable.set("height", "204px", true);
}
else
{
// Hide the upload status label, only interesting for multiple files
Dom.addClass(this.statusText, "hidden");
// Hide the help label for how to select multiple files
Dom.addClass(this.multiUploadTip, "hidden");
// Show the help label for single updates
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
// Show the help label for single updates
Dom.removeClass(this.singleUpdateTip, "hidden");
}
else
{
// Hide the help label for single updates
Dom.addClass(this.singleUpdateTip, "hidden");
}
// Make the file list short
this.dataTable.set("height", "40px");
}
// Check if flash player existed or if the no flash message is displayed
var uploaderDiv = Dom.get(this.id + "-flashuploader-div");
var p = Dom.getFirstChild(uploaderDiv);
if (p && p.tagName.toLowerCase() == "p")
{
// Flash isn't installed, make sure the no flash error message is displayed
Dom.setStyle(uploaderDiv, "height", "30px");
Dom.setStyle(uploaderDiv, "height", "200px");
}
else
{
this._applyUploaderConfig(
{
multiSelect: this.showConfig.mode === this.MODE_MULTI_UPLOAD,
filter: this.showConfig.filter
}, 0);
}
},
/**
* Function to try to apply configuration to Flash movie.
*
* @method _applyUploaderConfig
* @param obj {Object} Object literal containing configuration
* @param attempt {int} Counter for retry attempts
* @private
*/
_applyUploaderConfig: function (obj, attempt)
{
try
{
this.uploader.enable();
this.uploader.setAllowMultipleFiles(obj.multiSelect);
this.uploader.setFileFilters(obj.filter);
}
catch(e)
{
if (attempt == 7)
{
Alfresco.util.PopupManager.displayPrompt(
{
title: this.msg("message.flashError.title"),
text: this.msg("message.flashError.message"),
buttons: [
{
text: Alfresco.util.message("button.ok"),
handler:
{
fn: function _applyUploaderConfig_onOk(e, p_obj)
{
this.destroy();
p_obj.panel.destroy();
var fileUpload = p_obj._disableFlashUploader();
if (fileUpload)
{
fileUpload.show(p_obj.suppliedConfig);
}
},
obj: this
},
isDefault: true
},
{
text: Alfresco.util.message("button.refreshPage"),
handler: function _applyUploaderConfig_onRefreshPage()
{
window.location.reload(true);
}
}]
});
}
else
{
YAHOO.lang.later(100, this, this._applyUploaderConfig, [obj, ++attempt]);
}
}
},
/**
* Disables Flash uploader if an error is detected.
* Possibly a temporary workaround for bugs in SWFObject v1.5
*
* @method _disableFlashUploader
*/
_disableFlashUploader: function FlashUpload__disableFlashUploader()
{
var fileUpload = Alfresco.util.ComponentManager.findFirst("Alfresco.FileUpload");
if (fileUpload)
{
fileUpload.hasRequiredFlashPlayer = false;
fileUpload.onComponentsLoaded();
}
return fileUpload;
},
/**
* Helper function to create the data table and its cell formatter.
*
* @method _createEmptyDataTable
* @private
*/
_createEmptyDataTable: function FlashUpload__createEmptyDataTable()
{
/**
* Save a reference of 'this' so that the formatter below can use it
* later (since the formatter method gets called with another scope
* than 'this').
*/
var myThis = this;
/**
* Responsible for rendering the left row in the data table
*
* @param el HTMLElement the td element
* @param oRecord Holds the file data object
*/
var formatLeftCell = function(el, oRecord, oColumn, oData)
{
myThis._formatCellElements(el, oRecord, myThis.fileItemTemplates.left);
};
/**
* Responsible for rendering the center row in the data table
*
* @param el HTMLElement the td element
* @param oRecord Holds the file data object
*/
var formatCenterCell = function(el, oRecord, oColumn, oData)
{
myThis._formatCellElements(el, oRecord, myThis.fileItemTemplates.center);
};
/**
* Responsible for rendering the right row in the data table
*
* @param el HTMLElement the td element
* @param oRecord Holds the file data object
*/
var formatRightCell = function(el, oRecord, oColumn, oData)
{
myThis._formatCellElements(el, oRecord, myThis.fileItemTemplates.right);
};
/**
* Takes a left, center or right column template and looks for expected
* html components and vcreates yui objects or saves references to
* them so they can be updated during the upload progress.
*
* @param el HTMLElement the td element
* @param oRecord Holds the file data object
* @param template the template to display in the column
*/
this._formatCellElements = function(el, oRecord, template)
{
var record = oRecord.getData(),
flashId = record.id;
// Set the state for this file(/row) if it hasn't been set
if (!this.fileStore[flashId])
{
this.fileStore[flashId] =
{
state: this.STATE_BROWSING,
fileName: record.name,
nodeRef: null
};
}
// create an instance from the template and give it a uniqueue id.
var cell = new Element(el);
var templateInstance = template.cloneNode(true);
templateInstance.setAttribute("id", templateInstance.getAttribute("id") + flashId);
// Save references to elements that will be updated during upload.
var progress = Dom.getElementsByClassName("fileupload-progressSuccess-span", "span", templateInstance);
if (progress.length == 1)
{
this.fileStore[flashId].progress = progress[0];
}
var progressInfo = Dom.getElementsByClassName("fileupload-progressInfo-span", "span", templateInstance);
if (progressInfo.length == 1)
{
// Display the file size in human readable format after the filename.
var fileInfoStr = record.name + " (" + Alfresco.util.formatFileSize(record.size) + ")";
// Display the file name and size.
progressInfo = progressInfo[0];
this.fileStore[flashId].progressInfo = progressInfo;
this.fileStore[flashId].progressInfo.innerHTML = fileInfoStr;
// Save the cell element
this.fileStore[flashId].progressInfoCell = el;
}
// Save a reference to the contentType dropdown so we can find each file's contentType before upload.
var contentType = Dom.getElementsByClassName("fileupload-contentType-select", "select", templateInstance);
if (contentType.length == 1)
{
this.fileStore[flashId].contentType = contentType[0];
}
// Save references to elements that will be updated during upload.
var progressPercentage = Dom.getElementsByClassName("fileupload-percentage-span", "span", templateInstance);
if (progressPercentage.length == 1)
{
this.fileStore[flashId].progressPercentage = progressPercentage[0];
}
// Create a yui button for the fileButton.
var fButton = Dom.getElementsByClassName("fileupload-file-button", "button", templateInstance);
if (fButton.length == 1)
{
var fileButton = new YAHOO.widget.Button(fButton[0],
{
type: "button"
});
fileButton.subscribe("click", function()
{
this._onFileButtonClickHandler(flashId, oRecord.getId());
}, this, true);
this.fileStore[flashId].fileButton = fileButton;
fileButton.focus();
}
// Insert the templateInstance to the column.
cell.appendChild (templateInstance);
};
// Definition of the data table column
var myColumnDefs = [
{ key: "id", className:"col-left", resizable: false, formatter: formatLeftCell },
{ key: "name", className:"col-center", resizable: false, formatter: formatCenterCell },
{ key: "created", className:"col-right", resizable: false, formatter: formatRightCell }
];
// The data tables underlying data source.
var myDataSource = new YAHOO.util.DataSource([]);
myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
myDataSource.responseSchema =
{
fields: ["id", "name", "created", "modified", "type", "size", "progress"]
};
/**
* Create the data table.
* Set the properties even if they will get changed in applyConfig
* afterwards, if not set here they will not be changed later.
*/
YAHOO.widget.DataTable._bStylesheetFallback = !!YAHOO.env.ua.ie;
var dataTableDiv = Dom.get(this.id + "-filelist-table");
this.dataTable = new YAHOO.widget.DataTable(dataTableDiv, myColumnDefs, myDataSource,
{
scrollable: true,
height: "100px", // must be set to something so it can be changed afterwards, when the showconfig options decides if its a sinlge or multi upload
width: "620px",
renderLoopSize: 0, // value > 0 results in an error in IE & Safari from YIU2.6.0
MSG_EMPTY: this.msg("label.noFiles")
});
this.dataTable.subscribe("postRenderEvent", this.onPostRenderEvent, this, true);
this.dataTable.subscribe("rowDeleteEvent", this.onRowDeleteEvent, this, true);
},
/**
* Helper function to create a unique file token from the file data object
*
* @method _getUniqueFileToken
* @param data {object} a file data object describing a file
* @private
*/
_getUniqueFileToken: function FlashUpload__getUniqueFileToken(data)
{
return data.name + ":" + data.size + ":" + data.cDate + ":" + data.mDate;
},
/**
* Update the status label with the latest information about the upload progress
*
* @method _updateStatus
* @private
*/
_updateStatus: function FlashUpload__updateStatus()
{
// Update the status label with the latest information about the upload progress
this.statusText.innerHTML = YAHOO.lang.substitute(this.msg("label.uploadStatus"),
{
"0" : this.noOfSuccessfulUploads,
"1" : this.dataTable.getRecordSet().getLength(),
"2" : this.noOfFailedUploads
});
},
/**
* Checks if all files are finished (successfully uploaded or failed)
* and if so adjusts the gui.
*
* @method _adjustGuiIfFinished
* @private
*/
_adjustGuiIfFinished: function FlashUpload__adjustGuiIfFinished()
{
var objComplete =
{
successful: [],
failed: []
};
var file = null;
// Go into finished state if all files are finished: successful or failures
for (var i in this.fileStore)
{
file = this.fileStore[i];
if (file)
{
if (file.state == this.STATE_SUCCESS)
{
// Push successful file
objComplete.successful.push(
{
fileName: file.fileName,
nodeRef: file.nodeRef
});
}
else if (file.state == this.STATE_FAILURE)
{
// Push failed file
objComplete.failed.push(
{
fileName: file.fileName
});
}
else
{
return;
}
}
}
this.state = this.STATE_FINISHED;
this.widgets.cancelOkButton.set("label", this.msg("button.ok"));
this.widgets.uploadButton.set("disabled", true);
var callback = this.showConfig.onFileUploadComplete;
if (callback && typeof callback.fn == "function")
{
// Call the onFileUploadComplete callback in the correct scope
callback.fn.call((typeof callback.scope == "object" ? callback.scope : this), objComplete, callback.obj);
}
},
/**
* Starts to upload as many files as specified by noOfUploadsToStart
* as long as there are files left to upload.
*
* @method _uploadFromQueue
* @param noOfUploadsToStart
* @private
*/
_uploadFromQueue: function FlashUpload__uploadFromQueue(noOfUploadsToStart)
{
// generate upload POST url
var url;
if (this.showConfig.uploadURL === null)
{
url = Alfresco.constants.PROXY_URI + "api/upload";
}
else
{
url = Alfresco.constants.PROXY_URI + this.showConfig.uploadURL;
}
// Flash does not correctly bind to the session cookies during POST
// so we manually patch the jsessionid directly onto the URL instead
url += ";jsessionid=" + YAHOO.util.Cookie.get("JSESSIONID");
// Find files to upload
var startedUploads = 0,
length = this.dataTable.getRecordSet().getLength(),
record, flashId, fileInfo, attributes;
for (var i = 0; i < length && startedUploads < noOfUploadsToStart; i++)
{
record = this.dataTable.getRecordSet().getRecord(i);
flashId = record.getData("id");
fileInfo = this.fileStore[flashId];
if (fileInfo.state === this.STATE_BROWSING)
{
// Upload has NOT been started for this file, start it now
fileInfo.state = this.STATE_UPLOADING;
attributes =
{
siteId: this.showConfig.siteId,
containerId: this.showConfig.containerId,
username: this.showConfig.username
};
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
attributes.updateNodeRef = this.showConfig.updateNodeRef;
attributes.majorVersion = !this.minorVersion.checked;
attributes.description = this.description.value;
}
else
{
attributes.uploadDirectory = this.showConfig.uploadDirectory;
attributes.contentType = fileInfo.contentType.options[fileInfo.contentType.selectedIndex].value;
attributes.overwrite = this.showConfig.overwrite;
if (this.showConfig.thumbnails)
{
attributes.thumbnails = this.showConfig.thumbnails;
}
}
this.uploader.upload(flashId, url, "POST", attributes, "filedata");
startedUploads++;
}
}
},
/**
* Cancels all uploads inside the flash movie.
*
* @method _cancelAllUploads
* @private
*/
_cancelAllUploads: function FlashUpload__cancelAllUploads()
{
// Cancel all uploads inside the flash movie
var length = this.dataTable.getRecordSet().getLength();
for (var i = 0; i < length; i++)
{
var record = this.dataTable.getRecordSet().getRecord(i);
var flashId = record.getData("id");
this.uploader.cancel(flashId);
}
},
/**
* Remove all references to files inside the data table, flash movie
* and the this class references.
*
* @method _clear
* @private
*/
_clear: function FlashUpload__clear()
{
/**
* Remove all references to files inside the data table, flash movie
* and this class's references.
*/
var length = this.dataTable.getRecordSet().getLength();
this.addedFiles = {};
this.fileStore = {};
this.dataTable.deleteRows(0, length);
this.uploader.clearFileList();
}
});
})();
/**
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
/**
* HtmlUpload component.
*
* Popups a YUI panel and displays a filelist and buttons to browse for files
* and upload them. Files can be removed and uploads can be cancelled.
* For single file uploads version input can be submitted.
*
* A multi file upload scenario could look like:
*
* var htmlUpload = Alfresco.getHtmlUploadInstance();
* var multiUploadConfig =
* {
* siteId: siteId, * containerId: doclibContainerId,
* path: docLibUploadPath,
* filter: [],
* mode: htmlUpload.MODE_MULTI_UPLOAD,
* }
* this.htmlUpload.show(multiUploadConfig);
*
* @namespace Alfresco
* @class Alfresco.HtmlUpload
* @extends Alfresco.component.Base
*/
(function()
{
/**
* YUI Library aliases
*/
var Dom = YAHOO.util.Dom,
KeyListener = YAHOO.util.KeyListener;
/**
* HtmlUpload constructor.
*
* HtmlUpload is considered a singleton so constructor should be treated as private,
* please use Alfresco.getHtmlUploadInstance() instead.
*
* @param htmlId {String} The HTML id of the parent element
* @return {Alfresco.HtmlUpload} The new HtmlUpload instance
* @constructor
* @private
*/
Alfresco.HtmlUpload = function(htmlId)
{
Alfresco.HtmlUpload.superclass.constructor.call(this, "Alfresco.HtmlUpload", htmlId, ["button", "container"]);
this.defaultShowConfig =
{
siteId: null,
containerId: null,
uploadDirectory: null,
updateNodeRef: null,
updateFilename: null,
mode: this.MODE_SINGLE_UPLOAD,
onFileUploadComplete: null,
overwrite: false,
thumbnails: null,
uploadURL: null,
username: null
};
this.showConfig = {};
return this;
};
YAHOO.extend(Alfresco.HtmlUpload, Alfresco.component.Base,
{
/**
* Shows uploader in single upload mode.
*
* @property MODE_SINGLE_UPLOAD
* @static
* @type int
*/
MODE_SINGLE_UPLOAD: 1,
/**
* Shows uploader in single update mode.
*
* @property MODE_SINGLE_UPDATE
* @static
* @type int
*/
MODE_SINGLE_UPDATE: 2,
/**
* The default config for the gui state for the uploader.
* The user can override these properties in the show() method to use the
* uploader for both single & multi uploads and single updates.
*
* @property defaultShowConfig
* @type object
*/
defaultShowConfig: null,
/**
* The merged result of the defaultShowConfig and the config passed in
* to the show method.
*
* @property defaultShowConfig
* @type object
*/
showConfig: null,
/**
* HTMLElement of type div that displays the version input form.
*
* @property versionSection
* @type HTMLElement
*/
versionSection: null,
/**
* Fired by YUI when parent element is available for scripting.
* Initial History Manager event registration
*
* @method onReady
*/
onReady: function HtmlUpload_onReady()
{
Dom.removeClass(this.id + "-dialog", "hidden");
// Create the panel
this.widgets.panel = Alfresco.util.createYUIPanel(this.id + "-dialog");
// Save a reference to the HTMLElement displaying texts so we can alter the texts later
this.widgets.titleText = Dom.get(this.id + "-title-span");
this.widgets.singleUploadTip = Dom.get(this.id + "-singleUploadTip-span");
this.widgets.singleUpdateTip = Dom.get(this.id + "-singleUpdateTip-span");
// Save references to hidden fields so we can set them later
this.widgets.filedata = Dom.get(this.id + "-filedata-file");
this.widgets.filedata.contentEditable = false;
this.widgets.siteId = Dom.get(this.id + "-siteId-hidden");
this.widgets.containerId = Dom.get(this.id + "-containerId-hidden");
this.widgets.username = Dom.get(this.id + "-username-hidden");
this.widgets.updateNodeRef = Dom.get(this.id + "-updateNodeRef-hidden");
this.widgets.uploadDirectory = Dom.get(this.id + "-uploadDirectory-hidden");
this.widgets.overwrite = Dom.get(this.id + "-overwrite-hidden");
this.widgets.thumbnails = Dom.get(this.id + "-thumbnails-hidden");
this.widgets.successCallback = Dom.get(this.id + "-successCallback-hidden");
this.widgets.successScope = Dom.get(this.id + "-successScope-hidden");
this.widgets.failureCallback = Dom.get(this.id + "-failureCallback-hidden");
this.widgets.failureScope = Dom.get(this.id + "-failureScope-hidden");
// Save reference to version section elements so we can set its values later
this.widgets.description = Dom.get(this.id + "-description-textarea");
this.widgets.minorVersion = Dom.get(this.id + "-minorVersion-radioButton");
this.widgets.versionSection = Dom.get(this.id + "-versionSection-div");
// Create and save a reference to the buttons so we can alter them later
this.widgets.uploadButton = Alfresco.util.createYUIButton(this, "upload-button", null,
{
type: "submit"
});
this.widgets.cancelButton = Alfresco.util.createYUIButton(this, "cancel-button", this.onCancelButtonClick);
// Configure the forms runtime
var form = new Alfresco.forms.Form(this.id + "-htmlupload-form");
this.widgets.form = form;
// Title is mandatory
form.addValidation(this.id + "-filedata-file", Alfresco.forms.validation.mandatory, null, "change");
// The ok button is the submit button, and it should be enabled when the form is ready
form.setShowSubmitStateDynamically(true, false);
form.setSubmitElements(this.widgets.uploadButton);
form.doBeforeFormSubmit =
{
fn: function()
{
this.widgets.uploadButton.set("disabled", true);
this.widgets.cancelButton.set("disabled", true);
this.widgets.panel.hide();
this.widgets.feedbackMessage = Alfresco.util.PopupManager.displayMessage(
{
text: Alfresco.util.message("message.uploading", this.name),
spanClass: "wait",
displayTime: 0
});
},
obj: null,
scope: this
};
// Submit as an ajax submit (not leave the page), in json format
form.setAJAXSubmit(true, {});
// We're in a popup, so need the tabbing fix
form.applyTabFix();
form.init();
// Register the ESC key to close the dialog
this.widgets.escapeListener = new KeyListener(document,
{
keys: KeyListener.KEY.ESCAPE
},
{
fn: this.onCancelButtonClick,
scope: this,
correctScope: true
});
},
/**
* Show can be called multiple times and will display the uploader dialog
* in different ways depending on the config parameter.
*
* @method show
* @param config {object} describes how the upload dialog should be displayed
* The config object is in the form of:
* {
* siteId: {string}, // site to upload file(s) to
* containerId: {string}, // container to upload file(s) to (i.e. a doclib id)
* uploadPath: {string}, // directory path inside the component to where the uploaded file(s) should be save
* updateNodeRef: {string}, // nodeRef to the document that should be updated
* updateFilename: {string},// The name of the file that should be updated, used to display the tip
* mode: {int}, // MODE_SINGLE_UPLOAD or MODE_SINGLE_UPDATE
* filter: {array}, // limits what kind of files the user can select in the OS file selector
* onFileUploadComplete: null, // Callback after upload
* overwrite: false // If true and in mode MODE_XXX_UPLOAD it tells
* // the backend to overwrite a versionable file with the existing name
* // If false and in mode MODE_XXX_UPLOAD it tells
* // the backend to append a number to the versionable filename to avoid
* // an overwrite and a new version
* }
*/
show: function HtmlUpload_show(config)
{
// Merge the supplied config with default config and check mandatory properties
this.showConfig = YAHOO.lang.merge(this.defaultShowConfig, config);
if (this.showConfig.uploadDirectory === undefined && this.showConfig.updateNodeRef === undefined)
{
throw new Error("An updateNodeRef OR uploadDirectory must be provided");
}
if (this.showConfig.uploadDirectory !== null && this.showConfig.uploadDirectory.length === 0)
{
this.showConfig.uploadDirectory = "/";
}
// Enable the Esc key listener
this.widgets.escapeListener.enable();
this._showPanel();
},
/**
* Called when a file has been successfully uploaded
* Informs the user and reloads the doclib.
*
* @method onUploadSuccess
*/
onUploadSuccess: function HtmlUpload_onUploadSuccess(response)
{
// Hide the current message display
this.widgets.feedbackMessage.destroy();
// Tell the document list to refresh itself if present
var fileName = response.fileName ? response.fileName : this.widgets.filedata.value;
YAHOO.Bubbling.fire("metadataRefresh",
{
currentPath: this.showConfig.path,
highlightFile: fileName
});
// Todo see if the nodeRef can be added to the list
var objComplete =
{
successful: [{nodeRef: response.nodeRef, fileName: fileName}]
};
var callback = this.showConfig.onFileUploadComplete;
if (callback && typeof callback.fn == "function")
{
// Call the onFileUploadComplete callback in the correct scope
callback.fn.call((typeof callback.scope == "object" ? callback.scope : this), objComplete, callback.obj);
}
},
/**
* Called when a file failed to be uploaded
* Informs the user.
*
* @method onUploadFailure
*/
onUploadFailure: function HtmlUpload_onUploadFailure(e)
{
// Hide the current message display
this.widgets.feedbackMessage.destroy();
// Inform user that the upload failed
var key = "message.failure." + event.status.code,
text = Alfresco.util.message(key, this.name);
if(text == key)
{
text = event.status.code ? event.status.code : Alfresco.util.message("message.failure", this.name);
}
Alfresco.util.PopupManager.displayPrompt(
{
title: Alfresco.util.message("message.failure", this.name),
text: text
});
},
/**
* Fired when the user clicks the cancel button.
* Closes the panel.
*
* @method onCancelButtonClick
* @param event {object} a Button "click" event
*/
onCancelButtonClick: function HtmlUpload_onCancelButtonClick()
{
// Disable the Esc key listener
this.widgets.escapeListener.disable();
// Hide the panel
this.widgets.panel.hide();
},
/**
* Adjust the gui according to the config passed into the show method.
*
* @method _applyConfig
* @private
*/
_applyConfig: function HtmlUpload__applyConfig()
{
// Set the panel title
var title;
if (this.showConfig.mode === this.MODE_SINGLE_UPLOAD)
{
title = Alfresco.util.message("header.singleUpload", this.name);
}
else if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
title = Alfresco.util.message("header.singleUpdate", this.name);
}
this.widgets.titleText.innerHTML = title;
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
var tip = Alfresco.util.message("label.singleUpdateTip", this.name,
{
"0": this.showConfig.updateFilename
});
this.widgets.singleUpdateTip.innerHTML = tip;
// Display the version input form
Dom.removeClass(this.widgets.versionSection, "hidden");
}
else
{
// Hide the version input form
Dom.addClass(this.widgets.versionSection, "hidden");
}
// Show the help label for single updates
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
// Show the help label for single updates
Dom.removeClass(this.widgets.singleUpdateTip, "hidden");
Dom.addClass(this.widgets.singleUploadTip, "hidden");
}
else
{
// Show the help label for single uploads
Dom.removeClass(this.widgets.singleUploadTip, "hidden");
Dom.addClass(this.widgets.singleUpdateTip, "hidden");
}
this.widgets.cancelButton.set("disabled", false);
this.widgets.filedata.value = null;
this.widgets.uploadButton.set("disabled", true);
// Set the forms action url
var formEl = Dom.get(this.id + "-htmlupload-form");
if (this.showConfig.uploadURL === null)
{
// The .html suffix is required - it is not possible to do a multipart post using an ajax call.
// So it has to be a FORM submit, to make it feel like an ajax call a a hidden iframe is used.
// Since the component still needs to be called when the upload is finished, the script returns
// an html template with SCRIPT tags inside that which calls the component that triggered it.
formEl.action = Alfresco.constants.PROXY_URI + "api/upload.html";
}
else
{
formEl.action = Alfresco.constants.PROXY_URI + this.showConfig.uploadURL;
}
// Set the hidden parameters
this.widgets.siteId.value = this.showConfig.siteId;
this.widgets.containerId.value = this.showConfig.containerId;
this.widgets.username.value = this.showConfig.username;
if (this.showConfig.mode === this.MODE_SINGLE_UPDATE)
{
this.widgets.updateNodeRef.value = this.showConfig.updateNodeRef;
this.widgets.uploadDirectory.value = "";
this.widgets.overwrite.value = "";
this.widgets.thumbnails.value = "";
}
else
{
this.widgets.updateNodeRef.value = "";
this.widgets.uploadDirectory.value = this.showConfig.uploadDirectory;
this.widgets.overwrite.value = this.showConfig.overwrite;
this.widgets.thumbnails.value = this.showConfig.thumbnails;
}
var success = "window.parent.Alfresco.util.ComponentManager.get('" + this.id + "')";
this.widgets.successCallback.value = success + ".onUploadSuccess";
this.widgets.successScope.value = success;
var failure = "window.parent.Alfresco.util.ComponentManager.get('" + this.id + "')";
this.widgets.failureCallback.value = failure + ".onUploadFailure";
this.widgets.failureScope.value = failure;
},
/**
* Prepares the gui and shows the panel.
*
* @method _showPanel
* @private
*/
_showPanel: function HtmlUpload__showPanel()
{
// Reset references and the gui before showing it
this.widgets.description.value = "";
this.widgets.minorVersion.checked = true;
// Apply the config before it is showed
this._applyConfig();
// Show the upload panel
this.widgets.panel.show();
}
});
})();
et file-upload.js/**
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
/**
* FileUpload component.
*
* Checks if Flash is installed or not and uses either the FlashUpload or
* HtmlUpload component.
*
* A multi file upload scenario could look like:
*
* var fileUpload = Alfresco.getFileUploadInstance();
* var multiUploadConfig =
* {
* siteId: siteId,
* containerId: doclibContainerId,
* path: docLibUploadPath,
* filter: [],
* mode: fileUpload.MODE_MULTI_UPLOAD,
* }
* this.fileUpload.show(multiUploadConfig);
*
* If flash is installed it would use the FlashUpload component in multi upload mode
* If flash isn't installed it would use the HtmlUpload in single upload mode instead.
*
* @namespace Alfresco.component
* @class Alfresco.FileUpload
* @extends Alfresco.component.Base
*/
(function()
{
/**
* FileUpload constructor.
*
* FileUpload is considered a singleton so constructor should be treated as private,
* please use Alfresco.getFileUploadInstance() instead.
*
* @param {string} htmlId The HTML id of the parent element
* @return {Alfresco.FileUpload} The new FileUpload instance
* @constructor
* @private
*/
Alfresco.FileUpload = function(instanceId)
{
var instance = Alfresco.util.ComponentManager.get(instanceId);
if (instance !== null)
{
throw new Error("An instance of Alfresco.FileUpload already exists.");
}
// Determine minimum required Flash capability
this.hasRequiredFlashPlayer = !Alfresco.util.getVar("noflash") && Alfresco.util.hasRequiredFlashPlayer(9, 0, 45);
Alfresco.FileUpload.superclass.constructor.call(this, "Alfresco.FileUpload", instanceId);
return this;
};
YAHOO.extend(Alfresco.FileUpload, Alfresco.component.Base,
{
/**
* The uploader instance
*
* @property uploader
* @type Alfresco.FlashUpload or Alfresco.HtmlUpload
*/
uploader: null,
/**
* Shows uploader in single upload mode.
*
* @property MODE_SINGLE_UPLOAD
* @static
* @type int
*/
MODE_SINGLE_UPLOAD: 1,
/**
* Shows uploader in single update mode.
*
* @property MODE_SINGLE_UPDATE
* @static
* @type int
*/
MODE_SINGLE_UPDATE: 2,
/**
* Shows uploader in multi upload mode.
*
* @property MODE_MULTI_UPLOAD
* @static
* @type int
*/
MODE_MULTI_UPLOAD: 3,
/**
* The default config for the gui state for the uploader.
* The user can override these properties in the show() method to use the
* uploader for both single & multi uploads and single updates.
*
* @property defaultShowConfig
* @type object
*/
defaultShowConfig:
{
siteId: null,
containerId: null,
uploadDirectory: null,
updateNodeRef: null,
updateFilename: null,
mode: this.MODE_SINGLE_UPLOAD,
filter: [],
onFileUploadComplete: null,
overwrite: false,
thumbnails: null,
htmlUploadURL: null,
flashUploadURL: null,
username: null
},
/**
* The merged result of the defaultShowConfig and the config passed in
* to the show method.
*
* @property defaultShowConfig
* @type object
*/
showConfig: {},
/**
* Fired by YUILoaderHelper when required component script files have
* been loaded into the browser.
*
* @method onComponentsLoaded
*/
onComponentsLoaded: function FU_onComponentsLoaded()
{
// Create the appropriate uploader component
var uploadType = this.hasRequiredFlashPlayer ? "Alfresco.FlashUpload" : "Alfresco.HtmlUpload",
uploadInstance = Alfresco.util.ComponentManager.findFirst(uploadType);
if (uploadInstance)
{
this.uploader = uploadInstance;
}
else
{
throw new Error("No instance of uploader type '" + uploadType + "' exists.");
}
},
/**
* Show can be called multiple times and will display the uploader dialog
* in different ways depending on the config parameter.
*
* @method show
* @param config {object} describes how the upload dialog should be displayed
* The config object is in the form of:
* {
* siteId: {string}, // site to upload file(s) to
* containerId: {string}, // container to upload file(s) to (i.e. a doclib id)
* uploadPath: {string}, // directory path inside the component to where the uploaded file(s) should be save
* updateNodeRef: {string}, // nodeRef to the document that should be updated
* updateFilename: {string},// The name of the file that should be updated, used to display the tip
* mode: {int}, // MODE_SINGLE_UPLOAD, MODE_MULTI_UPLOAD or MODE_SINGLE_UPDATE
* filter: {array}, // limits what kind of files the user can select in the OS file selector
* onFileUploadComplete: null, // Callback after upload
* overwrite: false // If true and in mode MODE_XXX_UPLOAD it tells
* // the backend to overwrite a versionable file with the existing name
* // If false and in mode MODE_XXX_UPLOAD it tells
* // the backend to append a number to the versionable filename to avoid
* // an overwrite and a new version
* htmlUploadURL: null, // Overrides default url to post the file to if the html version is used
* flashUploadURL: null, // Overrides default url to post the files to if the flash version is used
* username: null // If a file should be associated with a user
* }
*/
show: function FU_show(config)
{
// Merge the supplied config with default config and check mandatory properties
this.showConfig = YAHOO.lang.merge(this.defaultShowConfig, config);
// If flash isn't installed multi upload mode isn't supported
if (!this.hasRequiredFlashPlayer && this.showConfig.mode == this.MODE_MULTI_UPLOAD)
{
this.showConfig.mode = this.MODE_SINGLE_UPLOAD;
}
if (this.hasRequiredFlashPlayer)
{
this.showConfig.uploadURL = this.showConfig.flashUploadURL;
}
else
{
this.showConfig.uploadURL = this.showConfig.htmlUploadURL;
}
// Let the uploader instance show itself
this.uploader.show(this.showConfig);
}
});
})();
Alfresco.getFileUploadInstance = function()
{
var instanceId = "alfresco-fileupload-instance";
return Alfresco.util.ComponentManager.get(instanceId) || new Alfresco.FileUpload(instanceId);
};
05-05-2011 10:57 AM
Tags
Find what you came for
We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.