SubPanel implementation:


Summary:

	DetailView pages now utilize the SubPanelTiles php class to display Subpanels of Related Objects. 
	Subpanels are generated asynchronously and on demand, and utilize an improved ListView class.


-------------------------------------------------------------------------------

Class Heirarchy: 

DetailView -> SubPanelTiles ->(remotely calls) -> 
	SubPanelViewer -> SubPanel -> ListView -> (calls template) --> SubPanelDynamic.html


-------------------------------------------------------------------------------

SubPanelTiles:

  The SubPanelTiles class creates the subpanel <div>s,  outputs the javascript to manage loading/displaying panels, and displays tabs.

    - Each Subpanel is outputted as empty <divs>

    - When a tab is selected, or a subpanel to be maximized, the showSubPanel javascript function is called.

	- an asynchronous XMLHTTPRequest object is used to remotely fetch snippets of the SubPanel HTML. When the call
		returns, the contents of the response from the server will be assigned to the innerHTML of the target <div>.

	- The XMLHTTPRequest calls the subpanel snippets with your normal Sugar URL with module/action/record


	- The header/menu/footer panels are not displayed by adding to the query string: "&sugar_body_only=1&inline=1"

	- the "action" is SubPanelViewer, which of course causes Sugar to execute:
			 modules/$_REQUEST['module']/SubPanelViewer.php

	- SubPanelViewer.php files in every module directory usually just call include/SubPanel/SubPanelViewer.php and return.

	- SubPanelViewer acts as a wrapper around the SubPanel when it is called remotely.
	
    - The Top "Create" and "Select" buttons are generated inside the hide/display <div>, but outside of the div that holds
	the innerHTML of the Subpanel listview.

	- the presence of, order of, and SugarWidget class of these buttons are controlled in the subpanel definitions.

    - (optional) The tabs are displayed using the SugarWidgetTabs class, which outputs the javascript/html.
        
	SugarWidgetTabs is generated by javascript, and tab selection is done by dynamically changing CSS attributes of the tabs. 

	Someone using this class would pass it a php array of the tab definition. It is converted to javascript data object
	definitions and outputted as javascript to the browser. The other input would be the name of the javascript callback function
	that should be called when a tab is clicked.


-------------------------------------------------------------------------------


SubPanel Snippets:


		SubPanel.php acts as a wrapper around ListView.php:

			- instantiates parent and related bean

			- gets subpanel definitions using a search path (custom, then module-specific, then global)

			- ListView manages sorting, paging and displaying the header and rows

			- SubPanel sets a flag in ListView that it knows to run dynamically

			- passes ListView the javascript link wrappers so that paging and sorting links will work correctly.

			  The links will call a javascript function that will return the HTML to the subpanel <DIV>, 
			  and not refresh the whole page

			- calls $ListView->loadListFieldDefs($list_fields,$child_focus); so that it can iterate through
			  the fields and display the appropriate widget and data

-------------------------------------------------------------------------------

		ListView and SugarWidgets
		

			- To generate the header and data cells, dynamic ListViews use SugarWidget singleton display functions.

			- as ListView prepares to display a cell, it looks at its corresponding field definition to 
				determine which SugarWidget to display. If there is no definition for the widget_class, then it
				will default to displaying SugarWidgetField

				snippet:
				<?php
				foreach($this->list_field_defs as $list_field)
                                {
                                        $list_field['fields'] = $fields;
                                        $list_field['start_link_wrapper'] = $this->start_link_wrapper;
                                        $list_field['end_link_wrapper'] = $this->end_link_wrapper;

                                        $widget_contents = $layout_manager->widgetDisplay($list_field);
                                                                                                   
                                        $this->xTemplate->assign('CELL', $widget_contents);
                                        $this->xTemplate->parse($xtemplateSection.".row.cell");
                                }
				?>
			- a list_field definition example (from layout_defs.php)

                        'list_fields'=> array(

                          array (

				// use the 'ENCODED_NAME' key to get the data
                                 'varname'=>'ENCODED_NAME',

				// the key into the vardef.php definition
				// also used as the sort order.. split that out
                                 'name'=>'last_name',

				// use this custom label in the header
                                 'vname'=>'LBL_LIST_NAME',

				// link this field
                                 'linked'=>true,

				// use this module because we are linking this field
                                 'module'=>'Contacts',

                          ),
			),


			- SugarWidgetField will call a different displayXXX() function depending on the context of the container.

				- if in the "HeaderCell" context, it calls $this->displayHeaderCell($args), which returns the HTML
				  content of the Header Cell

				- if in the "List" context, it calls $this->displayList($args), which returns the HTML content of 
				  a data cell of the ListView.
			
				- Before ListView displays the widget for a cell, it attaches a pointer to the data for that 
					SugarBean instance.

				- if the field definition contains a link = true and a module attribute, then it will create a link
				  to the DetailView of the target SugarBean instance


			- The edit and remove buttons in the row are also generated like the other cells except it uses
				SugarWidgetSubPanelEditButton to display. The buttons are defined in the subpanel definition just like 
				the fields that are being displayed

	Selecting and deleting relationships:

	- When either a relationship is added via a popup, or the remove button is clicked, an async XMLHTTPRequest is called.

		- The contents of the request is a POST or GET that is constructed and send to the server. The return_url is set

			so that the server returns the Subpanel snippet, which is then added to the innerHTML of the calling subpanel


