[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 /*+*********************************************************************************** 2 * The contents of this file are subject to the vtiger CRM Public License Version 1.0 3 * ("License"); You may not use this file except in compliance with the License 4 * The Original Code is: vtiger CRM Open Source 5 * The Initial Developer of the Original Code is vtiger. 6 * Portions created by vtiger are Copyright (C) vtiger. 7 * All Rights Reserved. 8 *************************************************************************************/ 9 jQuery.Class('Settings_LayoutEditor_Js', { 10 11 }, { 12 updatedBlockSequence : {}, 13 14 reactiveFieldsList : [], 15 16 updatedRelatedList : {'updated' : [], 'deleted' : []}, 17 18 removeModulesArray : false, 19 20 inActiveFieldsList : false, 21 22 updatedBlockFieldsList : [], 23 24 updatedBlocksList : [], 25 26 blockNamesList : [], 27 28 /** 29 * Function to set the removed modules array used in related list 30 */ 31 setRemovedModulesList : function() { 32 var thisInstance = this; 33 var relatedList = jQuery('#relatedTabOrder'); 34 var container = relatedList.find('.relatedTabModulesList'); 35 thisInstance.removeModulesArray = JSON.parse(container.find('.RemovedModulesListArray').val()); 36 }, 37 38 /** 39 * Function to set the inactive fields list used to show the inactive fields 40 */ 41 setInactiveFieldsList : function() { 42 var thisInstance = this; 43 var contents = jQuery('#layoutEditorContainer').find('.contents'); 44 thisInstance.inActiveFieldsList = JSON.parse(contents.find('.inActiveFieldsArray').val()); 45 }, 46 47 /** 48 * Function to regiser the event to make the blocks sortable 49 */ 50 makeBlocksListSortable : function() { 51 var thisInstance = this; 52 var contents = jQuery('#layoutEditorContainer').find('.contents'); 53 var table = contents.find('.blockSortable'); 54 contents.sortable({ 55 'containment' : contents, 56 'items' : table, 57 'revert' : true, 58 'tolerance':'pointer', 59 'cursor' : 'move', 60 'update' : function(e, ui) { 61 thisInstance.updateBlockSequence(); 62 } 63 }); 64 }, 65 66 /** 67 * Function which will update block sequence 68 */ 69 updateBlockSequence : function() { 70 var thisInstance = this; 71 var progressIndicatorElement = jQuery.progressIndicator({ 72 'position' : 'html', 73 'blockInfo' : { 74 'enabled' : true 75 } 76 }); 77 78 var sequence = JSON.stringify(thisInstance.updateBlocksListByOrder()); 79 var params = {}; 80 params['module'] = app.getModuleName(); 81 params['parent'] = app.getParentModuleName(); 82 params['action'] = 'Block'; 83 params['mode'] = 'updateSequenceNumber'; 84 params['sequence'] = sequence; 85 86 AppConnector.request(params).then( 87 function(data) { 88 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 89 var params = {}; 90 params['text'] = app.vtranslate('JS_BLOCK_SEQUENCE_UPDATED'); 91 Settings_Vtiger_Index_Js.showMessage(params); 92 }, 93 function(error) { 94 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 95 } 96 ); 97 }, 98 99 /** 100 * Function which will arrange the sequence number of blocks 101 */ 102 updateBlocksListByOrder : function() { 103 var thisInstance = this; 104 var contents = jQuery('#layoutEditorContainer').find('.contents'); 105 contents.find('.editFieldsTable').each(function(index,domElement){ 106 var blockTable = jQuery(domElement); 107 var blockId = blockTable.data('blockId'); 108 var actualBlockSequence = blockTable.data('sequence'); 109 var expectedBlockSequence = (index+1); 110 111 if(expectedBlockSequence != actualBlockSequence) { 112 blockTable.data('sequence', expectedBlockSequence); 113 } 114 thisInstance.updatedBlockSequence[blockId] = expectedBlockSequence; 115 }); 116 return thisInstance.updatedBlockSequence; 117 }, 118 119 /** 120 * Function to regiser the event to make the related modules sortable 121 */ 122 makeRelatedModuleSortable : function() { 123 var thisInstance = this; 124 var relatedModulesContainer = jQuery('#relatedTabOrder'); 125 var modulesList = relatedModulesContainer.find('li.relatedModule'); 126 relatedModulesContainer.sortable({ 127 'containment' : relatedModulesContainer, 128 'items' : modulesList, 129 'revert' : true, 130 'tolerance':'pointer', 131 'cursor' : 'move', 132 'update' : function(e, ui) { 133 thisInstance.showSaveButton(); 134 } 135 }); 136 }, 137 138 /** 139 * Function which will enable the save button in realted tabs list 140 */ 141 showSaveButton : function() { 142 var relatedList = jQuery('#relatedTabOrder'); 143 var saveButton = relatedList.find('.saveRelatedList'); 144 if(saveButton.attr('disabled') == 'disabled') { 145 saveButton.removeAttr('disabled'); 146 } 147 }, 148 149 /** 150 * Function which will disable the save button in related tabs list 151 */ 152 disableSaveButton : function() { 153 var relatedList = jQuery('#relatedTabOrder'); 154 var saveButton = relatedList.find('.saveRelatedList'); 155 saveButton.attr('disabled', 'disabled'); 156 }, 157 158 /** 159 * Function to register all the relatedList Events 160 */ 161 registerRelatedListEvents : function() { 162 var thisInstance = this; 163 var relatedList = jQuery('#relatedTabOrder'); 164 var container = relatedList.find('.relatedTabModulesList'); 165 var allModulesListArray = JSON.parse(container.find('.ModulesListArray').val()); 166 var ulEle = container.find('ul.relatedModulesList'); 167 168 var selectEle = container.find('[name="addToList"]'); 169 app.showSelect2ElementView(selectEle, {maximumSelectionSize : 1, closeOnSelect : true, dropdownCss : {'z-index' : 0}}); 170 selectEle.on('change', function() { 171 var selectedVal = selectEle.val(); 172 var moduleLabel = allModulesListArray[selectedVal]; 173 //remove the element if its already exists 174 ulEle.find('.module_'+selectedVal[0]).remove(); 175 176 //append li element for the selected module 177 var liEle = container.find('.moduleCopy').clone(true, true); 178 liEle.data('relationId', selectedVal[0]).find('.moduleLabel').text(moduleLabel); 179 ulEle.append(liEle.removeClass('hide moduleCopy').addClass('relatedModule module_'+selectedVal[0])); 180 thisInstance.makeRelatedModuleSortable(); 181 182 //remove that selected module from the select element 183 selectEle.select2('data',[]); 184 selectEle.find('option[value="'+selectedVal[0]+'"]').remove(); 185 186 thisInstance.removeModulesArray.splice(thisInstance.removeModulesArray.indexOf(selectedVal[0]),1); 187 thisInstance.showSaveButton(); 188 }) 189 190 //register the event to click on close the related module 191 container.find('.close').one('click', function(e) { 192 var currentTarget = jQuery(e.currentTarget); 193 thisInstance.showSaveButton(); 194 var liEle = currentTarget.closest('li.relatedModule'); 195 var relationId = liEle.data('relationId'); 196 var moduleLabel = liEle.find('.moduleLabel').text(); 197 liEle.fadeOut('slow').addClass('deleted'); 198 selectEle.append('<option value="'+relationId+'">'+moduleLabel+'</option>'); 199 }) 200 201 //register click event for save related list button 202 relatedList.on('click', '.saveRelatedList', function(e) { 203 var currentTarget = jQuery(e.currentTarget); 204 if(currentTarget.attr('disabled') != 'disabled') { 205 thisInstance.disableSaveButton(); 206 thisInstance.updatedRelatedList['deleted'] = []; 207 for(var key in thisInstance.removeModulesArray) { 208 thisInstance.updatedRelatedList['deleted'].push(thisInstance.removeModulesArray[key]); 209 } 210 thisInstance.saveRelatedListInfo(); 211 } 212 }) 213 }, 214 215 /** 216 * Function to save the updated information in related list 217 */ 218 saveRelatedListInfo : function() { 219 var thisInstance = this; 220 var aDeferred = jQuery.Deferred(); 221 var progressIndicatorElement = jQuery.progressIndicator({ 222 'position' : 'html', 223 'blockInfo' : { 224 'enabled' : true 225 } 226 }); 227 228 var params = {}; 229 params['module'] = app.getModuleName(); 230 params['parent'] = app.getParentModuleName(); 231 params['action'] = 'Relation'; 232 params['related_info'] = thisInstance.getUpdatedModulesInfo(); 233 params['sourceModule'] = jQuery('#selectedModuleName').val(); 234 235 AppConnector.request(params).then( 236 function(data) { 237 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 238 var params = {}; 239 params['text'] = app.vtranslate('JS_RELATED_INFO_SAVED'); 240 Settings_Vtiger_Index_Js.showMessage(params); 241 aDeferred.resolve(data); 242 }, 243 function(error) { 244 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 245 aDeferred.reject(error); 246 } 247 ); 248 return aDeferred.promise(); 249 }, 250 251 /** 252 * Function to get the updates happened with the related modules list 253 */ 254 getUpdatedModulesInfo : function() { 255 var thisInstance = this; 256 var relatedList = jQuery('#relatedTabOrder'); 257 var removedModulesList = relatedList.find('li.relatedModule').filter('.deleted'); 258 var updatedModulesList = relatedList.find('li.relatedModule').not('.deleted'); 259 thisInstance.updatedRelatedList['updated'] = []; 260 261 //update deleted related modules list 262 removedModulesList.each(function(index,domElement) { 263 var relationId = jQuery(domElement).data('relationId'); 264 thisInstance.updatedRelatedList['deleted'].push(relationId); 265 }); 266 //update the existing related modules list 267 updatedModulesList.each(function(index,domElement){ 268 var relationId = jQuery(domElement).data('relationId'); 269 thisInstance.updatedRelatedList['updated'].push(relationId); 270 }); 271 return thisInstance.updatedRelatedList; 272 }, 273 274 /** 275 * Function to regiser the event to make the fields sortable 276 */ 277 makeFieldsListSortable : function() { 278 var thisInstance = this; 279 var contents = jQuery('#layoutEditorContainer').find('.contents'); 280 var table = contents.find('.editFieldsTable'); 281 table.find('ul[name=sortable1], ul[name=sortable2]').sortable({ 282 'containment' : '#moduleBlocks', 283 'revert' : true, 284 'tolerance':'pointer', 285 'cursor' : 'move', 286 'connectWith' : '.connectedSortable', 287 'update' : function(e, ui) { 288 var currentField = ui['item']; 289 thisInstance.showSaveFieldSequenceButton(); 290 thisInstance.createUpdatedBlocksList(currentField); 291 // rearrange the older block fields 292 if(ui.sender) { 293 var olderBlock = ui.sender.closest('.editFieldsTable'); 294 thisInstance.reArrangeBlockFields(olderBlock); 295 } 296 } 297 }); 298 }, 299 300 /** 301 * Function to show the save button of fieldSequence 302 */ 303 showSaveFieldSequenceButton : function() { 304 var thisInstance = this; 305 var layout = jQuery('#detailViewLayout'); 306 var saveButton = layout.find('.saveFieldSequence'); 307 if(app.isHidden(saveButton)) { 308 thisInstance.updatedBlocksList = []; 309 thisInstance.updatedBlockFieldsList = []; 310 saveButton.removeClass('hide'); 311 var params = {}; 312 params['text'] = app.vtranslate('JS_SAVE_THE_CHANGES_TO_UPDATE_FIELD_SEQUENCE'); 313 Settings_Vtiger_Index_Js.showMessage(params); 314 } 315 }, 316 317 /** 318 * Function which will hide the saveFieldSequence button 319 */ 320 hideSaveFieldSequenceButton : function() { 321 var layout = jQuery('#detailViewLayout'); 322 var saveButton = layout.find('.saveFieldSequence'); 323 saveButton.addClass('hide'); 324 }, 325 326 /** 327 * Function to create the blocks list which are updated while sorting 328 */ 329 createUpdatedBlocksList : function(currentField) { 330 var thisInstance = this; 331 var block = currentField.closest('.editFieldsTable'); 332 var updatedBlockId = block.data('blockId'); 333 if(jQuery.inArray(updatedBlockId, thisInstance.updatedBlocksList) == -1) { 334 thisInstance.updatedBlocksList.push(updatedBlockId); 335 } 336 thisInstance.reArrangeBlockFields(block); 337 }, 338 339 /** 340 * Function that rearranges fields in the block when the fields are moved 341 * @param <jQuery object> block 342 */ 343 reArrangeBlockFields : function(block) { 344 // 1.get the containers, 2.compare the length, 3.if uneven then move the last element 345 var leftSideContainer = block.find('ul[name=sortable1]'); 346 var rightSideContainer = block.find('ul[name=sortable2]'); 347 if(leftSideContainer.children().length < rightSideContainer.children().length) { 348 var lastElementInRightContainer = rightSideContainer.children(':last'); 349 leftSideContainer.append(lastElementInRightContainer); 350 } else if(leftSideContainer.children().length > rightSideContainer.children().length+1) { //greater than 1 351 var lastElementInLeftContainer = leftSideContainer.children(':last'); 352 rightSideContainer.append(lastElementInLeftContainer); 353 } 354 }, 355 /** 356 * Function to create the list of updated blocks with all the fields and their sequences 357 */ 358 createUpdatedBlockFieldsList : function() { 359 var thisInstance = this; 360 var contents = jQuery('#layoutEditorContainer').find('.contents'); 361 362 for(var index in thisInstance.updatedBlocksList) { 363 var updatedBlockId = thisInstance.updatedBlocksList[index]; 364 var updatedBlock = contents.find('.block_'+updatedBlockId); 365 var firstBlockSortFields = updatedBlock.find('ul[name=sortable1]'); 366 var editFields = firstBlockSortFields.find('.editFields'); 367 var expectedFieldSequence = 1; 368 editFields.each(function(i,domElement){ 369 var fieldEle = jQuery(domElement); 370 var fieldId = fieldEle.data('fieldId'); 371 thisInstance.updatedBlockFieldsList.push({'fieldid' : fieldId,'sequence' : expectedFieldSequence, 'block' : updatedBlockId}); 372 expectedFieldSequence = expectedFieldSequence+2; 373 }); 374 var secondBlockSortFields = updatedBlock.find('ul[name=sortable2]'); 375 var secondEditFields = secondBlockSortFields.find('.editFields'); 376 var sequenceValue = 2; 377 secondEditFields.each(function(i,domElement){ 378 var fieldEle = jQuery(domElement); 379 var fieldId = fieldEle.data('fieldId'); 380 thisInstance.updatedBlockFieldsList.push({'fieldid' : fieldId,'sequence' : sequenceValue, 'block' : updatedBlockId}); 381 sequenceValue = sequenceValue+2; 382 }); 383 } 384 }, 385 386 /** 387 * Function to register click event for save button of fields sequence 388 */ 389 registerFieldSequenceSaveClick : function() { 390 var thisInstance = this; 391 var layout = jQuery('#detailViewLayout'); 392 layout.on('click', '.saveFieldSequence', function() { 393 thisInstance.hideSaveFieldSequenceButton(); 394 thisInstance.createUpdatedBlockFieldsList(); 395 thisInstance.updateFieldSequence(); 396 }); 397 }, 398 399 /** 400 * Function will save the field sequences 401 */ 402 updateFieldSequence : function() { 403 var thisInstance = this; 404 var progressIndicatorElement = jQuery.progressIndicator({ 405 'position' : 'html', 406 'blockInfo' : { 407 'enabled' : true 408 } 409 }); 410 var params = {}; 411 params['module'] = app.getModuleName(); 412 params['parent'] = app.getParentModuleName(); 413 params['action'] = 'Field'; 414 params['mode'] = 'move'; 415 params['updatedFields'] = thisInstance.updatedBlockFieldsList; 416 417 AppConnector.request(params).then( 418 function(data) { 419 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 420 window.location.reload(); 421 var params = {}; 422 params['text'] = app.vtranslate('JS_FIELD_SEQUENCE_UPDATED'); 423 Settings_Vtiger_Index_Js.showMessage(params); 424 }, 425 function(error) { 426 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 427 } 428 ); 429 }, 430 431 /** 432 * Function to register click evnet add custom field button 433 */ 434 registerAddCustomFieldEvent : function() { 435 var thisInstance = this; 436 var contents = jQuery('#layoutEditorContainer').find('.contents'); 437 contents.find('.addCustomField').click(function(e) { 438 var blockId = jQuery(e.currentTarget).closest('.editFieldsTable').data('blockId'); 439 var addFieldContainer = contents.find('.createFieldModal').clone(true, true); 440 addFieldContainer.removeClass('hide'); 441 442 var callBackFunction = function(data) { 443 //register all select2 Elements 444 app.showSelect2ElementView(data.find('select')); 445 446 var form = data.find('.createCustomFieldForm'); 447 form.attr('id', 'createFieldForm'); 448 var select2params = {tags: [],tokenSeparators: [","]} 449 app.showSelect2ElementView(form.find('[name="pickListValues"]'), select2params); 450 451 thisInstance.registerFieldTypeChangeEvent(form); 452 453 var params = app.getvalidationEngineOptions(true); 454 params.onValidationComplete = function(form, valid){ 455 if(valid) { 456 var fieldTypeValue = jQuery('[name="fieldType"]',form).val(); 457 if(fieldTypeValue == 'Picklist' || fieldTypeValue == 'MultiSelectCombo') { 458 var pickListValueElement = jQuery('#picklistUi',form); 459 var pickLisValues = pickListValueElement.val(); 460 var pickListValuesArray = pickLisValues.split(','); 461 var pickListValuesArraySize = pickListValuesArray.length; 462 var specialChars = /["]/ ; 463 for(var i=0;i<pickListValuesArray.length;i++) { 464 if (specialChars.test(pickListValuesArray[i])) { 465 var select2Element = app.getSelect2ElementFromSelect(pickListValueElement); 466 var message = app.vtranslate('JS_SPECIAL_CHARACTERS')+' " '+app.vtranslate('JS_NOT_ALLOWED'); 467 select2Element.validationEngine('showPrompt', message , 'error','bottomLeft',true); 468 return false; 469 } 470 } 471 var lowerCasedpickListValuesArray = jQuery.map(pickListValuesArray, function(item, index) { 472 return item.toLowerCase(); 473 }); 474 var uniqueLowerCasedpickListValuesArray = jQuery.unique(lowerCasedpickListValuesArray); 475 var uniqueLowerCasedpickListValuesArraySize = uniqueLowerCasedpickListValuesArray.length; 476 var arrayDiffSize = pickListValuesArraySize-uniqueLowerCasedpickListValuesArraySize; 477 if(arrayDiffSize > 0) { 478 var select2Element = app.getSelect2ElementFromSelect(pickListValueElement); 479 var message = app.vtranslate('JS_DUPLICATES_VALUES_FOUND'); 480 select2Element.validationEngine('showPrompt', message , 'error','bottomLeft',true); 481 return false; 482 } 483 484 } 485 var saveButton = form.find(':submit'); 486 saveButton.attr('disabled', 'disabled'); 487 thisInstance.addCustomField(blockId, form).then( 488 function(data) { 489 var result = data['result']; 490 var params = {}; 491 if(data['success']) { 492 app.hideModalWindow(); 493 params['text'] = app.vtranslate('JS_CUSTOM_FIELD_ADDED'); 494 Settings_Vtiger_Index_Js.showMessage(params); 495 thisInstance.showCustomField(result); 496 } else { 497 var message = data['error']['message']; 498 form.find('[name="fieldLabel"]').validationEngine('showPrompt', message , 'error','topLeft',true); 499 saveButton.removeAttr('disabled'); 500 } 501 } 502 ); 503 } 504 //To prevent form submit 505 return false; 506 } 507 form.validationEngine(params); 508 } 509 510 app.showModalWindow(addFieldContainer,function(data) { 511 if(typeof callBackFunction == 'function') { 512 callBackFunction(data); 513 } 514 }, {'width':'1000px'}); 515 }); 516 }, 517 518 /** 519 * Function to create the array of block names list 520 */ 521 setBlocksListArray : function(form) { 522 var thisInstance = this; 523 thisInstance.blockNamesList = []; 524 var blocksListSelect = form.find('[name="beforeBlockId"]'); 525 blocksListSelect.find('option').each(function(index, ele) { 526 var option = jQuery(ele); 527 var label = option.data('label'); 528 thisInstance.blockNamesList.push(label); 529 }) 530 }, 531 532 /** 533 * Function to save the custom field details 534 */ 535 addCustomField : function(blockId, form) { 536 var thisInstance = this; 537 var modalHeader = form.closest('#globalmodal').find('.modal-header h3'); 538 var aDeferred = jQuery.Deferred(); 539 540 modalHeader.progressIndicator({smallLoadingImage : true, imageContainerCss : {display : 'inline', 'margin-left' : '18%',position : 'absolute'}}); 541 542 var params = form.serializeFormData(); 543 params['module'] = app.getModuleName(); 544 params['parent'] = app.getParentModuleName(); 545 params['action'] = 'Field'; 546 params['mode'] = 'add'; 547 params['blockid'] = blockId; 548 params['sourceModule'] = jQuery('#selectedModuleName').val(); 549 550 AppConnector.request(params).then( 551 function(data) { 552 modalHeader.progressIndicator({'mode' : 'hide'}); 553 aDeferred.resolve(data); 554 }, 555 function(error) { 556 modalHeader.progressIndicator({'mode' : 'hide'}); 557 aDeferred.reject(error); 558 } 559 ); 560 return aDeferred.promise(); 561 }, 562 563 /** 564 * Function to register change event for fieldType while adding custom field 565 */ 566 registerFieldTypeChangeEvent : function(form) { 567 var thisInstance = this; 568 var lengthInput = form.find('[name="fieldLength"]'); 569 570 //special validators while adding new field 571 var lengthValidator = [{'name' : 'DecimalMaxLength'}]; 572 var maxLengthValidator = [{'name' : 'MaxLength'}]; 573 var decimalValidator = [{'name' : 'FloatingDigits'}]; 574 575 //By default add the max length validator 576 lengthInput.data('validator', maxLengthValidator); 577 578 //register the change event for field types 579 form.find('[name="fieldType"]').on('change', function(e) { 580 var currentTarget = jQuery(e.currentTarget); 581 var lengthInput = form.find('[name="fieldLength"]'); 582 var selectedOption = currentTarget.find('option:selected'); 583 584 //hide all the elements like length, decimal,picklist 585 form.find('.supportedType').addClass('hide'); 586 587 if(selectedOption.data('lengthsupported')) { 588 form.find('.lengthsupported').removeClass('hide'); 589 lengthInput.data('validator', maxLengthValidator); 590 } 591 592 if(selectedOption.data('decimalsupported')) { 593 var decimalFieldUi = form.find('.decimalsupported'); 594 decimalFieldUi.removeClass('hide'); 595 596 var decimalInput = decimalFieldUi.find('[name="decimal"]'); 597 var maxFloatingDigits = selectedOption.data('maxfloatingdigits'); 598 599 if(typeof maxFloatingDigits != "undefined") { 600 decimalInput.data('validator', decimalValidator); 601 lengthInput.data('validator', lengthValidator); 602 } 603 604 if(selectedOption.data('decimalreadonly')) { 605 decimalInput.val(maxFloatingDigits).attr('readonly', true); 606 } else { 607 decimalInput.removeAttr('readonly').val(''); 608 } 609 } 610 611 if(selectedOption.data('predefinedvalueexists')) { 612 var pickListUi = form.find('.preDefinedValueExists'); 613 pickListUi.removeClass('hide'); 614 } 615 if(selectedOption.data('picklistoption')) { 616 var pickListOption = form.find('.picklistOption'); 617 pickListOption.removeClass('hide'); 618 } 619 }) 620 }, 621 622 /** 623 * Function to add new custom field ui to the list 624 */ 625 showCustomField : function(result) { 626 var thisInstance = this; 627 var contents = jQuery('#layoutEditorContainer').find('.contents'); 628 var relatedBlock = contents.find('.block_'+result['blockid']); 629 var fieldCopy = contents.find('.newCustomFieldCopy').clone(true, true); 630 var fieldContainer = fieldCopy.find('div.marginLeftZero.border1px'); 631 fieldContainer.addClass('opacity editFields').attr('data-field-id', result['id']).attr('data-block-id', result['blockid']); 632 fieldContainer.find('.deleteCustomField, .saveFieldDetails').attr('data-field-id', result['id']); 633 fieldContainer.find('.fieldLabel').html(result['label']); 634 if(!result['customField']){ 635 fieldContainer.find('.deleteCustomField').remove(); 636 } 637 var block = relatedBlock.find('.blockFieldsList'); 638 var sortable1 = block.find('ul[name=sortable1]'); 639 var length1 = sortable1.children().length; 640 var sortable2 = block.find('ul[name=sortable2]'); 641 var length2 = sortable2.children().length; 642 // Deciding where to add the new field 643 if(length1 > length2) { 644 sortable2.append(fieldCopy.removeClass('hide newCustomFieldCopy')); 645 } else { 646 sortable1.append(fieldCopy.removeClass('hide newCustomFieldCopy')); 647 } 648 var form = fieldCopy.find('form.fieldDetailsForm'); 649 thisInstance.setFieldDetails(result, form); 650 thisInstance.makeFieldsListSortable(); 651 }, 652 653 /** 654 * Function to set the field info for edit field actions 655 */ 656 setFieldDetails : function(result, form) { 657 var thisInstance = this; 658 //add field label to the field details 659 form.find('.modal-header').html(jQuery('<strong>'+result['label']+'</strong><div class="pull-right"><a href="javascript:void(0)" class="cancel">X</a></div>')); 660 661 var defaultValueUi = form.find('.defaultValueUi'); 662 if(result['mandatory']) { 663 form.find('[name="mandatory"]').filter(':checkbox').attr('checked', true); 664 } 665 if(result['presence']) { 666 form.find('[name="presence"]').filter(':checkbox').attr('checked', true); 667 } 668 if(result['quickcreate']) { 669 form.find('[name="quickcreate"]').filter(':checkbox').attr('checked', true); 670 } 671 if(result['isQuickCreateDisabled']) { 672 form.find('[name="quickcreate"]').filter(':checkbox').attr('readonly', 'readonly').addClass('optionDisabled'); 673 } 674 if(result['isSummaryField']) { 675 form.find('[name="summaryfield"]').filter(':checkbox').attr('checked', true); 676 } 677 if(result['isSummaryFieldDisabled']) { 678 form.find('[name="summaryfield"]').filter(':checkbox').attr('readonly', 'readonly').addClass('optionDisabled'); 679 } 680 if(result['masseditable']) { 681 form.find('[name="masseditable"]').filter(':checkbox').attr('checked', true); 682 } 683 if(result['isMassEditDisabled']) { 684 form.find('[name="masseditable"]').filter(':checkbox').attr('readonly', 'readonly').addClass('optionDisabled'); 685 } 686 if(result['isDefaultValueDisabled']) { 687 form.find('[name="defaultvalue"]').filter(':checkbox').attr('readonly', 'readonly').addClass('optionDisabled'); 688 } 689 if(result['defaultvalue']) { 690 form.find('[name="defaultvalue"]').filter(':checkbox').attr('checked', true); 691 defaultValueUi.removeClass('zeroOpacity'); 692 } else { 693 defaultValueUi.addClass('zeroOpacity'); 694 } 695 //based on the field model it will give the respective ui for the field 696 var fieldModel = Vtiger_Field_Js.getInstance(result); 697 var fieldUi = fieldModel.getUiTypeSpecificHtml(); 698 defaultValueUi.html(fieldUi); 699 defaultValueUi.find('.chzn-select').removeClass('chzn-select'); 700 701 //Handled Time field UI 702 var timeField = defaultValueUi.find('.timepicker-default'); 703 timeField.removeClass('timePicker timepicker-default'); 704 timeField.attr('data-toregister','time'); 705 706 //Handled date field UI 707 var dateField = defaultValueUi.find('.dateField') 708 dateField.removeClass('dateField'); 709 dateField.attr('data-toregister','date'); 710 711 defaultValueUi.find('[data-validation-engine]').attr('data-validation-engine','validate[required,funcCall[Vtiger_Base_Validator_Js.invokeValidation]]'); 712 defaultValueUi.find('[name*='+result['name']+']').attr('name', 'fieldDefaultValue'); 713 defaultValueUi.find('[name="fieldDefaultValue"]').attr('disabled','disabled'); 714 defaultValueUi.find('input').addClass('input-medium'); 715 defaultValueUi.find('.select2').addClass('row-fluid'); 716 }, 717 718 /** 719 * Function to register click event for add custom block button 720 */ 721 registerAddCustomBlockEvent : function() { 722 var thisInstance = this; 723 var contents = jQuery('#layoutEditorContainer').find('.contents'); 724 contents.find('.addCustomBlock').click(function(e) { 725 var addBlockContainer = contents.find('.addBlockModal').clone(true, true); 726 727 var callBackFunction = function(data) { 728 data.find('.addBlockModal').removeClass('hide'); 729 //register all select2 Elements 730 app.showSelect2ElementView(data.find('select')); 731 732 var form = data.find('.addCustomBlockForm'); 733 thisInstance.setBlocksListArray(form); 734 var fieldLabel = form.find('[name="label"]'); 735 var params = app.validationEngineOptions; 736 params.onValidationComplete = function(form, valid){ 737 if(valid) { 738 var formData = form.serializeFormData(); 739 if(jQuery.inArray(formData['label'], thisInstance.blockNamesList) == -1) { 740 thisInstance.saveBlockDetails(form).then( 741 function(data) { 742 var params = {}; 743 if(data['success']) { 744 var result = data['result']; 745 thisInstance.displayNewCustomBlock(result); 746 thisInstance.updateNewSequenceForBlocks(result['sequenceList']); 747 thisInstance.appendNewBlockToBlocksList(result, form); 748 thisInstance.makeFieldsListSortable(); 749 750 params['text'] = app.vtranslate('JS_CUSTOM_BLOCK_ADDED'); 751 } else { 752 params['text'] = data['error']['message']; 753 params['type'] = 'error'; 754 } 755 Settings_Vtiger_Index_Js.showMessage(params); 756 } 757 ); 758 app.hideModalWindow(); 759 return valid; 760 } else { 761 var result = app.vtranslate('JS_BLOCK_NAME_EXISTS'); 762 fieldLabel.validationEngine('showPrompt', result , 'error','topLeft',true); 763 e.preventDefault(); 764 return; 765 } 766 } 767 } 768 form.validationEngine(params); 769 770 form.submit(function(e) { 771 e.preventDefault(); 772 }) 773 } 774 app.showModalWindow(addBlockContainer,function(data) { 775 if(typeof callBackFunction == 'function') { 776 callBackFunction(data); 777 } 778 }, {'width':'1000px'}); 779 }); 780 }, 781 782 /** 783 * Function to save the new custom block details 784 */ 785 saveBlockDetails : function(form) { 786 var thisInstance = this; 787 var aDeferred = jQuery.Deferred(); 788 var progressIndicatorElement = jQuery.progressIndicator({ 789 'position' : 'html', 790 'blockInfo' : { 791 'enabled' : true 792 } 793 }); 794 var params = form.serializeFormData(); 795 params['module'] = app.getModuleName(); 796 params['parent'] = app.getParentModuleName(); 797 params['sourceModule'] = jQuery('#selectedModuleName').val(); 798 params['action'] = 'Block'; 799 params['mode'] = 'save'; 800 801 AppConnector.request(params).then( 802 function(data) { 803 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 804 aDeferred.resolve(data); 805 }, 806 function(error) { 807 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 808 aDeferred.reject(error); 809 } 810 ); 811 return aDeferred.promise(); 812 }, 813 814 /** 815 * Function used to display the new custom block ui after save 816 */ 817 displayNewCustomBlock : function(result) { 818 var thisInstance = this; 819 var contents = jQuery('#layoutEditorContainer').find('.contents'); 820 var beforeBlockId = result['beforeBlockId']; 821 var beforeBlock = contents.find('.block_'+beforeBlockId); 822 823 var newBlockCloneCopy = contents.find('.newCustomBlockCopy').clone(true, true); 824 newBlockCloneCopy.data('blockId', result['id']).find('.blockLabel').append(jQuery('<strong>'+result['label']+'</strong>')); 825 newBlockCloneCopy.find('.blockVisibility').data('blockId', result['id']); 826 if(result['isAddCustomFieldEnabled']) { 827 newBlockCloneCopy.find('.addCustomField').removeClass('hide'); 828 } 829 beforeBlock.after(newBlockCloneCopy.removeClass('hide newCustomBlockCopy').addClass('editFieldsTable block_'+result['id'])); 830 831 newBlockCloneCopy.find('.blockFieldsList').sortable({'connectWith' : '.blockFieldsList'}); 832 }, 833 834 /** 835 * Function to update the sequence for all blocks after adding new Block 836 */ 837 updateNewSequenceForBlocks : function(sequenceList) { 838 var contents = jQuery('#layoutEditorContainer').find('.contents'); 839 jQuery.each(sequenceList, function(blockId, sequence) { 840 contents.find('.block_'+blockId).data('sequence', sequence); 841 }); 842 }, 843 844 /** 845 * Function to update the block list with the new block label in the clone container 846 */ 847 appendNewBlockToBlocksList : function(result, form) { 848 var contents = jQuery('#layoutEditorContainer').find('.contents'); 849 var hiddenAddBlockModel = contents.find('.addBlockModal'); 850 var blocksListSelect = hiddenAddBlockModel.find('[name="beforeBlockId"]'); 851 var option = jQuery("<option>",{ 852 value: result['id'], 853 text: result['label'] 854 }) 855 blocksListSelect.append(option.attr('data-label', result['label'])); 856 }, 857 858 /** 859 * Function to update the block list to remove the deleted custom block label in the clone container 860 */ 861 removeBlockFromBlocksList : function(blockId) { 862 var contents = jQuery('#layoutEditorContainer').find('.contents'); 863 var hiddenAddBlockModel = contents.find('.addBlockModal'); 864 var blocksListSelect = hiddenAddBlockModel.find('[name="beforeBlockId"]'); 865 blocksListSelect.find('option[value="'+blockId+'"]').remove(); 866 }, 867 868 /** 869 * Function to register the change event for block visibility 870 */ 871 registerBlockVisibilityEvent : function() { 872 var thisInstance = this; 873 var contents = jQuery('#layoutEditorContainer').find('.contents'); 874 contents.on('click', 'li.blockVisibility', function(e) { 875 var currentTarget = jQuery(e.currentTarget); 876 var oldDisplayStatus = currentTarget.data('visible'); 877 if(oldDisplayStatus == '0') { 878 currentTarget.find('.icon-ok').removeClass('hide'); 879 currentTarget.data('visible', '1'); 880 } else { 881 currentTarget.find('.icon-ok').addClass('hide'); 882 currentTarget.data('visible', '0'); 883 } 884 thisInstance.updateBlockStatus(currentTarget); 885 }) 886 }, 887 888 /** 889 * Function to save the changed visibility for the block 890 */ 891 updateBlockStatus : function(currentTarget) { 892 var thisInstance = this; 893 var blockStatus = currentTarget.data('visible'); 894 var progressIndicatorElement = jQuery.progressIndicator({ 895 'position' : 'html', 896 'blockInfo' : { 897 'enabled' : true 898 } 899 }); 900 var params = {}; 901 params['module'] = app.getModuleName(); 902 params['parent'] = app.getParentModuleName(); 903 params['sourceModule'] = jQuery('#selectedModuleName').val(); 904 params['action'] = 'Block'; 905 params['mode'] = 'save'; 906 params['blockid'] = currentTarget.data('blockId'); 907 params['display_status'] = blockStatus; 908 909 AppConnector.request(params).then( 910 function(data) { 911 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 912 var params = {}; 913 if(blockStatus == '1') { 914 params['text'] = app.vtranslate('JS_BLOCK_VISIBILITY_SHOW'); 915 } else { 916 params['text'] = app.vtranslate('JS_BLOCK_VISIBILITY_HIDE'); 917 } 918 Settings_Vtiger_Index_Js.showMessage(params); 919 }, 920 function(error) { 921 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 922 } 923 ); 924 }, 925 926 /** 927 * Function to register the click event for inactive fields list 928 */ 929 registerInactiveFieldsEvent : function() { 930 var thisInstance = this; 931 var contents = jQuery('#layoutEditorContainer').find('.contents'); 932 contents.on('click', 'li.inActiveFields', function(e) { 933 var currentTarget = jQuery(e.currentTarget); 934 var currentBlock = currentTarget.closest('.editFieldsTable'); 935 var blockId = currentBlock.data('blockId'); 936 //If there are no hidden fields, show pnotify 937 if(jQuery.isEmptyObject(thisInstance.inActiveFieldsList[blockId])) { 938 var params = {}; 939 params['text'] = app.vtranslate('JS_NO_HIDDEN_FIELDS_EXISTS'); 940 params['type'] = 'error'; 941 Settings_Vtiger_Index_Js.showMessage(params); 942 } else { 943 var inActiveFieldsContainer = contents.find('.inactiveFieldsModal').clone(true, true); 944 945 var callBackFunction = function(data) { 946 data.find('.inactiveFieldsModal').removeClass('hide'); 947 thisInstance.reactiveFieldsList = []; 948 var form = data.find('.inactiveFieldsForm'); 949 thisInstance.showHiddenFields(blockId, form); 950 //register click event for reactivate button in the inactive fields modal 951 data.find('[name="reactivateButton"]').click(function(e) { 952 thisInstance.createReactivateFieldslist(blockId, form); 953 thisInstance.reActivateHiddenFields(currentBlock); 954 app.hideModalWindow(); 955 }); 956 } 957 958 app.showModalWindow(inActiveFieldsContainer,function(data) { 959 if(typeof callBackFunction == 'function') { 960 callBackFunction(data); 961 } 962 }, {'width':'1000px'}); 963 } 964 }); 965 966 }, 967 968 /** 969 * Function to show the list of inactive fields in the modal 970 */ 971 showHiddenFields : function(blockId, form) { 972 var thisInstance = this; 973 jQuery.each(thisInstance.inActiveFieldsList[blockId], function(key, value) { 974 var inActiveField = jQuery('<div class="span4 marginLeftZero padding-bottom1per"><label class="checkbox">\n\ 975 <input type="checkbox" class="inActiveField" value="'+key+'" /> '+value+'</label></div>'); 976 form.find('.inActiveList').append(inActiveField); 977 }); 978 }, 979 980 /** 981 * Function to create the list of reactivate fields list 982 */ 983 createReactivateFieldslist : function(blockId, form) { 984 var thisInstance = this; 985 form.find('.inActiveField').each(function(index,domElement){ 986 var element = jQuery(domElement); 987 var fieldId = element.val(); 988 if(element.is(':checked')) { 989 delete thisInstance.inActiveFieldsList[blockId][fieldId]; 990 thisInstance.reactiveFieldsList.push(fieldId); 991 } 992 }); 993 }, 994 995 /** 996 * Function to unHide the selected fields in the inactive fields modal 997 */ 998 reActivateHiddenFields : function(currentBlock) { 999 var thisInstance = this; 1000 var progressIndicatorElement = jQuery.progressIndicator({ 1001 'position' : 'html', 1002 'blockInfo' : { 1003 'enabled' : true 1004 } 1005 }); 1006 var params = {}; 1007 params['module'] = app.getModuleName(); 1008 params['parent'] = app.getParentModuleName(); 1009 params['action'] = 'Field'; 1010 params['mode'] = 'unHide'; 1011 params['blockId'] = currentBlock.data('blockId'); 1012 params['fieldIdList'] = JSON.stringify(thisInstance.reactiveFieldsList); 1013 1014 AppConnector.request(params).then( 1015 function(data) { 1016 for(var index in data.result) { 1017 thisInstance.showCustomField(data.result[index]); 1018 } 1019 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1020 var params = {}; 1021 params['text'] = app.vtranslate('JS_SELECTED_FIELDS_REACTIVATED'); 1022 Settings_Vtiger_Index_Js.showMessage(params); 1023 }, 1024 function(error) { 1025 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1026 } 1027 ); 1028 }, 1029 /** 1030 * Function to register the click event for delete custom block 1031 */ 1032 registerDeleteCustomBlockEvent : function() { 1033 var thisInstance = this; 1034 var contents = jQuery('#layoutEditorContainer').find('.contents'); 1035 var table = contents.find('.editFieldsTable'); 1036 contents.on('click', 'li.deleteCustomBlock', function(e) { 1037 var currentTarget = jQuery(e.currentTarget); 1038 var table = currentTarget.closest('div.editFieldsTable'); 1039 var blockId = table.data('blockId'); 1040 1041 var message = app.vtranslate('JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_DELETE'); 1042 Vtiger_Helper_Js.showConfirmationBox({'message' : message}).then( 1043 function(e) { 1044 thisInstance.deleteCustomBlock(blockId); 1045 }, 1046 function(error, err){ 1047 1048 } 1049 ); 1050 }); 1051 }, 1052 1053 /** 1054 * Function to delete the custom block 1055 */ 1056 deleteCustomBlock : function(blockId) { 1057 var thisInstance = this; 1058 var progressIndicatorElement = jQuery.progressIndicator({ 1059 'position' : 'html', 1060 'blockInfo' : { 1061 'enabled' : true 1062 } 1063 }); 1064 1065 var params = {}; 1066 params['module'] = app.getModuleName(); 1067 params['parent'] = app.getParentModuleName(); 1068 params['action'] = 'Block'; 1069 params['mode'] = 'delete'; 1070 params['blockid'] = blockId; 1071 1072 AppConnector.request(params).then( 1073 function(data) { 1074 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1075 var params = {}; 1076 if(data['success']) { 1077 thisInstance.removeDeletedBlock(blockId); 1078 thisInstance.removeBlockFromBlocksList(blockId); 1079 params['text'] = app.vtranslate('JS_CUSTOM_BLOCK_DELETED'); 1080 } else { 1081 params['text'] = data['error']['message']; 1082 params['type'] = 'error'; 1083 } 1084 Settings_Vtiger_Index_Js.showMessage(params); 1085 }, 1086 function(error) { 1087 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1088 } 1089 ); 1090 }, 1091 1092 /** 1093 * Function to remove the deleted custom block from the ui 1094 */ 1095 removeDeletedBlock : function(blockId) { 1096 var contents = jQuery('#layoutEditorContainer').find('.contents'); 1097 var deletedTable = contents.find('.block_'+blockId); 1098 deletedTable.fadeOut('slow').remove(); 1099 }, 1100 1101 /** 1102 * Function to register the click event for delete custom field 1103 */ 1104 registerDeleteCustomFieldEvent : function(contents) { 1105 var thisInstance = this; 1106 if(typeof contents == 'undefined') { 1107 contents = jQuery('#layoutEditorContainer').find('.contents'); 1108 } 1109 contents.find('a.deleteCustomField').click(function(e) { 1110 var currentTarget = jQuery(e.currentTarget); 1111 var fieldId = currentTarget.data('fieldId'); 1112 var message = app.vtranslate('JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_DELETE'); 1113 Vtiger_Helper_Js.showConfirmationBox({'message' : message}).then( 1114 function(e) { 1115 thisInstance.deleteCustomField(fieldId).then( 1116 function(data) { 1117 var field = currentTarget.closest('div.editFields'); 1118 var blockId = field.data('blockId'); 1119 field.parent().fadeOut('slow').remove(); 1120 var block = jQuery('#block_'+blockId); 1121 thisInstance.reArrangeBlockFields(block); 1122 var params = {}; 1123 params['text'] = app.vtranslate('JS_CUSTOM_FIELD_DELETED'); 1124 Settings_Vtiger_Index_Js.showMessage(params); 1125 },function(error, err) { 1126 1127 } 1128 ); 1129 }, 1130 function(error, err){ 1131 1132 } 1133 ); 1134 }); 1135 }, 1136 1137 /** 1138 * Function to delete the custom field 1139 */ 1140 deleteCustomField : function(fieldId) { 1141 var thisInstance = this; 1142 var aDeferred = jQuery.Deferred(); 1143 var progressIndicatorElement = jQuery.progressIndicator({ 1144 'position' : 'html', 1145 'blockInfo' : { 1146 'enabled' : true 1147 } 1148 }); 1149 1150 var params = {}; 1151 params['module'] = app.getModuleName(); 1152 params['parent'] = app.getParentModuleName(); 1153 params['action'] = 'Field'; 1154 params['mode'] = 'delete'; 1155 params['fieldid'] = fieldId; 1156 1157 AppConnector.request(params).then( 1158 function(data) { 1159 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1160 aDeferred.resolve(data); 1161 }, 1162 function(error) { 1163 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1164 aDeferred.reject(); 1165 } 1166 ); 1167 return aDeferred.promise(); 1168 }, 1169 1170 1171 /** 1172 * Function to register the click event for save button after edit field details 1173 */ 1174 registerSaveFieldDetailsEvent : function(form) { 1175 var thisInstance = this; 1176 var submitButtton = form.find('.saveFieldDetails'); 1177 var fieldId = submitButtton.data('fieldId'); 1178 var block = submitButtton.closest('.editFieldsTable'); 1179 var blockId = block.data('blockId'); 1180 //close the drop down 1181 submitButtton.closest('.btn-group').removeClass('open'); 1182 //adding class opacity to fieldRow - to give opacity to the actions of the fields 1183 var fieldRow = submitButtton.closest('.editFields'); 1184 fieldRow.addClass('opacity'); 1185 1186 thisInstance.saveFieldDetails(submitButtton).then( 1187 function(data) { 1188 var result = data['result']; 1189 var fieldLabel = fieldRow.find('.fieldLabel'); 1190 if(result['presence'] == '1') { 1191 fieldRow.parent().fadeOut('slow').remove(); 1192 1193 if(jQuery.isEmptyObject(thisInstance.inActiveFieldsList[blockId])) { 1194 if(thisInstance.inActiveFieldsList.length == '0') { 1195 thisInstance.inActiveFieldsList = {}; 1196 } 1197 thisInstance.inActiveFieldsList[blockId] = {}; 1198 thisInstance.inActiveFieldsList[blockId][fieldId] = result['label']; 1199 } else { 1200 thisInstance.inActiveFieldsList[blockId][fieldId] = result['label']; 1201 } 1202 thisInstance.reArrangeBlockFields(block); 1203 } 1204 if(result['mandatory']) { 1205 if(fieldLabel.find('.redColor').length == '0') { 1206 fieldRow.find('.fieldLabel').append(jQuery('<span class="redColor">*</span>')); 1207 } 1208 } else { 1209 fieldRow.find('.fieldLabel').find('.redColor').remove(); 1210 } 1211 1212 //updating the hidden container with saved values. 1213 var dropDownMenu = form.closest('.dropdown-menu'); 1214 app.destroyChosenElement(form); 1215 var selectElemet = form.find('.defaultValueUi ').find('select'); 1216 var selectedvalue = selectElemet.val(); 1217 selectElemet.removeAttr('disabled'); 1218 selectElemet.find('option').removeAttr('selected'); 1219 if(selectedvalue != null ){ 1220 if(typeof(selectElemet.attr('multiple')) == 'undefined'){ 1221 var encodedSelectedValue = selectedvalue.replace(/"/g, '\\"'); 1222 selectElemet.find('[value="'+encodedSelectedValue+'"]').attr('selected','selected'); 1223 } else { 1224 for (var i = 0; i < selectedvalue.length; i++) { 1225 var encodedSelectedValue = selectedvalue[i].replace(/"/g, '\\"'); 1226 selectElemet.find('[value="'+encodedSelectedValue+'"]').attr('selected','selected'); 1227 } 1228 } 1229 } 1230 //handled registration of time field 1231 var timeFieldElement = form.find('[data-toregister="time"]'); 1232 if(timeFieldElement.length > 0){ 1233 app.destroyTimeFields(timeFieldElement); 1234 } 1235 var basicContents = form.closest('.editFields').find('.basicFieldOperations'); 1236 basicContents.html(form); 1237 dropDownMenu.remove(); 1238 }, 1239 function(error, err) { 1240 1241 } 1242 ); 1243 }, 1244 1245 /** 1246 * Function to save all the field details which are changed 1247 */ 1248 saveFieldDetails : function(currentTarget) { 1249 var thisInstance = this; 1250 var aDeferred = jQuery.Deferred(); 1251 var form = currentTarget.closest('form.fieldDetailsForm'); 1252 var fieldId = currentTarget.data('fieldId'); 1253 var defaultValueField = form.find('[name=fieldDefaultValue]'); 1254 var defaultValue = defaultValueField.val(); 1255 var progressIndicatorElement = jQuery.progressIndicator({ 1256 'position' : 'html', 1257 'blockInfo' : { 1258 'enabled' : true 1259 } 1260 }); 1261 1262 var params = form.serializeFormData(); 1263 params['module'] = app.getModuleName(); 1264 params['parent'] = app.getParentModuleName(); 1265 params['action'] = 'Field'; 1266 params['mode'] = 'save'; 1267 params['fieldid'] = fieldId; 1268 params['sourceModule'] = jQuery('#selectedModuleName').val(); 1269 1270 AppConnector.request(params).then( 1271 function(data) { 1272 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1273 var params = {}; 1274 params['text'] = app.vtranslate('JS_FIELD_DETAILS_SAVED'); 1275 Settings_Vtiger_Index_Js.showMessage(params); 1276 if(defaultValueField.prop("tagName") == 'TEXTAREA') { 1277 defaultValueField.text(defaultValue); 1278 } 1279 aDeferred.resolve(data); 1280 }, 1281 function(error) { 1282 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1283 aDeferred.reject(); 1284 } 1285 ); 1286 return aDeferred.promise(); 1287 }, 1288 1289 /** 1290 * Function to register the cahnge event for mandatory & default checkboxes in edit field details 1291 */ 1292 registerFieldDetailsChange : function(contents) { 1293 if(typeof contents == 'undefined') { 1294 contents = jQuery('#layoutEditorContainer').find('.contents'); 1295 } 1296 contents.on('change', '[name="mandatory"]', function(e) { 1297 var currentTarget = jQuery(e.currentTarget); 1298 if(currentTarget.attr('readonly') != 'readonly') { 1299 var form = currentTarget.closest('.fieldDetailsForm'); 1300 var quickcreateEle = form.find('[name="quickcreate"]').filter(':checkbox').not('.optionDisabled'); 1301 var presenceEle = form.find('[name="presence"]').filter(':checkbox').not('.optionDisabled'); 1302 if(currentTarget.is(':checked')) { 1303 quickcreateEle.attr('checked', true).attr('readonly', 'readonly'); 1304 presenceEle.attr('checked', true).attr('readonly', 'readonly'); 1305 } else { 1306 quickcreateEle.removeAttr('readonly'); 1307 presenceEle.removeAttr('readonly'); 1308 } 1309 } 1310 }) 1311 1312 contents.on('change', '[name="defaultvalue"]', function(e) { 1313 var currentTarget = jQuery(e.currentTarget); 1314 var defaultValueUi = currentTarget.closest('span').find('.defaultValueUi'); 1315 var defaultField = defaultValueUi.find('[name="fieldDefaultValue"]'); 1316 if(currentTarget.is(':checked')) { 1317 defaultValueUi.removeClass('zeroOpacity'); 1318 defaultField.removeAttr('disabled'); 1319 if(defaultField.is('select')){ 1320 defaultField.trigger("liszt:updated"); 1321 } 1322 } else { 1323 defaultField.attr('disabled', 'disabled'); 1324 // defaultField.val(''); 1325 defaultValueUi.addClass('zeroOpacity'); 1326 } 1327 }) 1328 1329 }, 1330 1331 /** 1332 * Function to register the click event for related modules list tab 1333 */ 1334 relatedModulesTabClickEvent : function() { 1335 var thisInstance = this; 1336 var contents = jQuery('#layoutEditorContainer').find('.contents'); 1337 var relatedContainer = contents.find('#relatedTabOrder'); 1338 var relatedTab = contents.find('.relatedListTab'); 1339 relatedTab.click(function() { 1340 if(relatedContainer.find('.relatedTabModulesList').length > 0) { 1341 1342 } else { 1343 thisInstance.showRelatedTabModulesList(relatedContainer); 1344 } 1345 }); 1346 }, 1347 1348 /** 1349 * Function to show the related tab modules list in the tab 1350 */ 1351 showRelatedTabModulesList : function(relatedContainer) { 1352 var thisInstance = this; 1353 var params = {}; 1354 params['module'] = app.getModuleName(); 1355 params['parent'] = app.getParentModuleName(); 1356 params['sourceModule'] = jQuery('#selectedModuleName').val(); 1357 params['view'] = 'Index'; 1358 params['mode'] = 'showRelatedListLayout'; 1359 1360 AppConnector.request(params).then( 1361 function(data) { 1362 relatedContainer.html(data); 1363 if(jQuery(data).find('.relatedListContainer').length > 0) { 1364 thisInstance.makeRelatedModuleSortable(); 1365 thisInstance.registerRelatedListEvents(); 1366 thisInstance.setRemovedModulesList(); 1367 } 1368 }, 1369 function(error) { 1370 } 1371 ); 1372 }, 1373 1374 /** 1375 * Function to get the respective module layout editor through pjax 1376 */ 1377 getModuleLayoutEditor : function(selectedModule) { 1378 var thisInstance = this; 1379 var aDeferred = jQuery.Deferred(); 1380 var progressIndicatorElement = jQuery.progressIndicator({ 1381 'position' : 'html', 1382 'blockInfo' : { 1383 'enabled' : true 1384 } 1385 }); 1386 1387 var params = {}; 1388 params['module'] = app.getModuleName(); 1389 params['parent'] = app.getParentModuleName(); 1390 params['view'] = 'Index'; 1391 params['sourceModule'] = selectedModule; 1392 1393 AppConnector.requestPjax(params).then( 1394 function(data) { 1395 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1396 aDeferred.resolve(data); 1397 }, 1398 function(error) { 1399 progressIndicatorElement.progressIndicator({'mode' : 'hide'}); 1400 aDeferred.reject(); 1401 } 1402 ); 1403 return aDeferred.promise(); 1404 }, 1405 1406 /** 1407 * Function to register the change event for layout editor modules list 1408 */ 1409 registerModulesChangeEvent : function() { 1410 var thisInstance = this; 1411 var container = jQuery('#layoutEditorContainer'); 1412 var contentsDiv = container.closest('.contentsDiv'); 1413 1414 app.showSelect2ElementView(container.find('[name="layoutEditorModules"]'), {dropdownCss : {'z-index' : 0}}); 1415 1416 container.on('change', '[name="layoutEditorModules"]', function(e) { 1417 var currentTarget = jQuery(e.currentTarget); 1418 var selectedModule = currentTarget.val(); 1419 thisInstance.getModuleLayoutEditor(selectedModule).then( 1420 function(data) { 1421 contentsDiv.html(data); 1422 thisInstance.registerEvents(); 1423 } 1424 ); 1425 }); 1426 1427 }, 1428 1429 /** 1430 * Function to register click event for drop-downs in fields list 1431 */ 1432 avoidDropDownClick : function(dropDownContainer) { 1433 dropDownContainer.find('.dropdown-menu').click(function(e) { 1434 e.stopPropagation(); 1435 }); 1436 }, 1437 1438 registerEditFieldDetailsClick : function(contents) { 1439 var thisInstance = this; 1440 if(typeof contents == 'undefined') { 1441 contents = jQuery('#layoutEditorContainer').find('.contents'); 1442 } 1443 contents.find('.editFieldDetails').click(function(e) { 1444 var currentTarget = jQuery(e.currentTarget); 1445 var fieldRow = currentTarget.closest('div.editFields'); 1446 fieldRow.removeClass('opacity'); 1447 var basicDropDown = fieldRow.find('.basicFieldOperations'); 1448 var dropDownContainer = currentTarget.closest('.btn-group'); 1449 dropDownContainer.find('.dropdown-menu').remove(); 1450 var dropDown = basicDropDown.clone().removeClass('basicFieldOperations hide').addClass('dropdown-menu'); 1451 dropDownContainer.append(dropDown); 1452 var dropDownMenu = dropDownContainer.find('.dropdown-menu'); 1453 var params = app.getvalidationEngineOptions(true); 1454 params.binded = false, 1455 params.onValidationComplete = function(form,valid){ 1456 if(valid) { 1457 thisInstance.registerSaveFieldDetailsEvent(form); 1458 } 1459 return false; 1460 } 1461 dropDownMenu.find('form').validationEngine(params); 1462 var defaultValueUiContainer = basicDropDown.find('.defaultValueUi'); 1463 1464 1465 //handled registration of chosen for select element 1466 var selectElements = defaultValueUiContainer.find('select'); 1467 if(selectElements.length > 0) { 1468 dropDownMenu.find('select').addClass('chzn-select'); 1469 app.changeSelectElementView(dropDownMenu); 1470 } 1471 1472 //handled registration of time field 1473 var timeFieldElement = defaultValueUiContainer.find('[data-toregister="time"]'); 1474 if(timeFieldElement.length > 0){ 1475 dropDownMenu.find('[data-toregister="time"]').addClass('timepicker-default timePicker'); 1476 app.registerEventForTimeFields(dropDownMenu); 1477 } 1478 1479 //handled registration for date fields 1480 var dateField = defaultValueUiContainer.find('[data-toregister="date"]'); 1481 if(dateField.length > 0) { 1482 dropDownMenu.find('[data-toregister="date"]').addClass('dateField'); 1483 app.registerEventForDatePickerFields(dropDownMenu); 1484 } 1485 thisInstance.avoidDropDownClick(dropDownContainer); 1486 1487 dropDownMenu.on('change', ':checkbox', function(e) { 1488 var currentTarget = jQuery(e.currentTarget); 1489 if(currentTarget.attr('readonly') == 'readonly') { 1490 var status = jQuery(e.currentTarget).is(':checked'); 1491 if(!status){ 1492 jQuery(e.currentTarget).attr('checked','checked') 1493 }else{ 1494 jQuery(e.currentTarget).removeAttr('checked'); 1495 } 1496 e.preventDefault(); 1497 } 1498 }); 1499 1500 //added for drop down position change 1501 var offset = currentTarget.offset(), 1502 height = currentTarget.outerHeight(), 1503 dropHeight = dropDown.outerHeight(), 1504 viewportBottom = $(window).scrollTop() + document.documentElement.clientHeight, 1505 dropTop = offset.top + height, 1506 enoughRoomBelow = dropTop + dropHeight <= viewportBottom; 1507 if(!enoughRoomBelow) { 1508 dropDown.addClass('bottom-up'); 1509 } else { 1510 dropDown.removeClass('bottom-up'); 1511 } 1512 1513 var callbackFunction = function() { 1514 fieldRow.addClass('opacity'); 1515 dropDown.remove(); 1516 jQuery('body').off('click.dropdown.data-api.layouteditor'); 1517 } 1518 thisInstance.addClickOutSideEvent(dropDown, callbackFunction); 1519 1520 jQuery('.cancel').click(function(){ 1521 callbackFunction(); 1522 }); 1523 jQuery('body').on('click.dropdown.data-api.layouteditor',function(e){ 1524 var target = jQuery(e.target); 1525 //user clicked on time picker 1526 if(target.closest('.ui-timepicker-list').length > 0) { 1527 e.stopPropagation(); 1528 } 1529 }) 1530 }); 1531 }, 1532 1533 /** 1534 * Function to register all the events for blocks 1535 */ 1536 registerBlockEvents : function() { 1537 var thisInstance = this; 1538 thisInstance.makeBlocksListSortable(); 1539 thisInstance.registerAddCustomFieldEvent(); 1540 thisInstance.registerBlockVisibilityEvent(); 1541 thisInstance.registerInactiveFieldsEvent(); 1542 thisInstance.registerDeleteCustomBlockEvent(); 1543 }, 1544 1545 /** 1546 * Function to register all the events for fields 1547 */ 1548 registerFieldEvents : function(contents) { 1549 var thisInstance = this; 1550 if(typeof contents == 'undefined') { 1551 contents = jQuery('#layoutEditorContainer').find('.contents'); 1552 } 1553 app.registerEventForDatePickerFields(contents); 1554 app.registerEventForTimeFields(contents); 1555 app.changeSelectElementView(contents); 1556 1557 thisInstance.makeFieldsListSortable(); 1558 thisInstance.registerDeleteCustomFieldEvent(contents); 1559 thisInstance.registerFieldDetailsChange(contents); 1560 thisInstance.registerEditFieldDetailsClick(contents); 1561 1562 contents.find(':checkbox').change(function(e) { 1563 var currentTarget = jQuery(e.currentTarget); 1564 if(currentTarget.attr('readonly') == 'readonly') { 1565 var status = jQuery(e.currentTarget).is(':checked'); 1566 if(!status){ 1567 jQuery(e.currentTarget).attr('checked','checked') 1568 }else{ 1569 jQuery(e.currentTarget).removeAttr('checked'); 1570 } 1571 e.preventDefault(); 1572 } 1573 }); 1574 }, 1575 1576 /* 1577 * Function to add clickoutside event on the element - By using outside events plugin 1578 * @params element---On which element you want to apply the click outside event 1579 * @params callbackFunction---This function will contain the actions triggered after clickoutside event 1580 */ 1581 addClickOutSideEvent : function(element, callbackFunction) { 1582 element.one('clickoutside',callbackFunction); 1583 }, 1584 1585 /** 1586 * register events for layout editor 1587 */ 1588 registerEvents : function() { 1589 var thisInstance = this; 1590 1591 thisInstance.registerBlockEvents(); 1592 thisInstance.registerFieldEvents(); 1593 thisInstance.setInactiveFieldsList(); 1594 thisInstance.registerAddCustomBlockEvent(); 1595 thisInstance.registerFieldSequenceSaveClick(); 1596 1597 thisInstance.relatedModulesTabClickEvent(); 1598 thisInstance.registerModulesChangeEvent(); 1599 } 1600 1601 }); 1602 1603 jQuery(document).ready(function() { 1604 var instance = new Settings_LayoutEditor_Js(); 1605 instance.registerEvents(); 1606 }) 1607 1608 Vtiger_WholeNumberGreaterThanZero_Validator_Js("Vtiger_FloatingDigits_Validator_Js",{ 1609 1610 /** 1611 *Function which invokes field validation 1612 *@param accepts field element as parameter 1613 * @return error if validation fails true on success 1614 */ 1615 invokeValidation: function(field, rules, i, options){ 1616 var rangeInstance = new Vtiger_FloatingDigits_Validator_Js(); 1617 rangeInstance.setElement(field); 1618 var response = rangeInstance.validate(); 1619 if(response != true){ 1620 return rangeInstance.getError(); 1621 } 1622 } 1623 1624 },{ 1625 /** 1626 * Function to validate the decimals length 1627 * @return true if validation is successfull 1628 * @return false if validation error occurs 1629 */ 1630 validate: function(){ 1631 var response = this._super(); 1632 if(response != true){ 1633 return response; 1634 }else{ 1635 var fieldValue = this.getFieldValue(); 1636 if (fieldValue < 2 || fieldValue > 5) { 1637 var errorInfo = app.vtranslate('JS_PLEASE_ENTER_NUMBER_IN_RANGE_2TO5'); 1638 this.setError(errorInfo); 1639 return false; 1640 } 1641 1642 var specialChars = /^[+]/ ; 1643 if (specialChars.test(fieldValue)) { 1644 var error = app.vtranslate('JS_CONTAINS_ILLEGAL_CHARACTERS'); 1645 this.setError(error); 1646 return false; 1647 } 1648 return true; 1649 } 1650 } 1651 }); 1652 1653 Vtiger_WholeNumberGreaterThanZero_Validator_Js("Vtiger_DecimalMaxLength_Validator_Js",{ 1654 1655 /** 1656 *Function which invokes field validation 1657 *@param accepts field element as parameter 1658 * @return error if validation fails true on success 1659 */ 1660 invokeValidation: function(field, rules, i, options){ 1661 var rangeInstance = new Vtiger_DecimalMaxLength_Validator_Js(); 1662 rangeInstance.setElement(field); 1663 var response = rangeInstance.validate(); 1664 if(response != true){ 1665 return rangeInstance.getError(); 1666 } 1667 } 1668 1669 },{ 1670 /** 1671 * Function to validate the fieldLength 1672 * @return true if validation is successfull 1673 * @return false if validation error occurs 1674 */ 1675 validate: function(){ 1676 var response = this._super(); 1677 if(response != true){ 1678 return response; 1679 }else{ 1680 var fieldValue = this.getFieldValue(); 1681 var decimalFieldValue = jQuery('#createFieldForm').find('[name="decimal"]').val(); 1682 var fieldLength = parseInt(64)-parseInt(decimalFieldValue); 1683 if (fieldValue > fieldLength && !(fieldLength < 0) && fieldLength >= 59) { 1684 var errorInfo = app.vtranslate('JS_LENGTH_SHOULD_BE_LESS_THAN_EQUAL_TO')+' '+fieldLength; 1685 this.setError(errorInfo); 1686 return false; 1687 } 1688 1689 var specialChars = /^[+]/ ; 1690 if (specialChars.test(fieldValue)) { 1691 var error = app.vtranslate('JS_CONTAINS_ILLEGAL_CHARACTERS'); 1692 this.setError(error); 1693 return false; 1694 } 1695 return true; 1696 } 1697 } 1698 }); 1699 1700 Vtiger_WholeNumberGreaterThanZero_Validator_Js("Vtiger_MaxLength_Validator_Js",{ 1701 1702 /** 1703 *Function which invokes field validation 1704 *@param accepts field element as parameter 1705 * @return error if validation fails true on success 1706 */ 1707 invokeValidation: function(field, rules, i, options){ 1708 var rangeInstance = new Vtiger_DecimalMaxLength_Validator_Js(); 1709 rangeInstance.setElement(field); 1710 var response = rangeInstance.validate(); 1711 if(response != true){ 1712 return rangeInstance.getError(); 1713 } 1714 } 1715 1716 },{ 1717 /** 1718 * Function to validate the fieldLength 1719 * @return true if validation is successfull 1720 * @return false if validation error occurs 1721 */ 1722 validate: function(){ 1723 var response = this._super(); 1724 if(response != true){ 1725 return response; 1726 }else{ 1727 var fieldValue = this.getFieldValue(); 1728 if (fieldValue > 255) { 1729 var errorInfo = app.vtranslate('JS_LENGTH_SHOULD_BE_LESS_THAN_EQUAL_TO')+' 255'; 1730 this.setError(errorInfo); 1731 return false; 1732 } 1733 1734 var specialChars = /^[+]/ ; 1735 if (specialChars.test(fieldValue)) { 1736 var error = app.vtranslate('JS_CONTAINS_ILLEGAL_CHARACTERS'); 1737 this.setError(error); 1738 return false; 1739 } 1740 return true; 1741 } 1742 } 1743 }); 1744 1745 Vtiger_Base_Validator_Js("Vtiger_FieldLabel_Validator_Js",{ 1746 1747 /** 1748 *Function which invokes field validation 1749 *@param accepts field element as parameter 1750 * @return error if validation fails true on success 1751 */ 1752 invokeValidation: function(field, rules, i, options){ 1753 var instance = new Vtiger_FieldLabel_Validator_Js(); 1754 instance.setElement(field); 1755 var response = instance.validate(); 1756 if(response != true){ 1757 return instance.getError(); 1758 } 1759 } 1760 1761 },{ 1762 /** 1763 * Function to validate the field label 1764 * @return true if validation is successfull 1765 * @return false if validation error occurs 1766 */ 1767 validate: function(){ 1768 var fieldValue = this.getFieldValue(); 1769 return this.validateValue(fieldValue); 1770 }, 1771 1772 validateValue : function(fieldValue){ 1773 var specialChars = /[&\<\>\:\'\"\,\_]/ ; 1774 1775 if (specialChars.test(fieldValue)) { 1776 var errorInfo = app.vtranslate('JS_SPECIAL_CHARACTERS')+" & < > ' \" : , _ "+app.vtranslate('JS_NOT_ALLOWED'); 1777 this.setError(errorInfo); 1778 return false; 1779 } 1780 return true; 1781 } 1782 }); 1783 1784 Vtiger_Base_Validator_Js("Vtiger_PicklistFieldValues_Validator_Js",{ 1785 1786 /** 1787 *Function which invokes field validation 1788 *@param accepts field element as parameter 1789 * @return error if validation fails true on success 1790 */ 1791 invokeValidation: function(field, rules, i, options){ 1792 var instance = new Vtiger_PicklistFieldValues_Validator_Js(); 1793 instance.setElement(field); 1794 var response = instance.validate(); 1795 if(response != true){ 1796 return instance.getError(); 1797 } 1798 } 1799 1800 },{ 1801 /** 1802 * Function to validate the field label 1803 * @return true if validation is successfull 1804 * @return false if validation error occurs 1805 */ 1806 validate: function(){ 1807 var fieldValue = this.getFieldValue(); 1808 return this.validateValue(fieldValue); 1809 }, 1810 1811 validateValue : function(fieldValue){ 1812 var specialChars = /(\<|\>)/gi ; 1813 if (specialChars.test(fieldValue)) { 1814 var errorInfo = app.vtranslate('JS_SPECIAL_CHARACTERS')+" < >"+app.vtranslate('JS_NOT_ALLOWED'); 1815 this.setError(errorInfo); 1816 return false; 1817 } 1818 return true; 1819 } 1820 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |