View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.container;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
20  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
21  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
22  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
23  import org.kuali.rice.krad.uif.UifConstants;
24  import org.kuali.rice.krad.uif.component.Component;
25  import org.kuali.rice.krad.uif.util.BreadcrumbItem;
26  import org.kuali.rice.krad.uif.util.BreadcrumbOptions;
27  import org.kuali.rice.krad.uif.util.PageBreadcrumbOptions;
28  import org.kuali.rice.krad.uif.view.FormView;
29  import org.kuali.rice.krad.uif.view.View;
30  import org.kuali.rice.krad.web.form.UifFormBase;
31  
32  import java.util.ArrayList;
33  import java.util.List;
34  import java.util.Map;
35  
36  /**
37   * A PageGroup represents a page of a View.
38   *
39   * <p>
40   * PageGroups should only be used with a View component.  The contain the main content that will be seen by the
41   * user using the View.  Like all other groups, PageGroup can contain items, headers and footers.  Pages also
42   * have their own BreadcrumbItem.
43   * </p>
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  @BeanTags({@BeanTag(name = "page-bean", parent = "Uif-Page"),
48          @BeanTag(name = "disclosure-page-bean", parent = "Uif-Disclosure-Page"),
49          @BeanTag(name = "documentPage-bean", parent = "Uif-DocumentPage"),
50          @BeanTag(name = "inquiryPage-bean", parent = "Uif-InquiryPage"),
51          @BeanTag(name = "lookupPage-bean", parent = "Uif-LookupPage"),
52          @BeanTag(name = "maintenancePage-bean", parent = "Uif-MaintenancePage")})
53  public class PageGroup extends Group {
54      private static final long serialVersionUID = 7571981300587270274L;
55  
56      private boolean autoFocus = false;
57  
58      private PageBreadcrumbOptions breadcrumbOptions;
59      private BreadcrumbItem breadcrumbItem;
60      private boolean stickyFooter;
61  
62      /**
63       * Setup various breadcrumbOptions inherited from view if not explicitly set.
64       *
65       * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View,
66       *      Object)
67       */
68      @Override
69      public void performInitialization(View view, Object model) {
70          super.performInitialization(view, model);
71  
72          //check to see if one of the items is a page, if so throw an exception
73          for (Component item : this.getItems()) {
74              if (item != null && item instanceof PageGroup) {
75                  throw new RuntimeException("The page with id='"
76                          + this.getId()
77                          + "' contains a page with id='"
78                          + item.getId()
79                          + "'.  Nesting a page within a page is not allowed since only one "
80                          + "page's content can be shown on the View "
81                          + "at a time.  This may have been caused by possible misuse of the singlePageView flag (when "
82                          + "this flag is true, items set on the View become items of the single page.  Instead use "
83                          + "the page property on the View to set the page being used).");
84              }
85          }
86  
87          setupBreadcrumbs(view, model);
88      }
89  
90      /**
91       * Perform finalize here adds to its document ready script the
92       * setupValidator js function for setting up the validator for this view.  Also setup various breadcrumb related
93       * settings for the page.
94       *
95       * @see ContainerBase#performFinalize(org.kuali.rice.krad.uif.view.View,
96       *      Object, org.kuali.rice.krad.uif.component.Component)
97       */
98      @Override
99      public void performFinalize(View view, Object model, Component parent) {
100         super.performFinalize(view, model, parent);
101 
102         this.addDataAttribute(UifConstants.DataAttributes.TYPE, "Page");
103 
104         String prefixScript = "";
105         if (this.getOnDocumentReadyScript() != null) {
106             prefixScript = this.getOnDocumentReadyScript();
107         }
108 
109         if (view instanceof FormView && ((FormView) view).isValidateClientSide()) {
110             this.setOnDocumentReadyScript(prefixScript + "\nsetupPage(true);");
111         } else {
112             this.setOnDocumentReadyScript(prefixScript + "\nsetupPage(false);");
113         }
114 
115         finalizeBreadcrumbs(view, model);
116     }
117 
118     /**
119      * Setup the BreadcrumbOptions and BreadcrumbItem for a PageGroup.  To be called from performInitialization.
120      *
121      * @param view the page's View
122      * @param model the model
123      */
124     protected void setupBreadcrumbs(View view, Object model) {
125         BreadcrumbOptions viewBreadcrumbOptions = view.getBreadcrumbOptions();
126 
127         //inherit prePageBreadcrumbs, preViewBreadcrumbs, and overrides from the view if not set
128         if (breadcrumbOptions.getHomewardPathBreadcrumbs() == null
129                 && viewBreadcrumbOptions != null
130                 && viewBreadcrumbOptions.getHomewardPathBreadcrumbs() != null) {
131             breadcrumbOptions.setHomewardPathBreadcrumbs(viewBreadcrumbOptions.getHomewardPathBreadcrumbs());
132 
133             for (BreadcrumbItem item : breadcrumbOptions.getHomewardPathBreadcrumbs()) {
134                 view.assignComponentIds(item);
135             }
136         }
137 
138         if (breadcrumbOptions.getPrePageBreadcrumbs() == null
139                 && viewBreadcrumbOptions != null
140                 && viewBreadcrumbOptions.getPrePageBreadcrumbs() != null) {
141             breadcrumbOptions.setPrePageBreadcrumbs(viewBreadcrumbOptions.getPrePageBreadcrumbs());
142 
143             for (BreadcrumbItem item : breadcrumbOptions.getPrePageBreadcrumbs()) {
144                 view.assignComponentIds(item);
145             }
146         }
147 
148         if (breadcrumbOptions.getPreViewBreadcrumbs() == null
149                 && viewBreadcrumbOptions != null
150                 && viewBreadcrumbOptions.getPreViewBreadcrumbs() != null) {
151             breadcrumbOptions.setPreViewBreadcrumbs(viewBreadcrumbOptions.getPreViewBreadcrumbs());
152 
153             for (BreadcrumbItem item : breadcrumbOptions.getPreViewBreadcrumbs()) {
154                 view.assignComponentIds(item);
155             }
156         }
157 
158         if (breadcrumbOptions.getBreadcrumbOverrides() == null
159                 && viewBreadcrumbOptions != null
160                 && viewBreadcrumbOptions.getBreadcrumbOverrides() != null) {
161             breadcrumbOptions.setBreadcrumbOverrides(viewBreadcrumbOptions.getBreadcrumbOverrides());
162 
163             for (BreadcrumbItem item : breadcrumbOptions.getBreadcrumbOverrides()) {
164                 view.assignComponentIds(item);
165             }
166         }
167     }
168 
169     /**
170      * Finalize the setup of the BreadcrumbOptions and the BreadcrumbItem for the PageGroup.  To be called from the
171      * performFinalize method.
172      *
173      * @param view the page's View
174      * @param model the model
175      */
176     protected void finalizeBreadcrumbs(View view, Object model) {
177         //set breadcrumbItem label same as the header, if not set
178         if (StringUtils.isBlank(breadcrumbItem.getLabel()) && this.getHeader() != null && StringUtils.isNotBlank(
179                 this.getHeader().getHeaderText())) {
180             breadcrumbItem.setLabel(this.getHeader().getHeaderText());
181         }
182 
183         //if label still blank, dont render
184         if (StringUtils.isBlank(breadcrumbItem.getLabel())) {
185             breadcrumbItem.setRender(false);
186         }
187 
188         //special breadcrumb request param handling
189         if (breadcrumbItem.getUrl().getControllerMapping() == null
190                 && breadcrumbItem.getUrl().getViewId() == null
191                 && model instanceof UifFormBase
192                 && breadcrumbItem.getUrl().getRequestParameters() == null
193                 && ((UifFormBase) model).getInitialRequestParameters() != null) {
194             //add the current request parameters if controllerMapping, viewId, and requestParams are null
195             //(this means that no explicit breadcrumbItem customization was set)
196             Map<String, String> requestParameters = ((UifFormBase) model).getInitialRequestParameters();
197 
198             //remove ajax properties because breadcrumb should always be a full view request
199             requestParameters.remove("ajaxReturnType");
200             requestParameters.remove("ajaxRequest");
201 
202             //remove pageId because this should be set by the BreadcrumbItem setting
203             requestParameters.remove("pageId");
204 
205             breadcrumbItem.getUrl().setRequestParameters(requestParameters);
206         }
207 
208         //form key handling
209         if (breadcrumbItem.getUrl().getFormKey() == null
210                 && model instanceof UifFormBase
211                 && ((UifFormBase) model).getFormKey() != null) {
212             breadcrumbItem.getUrl().setFormKey(((UifFormBase) model).getFormKey());
213         }
214 
215         //automatically set breadcrumbItem UifUrl properties below, if not set
216         if (breadcrumbItem.getUrl().getControllerMapping() == null && model instanceof UifFormBase) {
217             breadcrumbItem.getUrl().setControllerMapping(((UifFormBase) model).getControllerMapping());
218         }
219 
220         if (breadcrumbItem.getUrl().getViewId() == null) {
221             breadcrumbItem.getUrl().setViewId(view.getId());
222         }
223 
224         if (breadcrumbItem.getUrl().getPageId() == null) {
225             breadcrumbItem.getUrl().setPageId(this.getId());
226         }
227     }
228 
229     /**
230      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
231      */
232     @Override
233     public List<Component> getComponentsForLifecycle() {
234         List<Component> components = new ArrayList<Component>();
235 
236         components.add(breadcrumbItem);
237 
238         if (breadcrumbOptions != null) {
239             if (breadcrumbOptions.getHomewardPathBreadcrumbs() != null) {
240                 components.addAll(breadcrumbOptions.getHomewardPathBreadcrumbs());
241             }
242 
243             if (breadcrumbOptions.getPreViewBreadcrumbs() != null) {
244                 components.addAll(breadcrumbOptions.getPreViewBreadcrumbs());
245             }
246 
247             if (breadcrumbOptions.getPrePageBreadcrumbs() != null) {
248                 components.addAll(breadcrumbOptions.getPrePageBreadcrumbs());
249             }
250 
251             if (breadcrumbOptions.getBreadcrumbOverrides() != null) {
252                 components.addAll(breadcrumbOptions.getBreadcrumbOverrides());
253             }
254         }
255 
256         components.addAll(super.getComponentsForLifecycle());
257 
258         return components;
259     }
260 
261     /**
262      * When this is true, the first field of the kualiForm will be focused by
263      * default, unless the parameter focusId is set on the form (by an
264      * actionField), then that field will be focused instead. When this setting
265      * if false, no field will be focused.
266      *
267      * @return the autoFocus
268      */
269     @BeanTagAttribute(name = "autoFocus")
270     public boolean isAutoFocus() {
271         return this.autoFocus;
272     }
273 
274     /**
275      * @param autoFocus the autoFocus to set
276      */
277     public void setAutoFocus(boolean autoFocus) {
278         this.autoFocus = autoFocus;
279     }
280 
281     /**
282      * The breadcrumbOptions specific to this page.
283      *
284      * <p>
285      * Important note: breadcrumbOptions for preViewBreadcrumbs, prePageBreadcrumbs, and
286      * breadcrumbOverrides are inherited from the View if not explicitly set from the PageGroup level's
287      * breadcrumbOptions
288      * (if they contain a value at the view level and the property is null at the page level - default behavior).
289      * Explicitly providing an empty list or setting these properties at the PageGroup level will
290      * override this inheritance.
291      * </p>
292      *
293      * @return the {@link BreadcrumbOptions}
294      */
295     @BeanTagAttribute(name = "breadcrumbOptions", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
296     public PageBreadcrumbOptions getBreadcrumbOptions() {
297         return breadcrumbOptions;
298     }
299 
300     /**
301      * Set the breadcrumbOptions
302      *
303      * @param breadcrumbOptions
304      */
305     public void setBreadcrumbOptions(PageBreadcrumbOptions breadcrumbOptions) {
306         this.breadcrumbOptions = breadcrumbOptions;
307     }
308 
309     /**
310      * The breadcrumbItem for this page.  This is the item that (generally) appears last in the breadcrumb list.
311      *
312      * <p>
313      * If a label is not explicitly defined, the label is retrieved from the headerText of the PageGroup's header.
314      * If this is also not defined, the breadcrumbItem is NOT rendered.  The url properties do not need to be provided
315      * for this breadcrumbItem because it is automatically determined based on the this PageGroup's pageId, viewId,
316      * and controllerMapping retrieved from the initial controller request.
317      * </p>
318      *
319      * @return the breadcrumbItem for this page
320      */
321     @BeanTagAttribute(name = "breadcrumbItem", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
322     public BreadcrumbItem getBreadcrumbItem() {
323         return breadcrumbItem;
324     }
325 
326     /**
327      * Set the breadcrumbItem for this PageGroup
328      *
329      * @param breadcrumbItem
330      */
331     public void setBreadcrumbItem(BreadcrumbItem breadcrumbItem) {
332         this.breadcrumbItem = breadcrumbItem;
333     }
334 
335     /**
336      * When true, this page's footer will become sticky (fixed) at the bottom of the window
337      *
338      * @return true if the page footer is sticky, false otherwise
339      */
340     @BeanTagAttribute(name = "stickyFooter")
341     public boolean isStickyFooter() {
342         return stickyFooter;
343     }
344 
345     /**
346      * Set to true to make this page's footer sticky
347      *
348      * @param stickyFooter
349      */
350     public void setStickyFooter(boolean stickyFooter) {
351         this.stickyFooter = stickyFooter;
352 
353         if (this.getFooter() != null) {
354             this.getFooter().addDataAttribute(UifConstants.DataAttributes.STICKY_FOOTER, Boolean.toString(
355                     stickyFooter));
356         }
357     }
358 
359     /**
360      * @see org.kuali.rice.krad.uif.component.Component#completeValidation
361      */
362     @Override
363     public void completeValidation(ValidationTrace tracer) {
364         tracer.addBean(this);
365 
366         // Checks that no invalid items are present
367         for (int i = 0; i < getItems().size(); i++) {
368             if (getItems().get(i).getClass() == PageGroup.class || getItems().get(i).getClass()
369                     == NavigationGroup.class) {
370                 String currentValues[] = {"item(" + i + ").class =" + getItems().get(i).getClass()};
371                 tracer.createError("Items in PageGroup cannot be PageGroup or NaviagtionGroup", currentValues);
372             }
373         }
374 
375         super.completeValidation(tracer.getCopy());
376     }
377 }