------------------------------------------------------------------------------
Back end methods:


	- When being used for Subpanels, ListView uses the get_related_list() method of the SugarBean Class to retrieve related objects.


		- in $sugarbean->get_related_list():

			// load relationship
			$this->load_relationship($related_field_name);

			// now get the query that fetches related records:
   			$query_array = $this->$related_field_name->getQuery(true);

	- adding and deleting relationships are done through the include/generic/Save2.php and include/generic/DeleteRelationship.php 

		- Link::add() and Link::delete() methods are the core functions that do the database work.


-------------------------------------------------------------------------------

FILES:

New:

include/SubPanel/SubPanelDynamic.html  
 - the xtemplate file that provides the skeleton of the dynamic ListView
   output

include/SubPanel/SubPanel.php  
 - prepares ListView to output related objects, and within a <div>

include/SubPanel/SubPanelTiles.php  
 - includes tabs and each subpanel, and manages the show/hide and UI.

include/SubPanel/SubPanelViewer.php
 - wrapper for SubPanel.php when called remotely

include/generic/DeleteRelationship.php  
 - generically deletes a relationship based on a parent focus, the linked_field, 
   and the linked id;

include/generic/LayoutManager.php  
 - Factory class to provide singleton access and repository for SugarWidget
 - provides global data registry that SugarWidgets can access

include/generic/Save2.php  
 - generically adds a relationship using EditView form variables, but is
   actually called via XMLHTTPRequest, and only tested with relationship
   fields.

include/generic/SugarWidgets/SugarWidget.php
 - base class, defines display(), and holds a reference to the LayoutManager;

include/generic/SugarWidgets/SugarWidgetField.php
 - base class to represent database columns as UI widgets

include/generic/SugarWidgets/SugarWidgetSubPanelTopButtons.php
 - they are the "Create" and "Select" buttons

include/generic/SugarWidgets/registered_widgets.php      
 - add new SugarWidget classes here

include/generic/SugarWidgets/SugarWidgetDynamicTabs.php  
 - javascript generated tabs

include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php
 - holds both SugarWidgetSubPanelEditButton and
   SugarWidgetSubPanelRemoveButton
 - defines 'edit' and 'rem' buttons within the row on the right

each module:

modules/$module_name/Save2.php
 - redirects to: include/generic/Save2.php

modules/$module_name/layout_defs.php
 - defines subpanels for each bean within this module directory

modules/$module_name/SubPanelViewer.php
 - redirects to: include/generic/SubPanelViewer.php

modules/$module_name/SaveRelationship.php
 - redirects to: include/generic/SaveRelationship.php

CHANGED:

modules/$module_name/DetailView.php
 - contains SubPanelTiles

include/ListView/ListView.php
 - added:
   loadListFieldDefs()
   processHeaderDynamic()
   getLayoutManager()
   is_dynamic

 - changed:
   processListRows()
   processListViewTwo()

data/SugarBean.php
 - added:
   get_related_list()



-------------------------------------------------------------------------------

