1 | $.widget( "custom.combobox", {
|
---|
2 | _create: function() {
|
---|
3 | this.wrapper = $( "<span>" )
|
---|
4 | .addClass( "custom-combobox" )
|
---|
5 | .insertAfter( this.element );
|
---|
6 | this.element.hide();
|
---|
7 | this._createAutocomplete();
|
---|
8 | this._createShowAllButton();
|
---|
9 | },
|
---|
10 |
|
---|
11 | _createAutocomplete: function() {
|
---|
12 | var selected = this.element.children( ":selected" ),
|
---|
13 | value = selected.val() ? selected.text() : "";
|
---|
14 | this.input = $( "<input>" )
|
---|
15 | .appendTo( this.wrapper )
|
---|
16 | .val( value )
|
---|
17 | .attr( "title", "" )
|
---|
18 | .addClass( "custom-combobox-input ui-widget ui-widget-content autocomplete-custom ui-corner-left" )
|
---|
19 | .autocomplete({
|
---|
20 | delay: 0,
|
---|
21 | minLength: 0,
|
---|
22 | source: $.proxy( this, "_source" )
|
---|
23 | })
|
---|
24 | .tooltip({
|
---|
25 | tooltipClass: "ui-state-highlight"
|
---|
26 | });
|
---|
27 | this._on( this.input, {
|
---|
28 | autocompleteselect: function( event, ui ) {
|
---|
29 | ui.item.option.selected = true;
|
---|
30 | this._trigger( "select", event, {
|
---|
31 | item: ui.item.option
|
---|
32 | });
|
---|
33 | },
|
---|
34 | autocompletechange: "_removeIfInvalid"
|
---|
35 | });
|
---|
36 | },
|
---|
37 |
|
---|
38 | _createShowAllButton: function() {
|
---|
39 | var input = this.input,
|
---|
40 | wasOpen = false;
|
---|
41 | $( "<a>" )
|
---|
42 | .attr( "tabIndex", -1 )
|
---|
43 | .attr( "title", "Show All Items" )
|
---|
44 | .appendTo( this.wrapper )
|
---|
45 | .button({
|
---|
46 | icons: {
|
---|
47 | primary: "ui-icon-triangle-1-s"
|
---|
48 | },
|
---|
49 | text: false
|
---|
50 | })
|
---|
51 | .removeClass( "ui-corner-all" )
|
---|
52 | .addClass( "custom-combobox-toggle ui-corner-right" )
|
---|
53 | .mousedown(function() {
|
---|
54 | wasOpen = input.autocomplete( "widget" ).is( ":visible" );
|
---|
55 | })
|
---|
56 | .click(function() {
|
---|
57 | input.focus();
|
---|
58 | // Close if already visible
|
---|
59 | if ( wasOpen ) {
|
---|
60 | return;
|
---|
61 | }
|
---|
62 | // Pass empty string as value to search for, displaying all results
|
---|
63 | input.autocomplete( "search", "" );
|
---|
64 | });
|
---|
65 | },
|
---|
66 |
|
---|
67 | _source: function( request, response ) {
|
---|
68 | var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
|
---|
69 | response( this.element.children( "option" ).map(function() {
|
---|
70 | var text = $( this ).text();
|
---|
71 | if ( this.value && ( !request.term || matcher.test(text) ) )
|
---|
72 | return {
|
---|
73 | label: text,
|
---|
74 | value: text,
|
---|
75 | option: this
|
---|
76 | };
|
---|
77 | }) );
|
---|
78 | },
|
---|
79 |
|
---|
80 | _removeIfInvalid: function( event, ui ) {
|
---|
81 | // Selected an item, nothing to do
|
---|
82 | if ( ui.item ) {
|
---|
83 | return;
|
---|
84 | }
|
---|
85 | // Search for a match (case-insensitive)
|
---|
86 | var value = this.input.val(),
|
---|
87 | valueLowerCase = value.toLowerCase(),
|
---|
88 | valid = false;
|
---|
89 | this.element.children( "option" ).each(function() {
|
---|
90 | if ( $( this ).text().toLowerCase() === valueLowerCase ) {
|
---|
91 | this.selected = valid = true;
|
---|
92 | return false;
|
---|
93 | }
|
---|
94 | });
|
---|
95 | // Found a match, nothing to do
|
---|
96 | if ( valid ) {
|
---|
97 | return;
|
---|
98 | }
|
---|
99 | // Remove invalid value
|
---|
100 | this.input
|
---|
101 | .val( "" )
|
---|
102 | .attr( "title", value + " didn't match any item" )
|
---|
103 | .tooltip( "open" );
|
---|
104 | this.element.val( "" );
|
---|
105 | this._delay(function() {
|
---|
106 | this.input.tooltip( "close" ).attr( "title", "" );
|
---|
107 | }, 2500 );
|
---|
108 | this.input.data( "ui-autocomplete" ).term = "";
|
---|
109 | },
|
---|
110 |
|
---|
111 | _destroy: function() {
|
---|
112 | this.wrapper.remove();
|
---|
113 | this.element.show();
|
---|
114 | }
|
---|
115 | });
|
---|