mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2025-01-28 19:39:40 +00:00
34eb8562c6
Copyright notice update for hotfix branch Changes: - Year - Double spaces - Brand fix for SalesAgility Ltd. (was Salesagility Ltd) Created from latest hotfix branch.
475 lines
18 KiB
Text
Executable file
475 lines
18 KiB
Text
Executable file
/**
|
|
*
|
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
|
*
|
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
|
* Free Software Foundation with the addition of the following permission added
|
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License along with
|
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA.
|
|
*
|
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of this program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU Affero General Public License version 3.
|
|
*
|
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
|
*/
|
|
|
|
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',
|
|
),
|
|
),
|
|
)
|
|
)
|
|
);
|
|
|