drag/drop feature for new content #443

This commit is contained in:
Karel Picman 2016-08-25 14:23:04 +02:00
parent 7626815961
commit cfbae13b56
18 changed files with 304 additions and 46 deletions

View File

@ -135,7 +135,8 @@ class DmsfFilesController < ApplicationController
else else
revision.increase_version(version) revision.increase_version(version)
end end
file_upload = params[:file_upload] #file_upload = params[:file_upload]
file_upload = params[:attachments]['1'] if params[:attachments].present?
unless file_upload unless file_upload
revision.size = last_revision.size revision.size = last_revision.size
revision.disk_filename = last_revision.disk_filename revision.disk_filename = last_revision.disk_filename
@ -146,10 +147,11 @@ class DmsfFilesController < ApplicationController
revision.digest = last_revision.digest revision.digest = last_revision.digest
end end
else else
upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, file_upload)
revision.size = file_upload.size revision.size = file_upload.size
revision.disk_filename = revision.new_storage_filename revision.disk_filename = revision.new_storage_filename
revision.mime_type = Redmine::MimeType.of(file_upload.original_filename) revision.mime_type = upload.mime_type
revision.digest = DmsfFileRevision.create_digest file_upload.path revision.digest = DmsfFileRevision.create_digest upload.disk_file
end end
# Custom fields # Custom fields
@ -163,8 +165,8 @@ class DmsfFilesController < ApplicationController
if revision.save if revision.save
revision.assign_workflow(params[:dmsf_workflow_id]) revision.assign_workflow(params[:dmsf_workflow_id])
if file_upload if upload
revision.copy_file_content(file_upload) FileUtils.mv(upload.disk_file, revision.disk_file)
end end
if @file.locked? && !@file.locks.empty? if @file.locked? && !@file.locks.empty?
begin begin

View File

@ -201,7 +201,7 @@ class DmsfFile < ActiveRecord::Base
def notify? def notify?
return true if self.notification return true if self.notification
return true if self.dmsf_folder && delf.dmsf_folder.notify? return true if self.dmsf_folder && self.dmsf_folder.notify?
return true if !self.dmsf_folder && self.project.dmsf_notification return true if !self.dmsf_folder && self.project.dmsf_notification
return false return false
end end

View File

@ -46,6 +46,13 @@
<%= f.text_area(:description, :rows => 6, :class => 'wiki-edit') %> <%= f.text_area(:description, :rows => 6, :class => 'wiki-edit') %>
</p> </p>
<div class="clear"> <div class="clear">
<div class="splitcontentright">
<div class="custom_fields">
<% @revision.custom_field_values.each do |value| %>
<p><%= custom_field_tag_with_label(:dmsf_file_revision, value) %></p>
<% end %>
</div>
</div>
<div class="splitcontentleft"> <div class="splitcontentleft">
<p> <p>
<%= label_tag('version_0', l(:label_dmsf_version)) %> <%= label_tag('version_0', l(:label_dmsf_version)) %>
@ -62,34 +69,15 @@
<%= select_tag 'custom_version_major', options_for_select(0..99, @file.last_revision.major_version + 2), :onchange => '$("#version_3").prop("checked", true)' %>. <%= select_tag 'custom_version_major', options_for_select(0..99, @file.last_revision.major_version + 2), :onchange => '$("#version_3").prop("checked", true)' %>.
<%= select_tag 'custom_version_minor', options_for_select(0..99, @file.last_revision.minor_version + 1), :onchange => '$("#version_3").prop("checked", true)' %> <%= select_tag 'custom_version_minor', options_for_select(0..99, @file.last_revision.minor_version + 1), :onchange => '$("#version_3").prop("checked", true)' %>
<%= l(:option_version_custom) %> <%= l(:option_version_custom) %>
</p>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('file_upload', l(:label_new_content)) %>
<span class="add_attachment">
<%= file_field_tag 'file_upload',
:id => 'file_upload',
:class => 'file_selector',
:multiple => false,
:onchange => "$('#dmsf_file_revision_name').val(this.files[0].name)",
:data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
:max_concurrent_uploads => 1,
:upload_path => uploads_path(:format => 'js')
}
%>
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
</span>
</p> </p>
</div> </div>
</div> </div>
<div class="custom_fields"> <div class="box">
<% @revision.custom_field_values.each do |value| %> <p>
<p><%= custom_field_tag_with_label(:dmsf_file_revision, value) %></p> <%= label_tag('file_upload', l(:label_new_content)) %>
<% end %> <%= render :partial => 'upload_form' %>
</div> </p>
</div>
<p> <p>
<%= f.text_area(:comment, :rows => 2, :label => l(:label_comment)) %> <%= f.text_area(:comment, :rows => 2, :label => l(:label_comment)) %>
</p> </p>
@ -99,4 +87,4 @@
</div> </div>
</div> </div>
<%= wikitoolbar_for 'dmsf_file_revision_description' %> <%= wikitoolbar_for 'dmsf_file_revision_description' %>

