Tuesday, September 07, 2010

Adding AJAX support in Module Builder's "Edit Relationship" in SugarCrm

In SugarCRM custom modules the default buttons in a subpanel are "Create" and "Select". In the framework SugarCrm is built on top there is support for AJAX / inline create in the subpanel as well as the normal full form create. There are also support for single row selection and multiple row selection. To utilize this you need to have knowledge about the various *defs.php files that are code generated by module builder and SugarCrm.

This hack shows how to add support for these buttons in Module Builder. We are going to UI support for selecting what buttons you want to show in your module's subpanel, the different buttons are AJAX Quick Create Button, Full Form Create Button, AJAX Single Select Button and/or AJAX Multiple Select Button.

After the hack is implemented your Edit Relationsship screen in Module Builder is going to look like the following.



After selecting required buttons save the changes, deploy the package (with the affected modules inside) to see the effect. The following screenshot shows the M1 Subpanel on M2 module where we have selected a Quick Create button.



The following screen shows the M2 Subpanel on M1 module where we have selected a Quick Create and Multi Select button.







Likewise we can select any combination we want for our subpanel. (apart from both having a single and a multiple select button - which I did not think made a lot of sense).

This hack is not upgrade safe.




This is the subversion diff file that outlines the changes made to a SugarCrm 5.5.2 code base to achieve the features described above.





Index: modules/ModuleBuilder/javascript/ModuleBuilder.js
===================================================================
--- modules/ModuleBuilder/javascript/ModuleBuilder.js (revision 1)
+++ modules/ModuleBuilder/javascript/ModuleBuilder.js (working copy)
@@ -872,7 +872,10 @@
     ajaxStatus.hideStatus();
     var tab = ModuleBuilder.findTabById('relEditor');
     tab.set("content", o.responseText);
-    SUGAR.util.evalScript(tab);
+    //SUGAR.util.evalScript(tab);
+    //Hack Relations between modules
+    SUGAR.util.evalScript(o.responseText);
+                //Hack Relations between modules
    });
   },
   moduleDropDown: function(name, field){
Index: modules/ModuleBuilder/language/en_us.lang.php
===================================================================
--- modules/ModuleBuilder/language/en_us.lang.php (revision 1)
+++ modules/ModuleBuilder/language/en_us.lang.php (working copy)
@@ -627,6 +627,12 @@
                 'encrypt'=>'Encrypt'
 ),
 
-'parent' => 'Flex Relate'
+'parent' => 'Flex Relate',
+//Hack Relations between modules
+'LBL_AJAX_QUICK_CREATE_BTN' => 'AJAX Quick Create Button',
+'LBL_AJAX_SINGLE_SELECT_BTN' => 'AJAX Single Select Button',
+'LBL_AJAX_MULTIPLE_SELECT_BTN' => 'AJAX Multiple Select Button',
+'LBL_FULL_FORM_CREATE_BTN' => 'Full Form Create Button',
+//Hack Relations between modules
 );
 
Index: modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php
===================================================================
--- modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php (revision 1)
+++ modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php (working copy)
@@ -80,6 +80,7 @@
         'relationship_type' , 
         'relationship_role_column' , 
         'relationship_role_column_value' , 
+        'ext1' ,  //Hack Relations between modules
         'reverse' ) ;
 
     /*
@@ -263,12 +264,52 @@
   }else{
    $subpanelDefinition [ 'title_key' ] = 'LBL_' . strtoupper ( $relationshipName . '_FROM_' . $sourceModule ) . '_TITLE' ;
   }
-        $subpanelDefinition [ 'get_subpanel_data' ] = $relationshipName ;
-        $subpanelDefinition [ 'top_buttons' ] = array(
+  $subpanelDefinition [ 'get_subpanel_data' ] = $relationshipName ;
+  //Hack Relations between modules
+  if(isset($this->definition['ext1']) AND $this->definition['ext1'] != ''){
+   $topBtnOption = explode('_@@_', $this->definition['ext1']);
+   // LHS Module
+   if ($this->definition['lhs_module'] == $sourceModule){
+    // Quick Create Button
+    if($topBtnOption[0] == '1'){
+     $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopButtonQuickCreate');
+    }
+    // Full Form Create Button
+    if($topBtnOption[1] == '1'){
+     $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopCreateButton');
+    }
+    // Single Select Button
+    if($topBtnOption[2] == '1'){
+                    $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopSelectButton');
+    }
+    // Multiple Select Button
+    if($topBtnOption[3] == '1'){
+                        $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => $this->definition['rhs_module'], 'mode' => 'MultiSelect', 'initial_filter_fields' => array());
+    }
+   }else{
+    // Quick Create Button
+    if($topBtnOption[4] == '1'){
+     $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopButtonQuickCreate');
+    }
+    // Full Form Create Button
+    if($topBtnOption[5] == '1'){
+     $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopCreateButton');
+    }
+    // Single Select Button
+    if($topBtnOption[6] == '1'){
+                    $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopSelectButton');
+    }
+    // Multiple Select Button
+    if($topBtnOption[7] == '1'){
+                        $subpanelDefinition [ 'top_buttons' ][] = array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => $this->definition['lhs_module'], 'mode' => 'MultiSelect', 'initial_filter_fields' => array());                        
+    }
+   }
+  }
+  /*$subpanelDefinition [ 'top_buttons' ] = array(
       array('widget_class' => "SubPanelTopCreateButton"),
       array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect')
-  );
-        
+  );*/
+        //Hack Relations between modules
         return array ( $subpanelDefinition );
     }   
     
