// setup namespace Zymonic.Field = {}; // setup cache and lookup Zymonic.FieldLookup = {}; function getZymonicField(ident) { return Zymonic.FieldLookup[ident]; } // setup cache on record, so can find fields in filter results Zymonic.FieldLookupByRecord = {}; function getZymonicRecordField(record_id, zname) { if (Zymonic.FieldLookupByRecord[record_id]) { return Zymonic.FieldLookupByRecord[record_id][zname]; } return null; } // similar cache on all fields in a record Zymonic.FieldsInRecord = {}; function getZymonicFieldsInRecord(record_id) { if (Zymonic.FieldsInRecord[record_id]) { return $(Zymonic.FieldsInRecord[record_id] || []); } return $([]); } // There is a potential issue here is that if a block refreshes and some // fields disappear then they will still be in the FieldLookupByBlock // cache - TODO consider clearing down on block load. Zymonic.FieldLookupByWrapperIdent = {}; function getZymonicFieldsByWrapperIdent(wIdent) { var fArray = new Array; if( Object.prototype.toString.call( Zymonic.FieldLookupByWrapperIdent[wIdent] ) === '[object Object]' ) { for(var i in Zymonic.FieldLookupByWrapperIdent[wIdent]) { fArray.push(Zymonic.FieldLookupByWrapperIdent[wIdent][i]); } } return fArray; } // base field // don't do anything here, makes it easy to establish inheritance Zymonic.Field.Field = function() {}; // add constants Zymonic.Field.Field.prototype.FIELD_CHANGED_CLASS = "ZymonicFieldChanged"; // init function Zymonic.Field.Field.prototype.init = function(args) { for (var key in args) { this[key] = args[key]; } this.validation_function = "validate_"+this.ident; // clear validation errors this.clearErrors(); // add to the lookups if (this.ident != "") { Zymonic.FieldLookup[this.ident] = this; this.addToWrapperLookup(); } if (this.js_ident && this.js_ident != "") { Zymonic.FieldLookup[this.js_ident] = this; } if (this.record) { this.addToRecordLookup(this.record.ident); } // Create a generic DefaultHandler event var field = this; if(this.ident != '') { this.input_elements().each(function(index) { field.addDefaultHandler.call(field, this); }); } }; Zymonic.Field.Field.prototype.addDefaultHandler = function(element) { var field = this; $(element).bind(this.defaultHandler, {}, function(event) { $(Zymonic).trigger(field.getIdent() + 'defaultHandler', [event]); }); $(element).focus(function() { field.container_div().addClass('hasFocus'); }); $(element).blur(function() { field.container_div().removeClass('hasFocus'); }); }; Zymonic.Field.Field.prototype.getZName = function() { return this.zname; }; Zymonic.Field.Field.prototype.getIdent = function() { return this.ident; }; Zymonic.Field.Field.prototype.addToWrapperLookup = function(ident) { if( !(Object.prototype.toString.call( Zymonic.FieldLookupByWrapperIdent[this.parent_form_ident] ) === '[object Object]') ) Zymonic.FieldLookupByWrapperIdent[this.parent_form_ident] = new Object; Zymonic.FieldLookupByWrapperIdent[this.parent_form_ident][this.ident] = this; }; Zymonic.Field.Field.prototype.getValue = function() { if (!this.hidden && (this.display_only || this.report_mode == "true")) { return this.display_only_element().text(); } else { return this.jquery().val(); } }; Zymonic.Field.Field.prototype.getValueURIEncoded = function() { return encodeURI(this.getValue()); }; Zymonic.Field.Field.prototype.setValue = function(value) { // do value changed checks this.setValueAsChanged(value); // be careful firing change event here // see linked field reverse fill for example of it if (this.report_mode == "true") { this.display_only_element().text(value); } else { this.jquery().val(value); } }; Zymonic.Field.Field.prototype.clearValue = function() { this.setValue(''); }; // set a field as having its value changed Zymonic.Field.Field.prototype.setValueAsChanged = function() { // TODO work out why original value is sometimes missing, // then can remove always setting for 'empty' fields. if (this.original_value && this.original_value == this.getValue()) { this.container_div().removeClass(this.FIELD_CHANGED_CLASS); } else { this.container_div().addClass(this.FIELD_CHANGED_CLASS); } }; // has a field had its value changed Zymonic.Field.Field.prototype.hasValueChanged = function(value) { // TODO: compare values in object // for now, check for the CSS class if (this.container_div().hasClass(this.FIELD_CHANGED_CLASS)) { return true; } else { return false; } }; // checks if this field is in a placeholder record Zymonic.Field.Field.prototype.inPlaceholder = function() { if (this.record && this.record.is_placeholder) { return true; } return false; }; //checks if this field is in a record on a multiple record form Zymonic.Field.Field.prototype.onMultipleRecordForm = function() { if (this.record && this.record.on_multiple_record_form) { return true; } return false; }; //checks if this field is in a placeholder record Zymonic.Field.Field.prototype.isBeingAdded = function() { if (this.record && this.record.being_added) { return true; } return false; }; // returns if this field needs validation as part of a submit Zymonic.Field.Field.prototype.needsValidationOnSubmit = function() { if ( this.onMultipleRecordForm() && this.inPlaceholder() ) { return false; } return true; }; /* Returns the input elements unless 'extra' is passed in, * in which case will return elements that have an id of * ident + extra */ Zymonic.Field.Field.prototype.jquery = function(extra) { extra = extra || ""; return $("#"+this.ident+extra); }; Zymonic.Field.Field.prototype.input_elements = function() { return this.jquery(); }; Zymonic.Field.Field.prototype.display_only_element = function() { return this.jquery("_display_only_value"); }; Zymonic.Field.Field.prototype.container_div = function() { return this.jquery("_div"); }; Zymonic.Field.Field.prototype.clearErrors = function() { this.errors = []; this.unique_errors = {}; this.has_errors = false; }; Zymonic.Field.Field.prototype.hasErrors = function() { return this.has_errors; }; Zymonic.Field.Field.prototype.setError = function(error) { if (!this.unique_errors[error]) { this.unique_errors[error] = true; this.errors.push(error); this.has_errors = true; } }; Zymonic.Field.Field.prototype.getError = function() { return this.errors.join(" "); }; Zymonic.Field.Field.prototype.validate = function(validOnly) { // call the validation function made by XSL if (window[this.validation_function]) { return window[this.validation_function]("field_validation", validOnly); } return true; }; Zymonic.Field.Field.prototype.addToRecordLookup = function(record_id) { if (!Zymonic.FieldLookupByRecord[record_id]) { Zymonic.FieldLookupByRecord[record_id] = {}; } // if we've already added this to the lookups, no need to add it again if (Zymonic.FieldLookupByRecord[record_id][this.zname]) { return; } Zymonic.FieldLookupByRecord[record_id][this.zname] = this; if (!Zymonic.FieldsInRecord[record_id]) { Zymonic.FieldsInRecord[record_id] = []; } Zymonic.FieldsInRecord[record_id].push(this); }; // reloads the current field via call to the server and puts it inplace of the existing fields // Params as per reload except ident which gives the html element to block and replace. Zymonic.Field.Field.prototype.reloadInPlace = function(extra_params, use_parent_form, save, validate, save_block_params, get_block_params, ident) { var wrapper_mode = true; if(!ident) { ident = this.ident+"_div"; wrapper_mode = false; } // reload with callbacks to trigger the XML var unblock = this.getBlock(ident); this.reload( // error handler function(field, can_continue, type, error) { unblock(); // can continue, display the error if (can_continue) { // TODO: trigger errors //field_server_validation_error_callback(zname, ident, null, type, error); } }, // success handler function(field, can_continue, xml) { unblock(); // can continue, replace the XML in place and unblock the GUI if (can_continue) { field.replaceWithTransformedXML(ident, xml, wrapper_mode); // If we're a search field then we probably need to refresh the results. if(field.search_field == 'true') { $(Zymonic).trigger(field.getIdent() + 'defaultHandler', []); } } }, // reload params extra_params, use_parent_form, save, validate, save_block_params, get_block_params ); } //This exists so that fields that need to do more complex processing of XML don't need to //override reloadInPlace. Zymonic.Field.Field.prototype.getBlock = function(ident) { return loading_gui_element(ident); }; // This exists so that fields that need to do more complex processing of XML don't need to // override reloadInPlace. Zymonic.Field.Field.prototype.replaceWithTransformedXML = function(ident, xml, wrapper_mode) { Zymonic.Utils.replaceWithTransformedXML($("#"+ident), xml, true, wrapper_mode); }; // Append to form data Zymonic.Field.Field.prototype.appendToForm = function(form_data, search) { var val = this.getValue(); // Send empty string instead of null if(!val) { val = ''; } if(search) { if(this.jquery('_check_empty').is(':checked')) { form_data.append(this.getIdent() + '_check_empty', 'true'); } else { form_data.append(this.getIdent() + '_check_empty', ''); } } if(!search || val !== null) { form_data.append(this.getIdent(), val); } this.appendOtherFieldsToForm(form_data, search); }; // Append other fields to form data Zymonic.Field.Field.prototype.appendOtherFieldsToForm = function(form_data, search) { // need to add any contained field values which have changed this.getFields().forEach(function(field) { field.appendToForm(form_data, search); }); }; // reloads the current field via call to the server and put the results in callbacks Zymonic.Field.Field.prototype.reload = function(error_cb, success_cb, extra_params, use_parent_form, save, validate, save_block_params, get_block_params) { // build list of params var form_data = new FormData(); this.appendToForm(form_data); // add field reload values form_data.append("ZZwebservicemode", "field"); form_data.append("ZZno_display_attributes","false"); form_data.append("ZZBzname", this.zname); form_data.append("ZZFident", this.ident); form_data.append("ZZFblock_id", this.block_id); form_data.append("ZZFparent_fap_from_block", 'true'); form_data.append("ZZFpage_id", this.page_id); form_data.append("ZZBprocess_id", this.process_id); form_data.append("ZZFform", this.parent_form_zname); form_data.append("ZZFform_ident", this.parent_form_ident); if (this.record) { form_data.append("ZZFrecord_ident", this.record.ident); } if (this.report_mode == 'true') { form_data.append("ZZFsubtype", "Report"); } else if (this.search_field == 'true') { form_data.append("ZZFsubtype", "Search"); } // set flags if (use_parent_form) { form_data.append("ZZFuse_parent_form", "true"); } if (save) { form_data.append("ZZFsave", "true"); } if (validate) { form_data.append("ZZFvalidate", "true"); } if (save_block_params) { form_data.append("ZZFsave_block_params","true"); } if (get_block_params) { form_data.append("ZZFget_block_params","true"); } // add extra params if (extra_params) { for (var i=0; i