Showing with 95 additions and 59 deletions.
  1. +54 −23 js/widgets/filterable.backcompat.js
  2. +38 −34 js/widgets/filterable.js
  3. +2 −2 tests/integration/filterable/filter_core.js
  4. +1 −0 tests/integration/filterable/index.html
@@ -27,43 +27,74 @@ $.mobile.filterable.prototype.options.filterCallback = function( index, searchVa
};

$.widget( "mobile.filterable", $.mobile.filterable, {
_handleCreate: function( evt ) {
this._setWidget( this.element.data( "mobile-" + evt.type.substring( 0, evt.type.length - 6 ) ) );
},

_setWidget: function( widget ) {
if ( !this._widget && widget ) {
this._widget = widget;
this._widget._setOptions = replaceSetOptions( this, this._widget._setOptions );
}

return !!this._widget;
},

_create: function() {
var idx, widgetName,
elem = this.element,
recognizedWidgets = [ "collapsibleset", "selectmenu", "controlgroup", "listview" ],
createHandlers = {};

this._super();

$.extend( this, {
_widget: null
});
},

_filterItems: function() {
var idx, widget, recognizedWidgets;

this._superApply( arguments );

if ( this._widget === null ) {

// Next time the filter gets called, do not try to search for the widget
this._widget = false;
for ( idx = recognizedWidgets.length - 1 ; idx > -1 ; idx-- ) {
widgetName = recognizedWidgets[ idx ];
if ( $.mobile[ widgetName ] ) {
if ( this._setWidget( elem.data( "mobile-" + widgetName ) ) ) {
break;
} else {
createHandlers[ widgetName + "create" ] = "_handleCreate";
}
}
}

recognizedWidgets = [ "controlgroup", "collapsibleset", "listview", "selectmenu" ];
if ( !this._widget ) {
this._on( elem, createHandlers );
}
},

for ( idx in recognizedWidgets ) {
widget = this.element.data( "mobile-" + recognizedWidgets[ idx ] );
if ( widget ) {
_isSearchInternal: function() {
return ( this._search && this._search.jqmData( "ui-filterable-" + this.uuid + "-internal" ) );
},

// Tap into _setOptions for a recognized widget so we may synchronize
// the widget's style with the textinput style, if the textinput is
// internal
widget._setOptions = replaceSetOptions( this, widget._setOptions );
this._syncTextInputOptions( widget.options );
this._widget = widget;
break;
_setInput: function( selector ) {
if ( !selector ) {

if ( !this._isSearchInternal() ) {
search = $( "<input data-" + $.mobile.ns + "type='search'></input>" )
.jqmData( "ui-filterable-" + this.uuid + "-internal", true );
$( "<form class='ui-filterable'></form>" )
.append( search )
.insertBefore( this.element );
if ( $.mobile.textinput ) {
search.textinput();
}
} else {
return;
}
}

if ( this._widget && $.isFunction( this._widget.refresh ) ) {
this._widget.refresh();
this._super( search );
},

_destroy: function() {
if ( this._isSearchInternal() ) {
this._search.remove();
}
},

@@ -3,7 +3,8 @@
//>>label: Filterable
//>>group: Widgets

define( [ "jquery" ], function( jQuery ) {
define( [ "jquery",
"jquery.mobile.widget" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

@@ -97,49 +98,47 @@ define( [ "jquery" ], function( jQuery ) {
} else {
filterItems[ opts.filterReveal ? "addClass" : "removeClass" ]( "ui-screen-hidden" );
}

this._refreshChildWidget();
},

_isSearchInternal: function() {
return ( this._search && this._search.jqmData( "ui-filterable-" + this.uuid + "-internal" ) );

// The Default implementation of _refreshChildWidget attempts to call
// refresh on collapsibleset, controlgroup, selectmenu, or listview
_refreshChildWidget: function() {
var widget, idx,
recognizedWidgets = [ "collapsibleset", "selectmenu", "controlgroup", "listview" ];

for ( idx = recognizedWidgets.length - 1 ; idx > -1 ; idx-- ) {
widget = recognizedWidgets[ idx ];
if ( $.mobile[ widget ] ) {
widget = this.element.data( "mobile-" + widget );
if ( widget && $.isFunction( widget.refresh ) ) {
widget.refresh();
}
}
}
},

// TODO: When the input is not internal, do not even store it in this._search
_setInput: function ( selector ) {
var search, bindEvents,
isCurrentInternal = this._isSearchInternal();
var search = this._search;

// Stop a pending filter operation
if ( this._timer ) {
clearTimeout( this._timer );
this._timer = 0;
}

if ( search ) {
this._off( search, "keyup change input" );
search = null;
}

if ( selector ) {
search = selector.jquery ? selector:
selector.nodeName ? $( selector ):
this.document.find( selector );
bindEvents = true;
if ( isCurrentInternal ) {
this._search.remove();
}
} else {
if ( isCurrentInternal ) {
search = this._search;
} else {
search = $( "<input " +
"data-" + $.mobile.ns + "type='search' " +
"></input>" )
.jqmData( "ui-filterable-" + this.uuid + "-internal", true )
.insertBefore( this.element );
if ( $.mobile.textinput ) {
search.textinput({ wrapperClass: "ui-filterable" });
}
bindEvents = true;
}
selector = search;
}

if ( bindEvents ) {
this._on( search, {
keyup: "_onKeyUp",
change: "_onKeyUp",
@@ -149,7 +148,7 @@ define( [ "jquery" ], function( jQuery ) {

this._search = search;

return selector;
return search;
},

_create: function() {
@@ -184,6 +183,17 @@ define( [ "jquery" ], function( jQuery ) {
}

if ( refilter ) {

// Update options needed by the filter before refiltering
if ( options.filterReveal !== undefined ) {
this.options.filterReveal = options.filterReveal;
}
if ( options.filterCallback !== undefined ) {
this.options.filterCallback = options.filterCallback;
}
if ( options.children !== undefined ) {
this.options.children = options.children;
}
this._getFilterableItems().removeClass( "ui-screen-hidden" );
this._filterItems( ( this._search.val() || "" ).toLowerCase() );
}
@@ -198,12 +208,6 @@ define( [ "jquery" ], function( jQuery ) {
._super( options );
},

_destroy: function() {
if ( this._isSearchInternal() ) {
this._search.remove();
}
}

});

$.mobile.filterable.initSelector = ":jqmData(filter='true')";
@@ -6,7 +6,7 @@
module( "Filter Widget Core Functions" );

asyncTest( "Filter hides/shows results when the user enters information", function() {
var input = $( "#filtered-listview-filterable" ),
var input = $( "#filtered-listview" ).prev().find( "input" ),
listview = $( "#filtered-listview" );

expect( 5 );
@@ -40,7 +40,7 @@
});

asyncTest( "Event filterablebeforefilter fires in response to input change", function() {
var input = $( "#filtered-listview-filterable" ),
var input = $( "#filtered-listview" ).prev().find( "input" ),
listview = $( "#filtered-listview" ),
beforeFilterCount = 0;

@@ -29,6 +29,7 @@
"widgets/forms/button",
"widgets/controlgroup",
"widgets/forms/select",
"widgets/forms/textinput",
"jquery.mobile.buttonMarkup",
"widgets/forms/checkboxradio",
"widgets/page" // Needed for controlgroup???