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));
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;
187 else if (!o.controlPanelShowIn) {
188 o.controlPanelShowIn = o.modesAvailable[0];
191 if (!this._validOption('controlPanelShowIn', o.controlPanelShowIn, o)) {
195 // done setting options
198 // mark the controls and the list with a class
199 this.element.removeClass(this._listviewCssClass).addClass(this._listviewCssClass);
200 this.controlPanel.removeClass(this._controlsCssClass).addClass(this._controlsCssClass);
203 if (page && !page.is(':visible')) {
204 page.bind('pageshow', function () { self.refresh(); });
211 _validOption: function (varName, value, otherOptions) {
214 if (varName === 'mode') {
215 ok = ($.inArray(value, otherOptions.modesAvailable) >= 0);
217 else if (varName === 'controlPanelSelector') {
218 ok = ($.type(value) === 'string');
220 else if (varName === 'modesAvailable') {
221 ok = ($.isArray(value) && value.length > 1);
224 for (var i = 0; i < value.length; i++) {
225 if (value[i] === '' || $.type(value[i]) !== 'string') {
231 else if (varName === 'controlPanelShowIn') {
232 ok = ($.inArray(value, otherOptions.modesAvailable) >= 0);
238 _setOption: function (varName, value) {
239 var oldValue = this.options[varName];
241 if (oldValue !== value && this._validOption(varName, value, this.options)) {
242 this.options[varName] = value;
247 visibleListItems: function () {
248 return this.element.find('li:not(:jqmData(role=list-divider)):visible');
251 refresh: function () {
253 triggerUpdateLayout = false,
258 // hide/show the control panel and hide/show controls inside
259 // list items based on their "show-in" option
260 isVisible = this.controlPanel.is(':visible');
262 if (this.options.mode === this.options.controlPanelShowIn) {
263 this.controlPanel.show();
266 this.controlPanel.hide();
269 if (this.controlPanel.is(':visible') !== isVisible) {
270 triggerUpdateLayout = true;
273 // we only operate on elements inside list items which aren't dividers
274 modalElements = this.element.find('li:not(:jqmData(role=list-divider))')
275 .find(':jqmData(listviewcontrols-show-in)');
277 modalElements.each(function () {
278 showIn = $(this).jqmData('listviewcontrols-show-in');
280 isVisible = $(this).is(':visible');
282 if (showIn === self.options.mode) {
289 if ($(this).is(':visible') !== isVisible) {
290 triggerUpdateLayout = true;
294 if (triggerUpdateLayout) {
295 this.element.trigger('updatelayout');
300 $('ul').live('listviewcreate', function () {
303 if (list.is(':jqmData(listviewcontrols)')) {
304 list.listviewcontrols();