/*+***********************************************************************************
* The contents of this file are subject to the vtiger CRM Public License Version 1.0
* ("License"); You may not use this file except in compliance with the License
* The Original Code is: vtiger CRM Open Source
* The Initial Developer of the Original Code is vtiger.
* Portions created by vtiger are Copyright (C) vtiger.
* All Rights Reserved.
*************************************************************************************/
jQuery.Class('Settings_LayoutEditor_Js', {
}, {
updatedBlockSequence : {},
reactiveFieldsList : [],
updatedRelatedList : {'updated' : [], 'deleted' : []},
removeModulesArray : false,
inActiveFieldsList : false,
updatedBlockFieldsList : [],
updatedBlocksList : [],
blockNamesList : [],
/**
* Function to set the removed modules array used in related list
*/
setRemovedModulesList : function() {
var thisInstance = this;
var relatedList = jQuery('#relatedTabOrder');
var container = relatedList.find('.relatedTabModulesList');
thisInstance.removeModulesArray = JSON.parse(container.find('.RemovedModulesListArray').val());
},
/**
* Function to set the inactive fields list used to show the inactive fields
*/
setInactiveFieldsList : function() {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
thisInstance.inActiveFieldsList = JSON.parse(contents.find('.inActiveFieldsArray').val());
},
/**
* Function to regiser the event to make the blocks sortable
*/
makeBlocksListSortable : function() {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
var table = contents.find('.blockSortable');
contents.sortable({
'containment' : contents,
'items' : table,
'revert' : true,
'tolerance':'pointer',
'cursor' : 'move',
'update' : function(e, ui) {
thisInstance.updateBlockSequence();
}
});
},
/**
* Function which will update block sequence
*/
updateBlockSequence : function() {
var thisInstance = this;
var progressIndicatorElement = jQuery.progressIndicator({
'position' : 'html',
'blockInfo' : {
'enabled' : true
}
});
var sequence = JSON.stringify(thisInstance.updateBlocksListByOrder());
var params = {};
params['module'] = app.getModuleName();
params['parent'] = app.getParentModuleName();
params['action'] = 'Block';
params['mode'] = 'updateSequenceNumber';
params['sequence'] = sequence;
AppConnector.request(params).then(
function(data) {
progressIndicatorElement.progressIndicator({'mode' : 'hide'});
var params = {};
params['text'] = app.vtranslate('JS_BLOCK_SEQUENCE_UPDATED');
Settings_Vtiger_Index_Js.showMessage(params);
},
function(error) {
progressIndicatorElement.progressIndicator({'mode' : 'hide'});
}
);
},
/**
* Function which will arrange the sequence number of blocks
*/
updateBlocksListByOrder : function() {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
contents.find('.editFieldsTable').each(function(index,domElement){
var blockTable = jQuery(domElement);
var blockId = blockTable.data('blockId');
var actualBlockSequence = blockTable.data('sequence');
var expectedBlockSequence = (index+1);
if(expectedBlockSequence != actualBlockSequence) {
blockTable.data('sequence', expectedBlockSequence);
}
thisInstance.updatedBlockSequence[blockId] = expectedBlockSequence;
});
return thisInstance.updatedBlockSequence;
},
/**
* Function to regiser the event to make the related modules sortable
*/
makeRelatedModuleSortable : function() {
var thisInstance = this;
var relatedModulesContainer = jQuery('#relatedTabOrder');
var modulesList = relatedModulesContainer.find('li.relatedModule');
relatedModulesContainer.sortable({
'containment' : relatedModulesContainer,
'items' : modulesList,
'revert' : true,
'tolerance':'pointer',
'cursor' : 'move',
'update' : function(e, ui) {
thisInstance.showSaveButton();
}
});
},
/**
* Function which will enable the save button in realted tabs list
*/
showSaveButton : function() {
var relatedList = jQuery('#relatedTabOrder');
var saveButton = relatedList.find('.saveRelatedList');
if(saveButton.attr('disabled') == 'disabled') {
saveButton.removeAttr('disabled');
}
},
/**
* Function which will disable the save button in related tabs list
*/
disableSaveButton : function() {
var relatedList = jQuery('#relatedTabOrder');
var saveButton = relatedList.find('.saveRelatedList');
saveButton.attr('disabled', 'disabled');
},
/**
* Function to register all the relatedList Events
*/
registerRelatedListEvents : function() {
var thisInstance = this;
var relatedList = jQuery('#relatedTabOrder');
var container = relatedList.find('.relatedTabModulesList');
var allModulesListArray = JSON.parse(container.find('.ModulesListArray').val());
var ulEle = container.find('ul.relatedModulesList');
var selectEle = container.find('[name="addToList"]');
app.showSelect2ElementView(selectEle, {maximumSelectionSize : 1, closeOnSelect : true, dropdownCss : {'z-index' : 0}});
selectEle.on('change', function() {
var selectedVal = selectEle.val();
var moduleLabel = allModulesListArray[selectedVal];
//remove the element if its already exists
ulEle.find('.module_'+selectedVal[0]).remove();
//append li element for the selected module
var liEle = container.find('.moduleCopy').clone(true, true);
liEle.data('relationId', selectedVal[0]).find('.moduleLabel').text(moduleLabel);
ulEle.append(liEle.removeClass('hide moduleCopy').addClass('relatedModule module_'+selectedVal[0]));
thisInstance.makeRelatedModuleSortable();
//remove that selected module from the select element
selectEle.select2('data',[]);
selectEle.find('option[value="'+selectedVal[0]+'"]').remove();
thisInstance.removeModulesArray.splice(thisInstance.removeModulesArray.indexOf(selectedVal[0]),1);
thisInstance.showSaveButton();
})
//register the event to click on close the related module
container.find('.close').one('click', function(e) {
var currentTarget = jQuery(e.currentTarget);
thisInstance.showSaveButton();
var liEle = currentTarget.closest('li.relatedModule');
var relationId = liEle.data('relationId');
var moduleLabel = liEle.find('.moduleLabel').text();
liEle.fadeOut('slow').addClass('deleted');
selectEle.append('');
})
//register click event for save related list button
relatedList.on('click', '.saveRelatedList', function(e) {
var currentTarget = jQuery(e.currentTarget);
if(currentTarget.attr('disabled') != 'disabled') {
thisInstance.disableSaveButton();
thisInstance.updatedRelatedList['deleted'] = [];
for(var key in thisInstance.removeModulesArray) {
thisInstance.updatedRelatedList['deleted'].push(thisInstance.removeModulesArray[key]);
}
thisInstance.saveRelatedListInfo();
}
})
},
/**
* Function to save the updated information in related list
*/
saveRelatedListInfo : function() {
var thisInstance = this;
var aDeferred = jQuery.Deferred();
var progressIndicatorElement = jQuery.progressIndicator({
'position' : 'html',
'blockInfo' : {
'enabled' : true
}
});
var params = {};
params['module'] = app.getModuleName();
params['parent'] = app.getParentModuleName();
params['action'] = 'Relation';
params['related_info'] = thisInstance.getUpdatedModulesInfo();
params['sourceModule'] = jQuery('#selectedModuleName').val();
AppConnector.request(params).then(
function(data) {
progressIndicatorElement.progressIndicator({'mode' : 'hide'});
var params = {};
params['text'] = app.vtranslate('JS_RELATED_INFO_SAVED');
Settings_Vtiger_Index_Js.showMessage(params);
aDeferred.resolve(data);
},
function(error) {
progressIndicatorElement.progressIndicator({'mode' : 'hide'});
aDeferred.reject(error);
}
);
return aDeferred.promise();
},
/**
* Function to get the updates happened with the related modules list
*/
getUpdatedModulesInfo : function() {
var thisInstance = this;
var relatedList = jQuery('#relatedTabOrder');
var removedModulesList = relatedList.find('li.relatedModule').filter('.deleted');
var updatedModulesList = relatedList.find('li.relatedModule').not('.deleted');
thisInstance.updatedRelatedList['updated'] = [];
//update deleted related modules list
removedModulesList.each(function(index,domElement) {
var relationId = jQuery(domElement).data('relationId');
thisInstance.updatedRelatedList['deleted'].push(relationId);
});
//update the existing related modules list
updatedModulesList.each(function(index,domElement){
var relationId = jQuery(domElement).data('relationId');
thisInstance.updatedRelatedList['updated'].push(relationId);
});
return thisInstance.updatedRelatedList;
},
/**
* Function to regiser the event to make the fields sortable
*/
makeFieldsListSortable : function() {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
var table = contents.find('.editFieldsTable');
table.find('ul[name=sortable1], ul[name=sortable2]').sortable({
'containment' : '#moduleBlocks',
'revert' : true,
'tolerance':'pointer',
'cursor' : 'move',
'connectWith' : '.connectedSortable',
'update' : function(e, ui) {
var currentField = ui['item'];
thisInstance.showSaveFieldSequenceButton();
thisInstance.createUpdatedBlocksList(currentField);
// rearrange the older block fields
if(ui.sender) {
var olderBlock = ui.sender.closest('.editFieldsTable');
thisInstance.reArrangeBlockFields(olderBlock);
}
}
});
},
/**
* Function to show the save button of fieldSequence
*/
showSaveFieldSequenceButton : function() {
var thisInstance = this;
var layout = jQuery('#detailViewLayout');
var saveButton = layout.find('.saveFieldSequence');
if(app.isHidden(saveButton)) {
thisInstance.updatedBlocksList = [];
thisInstance.updatedBlockFieldsList = [];
saveButton.removeClass('hide');
var params = {};
params['text'] = app.vtranslate('JS_SAVE_THE_CHANGES_TO_UPDATE_FIELD_SEQUENCE');
Settings_Vtiger_Index_Js.showMessage(params);
}
},
/**
* Function which will hide the saveFieldSequence button
*/
hideSaveFieldSequenceButton : function() {
var layout = jQuery('#detailViewLayout');
var saveButton = layout.find('.saveFieldSequence');
saveButton.addClass('hide');
},
/**
* Function to create the blocks list which are updated while sorting
*/
createUpdatedBlocksList : function(currentField) {
var thisInstance = this;
var block = currentField.closest('.editFieldsTable');
var updatedBlockId = block.data('blockId');
if(jQuery.inArray(updatedBlockId, thisInstance.updatedBlocksList) == -1) {
thisInstance.updatedBlocksList.push(updatedBlockId);
}
thisInstance.reArrangeBlockFields(block);
},
/**
* Function that rearranges fields in the block when the fields are moved
* @param block
*/
reArrangeBlockFields : function(block) {
// 1.get the containers, 2.compare the length, 3.if uneven then move the last element
var leftSideContainer = block.find('ul[name=sortable1]');
var rightSideContainer = block.find('ul[name=sortable2]');
if(leftSideContainer.children().length < rightSideContainer.children().length) {
var lastElementInRightContainer = rightSideContainer.children(':last');
leftSideContainer.append(lastElementInRightContainer);
} else if(leftSideContainer.children().length > rightSideContainer.children().length+1) { //greater than 1
var lastElementInLeftContainer = leftSideContainer.children(':last');
rightSideContainer.append(lastElementInLeftContainer);
}
},
/**
* Function to create the list of updated blocks with all the fields and their sequences
*/
createUpdatedBlockFieldsList : function() {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
for(var index in thisInstance.updatedBlocksList) {
var updatedBlockId = thisInstance.updatedBlocksList[index];
var updatedBlock = contents.find('.block_'+updatedBlockId);
var firstBlockSortFields = updatedBlock.find('ul[name=sortable1]');
var editFields = firstBlockSortFields.find('.editFields');
var expectedFieldSequence = 1;
editFields.each(function(i,domElement){
var fieldEle = jQuery(domElement);
var fieldId = fieldEle.data('fieldId');
thisInstance.updatedBlockFieldsList.push({'fieldid' : fieldId,'sequence' : expectedFieldSequence, 'block' : updatedBlockId});
expectedFieldSequence = expectedFieldSequence+2;
});
var secondBlockSortFields = updatedBlock.find('ul[name=sortable2]');
var secondEditFields = secondBlockSortFields.find('.editFields');
var sequenceValue = 2;
secondEditFields.each(function(i,domElement){
var fieldEle = jQuery(domElement);
var fieldId = fieldEle.data('fieldId');
thisInstance.updatedBlockFieldsList.push({'fieldid' : fieldId,'sequence' : sequenceValue, 'block' : updatedBlockId});
sequenceValue = sequenceValue+2;
});
}
},
/**
* Function to register click event for save button of fields sequence
*/
registerFieldSequenceSaveClick : function() {
var thisInstance = this;
var layout = jQuery('#detailViewLayout');
layout.on('click', '.saveFieldSequence', function() {
thisInstance.hideSaveFieldSequenceButton();
thisInstance.createUpdatedBlockFieldsList();
thisInstance.updateFieldSequence();
});
},
/**
* Function will save the field sequences
*/
updateFieldSequence : function() {
var thisInstance = this;
var progressIndicatorElement = jQuery.progressIndicator({
'position' : 'html',
'blockInfo' : {
'enabled' : true
}
});
var params = {};
params['module'] = app.getModuleName();
params['parent'] = app.getParentModuleName();
params['action'] = 'Field';
params['mode'] = 'move';
params['updatedFields'] = thisInstance.updatedBlockFieldsList;
AppConnector.request(params).then(
function(data) {
progressIndicatorElement.progressIndicator({'mode' : 'hide'});
window.location.reload();
var params = {};
params['text'] = app.vtranslate('JS_FIELD_SEQUENCE_UPDATED');
Settings_Vtiger_Index_Js.showMessage(params);
},
function(error) {
progressIndicatorElement.progressIndicator({'mode' : 'hide'});
}
);
},
/**
* Function to register click evnet add custom field button
*/
registerAddCustomFieldEvent : function() {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
contents.find('.addCustomField').click(function(e) {
var blockId = jQuery(e.currentTarget).closest('.editFieldsTable').data('blockId');
var addFieldContainer = contents.find('.createFieldModal').clone(true, true);
addFieldContainer.removeClass('hide');
var callBackFunction = function(data) {
//register all select2 Elements
app.showSelect2ElementView(data.find('select'));
var form = data.find('.createCustomFieldForm');
form.attr('id', 'createFieldForm');
var select2params = {tags: [],tokenSeparators: [","]}
app.showSelect2ElementView(form.find('[name="pickListValues"]'), select2params);
thisInstance.registerFieldTypeChangeEvent(form);
var params = app.getvalidationEngineOptions(true);
params.onValidationComplete = function(form, valid){
if(valid) {
var fieldTypeValue = jQuery('[name="fieldType"]',form).val();
if(fieldTypeValue == 'Picklist' || fieldTypeValue == 'MultiSelectCombo') {
var pickListValueElement = jQuery('#picklistUi',form);
var pickLisValues = pickListValueElement.val();
var pickListValuesArray = pickLisValues.split(',');
var pickListValuesArraySize = pickListValuesArray.length;
var specialChars = /["]/ ;
for(var i=0;i 0) {
var select2Element = app.getSelect2ElementFromSelect(pickListValueElement);
var message = app.vtranslate('JS_DUPLICATES_VALUES_FOUND');
select2Element.validationEngine('showPrompt', message , 'error','bottomLeft',true);
return false;
}
}
var saveButton = form.find(':submit');
saveButton.attr('disabled', 'disabled');
thisInstance.addCustomField(blockId, form).then(
function(data) {
var result = data['result'];
var params = {};
if(data['success']) {
app.hideModalWindow();
params['text'] = app.vtranslate('JS_CUSTOM_FIELD_ADDED');
Settings_Vtiger_Index_Js.showMessage(params);
thisInstance.showCustomField(result);
} else {
var message = data['error']['message'];
form.find('[name="fieldLabel"]').validationEngine('showPrompt', message , 'error','topLeft',true);
saveButton.removeAttr('disabled');
}
}
);
}
//To prevent form submit
return false;
}
form.validationEngine(params);
}
app.showModalWindow(addFieldContainer,function(data) {
if(typeof callBackFunction == 'function') {
callBackFunction(data);
}
}, {'width':'1000px'});
});
},
/**
* Function to create the array of block names list
*/
setBlocksListArray : function(form) {
var thisInstance = this;
thisInstance.blockNamesList = [];
var blocksListSelect = form.find('[name="beforeBlockId"]');
blocksListSelect.find('option').each(function(index, ele) {
var option = jQuery(ele);
var label = option.data('label');
thisInstance.blockNamesList.push(label);
})
},
/**
* Function to save the custom field details
*/
addCustomField : function(blockId, form) {
var thisInstance = this;
var modalHeader = form.closest('#globalmodal').find('.modal-header h3');
var aDeferred = jQuery.Deferred();
modalHeader.progressIndicator({smallLoadingImage : true, imageContainerCss : {display : 'inline', 'margin-left' : '18%',position : 'absolute'}});
var params = form.serializeFormData();
params['module'] = app.getModuleName();
params['parent'] = app.getParentModuleName();
params['action'] = 'Field';
params['mode'] = 'add';
params['blockid'] = blockId;
params['sourceModule'] = jQuery('#selectedModuleName').val();
AppConnector.request(params).then(
function(data) {
modalHeader.progressIndicator({'mode' : 'hide'});
aDeferred.resolve(data);
},
function(error) {
modalHeader.progressIndicator({'mode' : 'hide'});
aDeferred.reject(error);
}
);
return aDeferred.promise();
},
/**
* Function to register change event for fieldType while adding custom field
*/
registerFieldTypeChangeEvent : function(form) {
var thisInstance = this;
var lengthInput = form.find('[name="fieldLength"]');
//special validators while adding new field
var lengthValidator = [{'name' : 'DecimalMaxLength'}];
var maxLengthValidator = [{'name' : 'MaxLength'}];
var decimalValidator = [{'name' : 'FloatingDigits'}];
//By default add the max length validator
lengthInput.data('validator', maxLengthValidator);
//register the change event for field types
form.find('[name="fieldType"]').on('change', function(e) {
var currentTarget = jQuery(e.currentTarget);
var lengthInput = form.find('[name="fieldLength"]');
var selectedOption = currentTarget.find('option:selected');
//hide all the elements like length, decimal,picklist
form.find('.supportedType').addClass('hide');
if(selectedOption.data('lengthsupported')) {
form.find('.lengthsupported').removeClass('hide');
lengthInput.data('validator', maxLengthValidator);
}
if(selectedOption.data('decimalsupported')) {
var decimalFieldUi = form.find('.decimalsupported');
decimalFieldUi.removeClass('hide');
var decimalInput = decimalFieldUi.find('[name="decimal"]');
var maxFloatingDigits = selectedOption.data('maxfloatingdigits');
if(typeof maxFloatingDigits != "undefined") {
decimalInput.data('validator', decimalValidator);
lengthInput.data('validator', lengthValidator);
}
if(selectedOption.data('decimalreadonly')) {
decimalInput.val(maxFloatingDigits).attr('readonly', true);
} else {
decimalInput.removeAttr('readonly').val('');
}
}
if(selectedOption.data('predefinedvalueexists')) {
var pickListUi = form.find('.preDefinedValueExists');
pickListUi.removeClass('hide');
}
if(selectedOption.data('picklistoption')) {
var pickListOption = form.find('.picklistOption');
pickListOption.removeClass('hide');
}
})
},
/**
* Function to add new custom field ui to the list
*/
showCustomField : function(result) {
var thisInstance = this;
var contents = jQuery('#layoutEditorContainer').find('.contents');
var relatedBlock = contents.find('.block_'+result['blockid']);
var fieldCopy = contents.find('.newCustomFieldCopy').clone(true, true);
var fieldContainer = fieldCopy.find('div.marginLeftZero.border1px');
fieldContainer.addClass('opacity editFields').attr('data-field-id', result['id']).attr('data-block-id', result['blockid']);
fieldContainer.find('.deleteCustomField, .saveFieldDetails').attr('data-field-id', result['id']);
fieldContainer.find('.fieldLabel').html(result['label']);
if(!result['customField']){
fieldContainer.find('.deleteCustomField').remove();
}
var block = relatedBlock.find('.blockFieldsList');
var sortable1 = block.find('ul[name=sortable1]');
var length1 = sortable1.children().length;
var sortable2 = block.find('ul[name=sortable2]');
var length2 = sortable2.children().length;
// Deciding where to add the new field
if(length1 > length2) {
sortable2.append(fieldCopy.removeClass('hide newCustomFieldCopy'));
} else {
sortable1.append(fieldCopy.removeClass('hide newCustomFieldCopy'));
}
var form = fieldCopy.find('form.fieldDetailsForm');
thisInstance.setFieldDetails(result, form);
thisInstance.makeFieldsListSortable();
},
/**
* Function to set the field info for edit field actions
*/
setFieldDetails : function(result, form) {
var thisInstance = this;
//add field label to the field details
form.find('.modal-header').html(jQuery(''+result['label']+'