(function($) { $.widget('blueimpUIX.fileupload', $.blueimpUI.fileupload, { _initTemplates: function() { this.options.templateContainer = document.createElement( this._files.prop('nodeName') ); this.options.uploadTemplate = window.tmpl(this.options.uploadTemplateName); this.options.downloadTemplate = window.tmpl(this.options.downloadTemplateName); }, _enableFileInputButton: function() { $.blueimpUI.fileupload.prototype._enableFileInputButton.call(this); this.element.find('.ss-uploadfield-addfile').show(); }, _disableFileInputButton: function() { $.blueimpUI.fileupload.prototype._disableFileInputButton.call(this); this.element.find('.ss-uploadfield-addfile').hide(); }, _onAdd: function(e, data) { // use _onAdd instead of add since we only want it called once for a file set, not for each file var result = $.blueimpUI.fileupload.prototype._onAdd.call(this, e, data); var firstNewFile = this._files.find('.ss-uploadfield-item').slice(data.files.length*-1).first(); var top = '+=' + (firstNewFile.position().top - parseInt(firstNewFile.css('marginTop'), 10) || 0 - parseInt(firstNewFile.css('borderTopWidth'), 10) || 0); firstNewFile.offsetParent().animate({scrollTop: top}, 1000); /* Compute total size of files */ var fSize = 0; for(var i = 0; i < data.files.length; i++){ if(typeof data.files[i].size === 'number'){ fSize = fSize + data.files[i].size; } } $('.fileOverview .uploadStatus .details .total').text(data.files.length); if(typeof fSize === 'number' && fSize > 0){ fSize = this._formatFileSize(fSize); $('.fileOverview .uploadStatus .details .fileSize').text(fSize); } //Fixes case where someone uploads a single erroring file if(data.files.length == 1 && data.files[0].error !== null){ $('.fileOverview .uploadStatus .state').text(ss.i18n._t('AssetUploadField.UploadField.UPLOADFAIL', 'Sorry your upload failed')); $('.fileOverview .uploadStatus').addClass("bad").removeClass("good").removeClass("notice"); }else{ $('.fileOverview .uploadStatus .state').text(ss.i18n._t('AssetUploadField.UPLOADINPROGRESS', 'Please wait… upload in progress'));//.show(); $('.ss-uploadfield-item-edit-all').hide(); $('.fileOverview .uploadStatus').addClass("notice").removeClass("good").removeClass("bad"); } return result; }, _onDone: function (result, textStatus, jqXHR, options) { // Mark form as dirty on completion of successful upload if(this.options.changeDetection) { this.element.closest('form').trigger('dirty'); } $.blueimpUI.fileupload.prototype._onDone.call(this, result, textStatus, jqXHR, options); }, _onSend: function (e, data) { //check the array of existing files to see if we are trying to upload a file that already exists var that = this; var config = this.options; if (config.overwriteWarning && config.replaceFile) { $.get( config['urlFileExists'], {'filename': data.files[0].name}, function(response, status, xhr) { if(response.exists) { //display the dialogs with the question to overwrite or not data.context.find('.ss-uploadfield-item-status') .text(config.errorMessages.overwriteWarning) .addClass('ui-state-warning-text'); data.context.find('.ss-uploadfield-item-progress').hide(); data.context.find('.ss-uploadfield-item-overwrite').show(); data.context.find('.ss-uploadfield-item-overwrite-warning').on('click', function(e){ data.context.find('.ss-uploadfield-item-progress').show(); data.context.find('.ss-uploadfield-item-overwrite').hide(); data.context.find('.ss-uploadfield-item-status') .removeClass('ui-state-warning-text'); //upload only if the "overwrite" button is clicked $.blueimpUI.fileupload.prototype._onSend.call(that, e, data); e.preventDefault(); // Avoid a form submit return false; }); } else { //regular file upload return $.blueimpUI.fileupload.prototype._onSend.call(that, e, data); } } ); } else { return $.blueimpUI.fileupload.prototype._onSend.call(that, e, data); } }, _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { $.blueimpUI.fileupload.prototype._onAlways.call(this, jqXHRorResult, textStatus, jqXHRorError, options); if(typeof(jqXHRorError) === 'string') { $('.fileOverview .uploadStatus .state').text(ss.i18n._t('AssetUploadField.UploadField.UPLOADFAIL', 'Sorry your upload failed')); $('.fileOverview .uploadStatus').addClass("bad").removeClass("good").removeClass("notice"); } else if (jqXHRorError.status === 200) { $('.fileOverview .uploadStatus .state').text(ss.i18n._t('AssetUploadField.FILEUPLOADCOMPLETED', 'File upload completed!'));//.hide(); $('.ss-uploadfield-item-edit-all').show(); $('.fileOverview .uploadStatus').addClass("good").removeClass("notice").removeClass("bad"); } }, _create: function() { $.blueimpUI.fileupload.prototype._create.call(this); // Ensures that the visibility of the fileupload dialog is set correctly at initialisation this._adjustMaxNumberOfFiles(0); }, attach: function(data) { if(this.options.changeDetection) { this.element.closest('form').trigger('dirty'); } // Handles attachment of already uploaded files, similar to add var self = this, files = data.files, replaceFileID = data.replaceFileID, valid = true; // If replacing an element (and it exists), adjust max number of files at this point var replacedElement = null; if(replaceFileID) { replacedElement = $(".ss-uploadfield-item[data-fileid='"+replaceFileID+"']"); if(replacedElement.length === 0) { replacedElement = null; } else { self._adjustMaxNumberOfFiles(1); } } // Validate each file $.each(files, function (index, file) { self._adjustMaxNumberOfFiles(-1); error = self._validate([file]); valid = error && valid; }); data.isAdjusted = true; data.files.valid = data.isValidated = valid; // Generate new file HTMl, and either append or replace (if replacing // an already uploaded file). data.context = this._renderDownload(files); if(replacedElement) { replacedElement.replaceWith(data.context); } else { data.context.appendTo(this._files); } data.context.data('data', data); // Force reflow: this._reflow = this._transition && data.context[0].offsetWidth; data.context.addClass('in'); } }); $.entwine('ss', function($) { $('div.ss-upload').entwine({ Config: null, onmatch: function() { if (this.is('.readonly,.disabled')) { return; } var $fileInput = this.find('.ss-uploadfield-fromcomputer-fileinput'), $dropZone = $('.ss-uploadfield-dropzone'), config = $fileInput.data('config'); // Drag & drop is opt-in so we have to prevent the default behaviour // (which is 'do nothing') when the drop zone is dragged over. $dropZone.on('dragover', function (e) { e.preventDefault(); }); $dropZone.on('dragenter', function (e) { $dropZone.addClass('hover active'); }); $dropZone.on('dragleave', function (e) { if (e.target === $dropZone[0]) { $dropZone.removeClass('hover active'); } }); $dropZone.on('drop', function (e) { $dropZone.removeClass('hover active'); if (e.target !== $dropZone[0]) { return false; } }) this.setConfig(config); this.fileupload($.extend(true, { formData: function(form) { var idVal = $(form).find(':input[name=ID]').val(); var data = [{name: 'SecurityID', value: $(form).find(':input[name=SecurityID]').val()}]; if(idVal) data.push({name: 'ID', value: idVal}); return data; }, errorMessages: { // errorMessages for all error codes suggested from the plugin author, some will be overwritten by the config coming from php 1: ss.i18n._t('UploadField.PHP_MAXFILESIZE'), 2: ss.i18n._t('UploadField.HTML_MAXFILESIZE'), 3: ss.i18n._t('UploadField.ONLYPARTIALUPLOADED'), 4: ss.i18n._t('UploadField.NOFILEUPLOADED'), 5: ss.i18n._t('UploadField.NOTMPFOLDER'), 6: ss.i18n._t('UploadField.WRITEFAILED'), 7: ss.i18n._t('UploadField.STOPEDBYEXTENSION'), maxFileSize: ss.i18n._t('UploadField.TOOLARGESHORT'), minFileSize: ss.i18n._t('UploadField.TOOSMALL'), acceptFileTypes: ss.i18n._t('UploadField.INVALIDEXTENSIONSHORT'), maxNumberOfFiles: ss.i18n._t('UploadField.MAXNUMBEROFFILESSHORT'), uploadedBytes: ss.i18n._t('UploadField.UPLOADEDBYTES'), emptyResult: ss.i18n._t('UploadField.EMPTYRESULT') }, send: function(e, data) { if (data.context && data.dataType && data.dataType.substr(0, 6) === 'iframe') { // Iframe Transport does not support progress events. // In lack of an indeterminate progress bar, we set // the progress to 100%, showing the full animated bar: data.total = 1; data.loaded = 1; $(this).data('fileupload').options.progress(e, data); } }, progress: function(e, data) { if (data.context) { var value = parseInt(data.loaded / data.total * 100, 10) + '%'; data.context.find('.ss-uploadfield-item-status').html((data.total == 1)?ss.i18n._t('UploadField.LOADING'):value); data.context.find('.ss-uploadfield-item-progressbarvalue').css('width', value); } } }, config, { fileInput: $fileInput, dropZone: $dropZone, form: $fileInput.closest('form'), previewAsCanvas: false, acceptFileTypes: new RegExp(config.acceptFileTypes, 'i') } )); if (this.data('fileupload')._isXHRUpload({multipart: true})) { $('.ss-uploadfield-item-uploador').hide().show(); } this._super(); }, onunmatch: function() { $('.ss-uploadfield-dropzone').off('dragover dragenter dragleave drop'); this._super(); }, openSelectDialog: function(uploadedFile) { // Create dialog and load iframe var self = this, config = this.getConfig(), dialogId = 'ss-uploadfield-dialog-' + this.attr('id'), dialog = jQuery('#' + dialogId); if(!dialog.length) dialog = jQuery('
'); // If user selected 'Choose another file', we need the ID of the file to replace var iframeUrl = config['urlSelectDialog']; var uploadedFileId = null; if (uploadedFile && uploadedFile.attr('data-fileid') > 0){ uploadedFileId = uploadedFile.attr('data-fileid'); } // Show dialog dialog.ssdialog({iframeUrl: iframeUrl, height: 550}); // TODO Allow single-select dialog.find('iframe').bind('load', function(e) { var contents = $(this).contents(), gridField = contents.find('.ss-gridfield'); // TODO Fix jQuery custom event bubbling across iframes on same domain // gridField.find('.ss-gridfield-items')).bind('selectablestop', function() { // }); // Remove top margin (easier than including new selectors) contents.find('table.ss-gridfield').css('margin-top', 0); // Can't use live() in iframes... contents.find('input[name=action_doAttach]').unbind('click.openSelectDialog').bind('click.openSelectDialog', function() { // TODO Fix entwine method calls across iframe/document boundaries var ids = $.map(gridField.find('.ss-gridfield-item.ui-selected'), function(el) {return $(el).data('id');}); if(ids && ids.length) self.attachFiles(ids, uploadedFileId); dialog.ssdialog('close'); return false; }); }); dialog.ssdialog('open'); }, attachFiles: function(ids, uploadedFileId) { var self = this, config = this.getConfig(), indicator = $('
'), target = (uploadedFileId) ? this.find(".ss-uploadfield-item[data-fileid='"+uploadedFileId+"']") : this.find('.ss-uploadfield-addfile'); target.children().hide(); target.append(indicator); $.ajax({ type: "POST", url: config['urlAttach'], data: {'ids': ids}, complete: function(xhr, status) { target.children().show(); indicator.remove(); }, success: function(data, status, xhr) { if (!data || $.isEmptyObject(data)) return; self.fileupload('attach', { files: data, options: self.fileupload('option'), replaceFileID: uploadedFileId }); } }); } }); $('div.ss-upload *').entwine({ getUploadField: function() { return this.parents('div.ss-upload:first'); } }); $('div.ss-upload .ss-uploadfield-files .ss-uploadfield-item').entwine({ onadd: function() { this._super(); this.closest('.ss-upload').find('.ss-uploadfield-addfile').addClass('borderTop'); }, onremove: function() { $('.ss-uploadfield-files:not(:has(.ss-uploadfield-item))').closest('.ss-upload').find('.ss-uploadfield-addfile').removeClass('borderTop'); this._super(); } }); $('div.ss-upload .ss-uploadfield-startall').entwine({ onclick: function(e) { this.closest('.ss-upload').find('.ss-uploadfield-item-start button').click(); e.preventDefault(); // Avoid a form submit return false; } }); $('div.ss-upload .ss-uploadfield-item-cancelfailed').entwine({ onclick: function(e) { this.closest('.ss-uploadfield-item').remove(); e.preventDefault(); // Avoid a form submit return false; } }); $('div.ss-upload .ss-uploadfield-item-remove:not(.ui-state-disabled), .ss-uploadfield-item-delete:not(.ui-state-disabled)').entwine({ onclick: function(e) { var field = this.closest('div.ss-upload'), config = field.getConfig('changeDetection'), fileupload = field.data('fileupload'), item = this.closest('.ss-uploadfield-item'), msg = ''; if(this.is('.ss-uploadfield-item-delete')) { if(confirm(ss.i18n._t('UploadField.ConfirmDelete'))) { if(config.changeDetection) { this.closest('form').trigger('dirty'); } if (fileupload) { fileupload._trigger('destroy', e, { context: item, url: this.data('href'), type: 'get', dataType: fileupload.options.dataType }); } } } else { // Removed files will be applied to object on save if(config.changeDetection) { this.closest('form').trigger('dirty'); } if (fileupload) { fileupload._trigger('destroy', e, {context: item}); } } e.preventDefault(); // Avoid a form submit return false; } }); $('div.ss-upload .ss-uploadfield-item-edit-all').entwine({ onclick: function(e) { if($(this).hasClass('opened')){ $('.ss-uploadfield-item .ss-uploadfield-item-edit .toggle-details-icon.opened').each(function(i){ $(this).closest('.ss-uploadfield-item-edit').click(); }); $(this).removeClass('opened').find('.toggle-details-icon').removeClass('opened'); }else{ $('.ss-uploadfield-item .ss-uploadfield-item-edit .toggle-details-icon').each(function(i){ if(!$(this).hasClass('opened')){ $(this).closest('.ss-uploadfield-item-edit').click(); } }); $(this).addClass('opened').find('.toggle-details-icon').addClass('opened'); } e.preventDefault(); // Avoid a form submit return false; } }); $( 'div.ss-upload:not(.disabled):not(.readonly) .ss-uploadfield-item-edit').entwine({ onclick: function(e) { var self = this, editform = self.closest('.ss-uploadfield-item').find('.ss-uploadfield-item-editform'), itemInfo = editform.prev('.ss-uploadfield-item-info'), iframe = editform.find('iframe'); // Ignore clicks while the iframe is loading if (iframe.parent().hasClass('loading')) { e.preventDefault(); return false; } if (iframe.attr('src') == 'about:blank') { // Lazy-load the iframe on editform toggle iframe.attr('src', iframe.data('src')); // Add loading class, disable buttons while loading is in progress // (_prepareIframe() handles re-enabling them when appropriate) iframe.parent().addClass('loading'); disabled=this.siblings(); disabled.addClass('ui-state-disabled'); disabled.attr('disabled', 'disabled'); iframe.on('load', function() { iframe.parent().removeClass('loading'); // This ensures we only call _prepareIframe() on load once - otherwise it'll // be superfluously called after clicking 'save' in the editform if (iframe.data('src')) { self._prepareIframe(iframe, editform, itemInfo); iframe.data('src', ''); } }); } else { self._prepareIframe(iframe, editform, itemInfo); } e.preventDefault(); // Avoid a form submit return false; }, _prepareIframe: function(iframe, editform, itemInfo) { var disabled; // Mark the row as changed if any of its form fields are edited iframe.contents().ready(function() { // Need to use the iframe's own jQuery, as custom event triggers // (e.g. from TreeDropdownField) can't be captured by the parent jQuery object. var iframe_jQuery = iframe.get(0).contentWindow.jQuery; iframe_jQuery(iframe_jQuery.find(':input')).bind('change', function(e){ editform.removeClass('edited'); editform.addClass('edited'); }); }); if (editform.hasClass('loading')) { // TODO Display loading indication, and register an event to toggle edit form } else { if(this.hasClass('ss-uploadfield-item-edit')){ disabled=this.siblings(); }else{ disabled=this.find('ss-uploadfield-item-edit').siblings(); } editform.parent('.ss-uploadfield-item').removeClass('ui-state-warning'); editform.toggleEditForm(); if (itemInfo.find('.toggle-details-icon').hasClass('opened')) { disabled.addClass('ui-state-disabled'); disabled.attr('disabled', 'disabled'); } else { disabled.removeClass('ui-state-disabled'); disabled.removeAttr('disabled'); } } } }); $('div.ss-upload .ss-uploadfield-item-editform').entwine({ fitHeight: function() { var iframe = this.find('iframe'), contents = iframe.contents().find('body'), bodyH = contents.find('form').outerHeight(true), // We set the height to match the form's outer height iframeH = bodyH + (iframe.outerHeight(true) - iframe.height()), // content's height + padding on iframe elem containerH = iframeH + (this.outerHeight(true) - this.height()); // iframe height + padding on container elem /* Set height of body except in IE8. Setting this in IE8 breaks the dropdown */ if( ! $.browser.msie && $.browser.version.slice(0,3) != "8.0"){ contents.find('body').css({'height': bodyH}); } iframe.height(iframeH); this.animate({height: containerH}, 500); }, toggleEditForm: function() { var itemInfo = this.prev('.ss-uploadfield-item-info'), status = itemInfo.find('.ss-uploadfield-item-status'); var iframe = this.find('iframe').contents(), saved = iframe.find('#Form_EditForm_error'); var text = ""; if(this.height() === 0) { text = ss.i18n._t('UploadField.Editing', "Editing ..."); this.fitHeight(); this.addClass('opened'); itemInfo.find('.toggle-details-icon').addClass('opened'); status.removeClass('ui-state-success-text').removeClass('ui-state-warning-text'); iframe.find('#Form_EditForm_action_doEdit').click(function(){ itemInfo.find('label .name').text(iframe.find('#Name input').val()); }); if($('div.ss-upload .ss-uploadfield-files .ss-uploadfield-item-actions .toggle-details-icon:not(.opened)').index() < 0){ $('div.ss-upload .ss-uploadfield-item-edit-all').addClass('opened').find('.toggle-details-icon').addClass('opened'); } } else { this.animate({height: 0}, 500); this.removeClass('opened'); itemInfo.find('.toggle-details-icon').removeClass('opened'); $('div.ss-upload .ss-uploadfield-item-edit-all').removeClass('opened').find('.toggle-details-icon').removeClass('opened'); if(!this.hasClass('edited')){ text = ss.i18n._t('UploadField.NOCHANGES', 'No Changes'); status.addClass('ui-state-success-text'); }else{ if(saved.hasClass('good')){ text = ss.i18n._t('UploadField.CHANGESSAVED', 'Changes Saved'); this.removeClass('edited').parent('.ss-uploadfield-item').removeClass('ui-state-warning'); status.addClass('ui-state-success-text'); }else{ text = ss.i18n._t('UploadField.UNSAVEDCHANGES', 'Unsaved Changes'); this.parent('.ss-uploadfield-item').addClass('ui-state-warning'); status.addClass('ui-state-warning-text'); } } saved.removeClass('good').hide(); } status.attr('title',text).text(text); } }); $('div.ss-upload .ss-uploadfield-fromfiles').entwine({ onclick: function(e) { this.getUploadField().openSelectDialog(this.closest('.ss-uploadfield-item')); e.preventDefault(); // Avoid a form submit return false; } }); }); }(jQuery));