mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 23:16:15 +08:00
Some hotfixes to previous commit. Client-side file validation added (except file type validation). Some refactoring.
This commit is contained in:
parent
e2f94caa96
commit
01aad1764c
|
@ -47,7 +47,6 @@
|
|||
data.push("file_size=" + file.size);
|
||||
data.push(csrfParam + "=" + encodeURIComponent(csrfToken));
|
||||
|
||||
|
||||
if (origId) {
|
||||
data.push("asset_id=" + origId);
|
||||
}
|
||||
|
@ -110,9 +109,7 @@
|
|||
|
||||
if (!isValid) {
|
||||
cbErr();
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
fetchUploadSignature(file, origId, signUrl, function (data) {
|
||||
|
||||
function processPost(error) {
|
||||
|
@ -124,10 +121,12 @@
|
|||
errObj[errKey] = [error];
|
||||
|
||||
cbErr(errObj);
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
if (!postData) {
|
||||
cb(data.asset_id);
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -153,6 +152,7 @@
|
|||
|
||||
if (!data || data.status === 'error') {
|
||||
cbErr(data && data.errors);
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -161,6 +161,9 @@
|
|||
|
||||
processPost();
|
||||
});
|
||||
}
|
||||
|
||||
return isValid;
|
||||
};
|
||||
|
||||
}(this));
|
||||
|
|
|
@ -311,10 +311,10 @@ function startFileUpload(ev, btn) {
|
|||
var origAssetId = assetInput ? assetInput.value : null;
|
||||
var url = '/asset_signature.json';
|
||||
|
||||
animateSpinner();
|
||||
$form.clear_form_errors();
|
||||
animateSpinner();
|
||||
|
||||
directUpload(form, origAssetId, url, function (assetId) {
|
||||
var noErrors = directUpload(form, origAssetId, url, function (assetId) {
|
||||
// edit mode - input field has to be removed
|
||||
if (assetInput) {
|
||||
assetInput.value = assetId;
|
||||
|
@ -334,7 +334,11 @@ function startFileUpload(ev, btn) {
|
|||
showResultFormErrors($form, errors);
|
||||
});
|
||||
|
||||
if(!noErrors) {
|
||||
animateSpinner(null, false);
|
||||
}
|
||||
ev.preventDefault();
|
||||
return noErrors;
|
||||
}
|
||||
|
||||
// This checks if the ctarget param exist in the
|
||||
|
|
|
@ -162,11 +162,6 @@ function formCallback($form) {
|
|||
}
|
||||
});
|
||||
|
||||
// Add asset validation
|
||||
$form.add_upload_file_size_check(function() {
|
||||
tabsPropagateErrorClass($form);
|
||||
});
|
||||
|
||||
// Add hidden fields for tables
|
||||
$form.submit(function(){
|
||||
$(this).find("[data-role='editable-table']").each(function() {
|
||||
|
@ -589,7 +584,7 @@ $("[data-action='new-step']").on("ajax:success", function(e, data) {
|
|||
});
|
||||
|
||||
function nameValidator(event) {
|
||||
var form = $(event.target.form);
|
||||
var $form = $(event.target.form);
|
||||
var nameTooShort = $( "#step_name" ).val().length === 0;
|
||||
var nameTooLong = $( "#step_name" ).val().length > 50;
|
||||
var errMsg;
|
||||
|
@ -602,20 +597,19 @@ function nameValidator(event) {
|
|||
|
||||
var hasErrors = !_.isUndefined(errMsg);
|
||||
if (hasErrors) {
|
||||
renderError($("#step_name"), errMsg, form);
|
||||
renderError($("#step_name"), errMsg);
|
||||
}
|
||||
return !hasErrors;
|
||||
}
|
||||
|
||||
function checklistsValidator(event, editMode) {
|
||||
var form = event.target.form;
|
||||
$(form).clear_form_errors();
|
||||
var $form = $(event.target.form);
|
||||
var noErrors = true;
|
||||
|
||||
// For every visible (i.e. not removed) checklist
|
||||
$(form).find(".nested_step_checklists[style!='display: none']").each(function() {
|
||||
var checklistNameInput = $(this).find(".checklist_name");
|
||||
var checklistNameEmpty = !checklistNameInput.val();
|
||||
$form.find(".nested_step_checklists[style!='display: none']").each(function() {
|
||||
var $checklistNameInput = $(this).find(".checklist_name");
|
||||
var checklistNameEmpty = !$checklistNameInput.val();
|
||||
anyChecklistItemFilled = false;
|
||||
|
||||
// For every ckecklist item input
|
||||
|
@ -632,7 +626,7 @@ function checklistsValidator(event, editMode) {
|
|||
if(anyChecklistItemFilled || editMode) {
|
||||
// In edit mode, name can't be blank
|
||||
var errMsg = I18n.t("devise.names.not_blank");
|
||||
renderError(checklistNameInput, errMsg, $(form));
|
||||
renderError($checklistNameInput, errMsg);
|
||||
noErrors = false;
|
||||
} else {
|
||||
// Hide empty checklist
|
||||
|
@ -648,28 +642,30 @@ function checklistsValidator(event, editMode) {
|
|||
// Needed because server-side validation failure clears locations of
|
||||
// files to be uploaded and checklist's items etc. Also user
|
||||
// experience is improved
|
||||
function localStepValidator(event, editMode) {
|
||||
function stepValidator(event, editMode, forS3) {
|
||||
var $form = $(event.target.form);
|
||||
$form.clear_form_errors();
|
||||
if(!editMode) {
|
||||
// Most td's disappear when editing step and not pressing on
|
||||
// edit tab, so we can't use this function
|
||||
clearBlankTables(event.target.form)
|
||||
// tables tab, so we can't use this function
|
||||
clearBlankTables($form)
|
||||
}
|
||||
clearBlankFileForms(event.target.form);
|
||||
clearBlankFileForms($form);
|
||||
// TODO File type check
|
||||
var fileSizeValid = uploadFileSizeCheck(event);
|
||||
var checklistsValid = checklistsValidator(event, editMode);
|
||||
var nameValid = nameValidator(event);
|
||||
|
||||
var noErrors = checklistsValid && nameValid;
|
||||
if(noErrors) {
|
||||
// Validations passed, so animate spinner for possible file
|
||||
// uploading
|
||||
if(fileSizeValid && checklistsValid && nameValid) {
|
||||
if(forS3) {
|
||||
// Needed to redirect uploaded files to S3
|
||||
startFileUpload(event, event.target);
|
||||
} else {
|
||||
// Files are saved locally
|
||||
// Validations passed, so animate spinner for possible file uploading
|
||||
// (startFileUpload already calls it)
|
||||
animateSpinner();
|
||||
}
|
||||
return noErrors;
|
||||
}
|
||||
|
||||
function S3StepValidator(event, editMode) {
|
||||
if(localStepValidator(event, editMode)) {
|
||||
startFileUpload(event, event.target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,9 +727,9 @@ function startFileUpload(ev, btn) {
|
|||
var inputPos = 0;
|
||||
var inputPointer = 0;
|
||||
|
||||
animateSpinner();
|
||||
$form.clear_form_errors();
|
||||
clearBlankFileForms(form);
|
||||
animateSpinner();
|
||||
|
||||
function processFile () {
|
||||
var fileInput = fileInputs.get(inputPos);
|
||||
|
@ -743,17 +739,16 @@ function startFileUpload(ev, btn) {
|
|||
if (!fileInput) {
|
||||
btn.onclick = null;
|
||||
$(btn).click();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
directUpload(form, null, url, function (assetId) {
|
||||
return directUpload(form, null, url, function (assetId) {
|
||||
fileInput.type = "hidden";
|
||||
fileInput.name = fileInput.name.replace("[file]", "[id]");
|
||||
fileInput.value = assetId;
|
||||
inputPointer -= 1;
|
||||
|
||||
processFile();
|
||||
|
||||
}, function (errors) {
|
||||
var assetError;
|
||||
|
||||
|
@ -768,16 +763,19 @@ function startFileUpload(ev, btn) {
|
|||
var $el = $(el);
|
||||
|
||||
$form.clear_form_errors();
|
||||
$el.closest(".form-group").addClass("has-error");
|
||||
$el.parent().append("<span class='help-block'>" + assetError + "</span>");
|
||||
renderError($el, assetError);
|
||||
} else {
|
||||
tabsPropagateErrorClass($form);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processFile();
|
||||
var noErrors = processFile();
|
||||
if(!noErrors) {
|
||||
animateSpinner(null, false);
|
||||
}
|
||||
ev.preventDefault();
|
||||
return noErrors;
|
||||
}
|
||||
|
||||
// Remove empty file forms in step
|
||||
|
|
|
@ -19,10 +19,7 @@ function checkFilesValidity(fileInputs) {
|
|||
input.closest('.form-group').removeClass('has-error');
|
||||
input.parent().find("[data-error='file-size']").remove();
|
||||
if (assetError) {
|
||||
input.closest('.form-group').addClass('has-error');
|
||||
input.parent().append(
|
||||
"<span class='help-block' data-error='file-size'>" + assetError + "</span>"
|
||||
);
|
||||
renderError(input, assetError, "data-error='file-size'");
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,7 +14,6 @@ $.fn.render_form_errors_input_group = function(model_name, errors) {
|
|||
$.fn.render_form_errors_no_clear = function(model_name, errors, input_group) {
|
||||
var form = $(this);
|
||||
|
||||
var firstErr = true;
|
||||
$.each(errors, function(field, messages) {
|
||||
input = $(_.filter(form.find('input, select, textarea'), function(el) {
|
||||
var name = $(el).attr('name');
|
||||
|
@ -34,17 +33,6 @@ $.fn.render_form_errors_no_clear = function(model_name, errors, input_group) {
|
|||
} else {
|
||||
input.parent().append(error_text);
|
||||
}
|
||||
|
||||
if(firstErr) {
|
||||
// Focus and scroll to the first error
|
||||
input.focus();
|
||||
firstErr = false;
|
||||
$('html, body').animate({
|
||||
scrollTop: input.closest(".form-group").offset().top
|
||||
- ($(".navbar-fixed-top").outerHeight(true)
|
||||
+ $(".navbar-secondary").outerHeight(true))
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -68,13 +56,19 @@ $.fn.clear_form_fields = function() {
|
|||
// Callback function can be provided to be called
|
||||
// any time at least one file size is too large
|
||||
$.fn.add_upload_file_size_check = function(callback) {
|
||||
var form = $(this);
|
||||
var $form = $(this);
|
||||
|
||||
if (form.length && form.length > 0) {
|
||||
form.submit(function (ev) {
|
||||
var fileInputs = $(this).find("input[type='file']");
|
||||
if (fileInputs.length && fileInputs.length > 0) {
|
||||
var isValid = checkFilesValidity(fileInputs);
|
||||
if ($form.length && $form.length > 0) {
|
||||
$form.submit(function (ev) {
|
||||
uploadFileSizeCheck(ev, callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function uploadFileSizeCheck(ev, callback) {
|
||||
var $fileInputs = $(ev.target.form).find("input[type='file']");
|
||||
if ($fileInputs.length && $fileInputs.length > 0) {
|
||||
var isValid = checkFilesValidity($fileInputs);
|
||||
|
||||
if (!isValid) {
|
||||
// Don't submit form
|
||||
|
@ -88,47 +82,49 @@ $.fn.add_upload_file_size_check = function(callback) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
// Show error message and mark error element and, if present, mark
|
||||
// and show the tab where the error occured.
|
||||
// NOTE: Similar to $.fn.render_form_errors, except here we process
|
||||
// one error at a time, which is not read from the form but is
|
||||
// specified manually.
|
||||
function renderError(nameInput, errMsg, form) {
|
||||
var errMsgSpan = nameInput.next(".help-block");
|
||||
if(!errMsgSpan.length) {
|
||||
nameInput.after("<span class='help-block'>" + errMsg + "</span>");
|
||||
nameInput.closest(".form-group").addClass("has-error");
|
||||
function renderError(nameInput, errMsg, errAttributes) {
|
||||
var $errMsgSpan = $(nameInput).next(".help-block");
|
||||
if(!$errMsgSpan.length) {
|
||||
errAttributes = (_.isUndefined(errAttributes)) ? "" : " " + errAttributes;
|
||||
$(nameInput).after("<span class='help-block'" + errAttributes + ">" + errMsg + "</span>");
|
||||
$(nameInput).closest(".form-group").addClass("has-error");
|
||||
} else {
|
||||
errMsgSpan.html(errMsg);
|
||||
$errMsgSpan.html(errMsg);
|
||||
}
|
||||
|
||||
$form = $(nameInput).closest("form");
|
||||
$tab = $(nameInput).closest(".tab-pane");
|
||||
if($tab.length) {
|
||||
tabsPropagateErrorClass($form);
|
||||
$parent = $tab;
|
||||
} else {
|
||||
$parent = $form;
|
||||
}
|
||||
tabsPropagateErrorClass($(form));
|
||||
|
||||
// Focus and scroll to the error if it is the first (most upper) one
|
||||
if($(form).find(".form-group.has-error").length === 1) {
|
||||
nameInput.focus();
|
||||
$('html, body').animate({
|
||||
scrollTop: nameInput.closest(".form-group").offset().top
|
||||
- ($(".navbar-fixed-top").outerHeight(true)
|
||||
+ $(".navbar-secondary").outerHeight(true))
|
||||
}, 2000);
|
||||
if($parent.find(".form-group.has-error").length === 1) {
|
||||
goToFormElement(nameInput);
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// If any of tabs has errors, add has-error class to
|
||||
// parent tab navigation link
|
||||
// If any of tabs (if exist) has errors, add has-error class to
|
||||
// parent tab navigation link and show the tab (if not already)
|
||||
function tabsPropagateErrorClass(parent) {
|
||||
var contents = parent.find("div.tab-pane");
|
||||
if(contents.length) {
|
||||
_.each(contents, function(tab) {
|
||||
var $contents = parent.find("div.tab-pane");
|
||||
_.each($contents, function(tab) {
|
||||
var $tab = $(tab);
|
||||
var errorFields = $tab.find(".has-error");
|
||||
if (errorFields.length > 0) {
|
||||
var $errorFields = $tab.find(".has-error");
|
||||
if ($errorFields.length > 0) {
|
||||
var id = $tab.attr("id");
|
||||
var navLink = parent.find("a[href='#" + id + "'][data-toggle='tab']");
|
||||
if (navLink.parent().length > 0) {
|
||||
|
@ -136,6 +132,5 @@ function tabsPropagateErrorClass(parent) {
|
|||
}
|
||||
}
|
||||
});
|
||||
$(".nav-tabs .has-error:first > a", parent).tab("show");
|
||||
}
|
||||
$(".nav-tabs .has-error:first:not(.active) > a", parent).tab("show");
|
||||
}
|
||||
|
|
13
app/assets/javascripts/sitewide/gestures.js
Normal file
13
app/assets/javascripts/sitewide/gestures.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Scroll to and focus on element
|
||||
function goToFormElement(el) {
|
||||
$("html, body").animate(
|
||||
{
|
||||
scrollTop: $(el).closest(".form-group").offset().top
|
||||
- ($(".navbar-fixed-top").outerHeight(true)
|
||||
+ $(".navbar-secondary").outerHeight(true)
|
||||
+ $(".alert-dismissable").outerHeight(true))
|
||||
},
|
||||
"slow",
|
||||
function() { $(el).focus(); }
|
||||
);
|
||||
}
|
|
@ -75,7 +75,7 @@ function startFileUpload(ev, btn) {
|
|||
$form.clear_form_errors();
|
||||
animateSpinner($form);
|
||||
|
||||
directUpload(form, null, url, function (assetId) {
|
||||
var noErrors = directUpload(form, null, url, function (assetId) {
|
||||
var file = fileInput.files[0];
|
||||
fileInput.type = "hidden";
|
||||
fileInput.name = fileInput.name.replace("[avatar]", "[avatar_file_name]");
|
||||
|
@ -103,12 +103,15 @@ function startFileUpload(ev, btn) {
|
|||
var $el = $form.find("input[type=file]");
|
||||
|
||||
$form.clear_form_errors();
|
||||
$el.closest(".form-group").addClass("has-error");
|
||||
$el.parent().append("<span class='help-block'>" + avatarError + "</span>");
|
||||
renderError($el, avatarError);
|
||||
}
|
||||
}, "avatar");
|
||||
|
||||
if(!noErrors) {
|
||||
animateSpinner(null, false);
|
||||
}
|
||||
ev.preventDefault();
|
||||
return noErrors;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,11 +4,7 @@
|
|||
<hr>
|
||||
<%= render partial: "empty_step.html.erb", locals: {step: @step, f: f} %>
|
||||
<hr>
|
||||
<% if direct_upload %>
|
||||
<%= f.submit t("protocols.steps.edit.edit_step"), class: 'btn btn-primary', onclick: 'S3StepValidator(event, true);' %>
|
||||
<% else %>
|
||||
<%= f.submit t("protocols.steps.edit.edit_step"), class: 'btn btn-primary', onclick: 'localStepValidator(event, true);' %>
|
||||
<% end %>
|
||||
<%= f.submit t("protocols.steps.edit.edit_step"), class: 'btn btn-primary', onclick: "stepValidator(event, true, #{direct_upload});" %>
|
||||
<a type="button" data-action="cancel-edit" class="btn btn-default" href="<%= step_path(id: @step, format: :json) %>" data-remote="true">
|
||||
<%= t("general.cancel")%>
|
||||
</a>
|
||||
|
|
|
@ -4,11 +4,7 @@
|
|||
<hr>
|
||||
<%= render partial: "empty_step.html.erb", locals: {step: @step, f: f} %>
|
||||
<hr>
|
||||
<% if direct_upload %>
|
||||
<%= f.submit t("protocols.steps.new.add_step"), class: 'btn btn-primary', onclick: 'S3StepValidator(event, false);' %>
|
||||
<% else %>
|
||||
<%= f.submit t("protocols.steps.new.add_step"), id: "create-step", class: 'btn btn-primary', onclick: 'localStepValidator(event, false);' %>
|
||||
<% end %>
|
||||
<%= f.submit t("protocols.steps.new.add_step"), class: 'btn btn-primary', onclick: "stepValidator(event, false, #{direct_upload});" %>
|
||||
<button type="button" data-action="cancel-new" class="btn btn-default">
|
||||
<%= t("general.cancel")%>
|
||||
</button>
|
||||
|
|
Loading…
Reference in a new issue