Index: modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php
===================================================================
--- modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php (revision 1)
+++ modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php (working copy)
@@ -151,7 +151,21 @@
                     $this->delete ( $_REQUEST [ 'relationship_name' ] ) ;
         }
         }
-        
+  //Hack Relations between modules
+  $buttonArr = array('lhs_quick_create', 'lhs_full_form_create','lhs_signle_select', 'lhs_multiple_select', 'rhs_quick_create',
+                     'rhs_full_form_create', 'rhs_signle_select', 'rhs_multiple_select');
+  $ext1 = '';
+  foreach($buttonArr as $option){
+   $btn = false;
+   if(isset($_REQUEST[$option]) AND $_REQUEST[$option] == '1'){
+    $ext1 .= '1_@@_';
+   }else{
+    $ext1 .= '0_@@_';
+   }
+  }
+  $ext1 = substr($ext1, 0, (strlen($ext1) - 4));
+  $definition ['ext1'] = $ext1;
+  //Hack Relations between modules
         $newRelationship = RelationshipFactory::newRelationship ( $definition ) ;
         // TODO: error handling in case we get a badly formed definition and hence relationship
         $this->add ( $newRelationship ) ;
Index: modules/ModuleBuilder/tpls/studioRelationship.tpl
===================================================================
--- modules/ModuleBuilder/tpls/studioRelationship.tpl (revision 1)
+++ modules/ModuleBuilder/tpls/studioRelationship.tpl (working copy)
@@ -178,6 +178,45 @@
 
    {/if} {* subpanels etc for all but one-to-one relationships *}
    {/if} {* if relationship_only *}
+  {* Hack Relations between modules *}
+  {if $rel.relationship_type != 'one-to-one'}
+  <tr>
+   <td colspan=2>
+   {if $rel.relationship_type == 'many-to-many'}
+   <table class="listView"><tr><td class="listViewThS1">
+   {sugar_translate label=$rel.lhs_module} Subpanel On {sugar_translate label=$rel.rhs_module}
+   </td></tr>
+   <tr><td class="evenListRowS1">
+   <input type="checkbox" name="lhs_quick_create" id="lhs_quick_create" value="1" onclick="lock_create_option(this.id, 'lhs')" 
+   {if $ckBoxOption.0 == 1}checked{/if} /> {$mod_strings.LBL_AJAX_QUICK_CREATE_BTN}<br>
+   <input type="checkbox" name="lhs_full_form_create" id="lhs_full_form_create" value="1" onclick="lock_create_option(this.id, 'lhs')" 
+   {if $ckBoxOption.1 == 1}checked{/if} /> {$mod_strings.LBL_FULL_FORM_CREATE_BTN}<br>
+   <input type="checkbox" name="lhs_signle_select" id="lhs_signle_select" value="1" onclick="lock_multiple_select(this.id, 'lhs')" 
+   {if $ckBoxOption.2 == 1}checked{/if}/> {$mod_strings.LBL_AJAX_SINGLE_SELECT_BTN}<br>
+   <input type="checkbox" name="lhs_multiple_select" id="lhs_multiple_select" value="1" onclick="lock_multiple_select(this.id, 'lhs')" 
+   {if $ckBoxOption.3 == 1}checked{/if} /> {$mod_strings.LBL_AJAX_MULTIPLE_SELECT_BTN}<br>
+   </td></tr></table>
+   {/if}&nbsp;
+   </td>
+   <td>&nbsp;</td>
+   <td colspan=2>
+   <table class="listView"><tr><td class="listViewThS1">
+   {sugar_translate label=$rel.rhs_module} Subpanel On {sugar_translate label=$rel.lhs_module}
+   </td></tr>
+   <tr><td class="evenListRowS1">
+   <input type="checkbox" name="rhs_quick_create" id="rhs_quick_create" value="1" onclick="lock_create_option(this.id, 'rhs')" 
+   {if $ckBoxOption.4 == 1}checked{/if} /> {$mod_strings.LBL_AJAX_QUICK_CREATE_BTN}<br>
+   <input type="checkbox" name="rhs_full_form_create" id="rhs_full_form_create" value="1" onclick="lock_create_option(this.id, 'rhs')" 
+   {if $ckBoxOption.5 == 1}checked{/if} /> {$mod_strings.LBL_FULL_FORM_CREATE_BTN}<br>
+   <input type="checkbox" name="rhs_signle_select" id="rhs_signle_select" value="1" onclick="lock_multiple_select(this.id, 'rhs')" 
+   {if $ckBoxOption.6 == 1}checked{/if} /> {$mod_strings.LBL_AJAX_SINGLE_SELECT_BTN}<br>
+   <input type="checkbox" name="rhs_multiple_select" id="rhs_multiple_select" value="1" onclick="lock_multiple_select(this.id, 'rhs')" 
+   {if $ckBoxOption.7 == 1}checked{/if} /> {$mod_strings.LBL_AJAX_MULTIPLE_SELECT_BTN}
+   </td></tr>            
+            </table>
+  </tr>
+  {/if}
+  {* Hack Relations between modules *}
   </table>
  </td></tr>
 </table>
