/src/main/webapp/js/app/views/fields/containerfield.js
JavaScript | 389 lines | 319 code | 29 blank | 41 comment | 39 complexity | 94c9c02ae7800d9a537562fd74b1077e MD5 | raw file
Possible License(s): GPL-2.0, MIT
- App.Views.ContainerField = App.Views.AbstractField.extend({
- type: 'ContainerField',
- events: {
- 'click button.add': 'createEntry'
- },
- errorSelector: 'fieldset > .error',
- initialize: function() {
- App.Views.AbstractField.prototype.initialize.apply(this, arguments);
- // init variables here. If you do it at the class level they will be static.
- this.fields = [];
- this.fieldHash = [];
- // convert model to Model or Collection
- this.originalModel = this.model;
- if (this.properties.list) {
- this.model = new Backbone.Collection(this.model);
- this.model.bind('add', this.addEntry, this);
- this.model.bind('change', this.changed, this);
- } else {
- this.model = new Backbone.Model(this.model);
- }
- },
- val: function() {
- if (this.properties.list) {
- return this.model.toJSON();
- }
- var data = {};
- for (var i = 0; i < this.fields.length; i++){
- var field = this.fields[i];
- data[field.properties.id] = field.val();
- }
- return data;
- },
- reset: function () {
- if (this.properties.list) {
- this.model = new Backbone.Collection(this.originalModel);
- } else {
- this.model = new Backbone.Model(this.originalModel);
- }
- this.render();
- },
- render: function () {
- this.template = this.getTemplate(this.type + '-' + this.mode);
- this.$el.html(this.template(this));
- this.$fields = this.$('.fields');
- var i, entry, $entry, field, view;
- if (this.properties.list) {
- if (this.mode == 'Edit') {
- for (i = 0; i < this.properties.fields.length; i++){
- field = this.properties.fields[i];
- view = new App.Views[field.type]({
- mode: this.mode,
- properties: field,
- formTemplate: this.formTemplate,
- fieldid: field.id
- });
- this.fields.push(view);
- this.fieldHash[field.id] = view;
- this.$fields.append(view.el);
- if (field.srcField) {
- view.srcField = this.fieldHash[field.srcField];
- view.srcField.on('ready', view.render, view);
- if (view.srcField.ready) {
- // if the source field has already loaded go ahead and render
- view.render();
- }
- } else {
- view.render();
- }
- view.on('change', this.fieldChanged, this);
- }
- var $add = $('<button type="button" class="add">Add</button>');
- this.$fields.append($('<div>').html($('<div class="field-label">').html($add)));
- }
- this.addAllEntries();
- // this.model.each(function(model) {
- // var view = new App.Views.ContainerEntry({
- // model: model,
- // properties: this.properties,
- // formTemplate: this.formTemplate
- // });
- // this.$fields.append(view.render().el);
- // }, this);
- // TODO: wire up remove buttons
- // TODO: wire up edit buttons
- } else {
- this.fields = [];
- this.fieldHash = [];
- for (i = 0; i < this.properties.fields.length; i++){
- field = this.properties.fields[i];
- view = new App.Views[field.type]({
- mode: this.mode,
- properties: field,
- formTemplate: this.formTemplate,
- fieldid: field.id
- });
- if (this.model.has(field.id)) {
- view.model = this.model.get(field.id);
- }
- this.fields.push(view);
- this.fieldHash[field.id] = view;
- this.$fields.append(view.render().el);
- view.on('change', this.fieldChanged, this);
- view.on('ready', this.fieldReady, this);
- }
- }
- return this;
- },
- createEntry: function () {
- // validate
- if (!_.reduce(this.fields, function(memo, field) {
- var isvalid = field.validate();
- return memo && isvalid;
- }, true)) {
- return;
- }
- //
- // TODO: change to on model.add create view
- var model = new Backbone.Model();
- for (i = 0; i < this.fields.length; i++){
- var field = this.fields[i];
- model.set(field.properties.id,field.val());
- }
- this.model.add(model);
- // clear input fields
- _.each(this.fields, function(field) {field.reset();});
- },
- addEntry: function(model) {
- var view = new App.Views.ContainerEntry({
- mode: this.mode,
- model: model,
- properties: this.properties,
- formTemplate: this.formTemplate
- });
- model.view = view;
- this.$fields.append(view.render().el);
- view.bind('edit', this.editEntry, this);
- },
- addAllEntries: function() {
- this.model.each(this.addEntry, this);
- },
- editEntry: function (model) {
- _.each(model.toJSON(), function (value, key) {
- // TODO: this needs to be way more model/event driven
- this.fieldHash[key].set(value);
- }, this);
- this.changed();
- },
- fieldChanged: function(field) {
- this.trigger('change', field);
- },
- focus: function() {
- // TODO: Implement
- }
- });
- App.Views.ContainerEntry = App.Views.AbstractView.extend({
- type: 'ContainerEntry',
- events: {
- 'click button.edit': 'edit',
- 'click button.delete': 'clear'
- },
- initialize: function() {
- this.properties = this.options.properties;
- this.formTemplate = this.options.formTemplate;
- this.fields = [];
- this.fieldHash = [];
- },
- render: function() {
- this.$el.addClass('entry');
- for (i = 0; i < this.properties.fields.length; i++){
- var field = this.properties.fields[i];
- // TODO: add input fields
- var view = new App.Views[field.type]({
- mode: 'View',
- properties: field,
- formTemplate: this.formTemplate,
- fieldid: field.id,
- model: this.model.get(field.id)
- });
- this.fields.push(view);
- this.fieldHash[field.id] = view;
- this.$el.append(view.el);
- if (field.srcField) {
- view.srcField = this.fieldHash[field.srcField];
- view.srcField.on('ready', view.render, view);
- if (view.srcField.ready) {
- // if the source field has already loaded go ahead and render
- view.render();
- }
- } else {
- view.render();
- }
- }
- if (this.options.mode == 'Edit') {
- this.$el.append('<button class="edit" type="button">Edit</button>');
- this.$el.append('<button class="delete" type="button">Delete</button>');
- }
- return this;
- },
- edit: function() {
- this.trigger('edit', this.model);
- this.clear();
- },
- clear: function() {
- this.model.destroy();
- this.remove();
- }
- });
- // TODO: Refactor this to derive from Container entry, or I should say, refactor Container entry to be a parent of this
- App.Views.ListField = App.Views.AbstractField.extend({
- type: 'ListField',
- events: {
- 'click button.add': 'createEntry'
- },
- initialize: function() {
- App.Views.AbstractField.prototype.initialize.apply(this, arguments);
- // init variables here. If you do it at the class level they will be static.
- // convert model to Model or Collection
- this.originalModel = this.model;
- this.model = new Backbone.Collection(this.model);
- this.model.bind('add', this.addEntry, this);
- // this.model.bind('change', this.changed, this);
- this.model.bind('destroy', this.entryRemoved, this);
- },
- validate: function(errorMode) {
- // Validate each field and return false if any return false
- return this.model.reduce(function(memo, model) {
- return model.view.validate(errorMode) && memo;
- }, true);
- },
- val: function() {
- return this.model.toJSON();
- },
- reset: function () {
- this.model = new Backbone.Collection(this.originalModel);
- this.render();
- },
- render: function () {
- // Render the outer control
- this.template = this.getTemplate(this.type + '-' + this.mode);
- this.$el.html(this.template(this));
- this.$fields = this.$('.fields');
- if (this.properties.addLabel) {
- this.$('button.add').text(this.properties.addLabel);
- }
- this.addAllEntries();
-
- // Add a blank entry if needed
- if (this.model.length == 0) {
- this.model.add({});
- }
- return this;
- },
- createEntry: function () {
- this.model.add({});
- },
- addEntry: function(model) {
- var view = new App.Views.ListEntry({
- mode: this.mode,
- model: model,
- properties: this.properties,
- formTemplate: this.formTemplate
- });
- model.view = view;
- this.$fields.append(view.render().el);
- // Show remove buttons if needed
- if (this.model.length > 1) {
- this.$('button.remove').show();
- } else {
- this.$('button.remove').hide();
- }
- },
- addAllEntries: function() {
- this.model.each(this.addEntry, this);
- },
- fieldChanged: function(field) {
- // this.trigger('change', field);
- },
- entryRemoved: function(model) {
- // Hide Remove buttons if there is only one entry left
- if (this.model.length <= 1) {
- this.$('button.remove').hide();
- }
- }
- });
-
- App.Views.ListEntry = App.Views.AbstractView.extend({
- type: 'ContainerEntry',
- events: {
- 'click button.remove': 'removeEntry'
- },
- initialize: function() {
- this.properties = this.options.properties;
- this.formTemplate = this.options.formTemplate;
- this.mode = this.options.mode;
- this.fields = [];
- this.fieldHash = [];
- },
- validate: function(errorMode) {
- // Validate each field and return false if any return false
- return _.reduce(this.fields, function(memo, field) {
- return field.validate(errorMode) && memo;
- }, true);
- },
- render: function() {
- this.$el.addClass('entry');
- if (this.options.mode == 'Edit') {
- this.$el.append('<button class="remove" type="button">Remove</button>');
- }
-
- // Build fields.
- _.each(this.properties.fields, this.buildField, this);
-
- // Link up dependencies.
- _.each(this.fields, this.linkField, this);
- // Render fields.
- _.each(this.fields, this.renderField, this);
-
- // Populate fields.
- _.each(this.fields, this.populateField, this);
-
- return this;
- },
- // Build fields and attach to DOM.
- buildField: function (field) {
- var view = new App.Views[field.type]({
- mode: this.mode,
- properties: field,
- formTemplate: this.formTemplate,
- fieldid: field.id,
- model: this.model.get(field.id)
- });
- view.on('change', this.fieldChanged, this)
- this.fields.push(view);
- this.fieldHash[field.id] = view;
- this.$el.append(view.el);
- },
- // Link field dependencies.
- linkField: function (field) {
- if (field.properties.srcField) {
- var srcField = field.srcField || (field.srcField = this.fieldHash[field.properties.srcField]);
- srcField.on('ready', field.populate, field);
- }
- },
- // Render fields that don't have dependencies.
- renderField: function (field) {
- field.render();
- },
- // Populate the field
- populateField: function (field) {
- if (!field.srcField) {
- field.populate();
- }
- },
- // Remove this item from the model and DOM.
- removeEntry: function() {
- if (!confirm('Are you sure you want to remove this entry?')) {
- return;
- }
- this.model.destroy();
- this.remove();
- },
- fieldChanged: function(field) {
- this.model.set(field.options.fieldid, field.val());
- this.trigger('change', field);
- }
- });
-