, 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
,
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:
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
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',
),
),
)
)
);