ui/controllers/job_metadata_controller.js
const $ = require('jquery');
const { BagItProfile } = require('../../bagit/bagit_profile');
const { BaseController } = require('./base_controller');
const { Context } = require('../../core/context');
const { Job } = require('../../core/job');
const { JobTagsForm } = require('../forms/job_tags_form');
const { TagDefinition } = require('../../bagit/tag_definition');
const { TagDefinitionForm } = require('../forms/tag_definition_form');
const Templates = require('../common/templates');
/**
* The JobMetadataController presents the page that allows users
* to define a bag's tag metadata. This page appears only for
* Jobs that require bagging and include a {@link BagItProfile}.
*
* @param {URLSearchParams} params - The URL search params parsed
* from the URL used to reach this page. This should contain at
* least the Job Id.
*
* @param {string} params.id - The id of the Job being worked
* on. Job.id is a UUID string.
*/
class JobMetadataController extends BaseController {
constructor(params) {
super(params, 'Jobs');
this.model = Job;
this.job = Job.find(this.params.get('id'));
}
/**
* This displays a form in which a user can edit the
* tags and tag values for the BagIt bag that this Job
* will produce.
*/
show() {
let form = new JobTagsForm(this.job);
let data = { job: this.job, form: form };
return this.containerContent(Templates.jobMetadata(data));
}
/**
* This handles the page's Back button click, saving changes
* to tag values without validating them, and sending the user
* back to the packaging page.
*/
back() {
this._parseMetadataForm();
this.job.save();
return this.redirect('JobPackaging', 'show', this.params);
}
/**
* This handles the click on the Next button, saving changes
* to the tag values and validating those changes. If the
* data is valid, the user moves on to the upload page.
*/
next() {
let tagsAreValid = this._validateMetadataForm();
this.job.save();
if(!tagsAreValid) {
return this.show();
}
let nextController = 'JobUpload';
// If we have a workflow id, the uploads for this job
// are already determined, so we can skip that screen.
if (this.job.workflowId) {
nextController = 'JobRun';
}
return this.redirect(nextController, 'show', this.params);
}
/**
* This presents a modal dialog in which a user can define a new
* tag. Tags created through this dialog apply only to the current
* job.
*/
newTag(form) {
form = form || new TagDefinitionForm(new TagDefinition());
form.fields.userValue.label = Context.y18n.__("Value");
let title = "New Tag";
let body = Templates.jobNewTag({
form: form,
job: this.job
});
return this.modalContent(title, body);
}
/**
* This saves the new tag that the user created in the modal
* dialog.
*/
saveNewTag() {
let form = new TagDefinitionForm(new TagDefinition());
form.parseFromDOM();
form.obj.errors = {};
if (form.obj.tagFile == '') {
form.obj.errors['tagFile'] = Context.y18n.__("Please specify a tag file.");
}
if (form.obj.tagName == '') {
form.obj.errors['tagName'] = Context.y18n.__("Please specify a tag name.");
}
if (form.obj.userValue == '') {
form.obj.errors['userValue'] = Context.y18n.__("Please specify a value for this tag.");
}
if (Object.keys(form.obj.errors).length > 0) {
form.setErrors();
return this.newTag(form);
}
let tagDef = form.obj;
tagDef.isUserAddedTag = true;
tagDef.wasAddedForJob = true;
this.job.bagItProfile.tags.push(tagDef);
this.job.save();
return this.show();
}
/**
* This parses user input from the tags form and copies the
* values into the Job's local copy of the BagItProfile.
*/
_parseMetadataForm() {
let form = new JobTagsForm(this.job);
form.copyFormValuesToTags(this.job);
}
/**
* This calls {@link _parseMetadataForm} to parse user-entered
* data and copy it into the Job. It also validates the data in
* each tag field.
*/
_validateMetadataForm() {
this._parseMetadataForm();
let isValid = true;
for (let t of this.job.bagItProfile.tags) {
if (!t.validateForJob()) {
isValid = false;
}
}
return isValid;
}
/**
* This attaches a jQuery autocomplete handler to the
* tag file name input in the modal dialog where users
* can create new job-level tags.
*/
_attachTagFileAutocomplete() {
$('#tagDefinitionForm_tagFile').autocomplete({
source: this.job.bagItProfile.tagFileNames(),
minLength: 1
});
}
/**
* This attaches an event to the button that allows users
* to show and hide form fields for tags that have
* been pre-populated with default values. The UI hides these
* by default so they don't overwhelm the user.
*/
_attachToggleHiddenTags() {
$("#btnToggleHidden").click(function() {
let showAll = Context.y18n.__('Show All Tags');
let hideDefaults = Context.y18n.__('Hide Default Tags');
let currentText = $("#btnToggleHidden").text().trim();
$('.form-group-hidden').toggle();
if (currentText == showAll) {
$("#btnToggleHidden").text(hideDefaults);
$('.what-is-showing i').text(
Context.y18n.__('Showing all tags.')
);
} else {
$("#btnToggleHidden").text(showAll);
$('.what-is-showing i').text(
Context.y18n.__('Tags with default values are not showing.')
);
}
});
}
/**
* This calls functions to attach event handlers to elements
* that have just been rendered on the page.
*/
postRenderCallback(fnName) {
if (fnName == "newTag" || fnName == "saveNewTag") {
this._attachTagFileAutocomplete();
} else {
this._attachToggleHiddenTags();
}
}
}
module.exports.JobMetadataController = JobMetadataController;