org.symbian.tools.wrttools/projecttemplates/WRTKit/UI/ContentPanel.js
changeset 309 c01f5ab28a11
parent 308 c521df56b15d
child 310 e9484be98cfe
equal deleted inserted replaced
308:c521df56b15d 309:c01f5ab28a11
     1 /**
       
     2  * Copyright (c) 2009-2010 Symbian Foundation and/or its subsidiary(-ies).
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of the License "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  * 
       
    12  * Contributors:
       
    13  * 
       
    14  * Description:
       
    15  * 
       
    16  */
       
    17 
       
    18 ///////////////////////////////////////////////////////////////////////////////
       
    19 // The ContentPanel class is a control for displaying content. The panel
       
    20 // can be expanded and collapsed.
       
    21 
       
    22 // Constructor.
       
    23 function ContentPanel(id, caption, content, foldable, expanded) {
       
    24     if (id != UI_NO_INIT_ID) {
       
    25         this.init(id, caption, content, foldable, expanded);
       
    26     }
       
    27 }
       
    28 
       
    29 // ContentPanel inherits from Control.
       
    30 ContentPanel.prototype = new Control(UI_NO_INIT_ID);
       
    31 
       
    32 // The element hierarchy in a content panel is as follows:
       
    33 //
       
    34 // rootElement
       
    35 //     assemblyElement
       
    36 //         captionElement
       
    37 //             foldToggleElement
       
    38 //                 captionLinkElement
       
    39 //                     captionTextElement
       
    40 //     contentElement
       
    41 //
       
    42 // captionTextElement is moved under foldToggleElement if disabled
       
    43 // or captionElement if not foldable
       
    44 
       
    45 // The fold toggle element used for folding content panels.
       
    46 ContentPanel.prototype.foldToggleElement = null;
       
    47 
       
    48 // The caption link element of this control.
       
    49 ContentPanel.prototype.captionLinkElement = null;
       
    50 
       
    51 // The caption text element of this control.
       
    52 ContentPanel.prototype.captionTextElement = null;
       
    53 
       
    54 // The content element of this control.
       
    55 ContentPanel.prototype.contentElement = null;
       
    56 
       
    57 // The foldable state of this control.
       
    58 ContentPanel.prototype.foldable = false;
       
    59 
       
    60 // The expanded state of this control.
       
    61 ContentPanel.prototype.expanded = false;
       
    62 
       
    63 // Enabled status.
       
    64 ContentPanel.prototype.enabled = false;
       
    65 
       
    66 // Initializer - called from constructor.
       
    67 ContentPanel.prototype.init = function(id, caption, content, foldable, expanded) {
       
    68     uiLogger.debug("ContentPanel.init(" + id + ", " + caption + ", " + content + ", " + foldable + ", " + expanded + ")");
       
    69     
       
    70     // call superclass initializer
       
    71     Control.prototype.init.call(this, id, caption);
       
    72     
       
    73     // the control defaults to enabled
       
    74     this.enabled = true;
       
    75     
       
    76     // create caption text element
       
    77     this.captionTextElement = document.createElement("span");
       
    78     
       
    79     // disconnect the control element
       
    80     this.assemblyElement.removeChild(this.controlElement);
       
    81     
       
    82     // set the foldable state
       
    83     this.foldable = foldable;
       
    84     
       
    85     // is this a foldable content panel?
       
    86     if (foldable) {
       
    87         // create fold toggle element
       
    88         this.foldToggleElement = document.createElement("div");
       
    89         this.captionElement.appendChild(this.foldToggleElement);
       
    90         
       
    91         // create caption link and add to caption element
       
    92         this.captionLinkElement = document.createElement("a");
       
    93         this.captionLinkElement.href = "JavaScript:void(0)";
       
    94         this.foldToggleElement.appendChild(this.captionLinkElement);
       
    95         
       
    96         // add the text element to the link element
       
    97         this.captionLinkElement.appendChild(this.captionTextElement);
       
    98         
       
    99         // bind event listeners
       
   100         var self = this;
       
   101         this.captionLinkElement.addEventListener("focus", function() { self.focusStateChanged(true); }, false);
       
   102         this.captionLinkElement.addEventListener("blur", function() { self.focusStateChanged(false); }, false);
       
   103         this.foldToggleElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
       
   104         this.foldToggleElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
       
   105         this.foldToggleElement.addEventListener("mousedown", function(event) {
       
   106                                                                  self.captionClicked();
       
   107                                                                  event.stopPropagation();
       
   108                                                                  event.preventDefault();
       
   109                                                              }, true);
       
   110         this.foldToggleElement.addEventListener("keydown", function(event) {
       
   111                                                                // center and enter trigger the action
       
   112                                                                if (event.keyCode == 0 || event.keyCode == 13) {
       
   113                                                                    self.captionClicked();
       
   114                                                                    event.stopPropagation();
       
   115                                                                    event.preventDefault();
       
   116                                                                }
       
   117                                                            }, true);
       
   118         
       
   119         this.expanded = expanded;
       
   120     } else {
       
   121         // since this is not a foldable panel the content should be expanded
       
   122         this.expanded = true;
       
   123         
       
   124         // add the text element directly to the caption element
       
   125         this.captionElement.appendChild(this.captionTextElement);
       
   126     }
       
   127     
       
   128     // create content element
       
   129     this.contentElement = document.createElement("div");
       
   130     this.contentElement.style.display = this.expanded ? "block" : "none";
       
   131     this.rootElement.appendChild(this.contentElement);
       
   132     
       
   133     // set caption, content and expanded state
       
   134     this.setCaption(caption);
       
   135     this.setContent(content);
       
   136     
       
   137     // update style
       
   138     this.updateStyleFromState();
       
   139 };
       
   140 
       
   141 // Returns the enabled state.
       
   142 ContentPanel.prototype.isEnabled = function() {
       
   143     return this.enabled;
       
   144 };
       
   145 
       
   146 // Sets the enabled state.
       
   147 ContentPanel.prototype.setEnabled = function(enabled) {
       
   148     uiLogger.debug("ContentPanel.setEnabled(" + enabled + ")");
       
   149     
       
   150     // bail out early if there is no change in state
       
   151     if (this.enabled == enabled) {
       
   152         return;
       
   153     }
       
   154     
       
   155     // set the enabled state
       
   156     this.enabled = enabled;
       
   157     
       
   158     // is this a foldable content?
       
   159     if (this.foldable) {
       
   160          // the caption link must be disabled
       
   161         if (this.enabled) {
       
   162             // diabled -> enabled
       
   163             this.foldToggleElement.removeChild(this.captionTextElement);
       
   164             this.foldToggleElement.appendChild(this.captionLinkElement);
       
   165             this.captionLinkElement.appendChild(this.captionTextElement);
       
   166         } else {
       
   167             // enabled -> diabled
       
   168             this.captionLinkElement.removeChild(this.captionTextElement);
       
   169             this.foldToggleElement.removeChild(this.captionLinkElement);
       
   170             this.foldToggleElement.appendChild(this.captionTextElement);
       
   171         }
       
   172     }
       
   173     
       
   174     // update style
       
   175     this.updateStyleFromState();    
       
   176 };
       
   177 
       
   178 // Returns the caption; null if none.
       
   179 ContentPanel.prototype.getCaption = function() {
       
   180     return this.caption;
       
   181 };
       
   182 
       
   183 // Sets the caption; null if none.
       
   184 ContentPanel.prototype.setCaption = function(caption) {
       
   185     // bail out if the caption text element has not been created
       
   186     // this is to prevent the superclass init calling this before
       
   187     // we've initialized our custom caption
       
   188     if (this.captionTextElement == null)
       
   189         return;
       
   190     
       
   191     uiLogger.debug("ContentPanel.setCaption(" + caption + ")");
       
   192     
       
   193     // set the display style
       
   194     this.captionElement.style.display = (caption == null) ? "none" : "block";
       
   195     
       
   196     // set the caption
       
   197     this.caption = caption;
       
   198     this.captionTextElement.innerHTML = (caption == null) ? "" : caption;
       
   199     
       
   200     // update style
       
   201     this.updateStyleFromState();
       
   202 };
       
   203 
       
   204 // Returns the content.
       
   205 ContentPanel.prototype.getContent = function() {
       
   206     return this.contentElement.innerHTML;
       
   207 };
       
   208 
       
   209 // Sets the content.
       
   210 ContentPanel.prototype.setContent = function(content) {
       
   211     uiLogger.debug("ContentPanel.setContent(" + content + ")");
       
   212     this.contentElement.innerHTML = (content == null) ? "" : content;
       
   213 };
       
   214 
       
   215 // Returns the focusable state for the control.
       
   216 ContentPanel.prototype.isFocusable = function() {
       
   217     // a content panel is focusable if it's foldable and enabled
       
   218     return (this.foldable && this.enabled);
       
   219 };
       
   220 
       
   221 // Sets the focused state for the control.
       
   222 // Note: This may not always succeed.
       
   223 ContentPanel.prototype.setFocused = function(focused) {
       
   224     uiLogger.debug("ContentPanel.setFocused(" + focused + ")");
       
   225     if (this.enabled && this.foldable) {
       
   226         if (focused) {
       
   227             this.captionLinkElement.focus();
       
   228         } else {
       
   229             this.captionLinkElement.blur();
       
   230         }
       
   231     }
       
   232     // note that this.focused gets set as a result of focusStateChanged() being called
       
   233     // rather than setting it explicitly here
       
   234 };
       
   235 
       
   236 // Returns the expanded state.
       
   237 ContentPanel.prototype.isExpanded = function() {
       
   238     return this.expanded;
       
   239 };
       
   240 
       
   241 // Sets the expanded state.
       
   242 ContentPanel.prototype.setExpanded = function(expanded) {
       
   243     uiLogger.debug("ContentPanel.setExpanded(" + expanded + ")");
       
   244     
       
   245     // make sure only foldable content panels are folded
       
   246     if (!this.foldable) {
       
   247         uiLogger.warn("Cannot fold a non-foldable content panel!");
       
   248         return;
       
   249     }
       
   250     
       
   251     this.expanded = expanded;
       
   252     if (this.expanded) {
       
   253         // expand
       
   254         this.contentElement.style.display = "block";
       
   255         
       
   256         // find out control top and bottom
       
   257         var controlTop = this.getAbsoluteTop(this.rootElement);
       
   258         var controlHeight = this.rootElement.clientHeight;
       
   259         var controlBottom = controlTop + controlHeight;
       
   260         
       
   261         // find out the viewport top and bottom
       
   262         var viewportTop = window.scrollY;
       
   263         var viewportHeight = window.innerHeight;
       
   264         var viewportBottom = viewportTop + viewportHeight;
       
   265         
       
   266         // make sure the control is positioned so that it can be seen
       
   267         var overflow = controlBottom - viewportBottom;
       
   268         if (overflow > 0) {
       
   269             // there's overflow so we need to scroll to get the control
       
   270             // into the viewport - however not so far that the control
       
   271             // goes past the viewport top.
       
   272             var distanceToTop = controlTop - viewportTop;
       
   273             var scrollAmount = Math.min(overflow, distanceToTop);
       
   274             window.scrollBy(0, scrollAmount);
       
   275         }
       
   276     } else {
       
   277         // collapse
       
   278         this.contentElement.style.display = "none";
       
   279     }
       
   280     
       
   281     // notify event listeners
       
   282     this.fireEvent(this.createEvent("ExpandedStateChanged", this.expanded));
       
   283     
       
   284     // update the style
       
   285     this.updateStyleFromState();
       
   286 };
       
   287 
       
   288 // Returns the absolute position (y) of the given element.
       
   289 ContentPanel.prototype.getAbsoluteTop = function(element) {
       
   290     // traverse from element to root and add top-offset
       
   291     // for each element we find on the way
       
   292     var absTop = 0;
       
   293     while (element != null) {
       
   294         absTop += element.offsetTop;
       
   295         element = element.offsetParent;
       
   296     }
       
   297     return absTop;
       
   298 };
       
   299 
       
   300 // Callback for when the caption is clicked.
       
   301 ContentPanel.prototype.captionClicked = function() {
       
   302     uiLogger.debug("ContentPanel.captionClicked()");
       
   303     
       
   304     // if we're enabled then a click results toggling the expanded state
       
   305     if (this.enabled) {
       
   306         // focus when clicked
       
   307         if (!this.focused) {
       
   308             this.captionLinkElement.focus();
       
   309         }
       
   310         
       
   311         // toggle the expanded state
       
   312         this.setExpanded(!this.expanded);
       
   313     }
       
   314 };
       
   315 
       
   316 // Updates the style of the control to reflects the state of the control.
       
   317 ContentPanel.prototype.updateStyleFromState = function() {
       
   318     uiLogger.debug("ContentPanel.updateStyleFromState()");
       
   319 
       
   320     // determine the state name
       
   321     var stateName = this.getStyleStateName();
       
   322     
       
   323     // set root element class name
       
   324     this.setClassName(this.rootElement, "Control");
       
   325 
       
   326     // set the control assembly class names
       
   327     this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
       
   328     
       
   329     if (this.foldable) {
       
   330         // foldable content panel
       
   331         this.setClassName(this.captionElement, "ContentPanelCaptionFoldable");
       
   332         this.setClassName(this.foldToggleElement, "ContentPanelFoldToggle ContentPanelFoldToggle" + (this.expanded ? "Expanded" : "Collapsed"));
       
   333     } else {
       
   334         // non-folding
       
   335         this.setClassName(this.captionElement, "ContentPanelCaptionNonFoldable");
       
   336     }
       
   337     
       
   338     // set the content caption text class names
       
   339     this.setClassName(this.captionTextElement, "ContentPanelCaptionText ContentPanelCaptionText" + stateName);
       
   340     
       
   341     // set the content element class names
       
   342     this.setClassName(this.contentElement, "ContentPanelContent");
       
   343 };