Wikipedia/WRTKit/UI/SelectionList.js
changeset 20 918767a9c8d3
equal deleted inserted replaced
19:f3521a11d878 20:918767a9c8d3
       
     1 /*
       
     2 © Copyright 2008 Nokia Corporation. All rights reserved.
       
     3 
       
     4 IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
       
     5 Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
       
     6 and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
       
     7 you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
       
     8 Widget files.
       
     9 
       
    10 In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
       
    11 grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
       
    12 Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
       
    13 CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
       
    14 Widgets.
       
    15 
       
    16 If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
       
    17 redistributions of the WRTKit and Example files.
       
    18 
       
    19 You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
       
    20 that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
       
    21 Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
       
    22 Nokia herein, including but not limited to any patent rights that may be infringed by your products that
       
    23 incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
       
    24 may be incorporated.
       
    25 
       
    26 The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
       
    27 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
       
    28 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
       
    29 PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
       
    30 ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
       
    31 
       
    32 IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
       
    33 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
       
    35 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
       
    36 DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
       
    37 OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
       
    38 EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    39 
       
    40 */
       
    41 
       
    42 ///////////////////////////////////////////////////////////////////////////////
       
    43 // The SelectionList class implements a single or multi selection control
       
    44 // that lets users select one or more options from a list of options.
       
    45 
       
    46 // Constructor.
       
    47 function SelectionList(id, caption, options, multipleSelection, selected) {
       
    48     if (id != UI_NO_INIT_ID) {
       
    49         this.init(id, caption, options, multipleSelection, selected);
       
    50     }
       
    51 }
       
    52 
       
    53 // SelectionList inherits from SelectionControl.
       
    54 SelectionList.prototype = new SelectionControl(UI_NO_INIT_ID);
       
    55 
       
    56 // Root element for options.
       
    57 SelectionList.prototype.optionListElement = null;
       
    58 
       
    59 // Array for tracking option elements.
       
    60 SelectionList.prototype.optionElements = null;
       
    61 
       
    62 // Tracking for currently focused option; null if none.
       
    63 SelectionList.prototype.focusedOption = null;
       
    64 
       
    65 // Enabled status.
       
    66 SelectionList.prototype.enabled = false;
       
    67 
       
    68 // Initializer - called from constructor.
       
    69 SelectionList.prototype.init = function(id, caption, options, multipleSelection, selected) {
       
    70     uiLogger.debug("SelectionList.init(" + id + ", " + caption + ", " + options + ", " + multipleSelection + ", " + selected + ")");
       
    71     
       
    72     // call superclass initializer
       
    73     SelectionControl.prototype.init.call(this, id, caption, options, multipleSelection, selected);
       
    74     
       
    75     // create option list element
       
    76     this.optionListElement = document.createElement("div");
       
    77     this.controlElement.appendChild(this.optionListElement);
       
    78     
       
    79     // the control defaults to enabled
       
    80     this.enabled = true;
       
    81     
       
    82     // init option element arrays
       
    83     this.optionElements = [];
       
    84     
       
    85     // update the option elements to match the options in this control
       
    86     this.updateOptionElements();
       
    87 }
       
    88 
       
    89 // Returns the enabled state.
       
    90 SelectionList.prototype.isEnabled = function() {
       
    91     return this.enabled;
       
    92 }
       
    93 
       
    94 // Sets the enabled state.
       
    95 SelectionList.prototype.setEnabled = function(enabled) {
       
    96     uiLogger.debug("SelectionList.setEnabled(" + enabled + ")");
       
    97     // switch the state and update the the control
       
    98     this.enabled = enabled;
       
    99     this.updateOptionElements();
       
   100 }
       
   101 
       
   102 // Sets the focused state for the control.
       
   103 // Note: This may not always succeed.
       
   104 SelectionList.prototype.setFocused = function(focused) {
       
   105     uiLogger.debug("SelectionList.setFocused(" + focused + ")");
       
   106     if (this.enabled && this.optionElements.length > 0) {
       
   107         if (focused) {
       
   108             this.optionElements[0].link.focus();
       
   109         } else {
       
   110             this.optionElements[0].link.blur();
       
   111         }
       
   112     }
       
   113 }
       
   114 
       
   115 // Sets the currently selected options. Pass a single option in a single selection
       
   116 // control or an array of selected controls in a multiple selection control. To
       
   117 // deselect all options pass null in a single selection control and an empty array
       
   118 // in a multiple selection control.
       
   119 SelectionList.prototype.setSelected = function(selected) {
       
   120     // call superclass setSelected()
       
   121     SelectionControl.prototype.setSelected.call(this, selected);
       
   122     this.updateStyleFromState();
       
   123 }
       
   124 
       
   125 // Sets the options in the control.
       
   126 SelectionList.prototype.setOptions = function(options) {
       
   127     // call superclass setOptions()
       
   128     SelectionControl.prototype.setOptions.call(this, options);
       
   129     this.updateOptionElements();
       
   130 }
       
   131 
       
   132 // Updates the option elements for the control element.
       
   133 SelectionList.prototype.updateOptionElements = function() {
       
   134     uiLogger.debug("SelectionControl.updateOptionElements()");
       
   135     
       
   136     // start by removing all current options from the option list element
       
   137     while (this.optionListElement.firstChild != null) {
       
   138         this.optionListElement.removeChild(this.optionListElement.firstChild);
       
   139     }
       
   140     
       
   141     // iterate through the options and add (and possibly create) a
       
   142     // properly configured option element for each option
       
   143     for (var i = 0; i < this.options.length; i++) {
       
   144         // get the option and option element we're working on
       
   145         var option = this.options[i];
       
   146         
       
   147         // option, link and text elements for this option
       
   148         var optionElement;
       
   149         var optionLinkElement;
       
   150         var optionTextElement;
       
   151         
       
   152         // get the elements
       
   153         if (i == this.optionElements.length) {
       
   154             // we need to create a new option element...
       
   155             optionElement = document.createElement("div");
       
   156             
       
   157             // ...and a new option link element...
       
   158             optionLinkElement = document.createElement("a");
       
   159             optionLinkElement.href = "JavaScript:void(0)";
       
   160             
       
   161             // ...and a new option text element
       
   162             optionTextElement = document.createElement("span");
       
   163             
       
   164             // hook up event listeners to the element
       
   165             var self = this;
       
   166             optionLinkElement.addEventListener("focus", function(event) { self.optionFocusStateChanged(event, true); }, false);
       
   167             optionLinkElement.addEventListener("blur", function(event) { self.optionFocusStateChanged(event, false); }, false);
       
   168             optionElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
       
   169             optionElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
       
   170             optionElement.addEventListener("mousedown", function(event) {
       
   171                                                                self.optionClicked(event)
       
   172                                                                event.stopPropagation();
       
   173                                                                event.preventDefault();
       
   174                                                         }, true);
       
   175             optionElement.addEventListener("keydown", function(event) {
       
   176                                                             // center and enter trigger the action
       
   177                                                             if (event.keyCode == 0 || event.keyCode == 13) {
       
   178                                                                 self.optionClicked(event)
       
   179                                                                 event.stopPropagation();
       
   180                                                                 event.preventDefault();
       
   181                                                             }
       
   182                                                       }, true);
       
   183             
       
   184             // add the elements to the option element array
       
   185             this.optionElements.push({ option: optionElement, link: optionLinkElement, text: optionTextElement });
       
   186         } else {
       
   187             // we already have ready elements so we'll reuse them
       
   188             optionElement = this.optionElements[i].option;
       
   189             optionLinkElement = this.optionElements[i].link;
       
   190             optionTextElement = this.optionElements[i].text;
       
   191             
       
   192             // remove the option link element from its current parent - if any
       
   193             if (optionLinkElement.parentNode != null) {
       
   194                 optionLinkElement.parentNode.removeChild(optionLinkElement);
       
   195             }
       
   196             
       
   197             // remove the option text element from its current parent - if any
       
   198             if (optionTextElement.parentNode != null) {
       
   199                 optionTextElement.parentNode.removeChild(optionTextElement);
       
   200             }
       
   201         }
       
   202         
       
   203         // set the option text
       
   204         optionTextElement.innerHTML = option.text;
       
   205         
       
   206         // hook up the option to the control
       
   207         if (this.enabled) {
       
   208             // add the option link element to the option element
       
   209             optionElement.appendChild(optionLinkElement);
       
   210             // add the text element to the option element
       
   211             optionLinkElement.appendChild(optionTextElement);
       
   212         } else {
       
   213             // add the text element directly to the control element
       
   214             optionElement.appendChild(optionTextElement);
       
   215         }
       
   216         // add the option element to the option list element
       
   217         this.optionListElement.appendChild(optionElement);
       
   218     }
       
   219     
       
   220     // update the style
       
   221     this.updateStyleFromState();
       
   222 }
       
   223 
       
   224 // Callback for focus state change events.
       
   225 SelectionList.prototype.optionFocusStateChanged = function(event, focused) {
       
   226     uiLogger.debug("SelectionControl.optionFocusStateChanged()");
       
   227     
       
   228     // get the event source option
       
   229     var option = null;
       
   230     var optionElement = null;
       
   231     for (var i = 0; i < this.optionElements.length; i++) {
       
   232         optionElement = this.optionElements[i];
       
   233         if (optionElement.link == event.currentTarget) {
       
   234             option = this.options[i];
       
   235             break;
       
   236         }
       
   237     }
       
   238     
       
   239     // remember the focused option; or null if none is focused
       
   240     if (focused) {
       
   241         this.focusedOption = option;
       
   242     } else {
       
   243         this.focusedOption = null;
       
   244     }
       
   245     
       
   246     // call the superclass focus state change handler
       
   247     this.focusStateChanged(focused);
       
   248 }
       
   249 
       
   250 // Callback for clicks.
       
   251 SelectionList.prototype.optionClicked = function(event) {
       
   252     uiLogger.debug("SelectionControl.optionClicked()");
       
   253     
       
   254     // bail out if we're not enabled
       
   255     if (!this.enabled) {
       
   256         return false;
       
   257     }
       
   258     
       
   259     // get the changed option
       
   260     var option = null;
       
   261     var optionElement = null;
       
   262     for (var i = 0; i < this.optionElements.length; i++) {
       
   263         optionElement = this.optionElements[i];
       
   264         if (optionElement.option == event.currentTarget) {
       
   265             option = this.options[i];
       
   266             break;
       
   267         }
       
   268     }
       
   269     
       
   270     // make sure the option is focused
       
   271     optionElement.link.focus();
       
   272     
       
   273     // toggle the selection
       
   274     if (this.multipleSelection) {
       
   275         // iterate through the selected options and see if this
       
   276         // option is selected. if not then add it to the selection.
       
   277         // if it already is selected then them remove it.
       
   278         var found = false;
       
   279         for (var i = 0; i < this.selected.length; i++) {
       
   280             if (this.selected[i] == option) {
       
   281                 // remove from selected set
       
   282                 found = true;
       
   283                 this.selected.splice(i, 1);
       
   284                 break;
       
   285             }
       
   286         }
       
   287         if (!found) {
       
   288             // add to the selected set
       
   289             this.selected.push(option);
       
   290         }
       
   291     } else {
       
   292         // update the selected option
       
   293         this.selected = option;
       
   294     }
       
   295     
       
   296     // update the style
       
   297     this.updateStyleFromState();
       
   298     
       
   299     // notify event listeners
       
   300     this.fireEvent(this.createEvent("SelectionChanged", this.getSelected()));
       
   301 }
       
   302 
       
   303 // Resets the state tracking for focus and hover.
       
   304 // Override this in subclasses as required to implement the state reset.
       
   305 SelectionList.prototype.resetFocusState = function() {
       
   306     uiLogger.debug("SelectionList.resetFocusState()");
       
   307     this.hovering = false;
       
   308     this.focused = false;
       
   309     this.focusedOption = null;
       
   310     this.updateStyleFromState();
       
   311 }
       
   312 
       
   313 // Updates the style of the control to reflects the state of the control.
       
   314 SelectionList.prototype.updateStyleFromState = function() {
       
   315     uiLogger.debug("SelectionList.updateStyleFromState()");
       
   316     
       
   317     // determine the state name
       
   318     var stateName = this.getStyleStateName();
       
   319     
       
   320     // set element class names
       
   321     this.setClassName(this.rootElement, "Control");
       
   322     this.setClassName(this.controlElement, "ControlElement");
       
   323     this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
       
   324     this.setClassName(this.captionElement, "ControlCaption ControlCaption" + stateName);
       
   325     
       
   326     // set option list and option class names
       
   327     this.setClassName(this.optionListElement, "SelectionList SelectionList" + stateName);
       
   328     for (var i = 0; i < this.options.length; i++) {
       
   329         var option = this.options[i];
       
   330         
       
   331         // get the option and option text elements for this option
       
   332         var optionElement = this.optionElements[i].option;
       
   333         var optionTextElement = this.optionElements[i].text;
       
   334         
       
   335         // figure out the option state
       
   336         var optionStateName = this.isSelected(option) ? "Checked" : "Unchecked";
       
   337         if (!this.enabled) {
       
   338             optionStateName += "Disabled";
       
   339         } else if (this.focusedOption == option) {
       
   340             optionStateName += "Focus";
       
   341         } else {
       
   342             optionStateName += "Normal";
       
   343         }
       
   344         
       
   345         // set option element class names
       
   346         if (this.multipleSelection) {
       
   347             this.setClassName(optionElement, "SelectionListOptionMulti SelectionListOptionMulti" + optionStateName);
       
   348         } else {
       
   349             this.setClassName(optionElement, "SelectionListOptionSingle SelectionListOptionSingle" + optionStateName);
       
   350         }
       
   351         
       
   352         // set option text class names
       
   353         this.setClassName(optionTextElement, "SelectionListOptionText SelectionListOptionText" + stateName);
       
   354     }
       
   355 }