@@ -190,5 +229,53 @@
 {else}
 ModuleBuilder.helpSetup('studioWizard','relationshipHelp');
 {/if}
+{* Hack Relations between modules *}
+{literal}
+    
+ function lock_multiple_select(id, side){
+  if(!document.getElementById(id)){return false;}
 
+  if(side == 'lhs'){
+   lock_field = (id == 'lhs_signle_select') ? 'lhs_multiple_select' : 'lhs_signle_select';
+  }
+  else{
+   lock_field = (id == 'rhs_signle_select') ? 'rhs_multiple_select' : 'rhs_signle_select';
+  }
+  if(document.getElementById(id).checked){
+   document.getElementById(lock_field).disabled = true;
+  }
+  else{
+   document.getElementById(lock_field).disabled = false;
+  }
+ }
+ function lock_create_option(id, side){
+  if(!document.getElementById(id)){return false;}
+  var lock_field_create="";
+  
+  if(side == 'lhs'){
+   lock_field_create = (id == 'lhs_quick_create') ? 'lhs_full_form_create' : 'lhs_quick_create';
+  }else {
+   lock_field_create = (id == 'rhs_quick_create') ? 'rhs_full_form_create' : 'rhs_quick_create';
+  }
+  
+  if(document.getElementById(id).checked){
+   document.getElementById(lock_field_create).disabled = true;
+  }else{
+   document.getElementById(lock_field_create).disabled = false;
+  }
+ }
+ YAHOO.util.Event.onDOMReady(function(){
+  lock_multiple_select('lhs_signle_select', 'lhs');
+  lock_multiple_select('lhs_multiple_select', 'lhs');
+  lock_multiple_select('rhs_signle_select', 'rhs');
+  lock_multiple_select('rhs_multiple_select', 'rhs');
+  
+  lock_create_option('lhs_quick_create', 'lhs');
+  lock_create_option('lhs_full_form_create', 'lhs');
+  lock_create_option('rhs_quick_create', 'rhs');
+  lock_create_option('rhs_full_form_create', 'rhs');
+ });
+{/literal}
+
+{* Hack Relations between modules *}
 </script>
Index: modules/ModuleBuilder/views/view.relationship.php
===================================================================
--- modules/ModuleBuilder/views/view.relationship.php (revision 1)
+++ modules/ModuleBuilder/views/view.relationship.php (working copy)
@@ -193,7 +193,10 @@
         $this->smarty->assign ( 'cardinality', array_keys ( $cardinality ) ) ;
         $this->smarty->assign ( 'translated_cardinality', $cardinality ) ;
         $this->smarty->assign ( 'selected_cardinality', translate ( $relationship->getType () ) ) ;
-        
+        //Hack Relations between modules
+  $ckBoxOption = explode('_@@_', $relationship->ext1);
+        $this->smarty->assign ( 'ckBoxOption', $ckBoxOption ) ;
+  //Hack Relations between modules
         $relatable = array ( ) ;
         foreach ( $relatableModules as $name => $dummy )
         {

You can download the diff file and the modified core files here MB-RelationshipButtons.zip

The directory modified_files contains the original sugarcrm files with this patch applied for those users that are not yet familiar with SVN.

You are however recommended to use the diff files since you that way have 100% say over what code gets included in your code base rather than trusting the code blindly.
(This is not for these files in particular but goes in general on the internet)

No liability ... normal disclaimer goes here.


5 comments:

Anonymous said...

Mate. This blog is amazing. How can I make it look this good ?

Kenneth Thorman said...

Thank you for your nice comment, I am unsure of exactly what you are asking about. This is a normal blogger account with a slightly customized template as well as using the SyntaxHighlighter script available at http://http://alexgorbatchev.com/SyntaxHighlighter/. I hope this helped.

/Kenneth Thorman

Anonymous said...

О! Somos un grupo de voluntarios y la iniciativa de comenzar una nueva marca en la comunidad. Su weblog nos proporcionó información valiosa para trabajar. Usted ha hecho un trabajo maravilloso!

Anonymous said...

There is obviously a lot to know about this. I think you made some good points in Features also. Keep working ,great job!.

Unknown said...

Awesome SugarCRM snippets, I'm testing some of them in my dev. environment.

One question, do you have a patch so that the relationship gets defined in the quick create form?

For example, if I have M1 with 1:n relationship with M2. I click inline create on M1 and the sub panel form for M2 shows, but the relationship between M1 and M2 is not specified in the M2 form.