View File

@ -0,0 +1,36 @@
<% hide = false %>
<span id="attachments_fields">
<% if defined?(container) && container && container.saved_attachments %>
<% container.saved_attachments.each_with_index do |attachment, i| %>
<span id="attachments_p<%= i %>">
<%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename') %>
<%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %>
<% hide = true %>
</span>
<% end %>
<% end %>
</span>
<% unless hide %>
<span class="add_attachment">
<%= file_field_tag 'attachments[dummy][file]',
:id => nil,
:class => 'file_selector',
:multiple => false,
:onchange => 'addInputFile(this);',
:data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
:max_file_count_message => l(:error_maximum_upload_filecount, :filecount => 1),
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
:upload_path => uploads_path(:format => 'js'),
:description_placeholder => l(:label_optional_description)
} %>
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
</span>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'attachments_dmsf', :plugin => 'redmine_dmsf' %>
<% end %>

View File

@ -0,0 +1,206 @@
/* Redmine - project management software
Copyright (C) 2006-2016 Jean-Philippe Lang */
function addFile(inputEl, file, eagerUpload) {
if ($('#attachments_fields').children().length < 10) {
var attachmentId = addFile.nextAttachmentId++;
var fileSpan = $('<span>', { id: 'attachments_' + attachmentId });
fileSpan.append(
$('<input>', { type: 'text', 'class': 'filename readonly', name: 'attachments[' + attachmentId + '][filename]', readonly: 'readonly'} ).val(file.name)
).appendTo('#attachments_fields');
if(eagerUpload) {
ajaxUpload(file, attachmentId, fileSpan, inputEl);
}
toggleFileAdding(false);
$('#dmsf_file_revision_name').val(file.name);
return attachmentId;
}
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) {
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).parent('span').remove();
toggleFileAdding(true);
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.File) {
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 addInputFile(inputEl) {
var clearedFileInput = $(inputEl).clone().val('');
if ($.ajaxSettings.xhr().upload && inputEl.files) {
// upload files using ajax
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: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId);
}
}
clearedFileInput.insertAfter('#attachments_fields');
toggleFileAdding(false);
}
function uploadAndAttachFiles(files, inputEl) {
var maxFileSize = $(inputEl).data('max-file-size');
var maxFileSizeExceeded = $(inputEl).data('max-file-size-message');
var maxFileCountExceeded = $(inputEl).data('max-file-count-message');
var sizeExceeded = false;
$.each(files, function() {
if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;}
});
if((files.length > 1) || (!$('input.file_selector').is(':visible'))){
window.alert(maxFileCountExceeded);
}
else if (sizeExceeded) {
window.alert(maxFileSizeExceeded);
} else {
$.each(files, function() {addFile(inputEl, this, true);});
}
}
function toggleFileAdding(toggle){
$('input.file_selector').toggle(toggle);
$('span.add_attachment').toggle(toggle);
}
function handleFileDropEvent(e) {
$(this).removeClass('fileover');
blockEventPropagation(e);
if ($.inArray('Files', e.dataTransfer.types) > -1) {
uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector'));
}
}
function dragOverHandler(e) {
$(this).addClass('fileover');
blockEventPropagation(e);
}
function dragOutHandler(e) {
$(this).removeClass('fileover');
blockEventPropagation(e);
}
function setupFileDrop() {
if (window.File && window.FileList && window.ProgressEvent && window.FormData) {
$.event.fixHooks.drop = { props: [ 'dataTransfer' ] };
$('form div.box').has('input:file').each(function() {
$(this).on({
dragover: dragOverHandler,
dragleave: dragOutHandler,
drop: handleFileDropEvent
});
});
}
}
$(document).ready(setupFileDrop);

View File

@ -330,4 +330,6 @@ cs:
label_maximum_ajax_upload_filesize: Maximální velikost souboru nahratelná přes AJAX label_maximum_ajax_upload_filesize: Maximální velikost souboru nahratelná přes AJAX
note_maximum_ajax_upload_filesize: Omezuje velikost souboru, který může být nahrán přes standardní rozhraní AJAX, jinak se použije standardní rozhraní Redminu. Číslo je v MB. note_maximum_ajax_upload_filesize: Omezuje velikost souboru, který může být nahrán přes standardní rozhraní AJAX, jinak se použije standardní rozhraní Redminu. Číslo je v MB.
label_classic: Klasický label_classic: Klasický
label_drag_drop: "Drag&Drop" label_drag_drop: Moderní
error_maximum_upload_filecount: "Nelze nahrát více než %{filecount} soubor(ů)."

