]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SubPanel/subpanels.txt
Release 6.5.0
[Github/sugarcrm.git] / include / SubPanel / subpanels.txt
1 /*********************************************************************************
2  * SugarCRM Community Edition is a customer relationship management program developed by
3  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
4  * 
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.
11  * 
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
15  * details.
16  * 
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
20  * 02110-1301 USA.
21  * 
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.
24  * 
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.
28  * 
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  ********************************************************************************/
35
36 SubPanel implementation:
37
38
39 Summary:
40
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.
43
44
45 -------------------------------------------------------------------------------
46
47 Class Heirarchy: 
48
49 DetailView -> SubPanelTiles ->(remotely calls) -> 
50         SubPanelViewer -> SubPanel -> ListView -> (calls template) --> SubPanelDynamic.html
51
52
53 -------------------------------------------------------------------------------
54
55 SubPanelTiles:
56
57   The SubPanelTiles class creates the subpanel <div>s,  outputs the javascript to manage loading/displaying panels, and displays tabs.
58
59     - Each Subpanel is outputted as empty <divs>
60
61     - When a tab is selected, or a subpanel to be maximized, the showSubPanel javascript function is called.
62
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>.
65
66         - The XMLHTTPRequest calls the subpanel snippets with your normal Sugar URL with module/action/record
67
68
69         - The header/menu/footer panels are not displayed by adding to the query string: "&sugar_body_only=1&inline=1"
70
71         - the "action" is SubPanelViewer, which of course causes Sugar to execute:
72                          modules/$_REQUEST['module']/SubPanelViewer.php
73
74         - SubPanelViewer.php files in every module directory usually just call include/SubPanel/SubPanelViewer.php and return.
75
76         - SubPanelViewer acts as a wrapper around the SubPanel when it is called remotely.
77         
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.
80
81         - the presence of, order of, and SugarWidget class of these buttons are controlled in the subpanel definitions.
82
83     - (optional) The tabs are displayed using the SugarWidgetTabs class, which outputs the javascript/html.
84         
85         SugarWidgetTabs is generated by javascript, and tab selection is done by dynamically changing CSS attributes of the tabs. 
86
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.
90
91
92 -------------------------------------------------------------------------------
93
94
95 SubPanel Snippets:
96
97
98                 SubPanel.php acts as a wrapper around ListView.php:
99
100                         - instantiates parent and related bean
101
102                         - gets subpanel definitions using a search path (custom, then module-specific, then global)
103
104                         - ListView manages sorting, paging and displaying the header and rows
105
106                         - SubPanel sets a flag in ListView that it knows to run dynamically
107
108                         - passes ListView the javascript link wrappers so that paging and sorting links will work correctly.
109
110                           The links will call a javascript function that will return the HTML to the subpanel <DIV>, 
111                           and not refresh the whole page
112
113                         - calls $ListView->loadListFieldDefs($list_fields,$child_focus); so that it can iterate through
114                           the fields and display the appropriate widget and data
115
116 -------------------------------------------------------------------------------
117
118                 ListView and SugarWidgets
119                 
120
121                         - To generate the header and data cells, dynamic ListViews use SugarWidget singleton display functions.
122
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
126
127                                 snippet:
128                                 <?php
129                                 foreach($this->list_field_defs as $list_field)
130                                 {
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;
134
135                                         $widget_contents = $layout_manager->widgetDisplay($list_field);
136                                                                                                    
137                                         $this->xTemplate->assign('CELL', $widget_contents);
138                                         $this->xTemplate->parse($xtemplateSection.".row.cell");
139                                 }
140                                 ?>
141                         - a list_field definition example (from layout_defs.php)
142
143                         'list_fields'=> array(
144
145                           array (
146
147                                 // use the 'ENCODED_NAME' key to get the data
148                                  'varname'=>'ENCODED_NAME',
149
150                                 // the key into the vardef.php definition
151                                 // also used as the sort order.. split that out
152                                  'name'=>'last_name',
153
154                                 // use this custom label in the header
155                                  'vname'=>'LBL_LIST_NAME',
156
157                                 // link this field
158                                  'linked'=>true,
159
160                                 // use this module because we are linking this field
161                                  'module'=>'Contacts',
162
163                           ),
164                         ),
165
166
167                         - SugarWidgetField will call a different displayXXX() function depending on the context of the container.
168
169                                 - if in the "HeaderCell" context, it calls $this->displayHeaderCell($args), which returns the HTML
170                                   content of the Header Cell
171
172                                 - if in the "List" context, it calls $this->displayList($args), which returns the HTML content of 
173                                   a data cell of the ListView.
174                         
175                                 - Before ListView displays the widget for a cell, it attaches a pointer to the data for that 
176                                         SugarBean instance.
177
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
180
181
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
185
186         Selecting and deleting relationships:
187
188         - When either a relationship is added via a popup, or the remove button is clicked, an async XMLHTTPRequest is called.
189
190                 - The contents of the request is a POST or GET that is constructed and send to the server. The return_url is set
191
192                         so that the server returns the Subpanel snippet, which is then added to the innerHTML of the calling subpanel
193
194
195 ------------------------------------------------------------------------------
196 Back end methods:
197
198
199         - When being used for Subpanels, ListView uses the get_related_list() method of the SugarBean Class to retrieve related objects.
200
201
202                 - in $sugarbean->get_related_list():
203
204                         // load relationship
205                         $this->load_relationship($related_field_name);
206
207                         // now get the query that fetches related records:
208                         $query_array = $this->$related_field_name->getQuery(true);
209
210         - adding and deleting relationships are done through the include/generic/Save2.php and include/generic/DeleteRelationship.php 
211
212                 - Link::add() and Link::delete() methods are the core functions that do the database work.
213
214
215 -------------------------------------------------------------------------------
216
217 FILES:
218
219 New:
220
221 include/SubPanel/SubPanelDynamic.html  
222  - the xtemplate file that provides the skeleton of the dynamic ListView
223    output
224
225 include/SubPanel/SubPanel.php  
226  - prepares ListView to output related objects, and within a <div>
227
228 include/SubPanel/SubPanelTiles.php  
229  - includes tabs and each subpanel, and manages the show/hide and UI.
230
231 include/SubPanel/SubPanelViewer.php
232  - wrapper for SubPanel.php when called remotely
233
234 include/generic/DeleteRelationship.php  
235  - generically deletes a relationship based on a parent focus, the linked_field, 
236    and the linked id;
237
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
241
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
245    fields.
246
247 include/generic/SugarWidgets/SugarWidget.php
248  - base class, defines display(), and holds a reference to the LayoutManager;
249
250 include/generic/SugarWidgets/SugarWidgetField.php
251  - base class to represent database columns as UI widgets
252
253 include/generic/SugarWidgets/SugarWidgetSubPanelTopButtons.php
254  - they are the "Create" and "Select" buttons
255
256 include/generic/SugarWidgets/registered_widgets.php      
257  - add new SugarWidget classes here
258
259 include/generic/SugarWidgets/SugarWidgetDynamicTabs.php  
260  - javascript generated tabs
261
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
266
267 each module:
268
269 modules/$module_name/Save2.php
270  - redirects to: include/generic/Save2.php
271
272 modules/$module_name/layout_defs.php
273  - defines subpanels for each bean within this module directory
274
275 modules/$module_name/SubPanelViewer.php
276  - redirects to: include/generic/SubPanelViewer.php
277
278 modules/$module_name/SaveRelationship.php
279  - redirects to: include/generic/SaveRelationship.php
280
281 CHANGED:
282
283 modules/$module_name/DetailView.php
284  - contains SubPanelTiles
285
286 include/ListView/ListView.php
287  - added:
288    loadListFieldDefs()
289    processHeaderDynamic()
290    getLayoutManager()
291    is_dynamic
292
293  - changed:
294    processListRows()
295    processListViewTwo()
296
297 data/SugarBean.php
298  - added:
299    get_related_list()
300
301
302
303 -------------------------------------------------------------------------------
304
305 TODO: 
306
307
308  - Within the SugarWidgetField display() function, based on the field data type being displayed, call another SugarWidget 
309         that can output it correctly
310
311     - this includes checkboxes, dropdowns, relationships, dates, etc..
312
313  - do it throughout the rest of the modules
314  
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
317       focus bean
318
319  - change how tabs are displayed/hidden. 
320
321         - right now it uses the linked_fields directly from the sugarbean
322
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
325
326         - define custom titles in visible_subpanels, else fall back to subpanel string.
327
328         - where do you put union subpanel definitions? change function that returns the definitions to another search path.
329
330  - create special union subpanel type.
331
332         - not just one focus, but an array of them, and some may have be the same class
333
334  - make layout editor work with subpanel listviews
335  
336
337 -------------------------------------------------------------------------------
338 PROBLEMS:
339
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
343   mozilla error.
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
346   cause refreshes.
347
348
349 sample layout_def:
350 -------------------------------------------------------------------------------
351
352 $layout_defs['account'] = array(
353
354         'subpanel_setup' => array (
355
356                 // sets up which panels to show, in which order, and with what
357                 // linked_fields
358                 'show_subpanels' => array (
359                         array(
360
361                         /// which subpanel to show
362                         'subpanel_key'=>'opportunities', 
363
364                         /// custom string for the title of this subpanel
365                         'string_key'=>'LBL_OPPORTUNITIES',
366                         ),
367                 ),
368         ),
369
370         // defines the default subpanel definition for this SugarBean
371         'default_subpanel_define' => array (
372                 'class_name'=>array('Opportunity'),
373
374                 // define top left buttons
375                 'top_buttons'=>array(
376                         array (
377                          'widget_class'=>'SubPanelTopCreateButton',
378                                 ),
379                         array (
380                          'widget_class'=>'SubPanelTopSelectButton',
381                                 ),
382                         ),
383                 // define list fields
384                 // yea, i know this will only show the Name
385                 'list_fields'=> array(
386                         array (
387                         'name'=>'name',
388                         'module'=>'Accounts',
389                         'linked'=>true,
390                         ),
391                 ),
392         ),
393
394         // defines custom subpanel definitions for this SugarBean
395         'subpanel_defines' => array (
396                 'opportunities' => array (
397                         // define top left buttons
398                         'top_buttons'=>array(
399                                 array (
400                                  'widget_class'=>'SubPanelTopCreateButton',
401                                 ),
402                                 array (
403                                  'widget_class'=>'SubPanelTopSelectButton',
404                                 ),
405                         ),
406                         'class_name'=>array('Opportunity'),
407                 // define list fields
408                 // this one displays the same fields as the original
409                         'list_fields'=> array(
410                                 array (
411                                  'name'=>'name',
412                                  'module'=>'Opportunities',
413                                  'linked'=>true,
414                                 ),
415                                 array (
416                                  'varname'=>'account_name',
417                                  'vname'=>'LBL_LIST_ACCOUNT_NAME',
418                                 ),
419                                 array (
420                                  'name'=>'date_closed',
421                                 ),
422                                 array (
423                                  'widget_class'=>'SubPanelEditButton',
424                                  'name'=>'edit_button',
425                                 ),
426                         ),
427                 ),
428                 'contact' => array (
429                         'class_name'=>array('Opportunity'),
430                         'top_buttons'=>array(
431                                 array (
432                                  'widget_class'=>'SubPanelTopCreateButton',
433                                 ),
434                                 array (
435                                  'widget_class'=>'SubPanelTopSelectButton',
436                                 ),
437                         ),
438
439                         // this one also displays the same fields as the original
440                         'list_fields'=> array(
441                         array (
442                                  'varname'=>'ENCODED_NAME',
443                                  'name'=>'last_name',
444                                  'vname'=>'LBL_LIST_NAME',
445                                  'module'=>'Contacts',
446                                  'linked'=>true,
447                         ),
448                         array (
449                                  'varname'=>'ACCOUNT_NAME',
450                                  'vname'=>'LBL_LIST_ACCOUNT_NAME',
451                         ),
452                         array (
453                                  'name'=>'email1',
454                         ),
455                         array (
456                                  'vname'=>'LBL_LIST_PHONE',
457                                  'name'=>'phone_home',
458                         ),
459                         array (
460                                  'widget_class'=>'SubPanelEditButton',
461                                  'name'=>'edit_button',
462                         ),
463                         array (
464                                  'widget_class'=>'SubPanelRemoveButton',
465                                  'name'=>'remove_button',
466                         ),
467                         ),
468                 )
469         )
470 );
471