//iTop Designer widget for editing properties line by line $(function() { // the widget definition, where "itop" is the namespace, // "property_field" the widget name $.widget( "itop.property_field", { // default options options: { parent_selector: null, field_id: '', submit_to: 'index.php', submit_parameters: {operation: 'async_action'}, do_apply: null, do_cancel: null, auto_apply: false }, // the constructor _create: function() { var me = this; this.element .addClass( "itop-property-field" ) .bind('apply_changes.itop-property-field', function(){me._do_apply();} ); this.bModified = false; if (this.options.field_id != '') { $('#'+this.options.field_id).bind('change.itop-property-field', function() { me._on_change(); }); this.value = this._get_field_value(); } this.element.find(".prop_apply").bind('click.itop-property-field', function() { me._do_apply(); }); this.element.find(".prop_cancel").bind('click.itop-property-field', function() { me._do_cancel(); }); this._refresh(); }, // called when created, and later when changing options _refresh: function() { if (this.bModified) { this.element.addClass("itop-property-field-modified"); this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: ''}); this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: ''}); } else { this.element.removeClass("itop-property-field-modified"); this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: 'hidden'}); this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: 'hidden'}); } }, // events bound via _bind are removed automatically // revert other modifications here _destroy: function() { this.element.removeClass( "itop-property-field" ); this.element.removeClass("itop-property-field-modified"); }, // _setOptions is called with a hash of all options that are changing // always refresh when changing options _setOptions: function() { // in 1.9 would use _superApply this._superApply(arguments); this._refresh(); }, // _setOption is called for each individual option that is changing _setOption: function( key, value ) { // in 1.9 would use _super this._superApply(arguments); }, _on_change: function() { var new_value = this._get_field_value(); if (new_value != this.value) { this.bModified = true; if (this.options.auto_apply) { this._do_apply(); } } else { this.bModified = false; } this._refresh(); }, _get_field_value: function() { var oField = $('#'+this.options.field_id); if (oField.attr('type') == 'checkbox') { return (oField.attr('checked') == 'checked'); } else { return oField.val(); } }, _get_committed_value: function() { return { name: $('#'+this.options.field_id).attr('name'), value: this.value }; }, _do_apply: function() { if (this.options.parent_selector) { $(this.options.parent_selector).trigger('mark_as_modified'); } if (this.options.do_apply) { // specific behavior... if (this.options.do_apply()) { this.bModified = false; this.previous_value = this.value; this.value = this._get_field_value(); this._refresh(); } } else { // Validate the field sFormId = this.element.closest('form').attr('id'); var oField = $('#'+this.options.field_id); oField.trigger('validate'); if ( $.inArray(this.options.field_id, oFormValidation[sFormId]) == -1) { this.bModified = false; this.previous_value = this.value; this.value = this._get_field_value(); this._do_submit(); this._refresh(); } } }, _do_cancel: function() { if (this.options.do_cancel) { // specific behavior... this.options.do_cancel(); } else { this.bModified = false; var oField = $('#'+this.options.field_id); if (oField.attr('type') == 'checkbox') { if (this.value) { oField.attr('checked', true); } else { oField.removeAttr('checked'); } } else { oField.val(this.value); } this._refresh(); oField.trigger('reverted', {type: 'designer', previous_value: this.value }); oField.trigger('validate'); } }, _do_submit: function() { var oData = {}; this.element.closest('form').find(':input[type=hidden]').each(function() { // Hidden form fields oData[$(this).attr('name')] = $(this).val(); }); this.element.closest('form').find('.itop-property-field').each(function() { var oWidget = $(this).data('property_field'); if (oWidget && oWidget._is_visible()) { var oVal = oWidget._get_committed_value(); oData[oVal.name] = oVal.value; } }); oPostedData = this.options.submit_parameters; oPostedData.params = oData; oPostedData.params.updated = [ $('#'+this.options.field_id).attr('name') ]; // only one field updated in this case oPostedData.params.previous_values = {}; oPostedData.params.previous_values[oPostedData.params.updated] = this.previous_value; // pass also the previous value(s) $.post(this.options.submit_to, oPostedData, function(data) { $('#prop_submit_result').html(data); }); }, _is_visible: function() { return this.element.parent().is(':visible'); } }); }); var oFormValidation = {}; function ValidateWithPattern(sFieldId, bMandatory, sPattern, sFormId) { var currentVal = $('#'+sFieldId).val(); var bValid = true; if (bMandatory && (currentVal == '')) { bValid = false; } if ((sPattern != '') && (currentVal != '')) { re = new RegExp(sPattern); bValid = re.test(currentVal); } if (oFormValidation[sFormId] == undefined) oFormValidation[sFormId] = []; if (!bValid) { $('#v_'+sFieldId).addClass('ui-state-error'); oFormValidation[sFormId].push(sFieldId); } else { $('#v_'+sFieldId).removeClass('ui-state-error'); // Remove the element from the array iFieldIdPos = oFormValidation[sFormId].indexOf(sFieldId); oFormValidation[sFormId].splice(iFieldIdPos, 1); } } function ValidateForm(sFormId, bValidateAll) { oFormValidation[sFormId] = []; if (bValidateAll) { $('#'+sFormId+' :input').trigger('validate'); } else { // Only the visible fields $('#'+sFormId+' :input:visible').each(function() { $(this).trigger('validate'); }); } return oFormValidation[sFormId]; } function ReadFormParams(sFormId) { var oMap = { }; $('#'+sFormId+' :input').each( function() { if ($(this).parent().is(':visible')) { var sName = $(this).attr('name'); if (sName && sName != '') { if (this.type == 'checkbox') { oMap[sName] = ($(this).attr('checked') == 'checked'); } else { oMap[sName] = $(this).val(); } } } }); return oMap; } function SubmitForm(sFormId, onSubmitResult) { var aErrors = ValidateForm(sFormId, false); if (aErrors.length == 0) { var oMap = ReadFormParams(sFormId); oMap.module_name = sCurrentModule; $('#'+sFormId+' :input').each( function() { if ($(this).parent().is(':visible')) { var sName = $(this).attr('name'); if (sName && sName != '') { if (this.type == 'checkbox') { oMap[sName] = ($(this).attr('checked') == 'checked'); } else { oMap[sName] = $(this).val(); } } } }); $.post(GetAbsoluteUrlAppRoot()+'designer/module.php', oMap, function(data) { onSubmitResult(data); }); } else { // TODO: better error reporting !!! alert('Please fill all the fields before continuing...'); } }