123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742 |
- //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: '',
- get_field_value: null,
- equals: null,
- submit_to: 'index.php',
- submit_parameters: {operation: 'async_action'},
- do_apply: null,
- do_cancel: null,
- auto_apply: false,
- can_apply: true
- },
-
- // 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 != '')
- {
- // In case there is an hidden input having the same id (somewhere else in the page), the change event does not occur unless the input loses the focus
- // To reduce the impact, let's handle keyup as well
- $('#'+this.options.field_id, this.element).bind('change.itop-property-field keyup.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");
- if (this.options.can_apply)
- {
- this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: ''});
- }
- else
- {
- 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: ''});
- }
- 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 (this._equals(new_value, this.value))
- {
- this.bModified = false;
- this._notify_as_clean(true);
- }
- else
- {
- this.bModified = true;
- if (this.options.auto_apply && this.options.can_apply)
- {
- this._do_apply();
- }
- else
- {
- this._notify_as_dirty();
- }
- }
- this._refresh();
- if (this.options.parent_selector)
- {
- $(this.options.parent_selector).trigger('subitem_changed');
- }
- },
- _notify_as_dirty: function()
- {
- this.element.closest('form').trigger('property_field_dirty', { id: this.options.field_id, reason: 'modified' });
- },
- _notify_as_clean: function(bRevert)
- {
- this.element.closest('form').trigger('property_field_clean', { id: this.options.field_id, reason: (bRevert ? 'revert' : 'apply') });
- },
- _equals: function( value1, value2 )
- {
- if (this.options.equals === null)
- {
- return value1 == value2;
- }
- else
- {
- return this.options.equals(value1, value2);
- }
- },
- _get_field_value: function()
- {
- if (this.options.get_field_value === null)
- {
- var oField = $('#'+this.options.field_id, this.element);
- if (oField.attr('type') == 'checkbox')
- {
- return (oField.attr('checked') == 'checked');
- }
- else
- {
- return oField.val();
- }
- }
- else
- {
- return this.options.get_field_value();
- }
- },
- get_field_value: function()
- {
- return this._get_field_value();
- },
- get_field_name: function()
- {
- return $('#'+this.options.field_id, this.element).attr('name');
- },
- _get_committed_value: function()
- {
- return { name: $('#'+this.options.field_id, this.element).attr('name'), value: this.value };
- },
- _get_current_value: function()
- {
- return { name: $('#'+this.options.field_id, this.element).attr('name'), value: this._get_field_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, this.element);
- 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();
- }
- }
- this._notify_as_clean(false);
- },
- _do_cancel: function()
- {
- if (this.options.do_cancel)
- {
- // specific behavior...
- this.options.do_cancel();
- }
- else
- {
- this.bModified = false;
- var oField = $('#'+this.options.field_id, this.element);
- 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');
- if (this.options.parent_selector)
- {
- $(this.options.parent_selector).trigger('subitem_changed');
- }
- }
- this._notify_as_clean(true);
- },
- _do_submit: function()
- {
- var oData = {};
- var me = this;
- 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 = me._get_widget($(this));
- 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, this.element).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.is(':visible');
- },
- mark_as_applied: function()
- {
- this.bModified = false;
- this.previous_value = this.value;
- this.value = this._get_field_value();
- this._refresh();
- },
- validate: function()
- {
- var oField = $('#'+this.options.field_id, this.element);
- oField.trigger('validate');
- },
- _get_widget: function(element)
- {
- var oWidget = element.data('itopProperty_field');
- if (oWidget == undefined)
- {
- oWidget = element.data('itopSelector_property_field');
- }
- return oWidget;
- }
- });
- });
- $(function()
- {
- // the widget definition, where "itop" is the namespace,
- // "selector_property_field" the widget name
- $.widget( "itop.selector_property_field", $.itop.property_field,
- {
- // default options
- options:
- {
- parent_selector: null,
- field_id: '',
- get_field_value: null,
- equals: null,
- submit_to: 'index.php',
- submit_parameters: {operation: 'async_action'},
- do_apply: null,
- do_cancel: null,
- auto_apply: false,
- can_apply: true,
- data_selector: ''
- },
-
- // the constructor
- _create: function()
- {
- var me = this;
- this._superApply();
-
- this.element
- .addClass( "itop-selector-property-field" );
-
- $('#'+this.options.field_id).bind('reverted init', function() {
- me._update_subform();
- }).trigger('init'); // initial refresh
-
- this.element.bind('subitem_changed', function() {
- me._on_subitem_changed();
- });
- },
- _update_subform: function()
- {
- var sSelector = this.options.data_selector;
- var me = this;
-
- // Mark all the direct children as hidden
- $('tr[data-selector="'+sSelector+'"]').attr('data-state', 'hidden');
- // Mark the selected one as visible
- var sSelectedHierarchy = sSelector+'-'+$('#'+this.options.field_id).val();
- $('tr[data-path="'+sSelectedHierarchy+'"]').attr('data-state', 'visible');
-
- // Show all items behind the current one
- $('tr[data-path^="'+sSelector+'"]').show();
- // Hide items behind the current one as soon as it is behind a hidden node (or itself is marked as hidden)
- $('tr[data-path^="'+sSelector+'"][data-state="hidden"]').each(function() {
- $(this).hide();
- var sPath = $(this).attr('data-path');
- $('tr[data-path^="'+sPath+'/"]').hide();
- });
- $('tr[data-path^="'+sSelector+'"]').each(function() {
- if($(this).is(':visible'))
- {
- var oWidget = me._get_widget($(this).closest('.itop-property-field'));
- if (oWidget)
- {
- try
- {
- oWidget._setOptions({can_apply: !me.bModified, parent_selector: '#'+me.element.attr('id') });
- oWidget.validate();
- }
- catch(e)
- {
- // Do nothing, form in read-only mode
- }
- }
- }
- });
- },
- // events bound via _bind are removed automatically
- // revert other modifications here
- _destroy: function()
- {
- this.element.removeClass( "itop-selector-property-field" );
- this._superApply();
- },
- _on_change: function()
- {
- var new_value = this._get_field_value();
- if (this._equals(new_value, this.value))
- {
- this.bModified = false;
- }
- else
- {
- this.bModified = true;
- }
-
- this._update_subform();
-
- if (this.options.auto_apply && this.options.can_apply)
- {
- this._do_apply();
- }
- this._on_subitem_changed(); // initial validation
- this._refresh();
- },
- _do_apply: function()
- {
- this._superApply();
- this._update_subform();
- },
- _do_submit: function()
- {
- var oData = {};
- this.element.closest('form').find(':input[type=hidden]').each(function()
- {
- // Hidden form fields
- oData[$(this).attr('name')] = $(this).val();
- });
- var sSelector = this.options.data_selector;
- var me = this;
- var aUpdated = [];
- $('tr[data-path^="'+sSelector+'"]').each(function() {
- if($(this).is(':visible'))
- {
- var oWidget = me._get_widget($(this).closest('.itop-property-field'));
- if (oWidget)
- {
- oWidget.mark_as_applied();
- sName = oWidget.get_field_name();
- if (typeof sName == 'string')
- {
- aUpdated.push(sName);
- }
- }
- }
- });
- this.element.closest('form').find('.itop-property-field').each(function()
- {
- var oWidget = me._get_widget($(this));
- if (oWidget && oWidget._is_visible())
- {
- var oVal = oWidget._get_committed_value();
- oData[oVal.name] = oVal.value;
- }
- });
- var oPostedData = this.options.submit_parameters;
- var sName = $('#'+this.options.field_id, this.element).attr('name');
- oPostedData.params = oData;
- oPostedData.params.updated = [];
- aUpdated.push(sName); // several fields updated in this case
- oPostedData.params.updated = aUpdated;
- oPostedData.params.previous_values = {};
- oPostedData.params.previous_values[sName] = this.previous_value; // pass also the previous value(s)
-
- $.post(this.options.submit_to, oPostedData, function(data)
- {
- $('#prop_submit_result').html(data);
- });
- },
- _on_subitem_changed : function()
- {
- sFormId = this.element.closest('form').attr('id');
- oFormValidation[sFormId] = [];
- this.options.can_apply = true;
- var sSelector = this.options.data_selector;
- var me = this;
- $('tr[data-path^="'+sSelector+'"]').each(function() {
- if($(this).is(':visible'))
- {
- var oWidget = me._get_widget($(this).closest('.itop-property-field'));
- if (oWidget)
- {
- oWidget.validate();
- }
- }
- });
- this.options.can_apply = (oFormValidation[sFormId].length == 0); // apply allowed only if no error
- this._refresh();
- }
- });
- });
- var oFormValidation = {};
- function ValidateWithPattern(sFieldId, bMandatory, sPattern, sFormId, aForbiddenValues)
- {
- var currentVal = $('#'+sFieldId).val();
- var bValid = true;
- var sMessage = null;
-
- if (bMandatory && (currentVal == ''))
- {
- bValid = false;
- }
- if ((sPattern != '') && (currentVal != ''))
- {
- re = new RegExp(sPattern);
- bValid = re.test(currentVal);
- }
- if (aForbiddenValues)
- {
- for(var i in aForbiddenValues)
- {
- for(j in aForbiddenValues[i].values)
- {
- if (aForbiddenValues[i].case_sensitive)
- {
- if (aForbiddenValues[i].values[j] == currentVal)
- {
- bValid = false;
- sMessage = aForbiddenValues[i].message;
- break;
- }
- }
- else
- {
- if (aForbiddenValues[i].values[j].toUpperCase() == currentVal.toUpperCase())
- {
- bValid = false;
- sMessage = aForbiddenValues[i].message;
- break;
- }
-
- }
- }
- }
- }
- if (oFormValidation[sFormId] == undefined) oFormValidation[sFormId] = [];
- if (!bValid)
- {
- $('#v_'+sFieldId).addClass('ui-state-error');
- iFieldIdPos = jQuery.inArray(sFieldId, oFormValidation[sFormId]);
- if (iFieldIdPos == -1)
- {
- oFormValidation[sFormId].push(sFieldId);
- }
- if (sMessage)
- {
- $('#'+sFieldId).attr('title', sMessage).tooltip();
- if ($('#'+sFieldId).is(":focus"))
- {
- $('#'+sFieldId).tooltip('open');
- }
- }
- }
- else
- {
- $('#v_'+sFieldId).removeClass('ui-state-error');
- if ($('#'+sFieldId).data('uiTooltip'))
- {
- $('#'+sFieldId).tooltip('close');
- }
- $('#'+sFieldId).removeAttr('title');
- // Remove the element from the array
- iFieldIdPos = jQuery.inArray(sFieldId, oFormValidation[sFormId]);
- if (iFieldIdPos > -1)
- {
- oFormValidation[sFormId].splice(iFieldIdPos, 1);
- }
- }
- }
- function ValidateInteger(sFieldId, bMandatory, sFormId, iMin, iMax, sExplainFormat)
- {
- var currentVal = $('#'+sFieldId).val();
- var bValid = true;
- var sMessage = null;
-
- if (bMandatory && (currentVal == ''))
- {
- bValid = false;
- }
- re = new RegExp('^$|^-?[0-9]+$');
- bValid = re.test(currentVal);
- if (bValid && (currentVal != ''))
- {
- // It is a valid number, let's check the boundaries
- var iValue = parseInt(currentVal, 10);
-
- if ((iMin != null) && (iValue < iMin))
- {
- bValid = false;
- }
-
- if ((iMax != null) && (iValue > iMax))
- {
- bValid = false;
- }
- if (!bValid && (sExplainFormat != undefined))
- {
- sMessage = sExplainFormat;
- }
- }
- if (oFormValidation[sFormId] == undefined) oFormValidation[sFormId] = [];
- if (!bValid)
- {
- $('#v_'+sFieldId).addClass('ui-state-error');
- iFieldIdPos = jQuery.inArray(sFieldId, oFormValidation[sFormId]);
- if (iFieldIdPos == -1)
- {
- oFormValidation[sFormId].push(sFieldId);
- }
- if (sMessage)
- {
- $('#'+sFieldId).attr('title', sMessage).tooltip();
- if ($('#'+sFieldId).is(":focus"))
- {
- $('#'+sFieldId).tooltip('open');
- }
- }
- }
- else
- {
- $('#v_'+sFieldId).removeClass('ui-state-error');
- if ($('#'+sFieldId).data('uiTooltip'))
- {
- $('#'+sFieldId).tooltip('close');
- }
- $('#'+sFieldId).removeAttr('title');
- // Remove the element from the array
- iFieldIdPos = jQuery.inArray(sFieldId, oFormValidation[sFormId]);
- if (iFieldIdPos > -1)
- {
- 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') && !$(this).prop('disabled'))
- {
- var sName = $(this).attr('name');
- if (sName && sName != '')
- {
- if (this.type == 'checkbox')
- {
- oMap[sName] = ($(this).attr('checked') == 'checked');
- }
- else if (this.type == 'radio')
- {
- if ($(this).prop('checked'))
- {
- oMap[sName] = $(this).val();
- }
- }
- 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...');
- }
- }
- function RemoveSubForm(sId, sUrl, oParams)
- {
- $.post(sUrl, oParams, function(data) {
- $('body').append(data);
- });
- }
- function AddSubForm(sId, sUrl, oParams)
- {
- var aIndexes = JSON.parse($('#'+sId).val());
- var iLast = aIndexes[aIndexes.length - 1];
- var iNewIdx = 1 + iLast;
- oParams.new_index = iNewIdx;
-
- $.post(sUrl, oParams, function(data) {
- $('body').append(data);
- });
- }
|