@@ -5,45 +5,72 @@
frappe.upload = {
make: function(opts) {
if(!opts.args) opts.args = {};
if(opts.allow_multiple === undefined) {
opts.allow_multiple = 1
}
var d = null;
// create new dialog if no parent given
if(!opts.parent) {
d = new frappe.ui.Dialog({
title: __('Upload Attachment'),
primary_action_label: __('Attach'),
primary_action: function() {}
});
opts.parent = d.body;
opts.btn = d.get_primary_btn();
d.show();
}
var $upload = $(frappe.render_template("upload", {opts:opts})).appendTo(opts.parent);
var $file_input = $upload.find(".input-upload-file");
var $uploaded_files_wrapper = $upload.find('.uploaded-filename');
// bind pseudo browse button
$upload.find(".btn-browse").on("click",
function() { $file_input.click(); });
$file_input.on("change", function() {
if (this.files.length > 0) {
$upload.find(".web-link-wrapper").addClass("hidden");
$upload.find(".btn-browse").removeClass("btn-primary").addClass("btn-default");
var $uploaded_file_display = $(repl('<div class="btn-group" role="group">\
<button type="button" class="btn btn-default btn-sm \
ellipsis uploaded-filename-display">%(filename)s\
</button>\
<button type="button" class="btn btn-default btn-sm uploaded-file-remove">\
×</button>\
</div>', {filename: this.files[0].name}))
.appendTo($upload.find(".uploaded-filename").removeClass("hidden").empty());
$uploaded_file_display.find(".uploaded-filename-display").on("click", function() {
$file_input.click();
});
$uploaded_file_display.find(".uploaded-file-remove").on("click", function() {
$file_input.val("");
$file_input.trigger("change");
});
if(opts.on_select) {
opts.on_select();
}
if ( !("is_private" in opts) ) {
// show Private checkbox
$upload.find(".private-file").removeClass("hidden");
if (this.files.length > 0 || opts.files) {
var fileobjs = null;
if (opts.files) {
// files added programmatically
fileobjs = opts.files;
delete opts.files;
} else {
// files from input type file
fileobjs = $upload.find(":file").get(0).files;
}
var file_array = $.makeArray(fileobjs);
$upload.find(".web-link-wrapper").addClass("hidden");
$upload.find(".btn-browse").removeClass("btn-primary").addClass("btn-default");
$uploaded_files_wrapper.removeClass('hidden').empty();
file_array = file_array.map(
file => Object.assign(file, {is_private: 1})
)
$upload.data('attached_files', file_array);
// List of files in a grid
$uploaded_files_wrapper.append(`
<div class="list-item list-item--head">
<div class="list-item__content list-item__content--flex-2">
${__('Filename')}
</div>
<div class="list-item__content" style="flex: 0 0 64px">
${__('Is Private')}
</div>
<div class="list-item__content list-item__content--activity" style="flex: 0 0 32px">
</div>
</div>
`);
var file_pills = file_array.map(
file => frappe.upload.make_file_row(file.name, !("is_private" in opts))
);
$uploaded_files_wrapper.append(file_pills);
} else {
$upload.find(".uploaded-filename").addClass("hidden")
$upload.find(".web-link-wrapper").removeClass("hidden");
@@ -52,6 +79,40 @@ frappe.upload = {
}
});
if(opts.files && opts.files.length > 0) {
$file_input.trigger('change');
}
// events
$uploaded_files_wrapper.on('click', '.list-item-container', function (e) {
var $item = $(this);
var filename = $item.attr('data-filename');
var attached_files = $upload.data('attached_files');
var $target = $(e.target);
if ($target.is(':checkbox')) {
var is_private = $target.is(':checked');
attached_files = attached_files.map(file => {
if (file.name === filename) {
file.is_private = is_private ? 1 : 0;
}
return file;
});
$upload.data('attached_files', attached_files);
}
else if ($target.is('.uploaded-file-remove, .fa-remove')) {
// remove file from attached_files object
attached_files = attached_files.filter(file => file.name !== filename);
$upload.data('attached_files', attached_files);
// remove row from dom
$uploaded_files_wrapper
.find(`.list-item-container[data-filename="${filename}"]`)
.remove();
}
});
if(!opts.btn) {
opts.btn = $('<button class="btn btn-default btn-sm">' + __("Attach")
@@ -60,21 +121,77 @@ frappe.upload = {
$(opts.btn).unbind("click");
}
// get the first file
// Primary button handler
opts.btn.click(function() {
// convert functions to values
// close created dialog
d && d.hide();
// convert functions to values
if(opts.get_params) {
opts.args.params = opts.get_params();
}
opts.args.file_url = $upload.find('[name="file_url"]').val();
opts.args.is_private = $upload.find('.private-file input').prop('checked') ? 1 : 0;
// Get file url if input is visible
var file_url = $upload.find('[name="file_url"]:visible');
file_url = file_url.length && file_url.get(0).value;
var fileobj = $upload.find(":file").get(0).files[0];
frappe.upload.upload_file(fileobj, opts.args, opts);
if(file_url) {
opts.args.file_url = file_url;
frappe.upload.upload_file(null, opts.args, opts);
} else {
var files = $upload.data('attached_files');
frappe.upload.upload_multiple_files(files, opts.args, opts);
}
});
},
make_file_row: function(filename, show_private) {
var template = `
<div class="list-item-container" data-filename="${filename}">
<div class="list-item">
<div class="list-item__content list-item__content--flex-2 ellipsis">
${filename}
</div>
${show_private
? `<div class="list-item__content ellipsis" style="flex: 0 0 64px;">
<input type="checkbox" checked/>
</div>`
: ''}
<div class="list-item__content list-item__content--activity ellipsis" style="flex: 0 0 32px;">
<button class="btn btn-default btn-xs text-muted uploaded-file-remove">
<span class="fa fa-remove"></span>
</button>
</div>
</div>
</div>
`
return $(template);
},
upload_multiple_files: function(files /*FileData array*/, args, opts) {
var i = -1;
// upload the first file
upload_next();
// subsequent files will be uploaded after
// upload_complete event is fired for the previous file
$(document).on('upload_complete', on_upload);
function upload_next() {
i += 1;
var file = files[i];
args.is_private = file.is_private;
frappe.upload.upload_file(file, args, opts);
frappe.show_progress(__('Uploading'), i+1, files.length);
}
function on_upload(e, attachment) {
if (i === files.length - 1) {
$(document).off('upload_complete', on_upload);
frappe.hide_progress();
return;
}
upload_next();
}
},
upload_file: function(fileobj, args, opts) {
if(!fileobj && !args.file_url) {
if(opts.on_no_attach) {
@@ -153,7 +270,7 @@ frappe.upload = {
},
upload_to_server: function(fileobj, args, opts, dataurl) {
var msgbox = msgprint(__("Uploading..."));
// var msgbox = msgprint(__("Uploading..."));
if(opts.start) {
opts.start();
}
@@ -162,11 +279,12 @@ frappe.upload = {
args: args,
callback: function(r) {
if(!r._server_messages) {
msgbox.hide();
// msgbox.hide();
}
if(r.exc) {
// if no onerror, assume callback will handle errors
opts.onerror ? opts.onerror(r) : opts.callback(null, r);
frappe.hide_progress();
return;
}
var attachment = r.message;
@@ -177,6 +295,7 @@ frappe.upload = {
error: function(r) {
// if no onerror, assume callback will handle errors
opts.onerror ? opts.onerror(r) : opts.callback(null, null, r);
frappe.hide_progress();
return;
}
}
@@ -216,7 +335,7 @@ frappe.upload = {
for (var i =0,j = fileobjs.length;i<j;i++) {
var filename = fileobjs[i].name;
fields.push({'fieldname': 'label1', 'fieldtype': 'Heading', 'label': filename});
fields.push({'fieldname': 'is_private', 'fieldtype': 'Check', 'label': 'Private', 'default': 1});
fields.push({'fieldname': filename+ '_ is_private', 'fieldtype': 'Check', 'label': 'Private', 'default': 1});
}
var d = new frappe.ui.Dialog({
@@ -227,6 +346,7 @@ frappe.upload = {
d.hide();
opts.loopcallback = function (){
if (i < j) {
args.is_private = d.fields_dict[fileobjs[i].name + "_is_private"].get_value()
frappe.upload.upload_file(fileobjs[i], args, opts);
i++;
}