TODO: 


 - Within the SugarWidgetField display() function, based on the field data type being displayed, call another SugarWidget 
	that can output it correctly

    - this includes checkboxes, dropdowns, relationships, dates, etc..

 - do it throughout the rest of the modules
 
 - might need to change the how "create" button passes form data. 
    - make it more configurable so that it can pass custom form data from
      focus bean

 - change how tabs are displayed/hidden. 

	- right now it uses the linked_fields directly from the sugarbean

	- use the visible_subpanels definition in the layout_def.php, or just use the order in subpanel_defines itself. if you do
          you have to add an order_index to each field and sort on that. maybe have a visible/hidden attribute

	- define custom titles in visible_subpanels, else fall back to subpanel string.

	- where do you put union subpanel definitions? change function that returns the definitions to another search path.

 - create special union subpanel type.

	- not just one focus, but an array of them, and some may have be the same class

 - make layout editor work with subpanel listviews
 

-------------------------------------------------------------------------------
PROBLEMS:

- using firefox, when the "select" button is within the div that gets it's innerHTML
  replaced, things break the second time you select a new relationship. it
  fails on the window.open that is called with the popup_helper. some internal
  mozilla error.
  this is why the top buttons are in SubPanelTiles.php and not SubPanel.php
  this needs to be resolve or else we will not be able to have popups that
  cause refreshes.


sample layout_def:
-------------------------------------------------------------------------------

$layout_defs['account'] = array(

        'subpanel_setup' => array (

        	// sets up which panels to show, in which order, and with what
        	// linked_fields
                'show_subpanels' => array (
                        array(

			/// which subpanel to show
                        'subpanel_key'=>'opportunities', 

			/// custom string for the title of this subpanel
                        'string_key'=>'LBL_OPPORTUNITIES',
                        ),
                ),
        ),

        // defines the default subpanel definition for this SugarBean
        'default_subpanel_define' => array (
                'class_name'=>array('Opportunity'),

                // define top left buttons
                'top_buttons'=>array(
                        array (
                         'widget_class'=>'SubPanelTopCreateButton',
                                ),
                        array (
                         'widget_class'=>'SubPanelTopSelectButton',
                                ),
                        ),
                // define list fields
		// yea, i know this will only show the Name
                'list_fields'=> array(
                        array (
                        'name'=>'name',
                        'module'=>'Accounts',
                        'linked'=>true,
                        ),
                ),
        ),

        // defines custom subpanel definitions for this SugarBean
        'subpanel_defines' => array (
                'opportunities' => array (
               	        // define top left buttons
                        'top_buttons'=>array(
                                array (
                                 'widget_class'=>'SubPanelTopCreateButton',
                                ),
                                array (
                                 'widget_class'=>'SubPanelTopSelectButton',
                                ),
                        ),
                        'class_name'=>array('Opportunity'),
                // define list fields
		// this one displays the same fields as the original
                        'list_fields'=> array(
                                array (
                                 'name'=>'name',
                                 'module'=>'Opportunities',
                                 'linked'=>true,
                                ),
                                array (
                                 'varname'=>'account_name',
                                 'vname'=>'LBL_LIST_ACCOUNT_NAME',
                                ),
                                array (
                                 'name'=>'date_closed',
                                ),
                                array (
                                 'widget_class'=>'SubPanelEditButton',
                                 'name'=>'edit_button',
                                ),
                        ),
                ),
                'contact' => array (
                        'class_name'=>array('Opportunity'),
                        'top_buttons'=>array(
                                array (
                                 'widget_class'=>'SubPanelTopCreateButton',
                                ),
                                array (
                                 'widget_class'=>'SubPanelTopSelectButton',
                                ),
                        ),

			// this one also displays the same fields as the original
                        'list_fields'=> array(
                        array (
                                 'varname'=>'ENCODED_NAME',
                                 'name'=>'last_name',
                                 'vname'=>'LBL_LIST_NAME',
                                 'module'=>'Contacts',
                                 'linked'=>true,
                        ),
                        array (
                                 'varname'=>'ACCOUNT_NAME',
                                 'vname'=>'LBL_LIST_ACCOUNT_NAME',
                        ),
                        array (
                                 'name'=>'email1',
                        ),
                        array (
                                 'vname'=>'LBL_LIST_PHONE',
                                 'name'=>'phone_home',
                        ),
                        array (
                                 'widget_class'=>'SubPanelEditButton',
                                 'name'=>'edit_button',
                        ),
                        array (
                                 'widget_class'=>'SubPanelRemoveButton',
                                 'name'=>'remove_button',
                        ),
                        ),
                )
        )
);