View File

@ -330,4 +330,6 @@ de:
label_maximum_ajax_upload_filesize: Maximale Dateigröße für den Upload via AJAX label_maximum_ajax_upload_filesize: Maximale Dateigröße für den Upload via AJAX
note_maximum_ajax_upload_filesize: Maximale Dateigröße für den Upload über die AJAX-Schnittstelle. Für größere Dateien muss der Standard-Uploader von Redmine verwendet werden. Angabe in MB. note_maximum_ajax_upload_filesize: Maximale Dateigröße für den Upload über die AJAX-Schnittstelle. Für größere Dateien muss der Standard-Uploader von Redmine verwendet werden. Angabe in MB.
label_classic: Klassisch label_classic: Klassisch
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "Nicht mehr als %{filecount} Datai(en) kann man hochladen."

View File

@ -330,4 +330,6 @@ en:
label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX
note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB. note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ es:
label_maximum_ajax_upload_filesize: "El máximo tamaño de archivo para subir por AJAX" label_maximum_ajax_upload_filesize: "El máximo tamaño de archivo para subir por AJAX"
note_maximum_ajax_upload_filesize: "El límite máximo de tamaño de archivo que puede ser subido por la interfaz AJAX estandar, de lo contrario se debe utilizar el formulario estandar de Redmine. El número es en MB." note_maximum_ajax_upload_filesize: "El límite máximo de tamaño de archivo que puede ser subido por la interfaz AJAX estandar, de lo contrario se debe utilizar el formulario estandar de Redmine. El número es en MB."
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ fr:
label_maximum_ajax_upload_filesize: Taille maximale de fichier pour téléversement via AJAX label_maximum_ajax_upload_filesize: Taille maximale de fichier pour téléversement via AJAX
note_maximum_ajax_upload_filesize: "Taille maximale, en méga octets, de fichier pour téléversement via l'interface standard AJAX. Sinon l'interface standard de Redmine doit être utilisée." note_maximum_ajax_upload_filesize: "Taille maximale, en méga octets, de fichier pour téléversement via l'interface standard AJAX. Sinon l'interface standard de Redmine doit être utilisée."
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ it: # Italian strings thx 2 Matteo Arceci!
label_maximum_ajax_upload_filesize: Dimensione massima dei documenti caricabili tramite AJAX label_maximum_ajax_upload_filesize: Dimensione massima dei documenti caricabili tramite AJAX
note_maximum_ajax_upload_filesize: Limita la dimensione massima dei documenti che possono essere caricati tramite interfaccia standard AJAX altrimenti sarà necessario utilizzare il modulo standard di Redmine. Il numero è espresso in MB. note_maximum_ajax_upload_filesize: Limita la dimensione massima dei documenti che possono essere caricati tramite interfaccia standard AJAX altrimenti sarà necessario utilizzare il modulo standard di Redmine. Il numero è espresso in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ ja:
label_maximum_ajax_upload_filesize: アップロードファイルサイズ上限 label_maximum_ajax_upload_filesize: アップロードファイルサイズ上限
note_maximum_ajax_upload_filesize: アップロード可能なファイルサイズの上限。AjaxおよびRedmineの仕様に制限される2ギガバイト程度までは確認済み単位はMB。 note_maximum_ajax_upload_filesize: アップロード可能なファイルサイズの上限。AjaxおよびRedmineの仕様に制限される2ギガバイト程度までは確認済み単位はMB。
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ pl:
label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX
note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB. note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ pt-BR:
label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX
note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB. note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ ru:
label_maximum_ajax_upload_filesize: Максимальный размер файла, загружаемого посредством AJAX label_maximum_ajax_upload_filesize: Максимальный размер файла, загружаемого посредством AJAX
note_maximum_ajax_upload_filesize: Превышает максимальный размер файла, загружаемого посредством интерфейса AJAX, для загрузки можно использовать стандартную форму Redmine. Размер указан в MB. note_maximum_ajax_upload_filesize: Превышает максимальный размер файла, загружаемого посредством интерфейса AJAX, для загрузки можно использовать стандартную форму Redmine. Размер указан в MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ sl:
label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX
note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB. note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ zh-TW:
label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX
note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB. note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."

View File

@ -330,4 +330,6 @@ zh:
label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX label_maximum_ajax_upload_filesize: Maximum file size uploadable via AJAX
note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB. note_maximum_ajax_upload_filesize: Limits maximum file size that can uploaded via standard AJAX interface otherwise Redmine standard upload form must be used. Number is in MB.
label_classic: Classic label_classic: Classic
label_drag_drop: "Drag&Drop" label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."