12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358 |
- /**
- * jquery.ui.plupload.js
- *
- * Copyright 2013, Moxiecode Systems AB
- * Released under GPL License.
- *
- * License: http://www.plupload.com/license
- * Contributing: http://www.plupload.com/contributing
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- * jquery.ui.button.js
- * jquery.ui.progressbar.js
- *
- * Optionally:
- * jquery.ui.sortable.js
- */
- /* global jQuery:true */
- /**
- jQuery UI based implementation of the Plupload API - multi-runtime file uploading API.
- To use the widget you must include _jQuery_ and _jQuery UI_ bundle (including `ui.core`, `ui.widget`, `ui.button`,
- `ui.progressbar` and `ui.sortable`).
- In general the widget is designed the way that you do not usually need to do anything to it after you instantiate it.
- But! You still can intervenue, to some extent, in case you need to. Although, due to the fact that widget is based on
- _jQuery UI_ widget factory, there are some specifics. See examples below for more details.
- @example
- <!-- Instantiating: -->
- <div id="uploader">
- <p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
- </div>
- <script>
- $('#uploader').plupload({
- url : '../upload.php',
- filters : [
- {title : "Image files", extensions : "jpg,gif,png"}
- ],
- rename: true,
- sortable: true,
- flash_swf_url : '../../js/Moxie.swf',
- silverlight_xap_url : '../../js/Moxie.xap',
- });
- </script>
- @example
- // Invoking methods:
- $('#uploader').plupload(options);
- // Display welcome message in the notification area
- $('#uploader').plupload('notify', 'info', "This might be obvious, but you need to click 'Add Files' to add some files.");
- @example
- // Subscribing to the events...
- // ... on initialization:
- $('#uploader').plupload({
- ...
- viewchanged: function(event, args) {
- // stuff ...
- }
- });
- // ... or after initialization
- $('#uploader').on("viewchanged", function(event, args) {
- // stuff ...
- });
- @class UI.Plupload
- @constructor
- @param {Object} settings For detailed information about each option check documentation.
- @param {String} settings.url URL of the server-side upload handler.
- @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
- @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
- @param {Object} [settings.filters={}] Set of file type filters.
- @param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
- @param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
- @param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
- @param {Number} [settings.filters.max_file_count=0] Limit the number of files that can reside in the queue at the same time (default is 0 - no limit).
- @param {String} [settings.flash_swf_url] URL of the Flash swf.
- @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
- @param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
- @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
- @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
- @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
- @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
- @param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
- @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
- @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
- @param {Number} [settings.resize.width] If image is bigger, it will be resized.
- @param {Number} [settings.resize.height] If image is bigger, it will be resized.
- @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
- @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
- @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
- @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
- @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
- @param {Boolean} [settings.autostart=false] Whether to auto start uploading right after file selection.
- @param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.
- @param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.
- @param {Boolean} [settings.sortable=false] Enable ability to sort files in the queue, changing their uploading priority.
- @param {Object} [settings.buttons] Control the visibility of functional buttons.
- @param {Boolean} [settings.buttons.browse=true] Display browse button.
- @param {Boolean} [settings.buttons.start=true] Display start button.
- @param {Boolean} [settings.buttons.stop=true] Display stop button.
- @param {Object} [settings.views] Control various views of the file queue.
- @param {Boolean} [settings.views.list=true] Enable list view.
- @param {Boolean} [settings.views.thumbs=false] Enable thumbs view.
- @param {String} [settings.views.default='list'] Default view.
- @param {Boolean} [settings.views.remember=true] Whether to remember the current view (requires jQuery Cookie plugin).
- @param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.
- */
- ;(function(window, document, plupload, o, $) {
- /**
- Dispatched when the widget is initialized and ready.
- @event ready
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- */
- /**
- Dispatched when file dialog is closed.
- @event selected
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {Array} files Array of selected files represented by plupload.File objects
- */
- /**
- Dispatched when file dialog is closed.
- @event removed
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {Array} files Array of removed files represented by plupload.File objects
- */
- /**
- Dispatched when upload is started.
- @event started
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- */
- /**
- Dispatched when upload is stopped.
- @event stopped
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- */
- /**
- Dispatched during the upload process.
- @event progress
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {plupload.File} file File that is being uploaded (includes loaded and percent properties among others).
- @param {Number} size Total file size in bytes.
- @param {Number} loaded Number of bytes uploaded of the files total size.
- @param {Number} percent Number of percentage uploaded of the file.
- */
- /**
- Dispatched when file is uploaded.
- @event uploaded
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {plupload.File} file File that was uploaded.
- @param {Enum} status Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
- */
- /**
- Dispatched when upload of the whole queue is complete.
- @event complete
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {Array} files Array of uploaded files represented by plupload.File objects
- */
- /**
- Dispatched when the view is changed, e.g. from `list` to `thumbs` or vice versa.
- @event viewchanged
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {String} type Current view type.
- */
- /**
- Dispatched when error of some kind is detected.
- @event error
- @param {plupload.Uploader} uploader Uploader instance sending the event.
- @param {String} error Error message.
- @param {plupload.File} file File that was uploaded.
- @param {Enum} status Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
- */
- var uploaders = {};
- function _(str) {
- return plupload.translate(str) || str;
- }
- function renderUI(obj) {
- obj.id = obj.attr('id');
- obj.html(
- '<div class="plupload_wrapper">' +
- '<div class="ui-widget-content plupload_container">' +
- '<div class="ui-state-default ui-widget-header plupload_header">' +
- '<div class="plupload_header_content">' +
- '<div class="plupload_logo"> </div>' +
- '<div class="plupload_header_title">' + _("Select files") + '</div>' +
- '<div class="plupload_header_text">' + _("Add files to the upload queue and click the start button.") + '</div>' +
- '<div class="plupload_view_switch">' +
- '<input type="radio" id="'+obj.id+'_view_list" name="view_mode_'+obj.id+'" checked="checked" /><label class="plupload_button" for="'+obj.id+'_view_list" data-view="list">' + _('List') + '</label>' +
- '<input type="radio" id="'+obj.id+'_view_thumbs" name="view_mode_'+obj.id+'" /><label class="plupload_button" for="'+obj.id+'_view_thumbs" data-view="thumbs">' + _('Thumbnails') + '</label>' +
- '</div>' +
- '</div>' +
- '</div>' +
- '<table class="plupload_filelist plupload_filelist_header ui-widget-header">' +
- '<tr>' +
- '<td class="plupload_cell plupload_file_name">' + _('Filename') + '</td>' +
- '<td class="plupload_cell plupload_file_status">' + _('Status') + '</td>' +
- '<td class="plupload_cell plupload_file_size">' + _('Size') + '</td>' +
- '<td class="plupload_cell plupload_file_action"> </td>' +
- '</tr>' +
- '</table>' +
- '<div class="plupload_content">' +
- '<div class="plupload_droptext">' + _("Drag files here.") + '</div>' +
- '<ul class="plupload_filelist_content"> </ul>' +
- '<div class="plupload_clearer"> </div>' +
- '</div>' +
- '<table class="plupload_filelist plupload_filelist_footer ui-widget-header">' +
- '<tr>' +
- '<td class="plupload_cell plupload_file_name">' +
- '<div class="plupload_buttons"><!-- Visible -->' +
- '<a class="plupload_button plupload_add">' + _("Add Files") + '</a> ' +
- '<a class="plupload_button plupload_start">' + _("Start Upload") + '</a> ' +
- '<a class="plupload_button plupload_stop plupload_hidden">'+_("Stop Upload") + '</a> ' +
- '</div>' +
- '<div class="plupload_started plupload_hidden"><!-- Hidden -->' +
- '<div class="plupload_progress plupload_right">' +
- '<div class="plupload_progress_container"></div>' +
- '</div>' +
- '<div class="plupload_cell plupload_upload_status"></div>' +
- '<div class="plupload_clearer"> </div>' +
- '</div>' +
- '</td>' +
- '<td class="plupload_file_status"><span class="plupload_total_status">0%</span></td>' +
- '<td class="plupload_file_size"><span class="plupload_total_file_size">0 kb</span></td>' +
- '<td class="plupload_file_action"></td>' +
- '</tr>' +
- '</table>' +
- '</div>' +
- '<input class="plupload_count" value="0" type="hidden">' +
- '</div>'
- );
- }
- $.widget("ui.plupload", {
- widgetEventPrefix: '',
- contents_bak: '',
- options: {
- browse_button_hover: 'ui-state-hover',
- browse_button_active: 'ui-state-active',
- filters: {},
- // widget specific
- buttons: {
- browse: true,
- start: true,
- stop: true
- },
- views: {
- list: true,
- thumbs: false,
- active: 'list',
- remember: true // requires: https://github.com/carhartl/jquery-cookie, otherwise disabled even if set to true
- },
- thumb_width: 100,
- thumb_height: 60,
- multiple_queues: true, // re-use widget by default
- dragdrop : true,
- autostart: false,
- sortable: false,
- rename: false
- },
- FILE_COUNT_ERROR: -9001,
- _create: function() {
- var id = this.element.attr('id');
- if (!id) {
- id = plupload.guid();
- this.element.attr('id', id);
- }
- this.id = id;
- // backup the elements initial state
- this.contents_bak = this.element.html();
- renderUI(this.element);
- // container, just in case
- this.container = $('.plupload_container', this.element).attr('id', id + '_container');
- this.content = $('.plupload_content', this.element);
- if ($.fn.resizable) {
- this.container.resizable({
- handles: 's',
- minHeight: 300
- });
- }
- // list of files, may become sortable
- this.filelist = $('.plupload_filelist_content', this.container)
- .attr({
- id: id + '_filelist',
- unselectable: 'on'
- });
- // buttons
- this.browse_button = $('.plupload_add', this.container).attr('id', id + '_browse');
- this.start_button = $('.plupload_start', this.container).attr('id', id + '_start');
- this.stop_button = $('.plupload_stop', this.container).attr('id', id + '_stop');
- this.thumbs_switcher = $('#' + id + '_view_thumbs');
- this.list_switcher = $('#' + id + '_view_list');
- if ($.ui.button) {
- this.browse_button.button({
- icons: { primary: 'ui-icon-circle-plus' },
- disabled: true
- });
- this.start_button.button({
- icons: { primary: 'ui-icon-circle-arrow-e' },
- disabled: true
- });
- this.stop_button.button({
- icons: { primary: 'ui-icon-circle-close' }
- });
- this.list_switcher.button({
- text: false,
- icons: { secondary: "ui-icon-grip-dotted-horizontal" }
- });
- this.thumbs_switcher.button({
- text: false,
- icons: { secondary: "ui-icon-image" }
- });
- }
- // progressbar
- this.progressbar = $('.plupload_progress_container', this.container);
- if ($.ui.progressbar) {
- this.progressbar.progressbar();
- }
- // counter
- this.counter = $('.plupload_count', this.element)
- .attr({
- id: id + '_count',
- name: id + '_count'
- });
- // initialize uploader instance
- this._initUploader();
- },
- _initUploader: function() {
- var self = this
- , id = this.id
- , uploader
- , options = {
- container: id + '_buttons',
- browse_button: id + '_browse'
- }
- ;
- $('.plupload_buttons', this.element).attr('id', id + '_buttons');
- if (self.options.dragdrop) {
- this.filelist.parent().attr('id', this.id + '_dropbox');
- options.drop_element = this.id + '_dropbox';
- }
- this.filelist.on('click', function(e) {
- var me = $(e.target), fileContainer;
- if (me.hasClass('plupload_action_icon')) {
- fileContainer = me.closest('.plupload_file');
- if (fileContainer.hasClass('plupload_delete')) {
- self.removeFile(fileContainer.attr('id'));
- e.preventDefault();
- }
- }
- });
- uploader = this.uploader = uploaders[id] = new plupload.Uploader($.extend(this.options, options));
- // retrieve full normalized set of options
- this.options = uploader.getOption();
- if (self.options.views.thumbs) {
- uploader.settings.required_features.display_media = true;
- }
- // for backward compatibility
- if (self.options.max_file_count) {
- plupload.extend(uploader.getOption('filters'), {
- max_file_count: self.options.max_file_count
- });
- }
- plupload.addFileFilter('max_file_count', function(maxCount, file, cb) {
- if (maxCount <= this.files.length - (this.total.uploaded + this.total.failed)) {
- self.browse_button.button('disable');
- this.disableBrowse();
- this.trigger('Error', {
- code : self.FILE_COUNT_ERROR,
- message : _("File count error."),
- file : file
- });
- cb(false);
- } else {
- cb(true);
- }
- });
- uploader.bind('Error', function(up, err) {
- var message, details = "";
- message = '<strong>' + err.message + '</strong>';
- switch (err.code) {
- case plupload.FILE_EXTENSION_ERROR:
- details = plupload.sprintf(_("File: %s"), err.file.name);
- break;
- case plupload.FILE_SIZE_ERROR:
- details = plupload.sprintf(_("File: %s, size: %d, max file size: %d"), err.file.name, plupload.formatSize(err.file.size), plupload.formatSize(plupload.parseSize(up.getOption('filters').max_file_size)));
- break;
- case plupload.FILE_DUPLICATE_ERROR:
- details = plupload.sprintf(_("%s already present in the queue."), err.file.name);
- break;
- case self.FILE_COUNT_ERROR:
- details = plupload.sprintf(_("Upload element accepts only %d file(s) at a time. Extra files were stripped."), up.getOption('filters').max_file_count || 0);
- break;
- case plupload.IMAGE_FORMAT_ERROR :
- details = _("Image format either wrong or not supported.");
- break;
- case plupload.IMAGE_MEMORY_ERROR :
- details = _("Runtime ran out of available memory.");
- break;
- /* // This needs a review
- case plupload.IMAGE_DIMENSIONS_ERROR :
- details = plupload.sprintf(_('Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.'), up.runtime, up.features.maxWidth, up.features.maxHeight);
- break; */
- case plupload.HTTP_ERROR:
- details = _("Upload URL might be wrong or doesn't exist.");
- break;
- }
- message += " <br /><i>" + details + "</i>";
- self._trigger('error', null, { up: up, error: err } );
- // do not show UI if no runtime can be initialized
- if (err.code === plupload.INIT_ERROR) {
- setTimeout(function() {
- self.destroy();
- }, 1);
- } else {
- self.notify('error', message);
- }
- });
- uploader.bind('PostInit', function(up) {
- // all buttons are optional, so they can be disabled and hidden
- if (!self.options.buttons.browse) {
- self.browse_button.button('disable').hide();
- up.disableBrowse(true);
- } else {
- self.browse_button.button('enable');
- }
- if (!self.options.buttons.start) {
- self.start_button.button('disable').hide();
- }
- if (!self.options.buttons.stop) {
- self.stop_button.button('disable').hide();
- }
- if (!self.options.unique_names && self.options.rename) {
- self._enableRenaming();
- }
- if (self.options.dragdrop && up.features.dragdrop) {
- self.filelist.parent().addClass('plupload_dropbox');
- }
- self._enableViewSwitcher();
- self.start_button.click(function(e) {
- if (!$(this).button('option', 'disabled')) {
- self.start();
- }
- e.preventDefault();
- });
- self.stop_button.click(function(e) {
- self.stop();
- e.preventDefault();
- });
- self._trigger('ready', null, { up: up });
- });
- // uploader internal events must run first
- uploader.init();
- uploader.bind('FileFiltered', function(up, file) {
- self._addFiles(file);
- });
- uploader.bind('FilesAdded', function(up, files) {
- self._trigger('selected', null, { up: up, files: files } );
- // re-enable sortable
- if (self.options.sortable && $.ui.sortable) {
- self._enableSortingList();
- }
- self._trigger('updatelist', null, { filelist: self.filelist });
- if (self.options.autostart) {
- // set a little delay to make sure that QueueChanged triggered by the core has time to complete
- setTimeout(function() {
- self.start();
- }, 10);
- }
- });
- uploader.bind('FilesRemoved', function(up, files) {
- // destroy sortable if enabled
- if ($.ui.sortable && self.options.sortable) {
- $('tbody', self.filelist).sortable('destroy');
- }
- $.each(files, function(i, file) {
- $('#' + file.id).toggle("highlight", function() {
- $(this).remove();
- });
- });
- if (up.files.length) {
- // re-initialize sortable
- if (self.options.sortable && $.ui.sortable) {
- self._enableSortingList();
- }
- }
- self._trigger('updatelist', null, { filelist: self.filelist });
- self._trigger('removed', null, { up: up, files: files } );
- });
- uploader.bind('QueueChanged', function() {
- self._handleState();
- });
- uploader.bind('StateChanged', function(up) {
- self._handleState();
- if (plupload.STARTED === up.state) {
- self._trigger('started', null, { up: this.uploader });
- } else if (plupload.STOPPED === up.state) {
- self._trigger('stopped', null, { up: this.uploader });
- }
- });
- uploader.bind('UploadFile', function(up, file) {
- self._handleFileStatus(file);
- });
- uploader.bind('FileUploaded', function(up, file, result) {
- self._handleFileStatus(file);
- self._trigger('uploaded', null, { up: up, file: file, result: result } );
- });
- uploader.bind('UploadProgress', function(up, file) {
- self._handleFileStatus(file);
- self._updateTotalProgress();
- self._trigger('progress', null, { up: up, file: file } );
- });
- uploader.bind('UploadComplete', function(up, files) {
- self._addFormFields();
- self._trigger('complete', null, { up: up, files: files } );
- });
- },
- _setOption: function(key, value) {
- var self = this;
- if (key == 'buttons' && typeof(value) == 'object') {
- value = $.extend(self.options.buttons, value);
- if (!value.browse) {
- self.browse_button.button('disable').hide();
- self.uploader.disableBrowse(true);
- } else {
- self.browse_button.button('enable').show();
- self.uploader.disableBrowse(false);
- }
- if (!value.start) {
- self.start_button.button('disable').hide();
- } else {
- self.start_button.button('enable').show();
- }
- if (!value.stop) {
- self.stop_button.button('disable').hide();
- } else {
- self.start_button.button('enable').show();
- }
- }
- self.uploader.setOption(key, value);
- },
- /**
- Start upload. Triggers `start` event.
- @method start
- */
- start: function() {
- this.uploader.start();
- },
- /**
- Stop upload. Triggers `stop` event.
- @method stop
- */
- stop: function() {
- this.uploader.stop();
- },
- /**
- Enable browse button.
- @method enable
- */
- enable: function() {
- this.browse_button.button('enable');
- this.uploader.disableBrowse(false);
- },
- /**
- Disable browse button.
- @method disable
- */
- disable: function() {
- this.browse_button.button('disable');
- this.uploader.disableBrowse(true);
- },
- /**
- Retrieve file by its unique id.
- @method getFile
- @param {String} id Unique id of the file
- @return {plupload.File}
- */
- getFile: function(id) {
- var file;
- if (typeof id === 'number') {
- file = this.uploader.files[id];
- } else {
- file = this.uploader.getFile(id);
- }
- return file;
- },
- /**
- Return array of files currently in the queue.
- @method getFiles
- @return {Array} Array of files in the queue represented by plupload.File objects
- */
- getFiles: function() {
- return this.uploader.files;
- },
- /**
- Remove the file from the queue.
- @method removeFile
- @param {plupload.File|String} file File to remove, might be specified directly or by its unique id
- */
- removeFile: function(file) {
- if (plupload.typeOf(file) === 'string') {
- file = this.getFile(file);
- }
- this.uploader.removeFile(file);
- },
- /**
- Clear the file queue.
- @method clearQueue
- */
- clearQueue: function() {
- this.uploader.splice();
- },
- /**
- Retrieve internal plupload.Uploader object (usually not required).
- @method getUploader
- @return {plupload.Uploader}
- */
- getUploader: function() {
- return this.uploader;
- },
- /**
- Trigger refresh procedure, specifically browse_button re-measure and re-position operations.
- Might get handy, when UI Widget is placed within the popup, that is constantly hidden and shown
- again - without calling this method after each show operation, dialog trigger might get displaced
- and disfunctional.
- @method refresh
- */
- refresh: function() {
- this.uploader.refresh();
- },
- /**
- Display a message in notification area.
- @method notify
- @param {Enum} type Type of the message, either `error` or `info`
- @param {String} message The text message to display.
- */
- notify: function(type, message) {
- var popup = $(
- '<div class="plupload_message">' +
- '<span class="plupload_message_close ui-icon ui-icon-circle-close" title="'+_('Close')+'"></span>' +
- '<p><span class="ui-icon"></span>' + message + '</p>' +
- '</div>'
- );
- popup
- .addClass('ui-state-' + (type === 'error' ? 'error' : 'highlight'))
- .find('p .ui-icon')
- .addClass('ui-icon-' + (type === 'error' ? 'alert' : 'info'))
- .end()
- .find('.plupload_message_close')
- .click(function() {
- popup.remove();
- })
- .end();
- $('.plupload_header', this.container).append(popup);
- },
- /**
- Destroy the widget, the uploader, free associated resources and bring back original html.
- @method destroy
- */
- destroy: function() {
- // destroy uploader instance
- this.uploader.destroy();
- // unbind all button events
- $('.plupload_button', this.element).unbind();
- // destroy buttons
- if ($.ui.button) {
- $('.plupload_add, .plupload_start, .plupload_stop', this.container)
- .button('destroy');
- }
- // destroy progressbar
- if ($.ui.progressbar) {
- this.progressbar.progressbar('destroy');
- }
- // destroy sortable behavior
- if ($.ui.sortable && this.options.sortable) {
- $('tbody', this.filelist).sortable('destroy');
- }
- // restore the elements initial state
- this.element
- .empty()
- .html(this.contents_bak);
- this.contents_bak = '';
- $.Widget.prototype.destroy.apply(this);
- },
- _handleState: function() {
- var up = this.uploader
- , filesPending = up.files.length - (up.total.uploaded + up.total.failed)
- , maxCount = up.getOption('filters').max_file_count || 0
- ;
- if (plupload.STARTED === up.state) {
- $([])
- .add(this.stop_button)
- .add('.plupload_started')
- .removeClass('plupload_hidden');
- this.start_button.button('disable');
- if (!this.options.multiple_queues) {
- this.browse_button.button('disable');
- up.disableBrowse();
- }
- $('.plupload_upload_status', this.element).html(plupload.sprintf(_('Uploaded %d/%d files'), up.total.uploaded, up.files.length));
- $('.plupload_header_content', this.element).addClass('plupload_header_content_bw');
- }
- else if (plupload.STOPPED === up.state) {
- $([])
- .add(this.stop_button)
- .add('.plupload_started')
- .addClass('plupload_hidden');
- if (filesPending) {
- this.start_button.button('enable');
- } else {
- this.start_button.button('disable');
- }
- if (this.options.multiple_queues) {
- $('.plupload_header_content', this.element).removeClass('plupload_header_content_bw');
- }
- // if max_file_count defined, only that many files can be queued at once
- if (this.options.multiple_queues && maxCount && maxCount > filesPending) {
- this.browse_button.button('enable');
- up.disableBrowse(false);
- }
- this._updateTotalProgress();
- }
- if (up.total.queued === 0) {
- $('.ui-button-text', this.browse_button).html(_('Add Files'));
- } else {
- $('.ui-button-text', this.browse_button).html(plupload.sprintf(_('%d files queued'), up.total.queued));
- }
- // have a helper class on a container expressing whether it has files queued or not
- this.container.toggleClass('plupload_files_queued', up.files.length);
- up.refresh();
- },
- _handleFileStatus: function(file) {
- var $file = $('#' + file.id), actionClass, iconClass;
- // since this method might be called asynchronously, file row might not yet be rendered
- if (!$file.length) {
- return;
- }
- switch (file.status) {
- case plupload.DONE:
- actionClass = 'plupload_done';
- iconClass = 'plupload_action_icon ui-icon ui-icon-circle-check';
- break;
- case plupload.FAILED:
- actionClass = 'ui-state-error plupload_failed';
- iconClass = 'plupload_action_icon ui-icon ui-icon-alert';
- break;
- case plupload.QUEUED:
- actionClass = 'plupload_delete';
- iconClass = 'plupload_action_icon ui-icon ui-icon-circle-minus';
- break;
- case plupload.UPLOADING:
- actionClass = 'ui-state-highlight plupload_uploading';
- iconClass = 'plupload_action_icon ui-icon ui-icon-circle-arrow-w';
- // scroll uploading file into the view if its bottom boundary is out of it
- var scroller = $('.plupload_scroll', this.container)
- , scrollTop = scroller.scrollTop()
- , scrollerHeight = scroller.height()
- , rowOffset = $file.position().top + $file.height()
- ;
- if (scrollerHeight < rowOffset) {
- scroller.scrollTop(scrollTop + rowOffset - scrollerHeight);
- }
- // Set file specific progress
- $file
- .find('.plupload_file_percent')
- .html(file.percent + '%')
- .end()
- .find('.plupload_file_progress')
- .css('width', file.percent + '%')
- .end()
- .find('.plupload_file_size')
- .html(plupload.formatSize(file.size));
- break;
- }
- actionClass += ' ui-state-default plupload_file';
- $file
- .attr('class', actionClass)
- .find('.plupload_action_icon')
- .attr('class', iconClass);
- },
- _updateTotalProgress: function() {
- var up = this.uploader;
- // Scroll to end of file list
- this.filelist[0].scrollTop = this.filelist[0].scrollHeight;
- this.progressbar.progressbar('value', up.total.percent);
- this.element
- .find('.plupload_total_status')
- .html(up.total.percent + '%')
- .end()
- .find('.plupload_total_file_size')
- .html(plupload.formatSize(up.total.size))
- .end()
- .find('.plupload_upload_status')
- .html(plupload.sprintf(_('Uploaded %d/%d files'), up.total.uploaded, up.files.length));
- },
- _displayThumbs: function() {
- var self = this
- , tw, th // thumb width/height
- , cols
- , num = 0 // number of simultaneously visible thumbs
- , thumbs = [] // array of thumbs to preload at any given moment
- , loading = false
- ;
- if (!this.options.views.thumbs) {
- return;
- }
- function onLast(el, eventName, cb) {
- var timer;
- el.on(eventName, function() {
- clearTimeout(timer);
- timer = setTimeout(function() {
- clearTimeout(timer);
- cb();
- }, 300);
- });
- }
- // calculate number of simultaneously visible thumbs
- function measure() {
- if (!tw || !th) {
- var wrapper = $('.plupload_file:eq(0)', self.filelist);
- tw = wrapper.outerWidth(true);
- th = wrapper.outerHeight(true);
- }
- var aw = self.content.width(), ah = self.content.height();
- cols = Math.floor(aw / tw);
- num = cols * (Math.ceil(ah / th) + 1);
- }
- function pickThumbsToLoad() {
- // calculate index of virst visible thumb
- var startIdx = Math.floor(self.content.scrollTop() / th) * cols;
- // get potentially visible thumbs that are not yet visible
- thumbs = $('.plupload_file .plupload_file_thumb', self.filelist)
- .slice(startIdx, startIdx + num)
- .filter('.plupload_thumb_toload')
- .get();
- }
- function init() {
- function mpl() { // measure, pick, load
- if (self.view_mode !== 'thumbs') {
- return;
- }
- measure();
- pickThumbsToLoad();
- lazyLoad();
- }
- if ($.fn.resizable) {
- onLast(self.container, 'resize', mpl);
- }
- onLast(self.window, 'resize', mpl);
- onLast(self.content, 'scroll', mpl);
- self.element.on('viewchanged selected', mpl);
- mpl();
- }
- function preloadThumb(file, cb) {
- var img = new o.image.Image();
- var resolveUrl = o.core.utils.Url.resolveUrl;
- img.onload = function() {
- var thumb = $('#' + file.id + ' .plupload_file_thumb', self.filelist);
- this.embed(thumb[0], {
- width: self.options.thumb_width,
- height: self.options.thumb_height,
- crop: true,
- fit: true,
- preserveHeaders: false,
- swf_url: resolveUrl(self.options.flash_swf_url),
- xap_url: resolveUrl(self.options.silverlight_xap_url)
- });
- };
- img.bind("embedded error", function(e) {
- $('#' + file.id, self.filelist)
- .find('.plupload_file_thumb')
- .removeClass('plupload_thumb_loading')
- .addClass('plupload_thumb_' + e.type)
- ;
- this.destroy();
- setTimeout(cb, 1); // detach, otherwise ui might hang (in SilverLight for example)
- });
- $('#' + file.id, self.filelist)
- .find('.plupload_file_thumb')
- .removeClass('plupload_thumb_toload')
- .addClass('plupload_thumb_loading')
- ;
- img.load(file.getSource());
- }
- function lazyLoad() {
- if (self.view_mode !== 'thumbs' || loading) {
- return;
- }
- pickThumbsToLoad();
- if (!thumbs.length) {
- return;
- }
- loading = true;
- preloadThumb(self.getFile($(thumbs.shift()).closest('.plupload_file').attr('id')), function() {
- loading = false;
- lazyLoad();
- });
- }
- // this has to run only once to measure structures and bind listeners
- this.element.on('selected', function onselected() {
- self.element.off('selected', onselected);
- init();
- });
- },
- _addFiles: function(files) {
- var self = this, file_html, html = '';
- file_html = '<li class="plupload_file ui-state-default plupload_delete" id="{id}" style="width:{thumb_width}px;">' +
- '<div class="plupload_file_thumb plupload_thumb_toload" style="width: {thumb_width}px; height: {thumb_height}px;">' +
- '<div class="plupload_file_dummy ui-widget-content" style="line-height: {thumb_height}px;"><span class="ui-state-disabled">{ext} </span></div>' +
- '</div>' +
- '<div class="plupload_file_status">' +
- '<div class="plupload_file_progress ui-widget-header" style="width: 0%"> </div>' +
- '<span class="plupload_file_percent">{percent} </span>' +
- '</div>' +
- '<div class="plupload_file_name" title="{name}">' +
- '<span class="plupload_file_name_wrapper">{name} </span>' +
- '</div>' +
- '<div class="plupload_file_action">' +
- '<div class="plupload_action_icon ui-icon ui-icon-circle-minus"> </div>' +
- '</div>' +
- '<div class="plupload_file_size">{size} </div>' +
- '<div class="plupload_file_fields"> </div>' +
- '</li>';
- if (plupload.typeOf(files) !== 'array') {
- files = [files];
- }
- $.each(files, function(i, file) {
- var ext = o.core.utils.Mime.getFileExtension(file.name) || 'none';
- html += file_html.replace(/\{(\w+)\}/g, function($0, $1) {
- switch ($1) {
- case 'thumb_width':
- case 'thumb_height':
- return self.options[$1];
- case 'size':
- return plupload.formatSize(file.size);
- case 'ext':
- return ext;
- default:
- return file[$1] || '';
- }
- });
- });
- self.filelist.append(html);
- },
- _addFormFields: function() {
- var self = this;
- // re-add from fresh
- $('.plupload_file_fields', this.filelist).html('');
- plupload.each(this.uploader.files, function(file, count) {
- var fields = ''
- , id = self.id + '_' + count
- ;
- if (file.target_name) {
- fields += '<input type="hidden" name="' + id + '_tmpname" value="'+plupload.xmlEncode(file.target_name)+'" />';
- }
- fields += '<input type="hidden" name="' + id + '_name" value="'+plupload.xmlEncode(file.name)+'" />';
- fields += '<input type="hidden" name="' + id + '_status" value="' + (file.status === plupload.DONE ? 'done' : 'failed') + '" />';
- $('#' + file.id).find('.plupload_file_fields').html(fields);
- });
- this.counter.val(this.uploader.files.length);
- },
- _viewChanged: function(view) {
- // update or write a new cookie
- if (this.options.views.remember && $.cookie) {
- $.cookie('plupload_ui_view', view, { expires: 7, path: '/' });
- }
- // ugly fix for IE6 - make content area stretchable
- if (plupload.ua.browser === 'IE' && plupload.ua.version < 7) {
- this.content.attr('style', 'height:expression(document.getElementById("' + this.id + '_container' + '").clientHeight - ' + (view === 'list' ? 132 : 102) + ')');
- }
- this.container.removeClass('plupload_view_list plupload_view_thumbs').addClass('plupload_view_' + view);
- this.view_mode = view;
- this._trigger('viewchanged', null, { view: view });
- },
- _enableViewSwitcher: function() {
- var self = this
- , view
- , switcher = $('.plupload_view_switch', this.container)
- , buttons
- , button
- ;
- plupload.each(['list', 'thumbs'], function(view) {
- if (!self.options.views[view]) {
- switcher.find('[for="' + self.id + '_view_' + view + '"], #'+ self.id +'_view_' + view).remove();
- }
- });
- // check if any visible left
- buttons = switcher.find('.plupload_button');
- if (buttons.length === 1) {
- switcher.hide();
- view = buttons.eq(0).data('view');
- this._viewChanged(view);
- } else if ($.ui.button && buttons.length > 1) {
- if (this.options.views.remember && $.cookie) {
- view = $.cookie('plupload_ui_view');
- }
- // if wierd case, bail out to default
- if (!~plupload.inArray(view, ['list', 'thumbs'])) {
- view = this.options.views.active;
- }
- switcher
- .show()
- .buttonset()
- .find('.ui-button')
- .click(function(e) {
- view = $(this).data('view');
- self._viewChanged(view);
- e.preventDefault(); // avoid auto scrolling to widget in IE and FF (see #850)
- });
- // if view not active - happens when switcher wasn't clicked manually
- button = switcher.find('[for="' + self.id + '_view_'+view+'"]');
- if (button.length) {
- button.trigger('click');
- }
- } else {
- switcher.show();
- this._viewChanged(this.options.views.active);
- }
- // initialize thumb viewer if requested
- if (this.options.views.thumbs) {
- this._displayThumbs();
- }
- },
- _enableRenaming: function() {
- var self = this;
- this.filelist.dblclick(function(e) {
- var nameInput, fileContainer, file, parts, name, ext = "";
- var nameSpan = $(e.target);
- if (!nameSpan.hasClass('plupload_file_name_wrapper')) {
- return;
- }
- fileContainer = nameSpan.closest('.plupload_file');
- if (!fileContainer.hasClass('plupload_delete')) {
- return;
- }
- // Get file name and split out name and extension
- file = self.uploader.getFile(fileContainer[0].id);
- name = file.name;
- parts = /^(.+)(\.[^.]+)$/.exec(name);
- if (parts) {
- name = parts[1];
- ext = parts[2];
- }
- // Display input element
- nameInput = $('<input class="plupload_file_rename" type="text" />').width(nameSpan.width()).insertAfter(nameSpan.hide());
- nameInput.val(name).blur(function() {
- nameSpan.show().parent().scrollLeft(0).end().next().remove();
- }).keydown(function(e) {
- var nameInput = $(this);
- if ($.inArray(e.keyCode, [13, 27]) !== -1) {
- e.preventDefault();
- // Rename file and glue extension back on
- if (e.keyCode === 13) {
- file.name = nameInput.val() + ext;
- nameSpan.html(file.name);
- }
- nameInput.blur();
- }
- })[0].focus();
- });
- },
- _enableSortingList: function() {
- var self = this;
- if ($('.plupload_file', this.filelist).length < 2) {
- return;
- }
- // destroy sortable if enabled
- $('tbody', this.filelist).sortable('destroy');
- // enable
- this.filelist.sortable({
- items: '.plupload_delete',
- cancel: 'object, .plupload_clearer',
- stop: function() {
- var files = [];
- $.each($(this).sortable('toArray'), function(i, id) {
- files[files.length] = self.uploader.getFile(id);
- });
- files.unshift(files.length);
- files.unshift(0);
- // re-populate files array
- Array.prototype.splice.apply(self.uploader.files, files);
- }
- });
- }
- });
- } (window, document, plupload, moxie, jQuery));
|