2 * jQuery Mobile Widget @VERSION - listview controls
4 * This software is licensed under the MIT licence (as defined by the OSI at
5 * http://www.opensource.org/licenses/mit-license.php)
7 * ***************************************************************************
8 * Copyright (C) 2011 by Intel Corporation Ltd.
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 * ***************************************************************************
29 * Authors: Elliot Smith <elliot.smith@intel.com>
32 // This extension supplies API to toggle the "mode" in which a list
33 // is displayed. The modes available is configurable, but defaults
34 // to ['edit', 'view']. A list can also have a control panel associated
35 // with it. The visibility of the control panel is governed by the current
36 // mode (by default, it is visible in 'edit' mode); elements within
37 // the listview can also be marked up to be visible in one or more of the
40 // One example use case would be a control panel with a "Select all" checkbox
41 // which, when clicked, selects all of the checkboxes in the associated
44 // The control panel itself should be defined as a form element.
45 // By default, the control panel will be hidden when the listview is
46 // initialised, unless you supply mode="edit" as a
47 // data-listview-controls option (when using the default modes). If you
48 // want the control panel to be visible in some mode other than
49 // the default, use a data-listviewcontrols-show-in="<mode>" attribute
50 // on the control panel element.
52 // Example usage (using the default 'edit' and 'view' modes):
54 // <!-- this is the controls element, displayed in 'edit' mode by default -->
55 // <form id="listviewcontrols-control-panel">
56 // <fieldset data-role="controlgroup">
57 // <input type="checkbox" id="listviewcontrols-demo-checkbox-uber" />
58 // <label for="listviewcontrols-demo-checkbox-uber">Select all</label>
62 // <!-- this is the list associated with the controls -->
63 // <ul data-role="listview" data-listviewcontrols="#listviewcontrols-control-panel">
67 // <!-- this element is only visible in 'edit' mode -->
68 // <fieldset data-role="controlgroup" data-listviewcontrols-show-in="edit">
69 // <input type="checkbox" id="listviewcontrols-demo-checkbox-1" />
70 // <label for="listviewcontrols-demo-checkbox-1">Greg</label>
73 // <!-- this element is only visible in 'view' mode -->
74 // <span data-listviewcontrols-show-in="view">Greg</span>
78 // ... more li elements marked up the same way ...
82 // To associate the listview with the control panel, add
83 // data-listviewcontrols="..selector.." to a listview, where
84 // selector selects a single element (the control panel
85 // you defined). You can then call
86 // listviewcontrols('option', 'mode', '<mode>') on the
87 // listview to set the mode.
89 // Inside the listview's items, add controls to each item
90 // which are only visible when in one of the modes. To do this,
91 // add form elements (e.g. checkboxes) to the items as you see fit. Then,
92 // mark each form element with data-listviewcontrols-show-in="<mode>".
93 // The control's visibility now depends on the mode of the listviewcontrols:
94 // it is only shown when its <mode> setting matches the current mode
95 // of the listviewcontrols widget. You are responsible for properly
96 // styling the form elements inside the listview so the listview looks
97 // correct when they are hidden or visible.
99 // The control panel (by default, visible when in "show" mode) is flexible
100 // and can contain any valid form elements (or other jqm components). It's
101 // up to you to define the behaviour associated with interactions on
102 // the control panel and/or controls inside list items.
107 // Returns a jQuery object containing all the li elements in the
108 // listview which are currently visible and not dividers. (This
109 // is just a convenience to make operating on the list as a whole
110 // slightly simpler.)
112 // Options (set in options hash passed to constructor, or via the
113 // option method, or declaratively by attribute described below):
115 // controlPanelSelector {String}
116 // Selector string for selecting the element representing the
117 // control panel for the listview. The context for find() is the
118 // document (to give the most flexibility), so your selector
119 // should be specific. Set declaratively with
120 // data-listviewcontrols="...selector...".
122 // modesAvailable {String[]; default=['edit', 'view']}
123 // An array of the modes available for these controls.
125 // mode {String; default='view'}
126 // Current mode for the widget, which governs the visibility
127 // of the listview control panel and any elements marked
128 // with data-listviewcontrols-show-in="<mode>".
129 // Set declaratively with
130 // data-listviewcontrols-options='{"mode":"<mode>"}'.
132 // controlPanelShowIn {String; default=modesAvailable[0]}
133 // The mode in which the control panel is visible; defaults to the
134 // first element of modesAvailable. Can be set declaratively
135 // on the listview controls element with
136 // data-listviewcontrols-show-in="<mode>"
140 $.widget( "todons.listviewcontrols", $.mobile.widget, {
142 controlPanelSelector: null,
143 modesAvailable: ['edit', 'view'],
145 controlPanelShowIn: null
148 _listviewCssClass: 'ui-listviewcontrols-listview',
149 _controlsCssClass: 'ui-listviewcontrols-panel',
151 _create: function () {
155 page = this.element.closest( '.ui-page' ),
156 controlPanelSelectorAttr = 'data-' + $.mobile.ns + 'listviewcontrols',
157 controlPanelSelector = this.element.attr( controlPanelSelectorAttr ),
158 dataOptions = this.element.jqmData( 'listviewcontrols-options' ),
159 controlPanelShowInAttr;
161 o.controlPanelSelector = o.controlPanelSelector || controlPanelSelector;
163 // precedence for options: defaults < jqmData attribute < options arg
164 o = $.extend( {}, this._defaults, dataOptions, o );
166 optionsValid = ( this._validOption( 'modesAvailable', o.modesAvailable, o ) &&
167 this._validOption( 'controlPanelSelector', o.controlPanelSelector, o ) &&
168 this._validOption( 'mode', o.mode, o ) );
170 if ( !optionsValid ) {
174 // get the controls element
175 this.controlPanel = $( document ).find( o.controlPanelSelector ).first();
177 if ( this.controlPanel.length === 0 ) {
181 // once we have the controls element, we may need to override the
182 // mode in which controls are shown
183 controlPanelShowInAttr = this.controlPanel.jqmData( 'listviewcontrols-show-in' );
184 if ( controlPanelShowInAttr ) {
185 o.controlPanelShowIn = controlPanelShowInAttr;
186 } else if ( !o.controlPanelShowIn ) {
187 o.controlPanelShowIn = o.modesAvailable[0];
190 if ( !this._validOption( 'controlPanelShowIn', o.controlPanelShowIn, o ) ) {
194 // done setting options
197 // mark the controls and the list with a class
198 this.element.removeClass(this._listviewCssClass).addClass(this._listviewCssClass);
199 this.controlPanel.removeClass(this._controlsCssClass).addClass(this._controlsCssClass);
202 if ( page && !page.is( ':visible' ) ) {
203 page.bind( 'pageshow', function () { self.refresh(); } );
209 _validOption: function ( varName, value, otherOptions ) {
213 if ( varName === 'mode' ) {
214 ok = ( $.inArray( value, otherOptions.modesAvailable ) >= 0 );
215 } else if ( varName === 'controlPanelSelector' ) {
216 ok = ( $.type( value ) === 'string' );
217 } else if ( varName === 'modesAvailable' ) {
218 ok = ( $.isArray( value ) && value.length > 1 );
221 for ( i = 0; i < value.length; i++ ) {
222 if ( value[i] === '' || $.type( value[i] ) !== 'string' ) {
227 } else if ( varName === 'controlPanelShowIn' ) {
228 ok = ( $.inArray( value, otherOptions.modesAvailable ) >= 0 );
234 _setOption: function ( varName, value ) {
235 var oldValue = this.options[varName];
237 if ( oldValue !== value && this._validOption( varName, value, this.options ) ) {
238 this.options[varName] = value;
243 visibleListItems: function () {
244 return this.element.find( 'li:not(:jqmData(role=list-divider)):visible' );
247 refresh: function () {
249 triggerUpdateLayout = false,
254 // hide/show the control panel and hide/show controls inside
255 // list items based on their "show-in" option
256 isVisible = this.controlPanel.is( ':visible' );
258 if ( this.options.mode === this.options.controlPanelShowIn ) {
259 this.controlPanel.show();
261 this.controlPanel.hide();
264 if ( this.controlPanel.is( ':visible' ) !== isVisible ) {
265 triggerUpdateLayout = true;
268 // we only operate on elements inside list items which aren't dividers
269 modalElements = this.element
270 .find( 'li:not(:jqmData(role=list-divider))' )
271 .find( ':jqmData(listviewcontrols-show-in)' );
273 modalElements.each(function () {
274 showIn = $( this ).jqmData( 'listviewcontrols-show-in' );
276 isVisible = $( this ).is( ':visible' );
278 if ( showIn === self.options.mode ) {
284 if ( $( this ).is( ':visible' ) !== isVisible ) {
285 triggerUpdateLayout = true;
289 if ( triggerUpdateLayout ) {
290 this.element.trigger( 'updatelayout' );
295 $( 'ul' ).live( 'listviewcreate', function () {
298 if ( list.is( ':jqmData(listviewcontrols)' ) ) {
299 list.listviewcontrols();