// Backbone Application View: Signatory Editor define([ 'jquery', 'underscore', 'backbone', 'gettext', 'js/utils/templates', 'common/js/components/utils/view_utils', 'common/js/components/views/feedback_prompt', 'common/js/components/views/feedback_notification', 'js/models/uploads', 'js/views/uploads', 'text!templates/signatory-editor.underscore' ], function($, _, Backbone, gettext, TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog, signatoryEditorTemplate) { 'use strict'; var SignatoryEditorView = Backbone.View.extend({ tagName: 'div', events: { 'change .signatory-name-input': 'setSignatoryName', 'change .signatory-title-input': 'setSignatoryTitle', 'change .signatory-organization-input': 'setSignatoryOrganization', 'click .signatory-panel-delete': 'deleteItem', 'change .signatory-signature-input': 'setSignatorySignatureImagePath', 'click .action-upload-signature': 'uploadSignatureImage' }, className: function() { // Determine the CSS class names for this model instance var index = this.getModelIndex(this.model); return [ 'signatory-edit', 'signatory-edit-view-' + index ].join(' '); }, initialize: function(options) { // Set up the initial state of the attributes set for this model instance _.bindAll(this, 'render'); this.model.bind('change', this.render); this.eventAgg = options.eventAgg; this.isEditingAllCollections = options.isEditingAllCollections; }, getModelIndex: function(givenModel) { // Retrieve the position of this model in its collection return this.model.collection.indexOf(givenModel); }, loadTemplate: function(name) { // Retrieve the corresponding template for this model return TemplateUtils.loadTemplate(name); }, getTotalSignatoriesOnServer: function() { // Retrieve the count of signatories stored server-side var count = 0; this.model.collection.each(function(modelSignatory) { if (!modelSignatory.isNew()) { count ++; } }); return count; }, render: function() { // Assemble the editor view for this model var attributes = $.extend({ modelIsValid: this.model.isValid(), error: this.model.validationError }, this.model.attributes, { signatory_number: this.getModelIndex(this.model) + 1, signatories_count: this.model.collection.length, isNew: this.model.isNew(), is_editing_all_collections: this.isEditingAllCollections, total_saved_signatories: this.getTotalSignatoriesOnServer() }); return $(this.el).html(_.template(signatoryEditorTemplate)(attributes)); }, setSignatoryName: function(event) { // Update the model with the provided data if (event && event.preventDefault) { event.preventDefault(); } this.model.set( 'name', this.$('.signatory-name-input').val(), {silent: true} ); this.toggleValidationErrorMessage('name'); this.eventAgg.trigger('onSignatoryUpdated', this.model); }, setSignatoryTitle: function(event) { // Update the model with the provided data if (event && event.preventDefault) { event.preventDefault(); } this.model.set( 'title', this.$('.signatory-title-input').val(), {silent: true} ); this.toggleValidationErrorMessage('title'); this.eventAgg.trigger('onSignatoryUpdated', this.model); }, setSignatoryOrganization: function(event) { // Update the model with the provided data if (event && event.preventDefault) { event.preventDefault(); } this.model.set( 'organization', this.$('.signatory-organization-input').val(), {silent: true} ); this.eventAgg.trigger('onSignatoryUpdated', this.model); }, setSignatorySignatureImagePath: function(event) { if (event && event.preventDefault) { event.preventDefault(); } this.model.set( 'signature_image_path', this.$('.signatory-signature-input').val(), {silent: true} ); }, deleteItem: function(event) { // Remove the specified model from the collection if (event && event.preventDefault) { event.preventDefault(); } var model = this.model; var self = this; var titleTextTemplate = _.template(gettext('Delete "<%= signatoryName %>" from the list of signatories?')); var confirm = new PromptView.Warning({ title: titleTextTemplate({signatoryName: model.get('name')}), message: gettext('This action cannot be undone.'), actions: { primary: { text: gettext('Delete'), click: function() { var deleting = new NotificationView.Mini({ title: gettext('Deleting') }); if (model.isNew()) { model.collection.remove(model); self.eventAgg.trigger('onSignatoryRemoved', model); } else { deleting.show(); model.destroy({ wait: true, success: function(model) { deleting.hide(); self.eventAgg.trigger('onSignatoryRemoved', model); } }); } confirm.hide(); } }, secondary: { text: gettext('Cancel'), click: function() { confirm.hide(); } } } }); confirm.show(); }, uploadSignatureImage: function(event) { event.preventDefault(); var upload = new FileUploadModel({ title: gettext('Upload signature image.'), message: gettext('Image must be in PNG format.'), mimeTypes: ['image/png'] }); var self = this; var modal = new FileUploadDialog({ model: upload, onSuccess: function(response) { self.model.set('signature_image_path', response.asset.url); } }); modal.show(); }, /** * @desc Toggle the validation error messages. If given model attribute is not valid then show the error message * else remove it. * @param string modelAttribute - the attribute of the signatory model e.g. name, title. */ toggleValidationErrorMessage: function(modelAttribute) { var selector = 'div.add-signatory-' + modelAttribute; if (!this.model.isValid() && _.has(this.model.validationError, modelAttribute)) { // Show the error message if it is not exist before. if (!$(selector).hasClass('error')) { var errorMessage = this.model.validationError[modelAttribute]; $(selector).addClass('error'); $(selector).append("<span class='message-error'>" + errorMessage + '</span>'); } } else { // Remove the error message. $(selector).removeClass('error'); $(selector + '>span.message-error').remove(); } } }); return SignatoryEditorView; });