1 /*********************************************************************************
2 * SugarCRM Community Edition is a customer relationship management program developed by
3 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Affero General Public License version 3 as published by the
7 * Free Software Foundation with the addition of the following permission added
8 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
9 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
10 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * You should have received a copy of the GNU Affero General Public License along with
18 * this program; if not, see http://www.gnu.org/licenses or write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
23 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU Affero General Public License version 3.
29 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
30 * these Appropriate Legal Notices must retain the display of the "Powered by
31 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
32 * technical reasons, the Appropriate Legal Notices must display the words
33 * "Powered by SugarCRM".
34 ********************************************************************************/
36 SubPanel implementation:
41 DetailView pages now utilize the SubPanelTiles php class to display Subpanels of Related Objects.
42 Subpanels are generated asynchronously and on demand, and utilize an improved ListView class.
45 -------------------------------------------------------------------------------
49 DetailView -> SubPanelTiles ->(remotely calls) ->
50 SubPanelViewer -> SubPanel -> ListView -> (calls template) --> SubPanelDynamic.html
53 -------------------------------------------------------------------------------
57 The SubPanelTiles class creates the subpanel <div>s, outputs the javascript to manage loading/displaying panels, and displays tabs.
59 - Each Subpanel is outputted as empty <divs>
61 - When a tab is selected, or a subpanel to be maximized, the showSubPanel javascript function is called.
63 - an asynchronous XMLHTTPRequest object is used to remotely fetch snippets of the SubPanel HTML. When the call
64 returns, the contents of the response from the server will be assigned to the innerHTML of the target <div>.
66 - The XMLHTTPRequest calls the subpanel snippets with your normal Sugar URL with module/action/record
69 - The header/menu/footer panels are not displayed by adding to the query string: "&sugar_body_only=1&inline=1"
71 - the "action" is SubPanelViewer, which of course causes Sugar to execute:
72 modules/$_REQUEST['module']/SubPanelViewer.php
74 - SubPanelViewer.php files in every module directory usually just call include/SubPanel/SubPanelViewer.php and return.
76 - SubPanelViewer acts as a wrapper around the SubPanel when it is called remotely.
78 - The Top "Create" and "Select" buttons are generated inside the hide/display <div>, but outside of the div that holds
79 the innerHTML of the Subpanel listview.
81 - the presence of, order of, and SugarWidget class of these buttons are controlled in the subpanel definitions.
83 - (optional) The tabs are displayed using the SugarWidgetTabs class, which outputs the javascript/html.
85 SugarWidgetTabs is generated by javascript, and tab selection is done by dynamically changing CSS attributes of the tabs.
87 Someone using this class would pass it a php array of the tab definition. It is converted to javascript data object
88 definitions and outputted as javascript to the browser. The other input would be the name of the javascript callback function
89 that should be called when a tab is clicked.
92 -------------------------------------------------------------------------------
98 SubPanel.php acts as a wrapper around ListView.php:
100 - instantiates parent and related bean
102 - gets subpanel definitions using a search path (custom, then module-specific, then global)
104 - ListView manages sorting, paging and displaying the header and rows
106 - SubPanel sets a flag in ListView that it knows to run dynamically
108 - passes ListView the javascript link wrappers so that paging and sorting links will work correctly.
110 The links will call a javascript function that will return the HTML to the subpanel <DIV>,
111 and not refresh the whole page
113 - calls $ListView->loadListFieldDefs($list_fields,$child_focus); so that it can iterate through
114 the fields and display the appropriate widget and data
116 -------------------------------------------------------------------------------
118 ListView and SugarWidgets
121 - To generate the header and data cells, dynamic ListViews use SugarWidget singleton display functions.
123 - as ListView prepares to display a cell, it looks at its corresponding field definition to
124 determine which SugarWidget to display. If there is no definition for the widget_class, then it
125 will default to displaying SugarWidgetField
129 foreach($this->list_field_defs as $list_field)
131 $list_field['fields'] = $fields;
132 $list_field['start_link_wrapper'] = $this->start_link_wrapper;
133 $list_field['end_link_wrapper'] = $this->end_link_wrapper;
135 $widget_contents = $layout_manager->widgetDisplay($list_field);
137 $this->xTemplate->assign('CELL', $widget_contents);
138 $this->xTemplate->parse($xtemplateSection.".row.cell");
141 - a list_field definition example (from layout_defs.php)
143 'list_fields'=> array(
147 // use the 'ENCODED_NAME' key to get the data
148 'varname'=>'ENCODED_NAME',
150 // the key into the vardef.php definition
151 // also used as the sort order.. split that out
154 // use this custom label in the header
155 'vname'=>'LBL_LIST_NAME',
160 // use this module because we are linking this field
161 'module'=>'Contacts',
167 - SugarWidgetField will call a different displayXXX() function depending on the context of the container.
169 - if in the "HeaderCell" context, it calls $this->displayHeaderCell($args), which returns the HTML
170 content of the Header Cell
172 - if in the "List" context, it calls $this->displayList($args), which returns the HTML content of
173 a data cell of the ListView.
175 - Before ListView displays the widget for a cell, it attaches a pointer to the data for that
178 - if the field definition contains a link = true and a module attribute, then it will create a link
179 to the DetailView of the target SugarBean instance
182 - The edit and remove buttons in the row are also generated like the other cells except it uses
183 SugarWidgetSubPanelEditButton to display. The buttons are defined in the subpanel definition just like
184 the fields that are being displayed
186 Selecting and deleting relationships:
188 - When either a relationship is added via a popup, or the remove button is clicked, an async XMLHTTPRequest is called.
190 - The contents of the request is a POST or GET that is constructed and send to the server. The return_url is set
192 so that the server returns the Subpanel snippet, which is then added to the innerHTML of the calling subpanel
195 ------------------------------------------------------------------------------
199 - When being used for Subpanels, ListView uses the get_related_list() method of the SugarBean Class to retrieve related objects.
202 - in $sugarbean->get_related_list():
205 $this->load_relationship($related_field_name);
207 // now get the query that fetches related records:
208 $query_array = $this->$related_field_name->getQuery(true);
210 - adding and deleting relationships are done through the include/generic/Save2.php and include/generic/DeleteRelationship.php
212 - Link::add() and Link::delete() methods are the core functions that do the database work.
215 -------------------------------------------------------------------------------
221 include/SubPanel/SubPanelDynamic.html
222 - the xtemplate file that provides the skeleton of the dynamic ListView
225 include/SubPanel/SubPanel.php
226 - prepares ListView to output related objects, and within a <div>
228 include/SubPanel/SubPanelTiles.php
229 - includes tabs and each subpanel, and manages the show/hide and UI.
231 include/SubPanel/SubPanelViewer.php
232 - wrapper for SubPanel.php when called remotely
234 include/generic/DeleteRelationship.php
235 - generically deletes a relationship based on a parent focus, the linked_field,
238 include/generic/LayoutManager.php
239 - Factory class to provide singleton access and repository for SugarWidget
240 - provides global data registry that SugarWidgets can access
242 include/generic/Save2.php
243 - generically adds a relationship using EditView form variables, but is
244 actually called via XMLHTTPRequest, and only tested with relationship
247 include/generic/SugarWidgets/SugarWidget.php
248 - base class, defines display(), and holds a reference to the LayoutManager;
250 include/generic/SugarWidgets/SugarWidgetField.php
251 - base class to represent database columns as UI widgets
253 include/generic/SugarWidgets/SugarWidgetSubPanelTopButtons.php
254 - they are the "Create" and "Select" buttons
256 include/generic/SugarWidgets/registered_widgets.php
257 - add new SugarWidget classes here
259 include/generic/SugarWidgets/SugarWidgetDynamicTabs.php
260 - javascript generated tabs
262 include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php
263 - holds both SugarWidgetSubPanelEditButton and
264 SugarWidgetSubPanelRemoveButton
265 - defines 'edit' and 'rem' buttons within the row on the right
269 modules/$module_name/Save2.php
270 - redirects to: include/generic/Save2.php
272 modules/$module_name/layout_defs.php
273 - defines subpanels for each bean within this module directory
275 modules/$module_name/SubPanelViewer.php
276 - redirects to: include/generic/SubPanelViewer.php
278 modules/$module_name/SaveRelationship.php
279 - redirects to: include/generic/SaveRelationship.php
283 modules/$module_name/DetailView.php
284 - contains SubPanelTiles
286 include/ListView/ListView.php
289 processHeaderDynamic()
303 -------------------------------------------------------------------------------
308 - Within the SugarWidgetField display() function, based on the field data type being displayed, call another SugarWidget
309 that can output it correctly
311 - this includes checkboxes, dropdowns, relationships, dates, etc..
313 - do it throughout the rest of the modules
315 - might need to change the how "create" button passes form data.
316 - make it more configurable so that it can pass custom form data from
319 - change how tabs are displayed/hidden.
321 - right now it uses the linked_fields directly from the sugarbean
323 - use the visible_subpanels definition in the layout_def.php, or just use the order in subpanel_defines itself. if you do
324 you have to add an order_index to each field and sort on that. maybe have a visible/hidden attribute
326 - define custom titles in visible_subpanels, else fall back to subpanel string.
328 - where do you put union subpanel definitions? change function that returns the definitions to another search path.
330 - create special union subpanel type.
332 - not just one focus, but an array of them, and some may have be the same class
334 - make layout editor work with subpanel listviews
337 -------------------------------------------------------------------------------
340 - using firefox, when the "select" button is within the div that gets it's innerHTML
341 replaced, things break the second time you select a new relationship. it
342 fails on the window.open that is called with the popup_helper. some internal
344 this is why the top buttons are in SubPanelTiles.php and not SubPanel.php
345 this needs to be resolve or else we will not be able to have popups that
350 -------------------------------------------------------------------------------
352 $layout_defs['account'] = array(
354 'subpanel_setup' => array (
356 // sets up which panels to show, in which order, and with what
358 'show_subpanels' => array (
361 /// which subpanel to show
362 'subpanel_key'=>'opportunities',
364 /// custom string for the title of this subpanel
365 'string_key'=>'LBL_OPPORTUNITIES',
370 // defines the default subpanel definition for this SugarBean
371 'default_subpanel_define' => array (
372 'class_name'=>array('Opportunity'),
374 // define top left buttons
375 'top_buttons'=>array(
377 'widget_class'=>'SubPanelTopCreateButton',
380 'widget_class'=>'SubPanelTopSelectButton',
383 // define list fields
384 // yea, i know this will only show the Name
385 'list_fields'=> array(
388 'module'=>'Accounts',
394 // defines custom subpanel definitions for this SugarBean
395 'subpanel_defines' => array (
396 'opportunities' => array (
397 // define top left buttons
398 'top_buttons'=>array(
400 'widget_class'=>'SubPanelTopCreateButton',
403 'widget_class'=>'SubPanelTopSelectButton',
406 'class_name'=>array('Opportunity'),
407 // define list fields
408 // this one displays the same fields as the original
409 'list_fields'=> array(
412 'module'=>'Opportunities',
416 'varname'=>'account_name',
417 'vname'=>'LBL_LIST_ACCOUNT_NAME',
420 'name'=>'date_closed',
423 'widget_class'=>'SubPanelEditButton',
424 'name'=>'edit_button',
429 'class_name'=>array('Opportunity'),
430 'top_buttons'=>array(
432 'widget_class'=>'SubPanelTopCreateButton',
435 'widget_class'=>'SubPanelTopSelectButton',
439 // this one also displays the same fields as the original
440 'list_fields'=> array(
442 'varname'=>'ENCODED_NAME',
444 'vname'=>'LBL_LIST_NAME',
445 'module'=>'Contacts',
449 'varname'=>'ACCOUNT_NAME',
450 'vname'=>'LBL_LIST_ACCOUNT_NAME',
456 'vname'=>'LBL_LIST_PHONE',
457 'name'=>'phone_home',
460 'widget_class'=>'SubPanelEditButton',
461 'name'=>'edit_button',
464 'widget_class'=>'SubPanelRemoveButton',
465 'name'=>'remove_button',