123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /* Redmine - project management software
- Copyright (C) 2006-2020 Jean-Philippe Lang */
-
- function addFile(inputEl, file, eagerUpload) {
- var attachmentsFields = $(inputEl).closest('.attachments_form').find('.attachments_fields');
- var addAttachment = $(inputEl).closest('.attachments_form').find('.add_attachment');
- var maxFiles = ($(inputEl).attr('multiple') == 'multiple' ? 10 : 1);
-
- if (attachmentsFields.children().length < maxFiles) {
- var attachmentId = addFile.nextAttachmentId++;
- var fileSpan = $('<span>', { id: 'attachments_' + attachmentId });
- var param = $(inputEl).data('param');
- if (!param) {param = 'attachments'};
-
- fileSpan.append(
- $('<input>', { type: 'text', 'class': 'icon icon-attachment filename readonly', name: param +'[' + attachmentId + '][filename]', readonly: 'readonly'} ).val(file.name),
- $('<input>', { type: 'text', 'class': 'description', name: param + '[' + attachmentId + '][description]', maxlength: 255, placeholder: $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload),
- $('<input>', { type: 'hidden', 'class': 'token', name: param + '[' + attachmentId + '][token]'} ),
- $('<a> </a>').attr({ href: "#", 'class': 'icon-only icon-del remove-upload' }).click(removeFile).toggle(!eagerUpload)
- ).appendTo(attachmentsFields);
-
- if ($(inputEl).data('description') == 0) {
- fileSpan.find('input.description').remove();
- }
-
- if(eagerUpload) {
- ajaxUpload(file, attachmentId, fileSpan, inputEl);
- }
-
- addAttachment.toggle(attachmentsFields.children().length < maxFiles);
- return attachmentId;
- } else {
- alert($('input.file_selector').data('max-number-of-files-message'));
- }
- return null;
- }
-
- addFile.nextAttachmentId = 1;
-
- function ajaxUpload(file, attachmentId, fileSpan, inputEl) {
-
- function onLoadstart(e) {
- fileSpan.removeClass('ajax-waiting');
- fileSpan.addClass('ajax-loading');
- $('input:submit', $(this).parents('form')).attr('disabled', 'disabled');
- }
-
- function onProgress(e) {
- if(e.lengthComputable) {
- this.progressbar( 'value', e.loaded * 100 / e.total );
- }
- }
-
- function actualUpload(file, attachmentId, fileSpan, inputEl) {
-
- ajaxUpload.uploading++;
-
- uploadBlob(file, $(inputEl).data('upload-path'), attachmentId, {
- loadstartEventHandler: onLoadstart.bind(progressSpan),
- progressEventHandler: onProgress.bind(progressSpan)
- })
- .done(function(result) {
- addInlineAttachmentMarkup(file);
- progressSpan.progressbar( 'value', 100 ).remove();
- fileSpan.find('input.description, a').css('display', 'inline-block');
- })
- .fail(function(result) {
- progressSpan.text(result.statusText);
- }).always(function() {
- ajaxUpload.uploading--;
- fileSpan.removeClass('ajax-loading');
- var form = fileSpan.parents('form');
- if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) {
- $('input:submit', form).removeAttr('disabled');
- }
- form.dequeue('upload');
- });
- }
-
- var progressSpan = $('<div>').insertAfter(fileSpan.find('input.filename'));
- progressSpan.progressbar();
- fileSpan.addClass('ajax-waiting');
-
- var maxSyncUpload = $(inputEl).data('max-concurrent-uploads');
-
- if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload)
- actualUpload(file, attachmentId, fileSpan, inputEl);
- else
- $(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl));
- }
-
- ajaxUpload.uploading = 0;
-
- function removeFile() {
- $(this).closest('.attachments_form').find('.add_attachment').show();
- $(this).parent('span').remove();
- return false;
- }
-
- function uploadBlob(blob, uploadUrl, attachmentId, options) {
-
- var actualOptions = $.extend({
- loadstartEventHandler: $.noop,
- progressEventHandler: $.noop
- }, options);
-
- uploadUrl = uploadUrl + '?attachment_id=' + attachmentId;
- if (blob instanceof window.Blob) {
- uploadUrl += '&filename=' + encodeURIComponent(blob.name);
- uploadUrl += '&content_type=' + encodeURIComponent(blob.type);
- }
-
- return $.ajax(uploadUrl, {
- type: 'POST',
- contentType: 'application/octet-stream',
- beforeSend: function(jqXhr, settings) {
- jqXhr.setRequestHeader('Accept', 'application/js');
- // attach proper File object
- settings.data = blob;
- },
- xhr: function() {
- var xhr = $.ajaxSettings.xhr();
- xhr.upload.onloadstart = actualOptions.loadstartEventHandler;
- xhr.upload.onprogress = actualOptions.progressEventHandler;
- return xhr;
- },
- data: blob,
- cache: false,
- processData: false
- });
- }
-
- function addInputFiles(inputEl) {
- var attachmentsFields = $(inputEl).closest('.attachments_form').find('.attachments_fields');
- var addAttachment = $(inputEl).closest('.attachments_form').find('.add_attachment');
- var clearedFileInput = $(inputEl).clone().val('');
- var sizeExceeded = false;
- var param = $(inputEl).data('param');
- if (!param) {param = 'attachments'};
-
- if ($.ajaxSettings.xhr().upload && inputEl.files) {
- // upload files using ajax
- sizeExceeded = uploadAndAttachFiles(inputEl.files, inputEl);
- $(inputEl).remove();
- } else {
- // browser not supporting the file API, upload on form submission
- var attachmentId;
- var aFilename = inputEl.value.split(/\/|\\/);
- attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false);
- if (attachmentId) {
- $(inputEl).attr({ name: param + '[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId);
- }
- }
-
- clearedFileInput.prependTo(addAttachment);
- }
-
- function uploadAndAttachFiles(files, inputEl) {
-
- var maxFileSize = $(inputEl).data('max-file-size');
- var maxFileSizeExceeded = $(inputEl).data('max-file-size-message');
-
- var sizeExceeded = false;
- $.each(files, function() {
- if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;}
- });
- if (sizeExceeded) {
- window.alert(maxFileSizeExceeded);
- } else {
- $.each(files, function() {addFile(inputEl, this, true);});
- }
- return sizeExceeded;
- }
-
- function handleFileDropEvent(e) {
-
- $(this).removeClass('fileover');
- blockEventPropagation(e);
-
- if ($.inArray('Files', e.dataTransfer.types) > -1) {
- handleFileDropEvent.target = e.target;
- uploadAndAttachFiles(e.dataTransfer.files, $('input:file.filedrop').first());
- }
- }
- handleFileDropEvent.target = '';
-
- function dragOverHandler(e) {
- $(this).addClass('fileover');
- blockEventPropagation(e);
- e.dataTransfer.dropEffect = 'copy';
- }
-
- function dragOutHandler(e) {
- $(this).removeClass('fileover');
- blockEventPropagation(e);
- }
-
- function setupFileDrop() {
- if (window.File && window.FileList && window.ProgressEvent && window.FormData) {
-
- $.event.addProp('dataTransfer');
-
- $('form div.box:not(.filedroplistner)').has('input:file.filedrop').each(function() {
- $(this).on({
- dragover: dragOverHandler,
- dragleave: dragOutHandler,
- drop: handleFileDropEvent,
- paste: copyImageFromClipboard
- }).addClass('filedroplistner');
- });
- }
- }
-
- function addInlineAttachmentMarkup(file) {
- // insert uploaded image inline if dropped area is currently focused textarea
- if($(handleFileDropEvent.target).hasClass('wiki-edit') && $.inArray(file.type, window.wikiImageMimeTypes) > -1) {
- var $textarea = $(handleFileDropEvent.target);
- var cursorPosition = $textarea.prop('selectionStart');
- var description = $textarea.val();
- var sanitizedFilename = file.name.replace(/[\/\?\%\*\:\|\"\'<>\n\r]+/, '_');
- var inlineFilename = encodeURIComponent(sanitizedFilename)
- .replace(/[!()]/g, function(match) { return "%" + match.charCodeAt(0).toString(16) });
- var newLineBefore = true;
- var newLineAfter = true;
- if(cursorPosition === 0 || description.substr(cursorPosition-1,1).match(/\r|\n/)) {
- newLineBefore = false;
- }
- if(description.substr(cursorPosition,1).match(/\r|\n/)) {
- newLineAfter = false;
- }
-
- $textarea.val(
- description.substring(0, cursorPosition)
- + (newLineBefore ? '\n' : '')
- + inlineFilename
- + (newLineAfter ? '\n' : '')
- + description.substring(cursorPosition, description.length)
- );
-
- $textarea.prop({
- 'selectionStart': cursorPosition + newLineBefore,
- 'selectionEnd': cursorPosition + inlineFilename.length + newLineBefore
- });
- $textarea.parents('.jstBlock')
- .find('.jstb_img').click();
-
- // move cursor into next line
- cursorPosition = $textarea.prop('selectionStart');
- $textarea.prop({
- 'selectionStart': cursorPosition + 1,
- 'selectionEnd': cursorPosition + 1
- });
-
- }
- }
-
- function copyImageFromClipboard(e) {
- if (!$(e.target).hasClass('wiki-edit')) { return; }
- var clipboardData = e.clipboardData || e.originalEvent.clipboardData
- if (!clipboardData) { return; }
- if (clipboardData.types.some(function(t){ return /^text\/plain$/.test(t); })) { return; }
-
- var items = clipboardData.items
- for (var i = 0 ; i < items.length ; i++) {
- var item = items[i];
- if (item.type.indexOf("image") != -1) {
- var blob = item.getAsFile();
- var date = new Date();
- var filename = 'clipboard-'
- + date.getFullYear()
- + ('0'+(date.getMonth()+1)).slice(-2)
- + ('0'+date.getDate()).slice(-2)
- + ('0'+date.getHours()).slice(-2)
- + ('0'+date.getMinutes()).slice(-2)
- + '-' + randomKey(5).toLocaleLowerCase()
- + '.' + blob.name.split('.').pop();
- var file = new Blob([blob], {type: blob.type});
- file.name = filename;
- var inputEl = $('input:file.filedrop').first()
- handleFileDropEvent.target = e.target;
- addFile(inputEl, file, true);
- }
- }
- }
-
- $(document).ready(setupFileDrop);
- $(document).ready(function(){
- $("input.deleted_attachment").change(function(){
- $(this).parents('.existing-attachment').toggleClass('deleted', $(this).is(":checked"));
- }).change();
- });
|