Skip to content

Loading…

Add autodividers functionality for listviews #2851

Closed
wants to merge 1 commit into from

3 participants

@townxelliot

Can be used to autogenerate dividers for a listview by
setting data-autodividers="alpha" (dividers are unique,
uppercased single characters from list items) or
data-autodividers="full" (unique full text strings selected
from list items) on the ul element of the listview.

It's also possible to apply a custom selector to find the
elements to be used for divider text, with
data-autodividers-selector="...".

This relates to #2466,
but is a different implementation which will automatically
update the list dividers if the list elements change. It also
has a fairly thorough test suite and documentation.

@townxelliot townxelliot Add autodividers functionality for listviews
Can be used to autogenerate dividers for a listview by
setting data-autodividers="alpha" (dividers are unique,
uppercased single characters from list items) or
data-autodividers="full" (unique full text strings selected
from list items) on the ul element of the listview.

It's also possible to apply a custom selector to find the
elements to be used for divider text, with
data-autodividers-selector="...".

This relates to jquery/jquery-mobile#2466,
but is a different implementation which will automatically
update the list dividers if the list elements change. It also
has a fairly thorough test suite and documentation.
7875e51
@townxelliot townxelliot commented on the diff
tests/unit/listview/listview_core.js
@@ -4,7 +4,7 @@

Apologies, my editor has corrected some of the whitespace in this file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@johnbender

@townxelliot

Thanks for the pull request. A couple quick notes:

  1. It's best to split up the changeset into multiple commits eg, library changes, tests, doc additions. That way history traversal/viewing/manipulation is easier down the road.

  2. This looks super nice, but this is the kind of thing the we might delegate to a plugin since it's hard to be in the business of knowing all, or even the best subset, of ways in which people will autodivide their listviews. I don't have the final word on this though so the team will have to discuss it.

  3. If we merge this in it'll be post 1.0. So I'm going to close this for now, and I've added it to the top of our listview feature request set.

At a quick glance this does appear useful though and it's built in such a way that people should be able to drop this into their applications pretty easily. Have you considered blogging about this or posting it to the jquery plugins page?

@johnbender johnbender closed this
@townxelliot
@toddparker

Thanks again Elliot. I think this might be worth adding after 1.0 but I wonder if this could be packaged as an extension to listview filter so if you add this script, you get this feature? We're heading int eh direction of keeping widgets simple and using extensions. Filer itself is an extension of listview.

@townxelliot

I have a slightly updated version of this at https://github.com/townxelliot/jquery-mobile/tree/autodividers. This incorporates the tests and docs into the jQuery Mobile ones.

This is also available in the web-ui-fw project I've been working on with colleagues at Intel (which is now open source): https://github.com/web-ui-fw/web-ui-fw. There, autodividers is integrated with our demos, tests and docs.

I'd like to hear whether you're interested in this for core (I can raise a formal pull request), or whether I should just maintain it as part of our project (the project is now more of a series of plugins for jQuery Mobile than it was before, and we've accentuated that angle in the README).

In reply to Todd's comments above, this will work with or without a listview filter, so I think it should be an extension of listview, rather than listview filter. Unless I've misunderstood the question.

@toddparker

@townxelliot - First off, all the stuff you guys are doing is great and we should coordinate more on what you're doing and how to bring things in or at least package them for easy consumption. Mind shooting me and email at todd [at] filamentgroup.com?

We've actually pulled in a version of the popup script that gabriel posted a while back and are refining it for inclusion, maybe at 1.1.

For the auto-divider, I agree that this would make sense as an extension to listview. If you want to prepare that as a pull request, we can take a look and decide whether now if a good time to pull this in.

@townxelliot

Please see #3302 for the updated pull request, which better separates the changes into different categories.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 26, 2011
  1. @townxelliot

    Add autodividers functionality for listviews

    townxelliot committed
    Can be used to autogenerate dividers for a listview by
    setting data-autodividers="alpha" (dividers are unique,
    uppercased single characters from list items) or
    data-autodividers="full" (unique full text strings selected
    from list items) on the ul element of the listview.
    
    It's also possible to apply a custom selector to find the
    elements to be used for divider text, with
    data-autodividers-selector="...".
    
    This relates to jquery/jquery-mobile#2466,
    but is a different implementation which will automatically
    update the list dividers if the list elements change. It also
    has a fairly thorough test suite and documentation.
View
12 docs/lists/docs-lists.html
@@ -64,6 +64,17 @@
<a href="lists-divider.html" data-role="button" data-icon="arrow-r" data-iconpos="right">List divider example</a>
+ <h2>Autodividers</h2>
+
+ <p>A listview can be configured to automatically generate dividers for its items. This is done by adding a <code>data-autodividers</code> attribute to any listview. The value of the attribute should be set to <code>"alpha"</code> (to create dividers based on unique, lowercased first characters of list items) or <code>"full"</code> (to create dividers based on unique full text strings of list items). Any existing dividers in the list are removed and replaced by the autogenerated dividers.</p>
+
+ <p>By default, the text used to create dividers is the link text (for link lists) or text (for read-only lists). Alternatively, if you are using formatted list items, you can specify the element to be used for dividers with <code>data-autodividers-selector="X"</code>, where <code>X</code> is a selector string. Note that the selector is applied in the context of individual list (&lt;li&gt;) items.</p>
+
+ <p>If new list items (not dividers) are added to the list, or if items are removed, the dividers are automatically updated.</p>
+
+ <a href="lists-autodividers.html" data-role="button" data-icon="arrow-r" data-iconpos="right">Autodividers example</a>
+
+
<h2>Search filter</h2>
<p>jQuery Mobile provides a very easy way to filter a list with a simple client-side search feature. To make a list filterable, simply add the <code>data-filter="true"</code> attribute to the list. The framework will then append a search box above the list and add the behavior to filter out list items that don't contain the current search string as the user types. The input's placeholder text defaults to "Filter items...". To configure the placeholder text in the search input, you can either bind to the <code>mobileinit</code> event and set the <code>$.mobile.listview.prototype.options.filterPlaceholder</code> option to a string of your choosing, or use the data-attribute <code>data-filter-placeholder</code> on your listview. By default the search box will inherit its theme from its parent. The search box theme can be configured using the data-attribute <code>data-filter-theme</code> on your listview.</p>
@@ -125,6 +136,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/index.html
@@ -34,6 +34,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-all-full.html
@@ -138,6 +138,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
99 docs/lists/lists-autodividers.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery Mobile Docs - List Dividers</title>
+ <link rel="stylesheet" href="../../css/themes/default/" />
+ <link rel="stylesheet" href="../_assets/css/jqm-docs.css"/>
+ <script src="../../js/jquery.js"></script>
+ <script src="../../experiments/themeswitcher/jquery.mobile.themeswitcher.js"></script>
+ <script src="../_assets/js/jqm-docs.js"></script>
+ <script src="../../js/"></script>
+</head>
+<body>
+
+ <div data-role="page" class="type-interior">
+
+ <div data-role="header" data-theme="f">
+ <h1>Autodividers</h1>
+ <a href="../../" data-icon="home" data-iconpos="notext" data-direction="reverse" class="ui-btn-right jqm-home">Home</a>
+ </div><!-- /header -->
+
+ <div data-role="content">
+ <div class="content-primary">
+ <ul data-role="listview" data-autodividers="alpha">
+ <li><a href="index.html">Adam Kinkaid</a></li>
+ <li><a href="index.html">Alex Wickerham</a></li>
+ <li><a href="index.html">Avery Johnson</a></li>
+ <li><a href="index.html">Bob Cabot</a></li>
+ <li><a href="index.html">Caleb Booth</a></li>
+ <li><a href="index.html">Christopher Adams</a></li>
+ <li><a href="index.html">Culver James</a></li>
+ <li><a href="index.html">David Walsh</a></li>
+ <li><a href="index.html">Drake Alfred</a></li>
+ <li><a href="index.html">Elizabeth Bacon</a></li>
+ <li><a href="index.html">Emery Parker</a></li>
+ <li><a href="index.html">Enid Voldon</a></li>
+ <li><a href="index.html">Francis Wall</a></li>
+ <li><a href="index.html">Graham Smith</a></li>
+ <li><a href="index.html">Greta Peete</a></li>
+ <li><a href="index.html">Harvey Walls</a></li>
+ <li><a href="index.html">Mike Farnsworth</a></li>
+ <li><a href="index.html">Murray Vanderbuilt</a></li>
+ <li><a href="index.html">Nathan Williams</a></li>
+ <li><a href="index.html">Paul Baker</a></li>
+ <li><a href="index.html">Pete Mason</a></li>
+ <li><a href="index.html">Rod Tarker</a></li>
+ <li><a href="index.html">Sawyer Wakefield</a></li>
+ </ul>
+ </div><!--/content-primary -->
+
+ <div class="content-secondary">
+
+ <div data-role="collapsible" data-collapsed="true" data-theme="b" data-content-theme="d">
+
+ <h3>More in this section</h3>
+
+ <ul data-role="listview" data-theme="c" data-dividertheme="d">
+
+ <li data-role="list-divider">List views</li>
+ <li><a href="docs-lists.html">List markup conventions</a></li>
+ <li><a href="lists-ul.html">Basic linked list</a></li>
+ <li><a href="lists-nested.html">Nested list</a></li>
+ <li><a href="lists-ol.html">Numbered list</a></li>
+
+ <li><a href="lists-split.html">Split button list</a></li>
+ <li><a href="lists-divider.html">List dividers</a></li>
+ <li data-theme="a"><a href="lists-autodividers.html">Autodividers</a></li>
+ <li><a href="lists-count.html">Count bubble</a></li>
+ <li><a href="lists-thumbnails.html">Thumbnails</a></li>
+ <li><a href="lists-icons.html">Icons</a></li>
+ <li><a href="lists-formatting.html">Content formatting</a></li>
+ <li><a href="lists-search.html">Search filter bar</a></li>
+ <li><a href="lists-search-inset.html">Inset search filter bar</a></li>
+ <li><a href="lists-search-with-dividers.html">Search filter bar with dividers</a></li>
+
+ <li><a href="lists-readonly.html">Read-only lists</a></li>
+ <li><a href="lists-readonly-inset.html">Read-only inset lists</a></li>
+ <li><a href="lists-forms.html">Lists with forms</a></li>
+ <li><a href="lists-forms-inset.html">Inset lists with forms</a></li>
+
+ <li><a href="lists-inset.html">Inset styled lists</a></li>
+ <li><a href="lists-performance.html">List performance test</a></li>
+ <li><a href="lists-themes.html">Theming lists</a></li>
+
+ </ul>
+ </div>
+ </div>
+
+ </div><!-- /content -->
+
+ <div data-role="footer" class="footer-docs" data-theme="c">
+ <p>&copy; 2011 The jQuery Project</p>
+ </div>
+
+ </div><!-- /page -->
+
+ </body>
+ </html>
View
1 docs/lists/lists-count.html
@@ -47,6 +47,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li data-theme="a"><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-divider.html
@@ -78,6 +78,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li data-theme="a"><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-formatting.html
@@ -98,6 +98,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-forms-inset.html
@@ -213,6 +213,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-forms.html
@@ -213,6 +213,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-icons.html
@@ -53,6 +53,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li data-theme="a"><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-inset.html
@@ -139,6 +139,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-nested.html
@@ -158,6 +158,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-ol.html
@@ -62,6 +62,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-performance.html
@@ -542,6 +542,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-readonly-inset.html
@@ -135,6 +135,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-readonly.html
@@ -137,6 +137,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-search-inset.html
@@ -64,6 +64,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-search-with-dividers.html
@@ -77,6 +77,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-search.html
@@ -64,6 +64,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-split.html
@@ -111,6 +111,7 @@
<li data-theme="a"><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-themes.html
@@ -228,6 +228,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-thumbnails.html
@@ -99,6 +99,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li data-theme="a"><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 docs/lists/lists-ul.html
@@ -65,6 +65,7 @@
<li><a href="lists-split.html">Split button list</a></li>
<li><a href="lists-divider.html">List dividers</a></li>
+ <li><a href="lists-autodividers.html">Autodividers</a></li>
<li><a href="lists-count.html">Count bubble</a></li>
<li><a href="lists-thumbnails.html">Thumbnails</a></li>
<li><a href="lists-icons.html">Icons</a></li>
View
1 js/index.php
@@ -22,6 +22,7 @@
'jquery.mobile.navbar.js',
'jquery.mobile.listview.js',
'jquery.mobile.listview.filter.js',
+ 'jquery.mobile.listview.autodividers.js',
'jquery.mobile.nojs.js',
'jquery.mobile.forms.checkboxradio.js',
'jquery.mobile.forms.button.js',
View
237 js/jquery.mobile.listview.autodividers.js
@@ -0,0 +1,237 @@
+/*
+* jQuery Mobile Framework : "listview" autodividers extension
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+/**
+ * Applies dividers automatically to a listview, using link text
+ * (for link lists) or text (for readonly lists) as the basis for the
+ * divider text.
+ *
+ * Apply using autodividers({type: 'X'}) on a <ul> with
+ * data-role="listview", or with data-autodividers="true", where X
+ * is the type of divider to create. The default divider type is 'alpha',
+ * meaning first characters of list item text, upper-cased.
+ *
+ * The element used to derive the text for the auto dividers defaults
+ * to the first link inside the li; failing that, the text directly inside
+ * the li element is used. This can be overridden with the
+ * data-autodividers-selector attribute or via options; the selector
+ * will use each li element as its context.
+ *
+ * Any time a new li element is added to the list, or an li element is
+ * removed, this extension will update the dividers in the listview
+ * accordingly.
+ *
+ * Note that if a listview already has dividers, applying this
+ * extension will remove all the existing dividers and replace them
+ * with new, generated ones.
+ *
+ * Also note that this extension doesn't sort the list: it only creates
+ * dividers based on text inside list items. So if your list isn't
+ * alphabetically-sorted, you may get duplicate dividers.
+ *
+ * So, for example, this markup:
+ *
+ * <ul id="has-no-dividers" data-role="listview" data-autodividers="alpha">
+ * <li>Barry</li>
+ * <li>Carrie</li>
+ * <li>Betty</li>
+ * <li>Harry</li>
+ * <li>Carly</li>
+ * <li>Hetty</li>
+ * </ul>
+ *
+ * will produce dividers like this:
+ *
+ * <ul data-role="listview" data-autodividers="alpha">
+ * <li data-role="list-divider">B</li>
+ * <li>Barry</li>
+ * <li data-role="list-divider">C</li>
+ * <li>Carrie</li>
+ * <li data-role="list-divider">B</li>
+ * <li>Betty</li>
+ * <li data-role="list-divider">H</li>
+ * <li>Harry</li>
+ * <li data-role="list-divider">C</li>
+ * <li>Carly</li>
+ * <li data-role="list-divider">H</li>
+ * <li>Hetty</li>
+ * </ul>
+ *
+ * with each divider occuring twice.
+ *
+ * Options:
+ *
+ * selector: The jQuery selector to use to find text for the
+ * generated dividers. Default is to use the first 'a'
+ * (link) element. If this selector doesn't find any
+ * text, the widget automatically falls back to the text
+ * inside the li (for read-only lists). Can be set to a custom
+ * selector via data-autodividers-selector="..." or the 'selector'
+ * option.
+ *
+ * type: 'alpha' (default) sets the auto divider type to "uppercased
+ * first character of text selected from each item"; "full" sets
+ * it to the unmodified text selected from each item. Set via
+ * the data-autodividers="<type>" attribute on the listview or
+ * the 'type' option.
+ *
+ * Events:
+ *
+ * dividerschange: Triggered if the dividers in the list change;
+ * this happens if list items are added to the listview,
+ * which causes the autodividers to be regenerated.
+ */
+
+(function( $, undefined ) {
+
+var autodividers = function(options) {
+ var list = $( this );
+ options = options || {};
+
+ var listview = list.data( 'listview' );
+
+ var dividerType = options.type || list.jqmData( 'autodividers' ) || 'alpha';
+
+ var textSelector = options.selector || list.jqmData( 'autodividers-selector' ) || 'a';
+
+ var getDividerText = function( elt ) {
+ // look for some text in the item
+ var text = elt.find( textSelector ).text() || elt.text() || null;
+
+ if ( !text ) {
+ return null;
+ }
+
+ // create the text for the divider
+ if ( dividerType === 'alpha' ) {
+ text = text.slice( 0, 1 ).toUpperCase();
+ }
+
+ return text;
+ };
+
+ var mergeDividers = function() {
+ // any dividers which are following siblings of a divider, where
+ // there are no dividers with different text inbetween, can be removed
+ list.find( 'li.ui-li-divider' ).each(function() {
+ var divider = $( this );
+ var dividerText = divider.text();
+ var selector = '.ui-li-divider:not(:contains(' + dividerText + '))';
+ var nextDividers = divider.nextUntil( selector );
+ nextDividers.filter( '.ui-li-divider:contains(' + dividerText + ')' ).remove();
+ });
+ };
+
+ // check that elt is a non-divider li element
+ var isNonDividerLi = function( elt ) {
+ return elt.is('li') && elt.jqmData( 'role' ) !== 'list-divider';
+ };
+
+ // li element inserted, so check whether it needs a divider
+ var liAdded = function( li ) {
+ var dividerText = getDividerText( li );
+
+ if ( !dividerText ) {
+ listview.refresh();
+ return;
+ }
+
+ // add expected divider for this li if it doesn't exist
+ var existingDividers = li.prevAll( '.ui-li-divider:first:contains(' + dividerText + ')' );
+
+ if ( existingDividers.length === 0 ) {
+ var divider = $( '<li>' + dividerText + '</li>' );
+ divider.jqmData( 'role', 'list-divider' );
+ li.before( divider );
+
+ listview.refresh();
+
+ mergeDividers();
+
+ list.trigger( 'dividerschange' );
+ }
+ else {
+ listview.refresh();
+ }
+ };
+
+ // li element removed, so check whether its divider should go
+ var liRemoved = function( li ) {
+
+ var dividerText = getDividerText( li );
+
+ if ( !dividerText ) {
+ listview.refresh();
+ return;
+ }
+
+ // remove divider for this li if there are no other
+ // li items for the divider before or after this li item
+ var precedingItems = li.prevUntil( '.ui-li-divider:contains(' + dividerText + ')' );
+ var nextItems = li.nextUntil( '.ui-li-divider' );
+
+ if ( precedingItems.length === 0 && nextItems.length === 0 ) {
+ li.prevAll( '.ui-li-divider:contains(' + dividerText + '):first' ).remove();
+
+ listview.refresh();
+
+ mergeDividers();
+
+ list.trigger( 'dividerschange' );
+ }
+ else {
+ listview.refresh();
+ }
+ };
+
+ // set up the dividers on first create
+ list.find( 'li' ).each( function() {
+ var li = $( this );
+
+ // remove existing dividers
+ if ( li.jqmData( 'role' ) === 'list-divider' ) {
+ li.remove();
+ }
+ // make new dividers for list items
+ else {
+ liAdded( li );
+ }
+ });
+
+ // bind to DOM events to keep list up to date
+ list.bind( 'DOMNodeInserted', function( e ) {
+ var elt = $( e.target );
+
+ if ( !isNonDividerLi( elt ) ) {
+ return;
+ }
+
+ liAdded( elt );
+ });
+
+ list.bind( 'DOMNodeRemoved', function( e ) {
+ var elt = $( e.target );
+
+ if ( !isNonDividerLi( elt ) ) {
+ return;
+ }
+
+ liRemoved( elt );
+ });
+};
+
+$.fn.autodividers = autodividers;
+
+$( ":jqmData(role=listview)" ).live( "listviewcreate", function() {
+ var list = $( this );
+
+ if ( list.is( ':jqmData(autodividers)' ) ) {
+ list.autodividers();
+ }
+});
+
+})( jQuery );
View
137 tests/functional/autodividers.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="utf-8" />
+ <title>jQuery Mobile: Autodividers</title>
+ <link rel="stylesheet" href="../../css/themes/default/" />
+ <script src="../../js/jquery.js"></script>
+ <script src="../../js/"></script>
+</head>
+
+<body>
+
+<div data-role="page" id="baseline">
+ <div data-role="header">
+ <h1>Autodividers</h1>
+ </div>
+
+ <div data-role="content">
+ <p>This should get auto-dividers based on link text.</p>
+ <ul id="link-text-dividers" data-role="listview" data-autodividers="alpha">
+ <li><a href="#">Amy</a></li>
+ <li><a href="#">Andrew</a></li>
+ <li><a href="#">Astrid</a></li>
+ <li><a href="#">Bertie</a></li>
+ <li><a href="#">Carrie</a></li>
+ <li><a href="#">Derek</a></li>
+ <li><a href="#">Ian</a></li>
+ <li><a href="#">Matthew</a></li>
+ </ul>
+ </div>
+
+ <div data-role="content">
+ <p>This should get auto-dividers based on link text but
+ shouldn't produce duplicate dividers. Should also
+ add more dividers if new list elements are added.</p>
+
+ <p>
+ <button id="add-gary-button" data-inline="true">Add Gary and refresh</button>
+ <button id="remove-bertie-button" data-inline="true">Remove Bertie and refresh</button>
+ </p>
+
+ <ul id="refreshable-dividers" data-role="listview" data-autodividers="alpha">
+ <li><a href="#">Amy</a></li>
+ <li><a href="#">Andrew</a></li>
+ <li><a href="#">Astrid</a></li>
+ <li><a href="#">Bertie</a></li>
+ <li><a href="#">Carrie</a></li>
+ <li><a href="#">Derek</a></li>
+ <li><a href="#">Ian</a></li>
+ <li><a href="#">Matthew</a></li>
+ </ul>
+ </div>
+
+ <div data-role="content">
+ <p>This uses a custom selector to draw text from formatted list
+ items.</p>
+
+ <ul data-role="listview" data-autodividers="alpha" data-autodividers-selector="span">
+ <li><span>Anne</span> likes to eat sweets</li>
+ <li><span>Beth</span> likes to eat treats</li>
+ <li><span>Bill</span> likes to eat meats</li>
+ <li><span>Carl</span> likes to eat beets</li>
+ </ul>
+ </div>
+
+ <div data-role="content">
+ <p>This should get auto-dividers based on text. NB this has
+ intentionally blank li elements to check they don't get dividers.</p>
+ <ul id="text-dividers" data-role="listview" data-autodividers="alpha">
+ <li>Barry</li>
+ <li>Betty</li>
+ <li>Carrie</li>
+ <li>Harry</li>
+ <li></li>
+ <li>Hetty</li>
+ <li>Kitty</li>
+ <li>Larry</li>
+ <li></li>
+ <li>Laurie</li>
+ <li>Mary</li>
+ </ul>
+ </div>
+
+ <div data-role="content">
+ <p>Non-sorted list will produce duplicate auto-dividers.</p>
+ <ul id="non-sorted" data-role="listview" data-autodividers="alpha">
+ <li>Barry</li>
+ <li>Carrie</li>
+ <li>Betty</li>
+ <li>Harry</li>
+ <li>Carly</li>
+ <li>Hetty</li>
+ </ul>
+ </div>
+
+ <div data-role="content">
+ <p>This had dividers already which were replaced.</p>
+ <ul id="has-dividers" data-role="listview" data-autodividers="alpha">
+ <li data-role="list-divider">Any old iron</li>
+ <li><a href="#">Amy</a></li>
+ <li><a href="#">Andrew</a></li>
+ <li><a href="#">Astrid</a></li>
+ <li data-role="list-divider">Barnacles</li>
+ <li><a href="#">Bertie</a></li>
+ <li data-role="list-divider">Crop circle</li>
+ <li><a href="#">Carrie</a></li>
+ <li data-role="list-divider">Dog</li>
+ <li><a href="#">Derek</a></li>
+ <li data-role="list-divider">Igloos</li>
+ <li><a href="#">Ian</a></li>
+ <li data-role="list-divider">Massive clouds</li>
+ <li><a href="#">Matthew</a></li>
+ </ul>
+ </div>
+
+</div>
+
+<script>
+$(document).bind('pagecreate', function () {
+ $('#add-gary-button').bind('click', function () {
+ var gary = $('<li><a href="#">Gary</a></li>');
+ $('#refreshable-dividers').find('li.ui-li-divider:contains(I)').before(gary);
+ });
+
+ $('#remove-bertie-button').bind('click', function () {
+ $('#refreshable-dividers').find('li:contains("Bertie")').remove();
+ });
+
+ $('#refreshable-dividers').bind('dividerschange', function () {
+ console.log('dividers were updated on refreshable list');
+ });
+});
+</script>
+
+</body>
+</html>
View
44 tests/unit/listview/index.html
@@ -211,6 +211,50 @@ <h2 id="qunit-userAgent"></h2>
</div>
</div>
+<!-- Autodivider -->
+<div data-nstest-role="page" id="autodividers-test">
+ <div data-nstest-role="header" data-nstest-position="inline">
+ <h1>Autodivider Test</h1>
+ </div>
+ <div data-nstest-role="content">
+ <ul data-nstest-role="listview" data-nstest-autodividers="alpha">
+ <li data-nstest-role="list-divider">SHOULD REMOVE</li>
+ <li>a is for aquaman</li>
+ <li>b is for batman</li>
+ <li>c is for catwoman</li>
+ <li>d is for darkwing</li>
+ </ul>
+ </div>
+</div>
+
+<div data-nstest-role="page" id="autodividers-selector-test">
+ <div data-nstest-role="header" data-nstest-position="inline">
+ <h1>Autodivider Selector Test</h1>
+ </div>
+ <div data-nstest-role="content">
+ <ul id="autodividers-selector-test-list1" data-nstest-role="listview" data-nstest-autodividers="alpha">
+ <li><a href="">a is for aquaman</a></li>
+ <li><a href="">b is for batman</a></li>
+ <li><a href="">c is for catwoman</a></li>
+ <li><a href="">d is for darkwing</a></li>
+ </ul>
+
+ <ul id="autodividers-selector-test-list2" data-nstest-role="listview" data-nstest-autodividers="alpha" data-nstest-autodividers-selector="div > span.autodividers-selector-test-selectme">
+ <li><div><span class="autodividers-selector-test-selectme">eddie</span> is for aquaman</div></li>
+ <li><div><span class="autodividers-selector-test-selectme">frankie</span> is for batman</div></li>
+ <li><div><span class="autodividers-selector-test-selectme">georgie</span> is for catwoman</div></li>
+ <li><div><span class="autodividers-selector-test-selectme">henry</span> is for darkwing</div></li>
+ </ul>
+
+ <ul id="autodividers-selector-test-list3" data-nstest-role="listview" data-nstest-autodividers="full" data-nstest-autodividers-selector="div > span.autodividers-selector-test-selectme">
+ <li><div><span class="autodividers-selector-test-selectme">eddie</span> is smart</div></li>
+ <li><div><span class="autodividers-selector-test-selectme">eddie</span> is tough</div></li>
+ <li><div><span class="autodividers-selector-test-selectme">frankie</span> is scruffy</div></li>
+ <li><div><span class="autodividers-selector-test-selectme">frankie</span> is week</div></li>
+ </ul>
+ </div>
+</div>
+
<!-- Search bar filter -->
<div data-nstest-role="page" id='search-filter-test'>
<div data-nstest-role="header" data-nstest-position="inline">
View
208 tests/unit/listview/listview_core.js
@@ -4,7 +4,7 @@
// TODO split out into seperate test files
(function($){
- var home = $.mobile.path.parseUrl( location.href ).pathname;
+ var home = $.mobile.path.parseUrl( location.href ).pathname;
$.mobile.defaultTransition = "none";
@@ -65,13 +65,13 @@
var page = $( ".ui-page-active" ),
items = page.find( "li" );
- ok( items.eq( 0 ).hasClass( "ui-li-has-count"), "First LI should have ui-li-has-count class" );
- ok( items.eq( 0 ).hasClass( "ui-li-has-arrow"), "First LI should have ui-li-has-arrow class" );
+ ok( items.eq( 0 ).hasClass( "ui-li-has-count"), "First LI should have ui-li-has-count class" );
+ ok( items.eq( 0 ).hasClass( "ui-li-has-arrow"), "First LI should have ui-li-has-arrow class" );
ok( !items.eq( 1 ).hasClass( "ui-li-has-count"), "Second LI should NOT have ui-li-has-count class" );
- ok( items.eq( 1 ).hasClass( "ui-li-has-arrow"), "Second LI should have ui-li-has-arrow class" );
+ ok( items.eq( 1 ).hasClass( "ui-li-has-arrow"), "Second LI should have ui-li-has-arrow class" );
ok( !items.eq( 2 ).hasClass( "ui-li-has-count"), "Third LI should NOT have ui-li-has-count class" );
ok( !items.eq( 2 ).hasClass( "ui-li-has-arrow"), "Third LI should NOT have ui-li-has-arrow class" );
- ok( items.eq( 3 ).hasClass( "ui-li-has-count"), "Fourth LI should have ui-li-has-count class" );
+ ok( items.eq( 3 ).hasClass( "ui-li-has-count"), "Fourth LI should have ui-li-has-count class" );
ok( !items.eq( 3 ).hasClass( "ui-li-has-arrow"), "Fourth LI should NOT have ui-li-has-arrow class" );
ok( !items.eq( 4 ).hasClass( "ui-li-has-count"), "Fifth LI should NOT have ui-li-has-count class" );
ok( !items.eq( 4 ).hasClass( "ui-li-has-arrow"), "Fifth LI should NOT have ui-li-has-arrow class" );
@@ -316,6 +316,176 @@
]);
});
+ module( "Autodividers" );
+
+ asyncTest( "Adds dividers based on first letters of list items.", function() {
+ $.testHelper.pageSequence([
+ function() {
+ $.testHelper.openPage( '#autodividers-test' );
+ },
+
+ function() {
+ var $new_page = $( '#autodividers-test' );
+ ok( $new_page.hasClass( 'ui-page-active' ) );
+ ok( $new_page.find( '.ui-li-divider' ).length === 4 );
+
+ start();
+ }
+ ]);
+ });
+
+ asyncTest( "Responds to addition/removal of list elements.", function() {
+ $.testHelper.pageSequence([
+ function() {
+ $.testHelper.openPage( '#autodividers-test' );
+ },
+
+ function() {
+ var $new_page = $( '#autodividers-test' );
+ ok($new_page.hasClass( 'ui-page-active' ));
+
+ var $listview = $new_page.find( 'ul' );
+
+ // should remove all existing dividers
+ ok( $new_page.find( 'li:contains("SHOULD REMOVE")' ).length === 0 );
+
+ // add li; should add an "X" divider
+ $listview.append( '<li>x is for xanthe</li>' );
+ ok( $new_page.find( '.ui-li-divider' ).length === 5 );
+ ok( $new_page.find( '.ui-li-divider' ).is( ':contains("X")' ) );
+
+ // adding the same element again should create a valid list
+ // item but no new divider
+ ok( $new_page.find( '.ui-li-static' ).length === 5 );
+ $listview.append( '<li>x is for xanthe</li>' );
+ ok( $new_page.find( '.ui-li-divider' ).length === 5 );
+ ok( $new_page.find( '.ui-li-divider:contains("X")' ).length === 1 );
+ ok( $new_page.find( '.ui-li-static' ).length === 6 );
+
+ // should ignore addition of non-li elements to the list
+ $listview.find( 'li:eq(0)' ).append( '<span>ignore me</span>' );
+ ok( $new_page.find( '.ui-li-divider' ).length === 5 );
+ ok( $new_page.find( '.ui-li-static' ).length === 6 );
+
+ // add li with the same initial letter as another li
+ // but after the X li item; should add a second "B" divider to the
+ // end of the list
+ $listview.append( '<li>b is for barry</li>' );
+ ok( $new_page.find( '.ui-li-divider' ).length === 6 );
+ ok( $new_page.find( '.ui-li-divider:contains("B")' ).length === 2 );
+
+ // remove the item with a repeated "b"; should remove the second
+ // "B" divider
+ $listview.find( 'li:contains("barry")' ).remove();
+ ok( $new_page.find( '.ui-li-divider' ).length === 5 );
+ ok( $new_page.find( '.ui-li-divider:contains("B")' ).length === 1 );
+
+ // remove li; should remove the "A" divider
+ $listview.find( 'li:contains("aquaman")' ).remove();
+ ok( $new_page.find( '.ui-li-divider' ).length === 4 );
+ ok( !$new_page.find( '.ui-li-divider' ).is( ':contains("A")' ) );
+
+ // adding another "B" item after "C" should create two separate
+ // "B" dividers
+ $listview.find( 'li:contains("catwoman")' ).after( '<li>b is for barry</li>' );
+ ok( $new_page.find( '.ui-li-divider' ).length === 5 );
+ ok( $new_page.find( '.ui-li-divider:contains("B")' ).length === 2 );
+
+ // if two dividers with the same letter have only non-dividers
+ // between them, they get merged
+
+ // removing catwoman should cause the two "B" dividers to merge
+ $listview.find( 'li:contains("catwoman")' ).remove();
+ ok( $new_page.find( '.ui-li-divider:contains("B")' ).length === 1 );
+
+ // adding another "D" item before the "D" divider should only
+ // result in a single "D" divider after merging
+ $listview.find( 'li:contains("barry")' ).after( '<li>d is for dan</li>' );
+ ok( $new_page.find( '.ui-li-divider:contains("D")' ).length === 1 );
+
+ start();
+ }
+ ]);
+ });
+
+ module( "Autodividers Selector" );
+
+ asyncTest( "Adds divider text from links.", function() {
+ $.testHelper.pageSequence([
+ function() {
+ $.testHelper.openPage( '#autodividers-selector-test' );
+ },
+
+ function() {
+ var $new_page = $( '#autodividers-selector-test' );
+ ok($new_page.hasClass( 'ui-page-active' ));
+
+ // check we have the right dividers based on link text
+ var $list = $( '#autodividers-selector-test-list1' );
+ ok( $list.find( '.ui-li-divider' ).length === 4 );
+ ok( $list.find( '.ui-li-divider:eq(0):contains(A)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(1):contains(B)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(2):contains(C)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(3):contains(D)' ).length === 1 );
+
+ // check that adding a new item with link creates the right divider
+ $list.append( '<li><a href="">e is for ethel</a></li>' );
+ ok( $list.find( '.ui-li-divider:eq(4):contains(E)' ).length === 1 );
+
+ start();
+ }
+ ]);
+ });
+
+ asyncTest( "Adds divider text based on custom selector.", function() {
+ $.testHelper.pageSequence([
+ function() {
+ $.testHelper.openPage( '#autodividers-selector-test' );
+ },
+
+ function() {
+ var $new_page = $( '#autodividers-selector-test' );
+ ok($new_page.hasClass( 'ui-page-active' ));
+
+ // check we have the right dividers based on custom selector
+ var $list = $( '#autodividers-selector-test-list2' );
+ ok( $list.find( '.ui-li-divider' ).length === 4 );
+ ok( $list.find( '.ui-li-divider:eq(0):contains(E)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(1):contains(F)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(2):contains(G)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(3):contains(H)' ).length === 1 );
+
+ // check that adding a new item creates the right divider
+ $list.append( '<li><div><span class="autodividers-selector-test-selectme">' +
+ 'i is for impy</span></div></li>' );
+
+ ok( $list.find( '.ui-li-divider:eq(4):contains(I)' ).length === 1 );
+
+ start();
+ }
+ ]);
+ });
+
+ asyncTest( "Adds divider text based on full text selected by custom selector.", function() {
+ $.testHelper.pageSequence([
+ function() {
+ $.testHelper.openPage( '#autodividers-selector-test' );
+ },
+
+ function() {
+ var $new_page = $( '#autodividers-selector-test' );
+ ok($new_page.hasClass( 'ui-page-active' ));
+
+ var $list = $( '#autodividers-selector-test-list3' );
+ ok( $list.find( '.ui-li-divider' ).length === 2 );
+ ok( $list.find( '.ui-li-divider:eq(0):contains(eddie)' ).length === 1 );
+ ok( $list.find( '.ui-li-divider:eq(1):contains(frankie)' ).length === 1 );
+
+ start();
+ }
+ ]);
+ });
+
module( "Search Filter");
var searchFilterId = "#search-filter-test";
@@ -355,22 +525,22 @@
]);
});
- asyncTest( "Filter works fine with \\W- or regexp-special-characters", function() {
- var $searchPage = $(searchFilterId);
- $.testHelper.pageSequence([
- function() {
- $.testHelper.openPage(searchFilterId);
- },
+ asyncTest( "Filter works fine with \\W- or regexp-special-characters", function() {
+ var $searchPage = $(searchFilterId);
+ $.testHelper.pageSequence([
+ function() {
+ $.testHelper.openPage(searchFilterId);
+ },
- function() {
- $searchPage.find('input').val('*');
- $searchPage.find('input').trigger('change');
+ function() {
+ $searchPage.find('input').val('*');
+ $searchPage.find('input').trigger('change');
- same($searchPage.find('li.ui-screen-hidden').length, 4);
- start();
- }
- ]);
- });
+ same($searchPage.find('li.ui-screen-hidden').length, 4);
+ start();
+ }
+ ]);
+ });
test( "Refresh applies thumb styling", function(){
var ul = $('.ui-page-active ul');
Something went wrong with that request. Please try again.