Révision 388c412d
Ajouté par Assos Assos il y a environ 7 ans
drupal7/sites/all/themes/bootstrap/js/misc/autocomplete.js | ||
---|---|---|
1 | 1 |
(function ($) { |
2 | 2 |
|
3 |
/** |
|
4 |
* Attaches the autocomplete behavior to all required fields. |
|
5 |
*/ |
|
6 |
Drupal.behaviors.autocomplete = { |
|
7 |
attach: function (context) { |
|
8 |
var $context = $(context); |
|
9 |
var acdb = []; |
|
10 |
$context.find('input.autocomplete').once('autocomplete', function () { |
|
11 |
var uri = this.value; |
|
12 |
if (!acdb[uri]) { |
|
13 |
acdb[uri] = new Drupal.ACDB(uri); |
|
14 |
} |
|
15 |
var $input = $context.find('#' + this.id.substr(0, this.id.length - 13)) |
|
16 |
.attr('autocomplete', 'OFF') |
|
17 |
.attr('aria-autocomplete', 'list'); |
|
18 |
$context.find($input[0].form).submit(Drupal.autocompleteSubmit); |
|
19 |
$input.parents('.form-item') |
|
20 |
.attr('role', 'application') |
|
21 |
.append($('<span class="element-invisible" aria-live="assertive"></span>') |
|
22 |
.attr('id', $input.attr('id') + '-autocomplete-aria-live') |
|
23 |
); |
|
24 |
new Drupal.jsAC($input, acdb[uri], $context); |
|
3 |
/** |
|
4 |
* Attaches the autocomplete behavior to all required fields. |
|
5 |
*/ |
|
6 |
Drupal.behaviors.autocomplete = { |
|
7 |
attach: function (context) { |
|
8 |
var $context = $(context); |
|
9 |
var acdb = []; |
|
10 |
$context.find('input.autocomplete').once('autocomplete', function () { |
|
11 |
var uri = this.value; |
|
12 |
if (!acdb[uri]) { |
|
13 |
acdb[uri] = new Drupal.ACDB(uri); |
|
14 |
} |
|
15 |
var $input = $context.find('#' + this.id.substr(0, this.id.length - 13)) |
|
16 |
.attr('autocomplete', 'OFF') |
|
17 |
.attr('aria-autocomplete', 'list'); |
|
18 |
$context.find($input[0].form).submit(Drupal.autocompleteSubmit); |
|
19 |
$input.parents('.form-item') |
|
20 |
.attr('role', 'application') |
|
21 |
.append($('<span class="element-invisible" aria-live="assertive"></span>') |
|
22 |
.attr('id', $input.attr('id') + '-autocomplete-aria-live') |
|
23 |
); |
|
24 |
new Drupal.jsAC($input, acdb[uri], $context); |
|
25 |
}); |
|
26 |
} |
|
27 |
}; |
|
28 |
|
|
29 |
/** |
|
30 |
* Prevents the form from submitting if the suggestions popup is open |
|
31 |
* and closes the suggestions popup when doing so. |
|
32 |
*/ |
|
33 |
Drupal.autocompleteSubmit = function () { |
|
34 |
$('.form-autocomplete > .dropdown').each(function () { |
|
35 |
this.owner.hidePopup(); |
|
25 | 36 |
}); |
26 |
} |
|
27 |
}; |
|
28 |
|
|
29 |
/** |
|
30 |
* Prevents the form from submitting if the suggestions popup is open |
|
31 |
* and closes the suggestions popup when doing so. |
|
32 |
*/ |
|
33 |
Drupal.autocompleteSubmit = function () { |
|
34 |
$('.form-autocomplete > .dropdown').each(function () { |
|
35 |
this.owner.hidePopup(); |
|
36 |
}); |
|
37 |
|
|
38 |
// Always return true to make it possible to submit even when there was an |
|
39 |
// autocomplete suggestion list open. |
|
37 |
|
|
38 |
// Always return true to make it possible to submit even when there was an |
|
39 |
// autocomplete suggestion list open. |
|
40 | 40 |
return true; |
41 |
}; |
|
42 |
|
|
43 |
/** |
|
44 |
* Highlights a suggestion. |
|
45 |
*/ |
|
46 |
Drupal.jsAC.prototype.highlight = function (node) { |
|
47 |
if (this.selected) { |
|
48 |
$(this.selected).removeClass('active'); |
|
49 |
} |
|
50 |
$(node).addClass('active'); |
|
51 |
this.selected = node; |
|
52 |
$(this.ariaLive).html($(this.selected).html()); |
|
53 |
}; |
|
54 |
|
|
55 |
/** |
|
56 |
* Unhighlights a suggestion. |
|
57 |
*/ |
|
58 |
Drupal.jsAC.prototype.unhighlight = function (node) { |
|
59 |
$(node).removeClass('active'); |
|
60 |
this.selected = false; |
|
61 |
$(this.ariaLive).empty(); |
|
62 |
}; |
|
63 |
|
|
64 |
/** |
|
65 |
* Positions the suggestions popup and starts a search. |
|
66 |
*/ |
|
67 |
Drupal.jsAC.prototype.populatePopup = function () { |
|
68 |
var $input = $(this.input); |
|
69 |
// Show popup. |
|
70 |
if (this.popup) { |
|
71 |
$(this.popup).remove(); |
|
72 |
} |
|
73 |
this.selected = false; |
|
74 |
this.popup = $('<div class="dropdown"></div>')[0]; |
|
75 |
this.popup.owner = this; |
|
76 |
$input.parent().after(this.popup); |
|
77 |
|
|
78 |
// Do search. |
|
79 |
this.db.owner = this; |
|
80 |
this.db.search(this.input.value); |
|
81 |
}; |
|
82 |
|
|
83 |
/** |
|
84 |
* Fills the suggestion popup with any matches received. |
|
85 |
*/ |
|
86 |
Drupal.jsAC.prototype.found = function (matches) { |
|
87 |
// If no value in the textfield, do not show the popup. |
|
88 |
if (!this.input.value.length) { |
|
89 |
return false; |
|
90 |
} |
|
91 |
|
|
92 |
// Prepare matches. |
|
93 |
var ul = $('<ul class="dropdown-menu"></ul>'); |
|
94 |
var ac = this; |
|
95 |
ul.css({ |
|
96 |
display: 'block', |
|
97 |
right: 0 |
|
98 |
}); |
|
99 |
for (var key in matches) { |
|
100 |
$('<li></li>') |
|
101 |
.html($('<a href="#"></a>').html(matches[key]).on('click', function (e) { e.preventDefault(); })) |
|
102 |
.on('mousedown', function () { ac.hidePopup(this); }) |
|
103 |
.on('mouseover', function () { ac.highlight(this); }) |
|
104 |
.on('mouseout', function () { ac.unhighlight(this); }) |
|
105 |
.data('autocompleteValue', key) |
|
106 |
.appendTo(ul); |
|
107 |
} |
|
108 |
|
|
109 |
// Show popup with matches, if any. |
|
110 |
if (this.popup) { |
|
111 |
if (ul.children().length) { |
|
112 |
$(this.popup).empty().append(ul).show(); |
|
113 |
$(this.ariaLive).html(Drupal.t('Autocomplete popup')); |
|
41 |
}; |
|
42 |
|
|
43 |
/** |
|
44 |
* Highlights a suggestion. |
|
45 |
*/ |
|
46 |
Drupal.jsAC.prototype.highlight = function (node) { |
|
47 |
if (this.selected) { |
|
48 |
$(this.selected).removeClass('active'); |
|
49 |
} |
|
50 |
$(node).addClass('active'); |
|
51 |
this.selected = node; |
|
52 |
$(this.ariaLive).html($(this.selected).html()); |
|
53 |
}; |
|
54 |
|
|
55 |
/** |
|
56 |
* Unhighlights a suggestion. |
|
57 |
*/ |
|
58 |
Drupal.jsAC.prototype.unhighlight = function (node) { |
|
59 |
$(node).removeClass('active'); |
|
60 |
this.selected = false; |
|
61 |
$(this.ariaLive).empty(); |
|
62 |
}; |
|
63 |
|
|
64 |
/** |
|
65 |
* Positions the suggestions popup and starts a search. |
|
66 |
*/ |
|
67 |
Drupal.jsAC.prototype.populatePopup = function () { |
|
68 |
var $input = $(this.input); |
|
69 |
// Show popup. |
|
70 |
if (this.popup) { |
|
71 |
$(this.popup).remove(); |
|
72 |
} |
|
73 |
this.selected = false; |
|
74 |
this.popup = $('<div class="dropdown"></div>')[0]; |
|
75 |
this.popup.owner = this; |
|
76 |
$input.parent().after(this.popup); |
|
77 |
|
|
78 |
// Do search. |
|
79 |
this.db.owner = this; |
|
80 |
this.db.search(this.input.value); |
|
81 |
}; |
|
82 |
|
|
83 |
/** |
|
84 |
* Fills the suggestion popup with any matches received. |
|
85 |
*/ |
|
86 |
Drupal.jsAC.prototype.found = function (matches) { |
|
87 |
// If no value in the textfield, do not show the popup. |
|
88 |
if (!this.input.value.length) { |
|
89 |
return false; |
|
90 |
} |
|
91 |
|
|
92 |
// Prepare matches. |
|
93 |
var ul = $('<ul class="dropdown-menu"></ul>'); |
|
94 |
var ac = this; |
|
95 |
ul.css({ |
|
96 |
display: 'block', |
|
97 |
right: 0 |
|
98 |
}); |
|
99 |
for (var key in matches) { |
|
100 |
$('<li></li>') |
|
101 |
.html($('<a href="#"></a>').html(matches[key]).on('click', function (e) { |
|
102 |
e.preventDefault(); |
|
103 |
})) |
|
104 |
.on('mousedown', function () { |
|
105 |
ac.hidePopup(this); |
|
106 |
}) |
|
107 |
.on('mouseover', function () { |
|
108 |
ac.highlight(this); |
|
109 |
}) |
|
110 |
.on('mouseout', function () { |
|
111 |
ac.unhighlight(this); |
|
112 |
}) |
|
113 |
.data('autocompleteValue', key) |
|
114 |
.appendTo(ul); |
|
115 |
} |
|
116 |
|
|
117 |
// Show popup with matches, if any. |
|
118 |
if (this.popup) { |
|
119 |
if (ul.children().length) { |
|
120 |
$(this.popup).empty().append(ul).show(); |
|
121 |
$(this.ariaLive).html(Drupal.t('Autocomplete popup')); |
|
122 |
} |
|
123 |
else { |
|
124 |
$(this.popup).css({visibility: 'hidden'}); |
|
125 |
this.hidePopup(); |
|
126 |
} |
|
127 |
} |
|
128 |
}; |
|
129 |
|
|
130 |
/** |
|
131 |
* Finds the next sibling item. |
|
132 |
*/ |
|
133 |
Drupal.jsAC.prototype.findNextSibling = function (element) { |
|
134 |
var sibling = element && element.nextSibling; |
|
135 |
if (sibling && !this.validItem(sibling)) { |
|
136 |
return this.findNextSibling(sibling.nextSibling); |
|
137 |
} |
|
138 |
return sibling; |
|
139 |
}; |
|
140 |
|
|
141 |
/** |
|
142 |
* Finds the previous sibling item. |
|
143 |
*/ |
|
144 |
Drupal.jsAC.prototype.findPreviousSibling = function (element) { |
|
145 |
var sibling = element && element.previousSibling; |
|
146 |
if (sibling && !this.validItem(sibling)) { |
|
147 |
return this.findPreviousSibling(sibling.previousSibling); |
|
148 |
} |
|
149 |
return sibling; |
|
150 |
}; |
|
151 |
|
|
152 |
/** |
|
153 |
* Highlights the next suggestion. |
|
154 |
*/ |
|
155 |
Drupal.jsAC.prototype.selectDown = function () { |
|
156 |
var sibling = this.findNextSibling(this.selected); |
|
157 |
if (sibling) { |
|
158 |
this.highlight(sibling); |
|
159 |
} |
|
160 |
else if (this.popup) { |
|
161 |
var lis = $('li', this.popup); |
|
162 |
if (lis.length > 0) { |
|
163 |
if (this.validItem(lis[0])) { |
|
164 |
this.highlight(lis[0]); |
|
165 |
} |
|
166 |
else { |
|
167 |
this.highlight(this.findNextSibling(lis[0])); |
|
168 |
} |
|
169 |
} |
|
170 |
} |
|
171 |
}; |
|
172 |
|
|
173 |
/** |
|
174 |
* Highlights the previous suggestion. |
|
175 |
*/ |
|
176 |
Drupal.jsAC.prototype.selectUp = function () { |
|
177 |
var sibling = this.findPreviousSibling(this.selected); |
|
178 |
if (sibling) { |
|
179 |
this.highlight(sibling); |
|
180 |
} |
|
181 |
else if (this.popup) { |
|
182 |
var lis = $('li', this.popup); |
|
183 |
if (lis.length > 0) { |
|
184 |
if (this.validItem(lis[lis.length - 1])) { |
|
185 |
this.highlight(lis[lis.length - 1]); |
|
186 |
} |
|
187 |
else { |
|
188 |
this.highlight(this.findPreviousSibling(lis[lis.length - 1])); |
|
189 |
} |
|
190 |
} |
|
114 | 191 |
} |
115 |
else { |
|
116 |
$(this.popup).css({ visibility: 'hidden' }); |
|
117 |
this.hidePopup(); |
|
192 |
}; |
|
193 |
|
|
194 |
/** |
|
195 |
* Ensures the item is valid. |
|
196 |
*/ |
|
197 |
Drupal.jsAC.prototype.validItem = function (element) { |
|
198 |
return !$(element).is('.dropdown-header, .divider, .disabled'); |
|
199 |
}; |
|
200 |
|
|
201 |
Drupal.jsAC.prototype.setStatus = function (status) { |
|
202 |
var $throbber = $(this.input).parent().find('.glyphicon-refresh, .autocomplete-throbber').first(); |
|
203 |
var throbbingClass = $throbber.is('.autocomplete-throbber') ? 'throbbing' : 'glyphicon-spin'; |
|
204 |
switch (status) { |
|
205 |
case 'begin': |
|
206 |
$throbber.addClass(throbbingClass); |
|
207 |
$(this.ariaLive).html(Drupal.t('Searching for matches...')); |
|
208 |
break; |
|
209 |
case 'cancel': |
|
210 |
case 'error': |
|
211 |
case 'found': |
|
212 |
$throbber.removeClass(throbbingClass); |
|
213 |
break; |
|
118 | 214 |
} |
119 |
} |
|
120 |
}; |
|
121 |
|
|
122 |
Drupal.jsAC.prototype.setStatus = function (status) { |
|
123 |
var $throbber = $(this.input).parent().find('.glyphicon-refresh, .autocomplete-throbber').first(); |
|
124 |
var throbbingClass = $throbber.is('.autocomplete-throbber') ? 'throbbing' : 'glyphicon-spin'; |
|
125 |
switch (status) { |
|
126 |
case 'begin': |
|
127 |
$throbber.addClass(throbbingClass); |
|
128 |
$(this.ariaLive).html(Drupal.t('Searching for matches...')); |
|
129 |
break; |
|
130 |
case 'cancel': |
|
131 |
case 'error': |
|
132 |
case 'found': |
|
133 |
$throbber.removeClass(throbbingClass); |
|
134 |
break; |
|
135 |
} |
|
136 |
}; |
|
137 |
|
|
138 |
// Save the previous autocomplete prototype. |
|
139 |
var oldPrototype = Drupal.jsAC.prototype; |
|
140 |
|
|
141 |
/** |
|
142 |
* Override the autocomplete constructor. |
|
143 |
*/ |
|
144 |
Drupal.jsAC = function ($input, db, context) { |
|
145 |
var ac = this; |
|
146 |
|
|
147 |
// Context is normally passed by Drupal.behaviors.autocomplete above. However, |
|
148 |
// if a module has manually invoked this method they will likely not know |
|
149 |
// about this feature and a global fallback context to document must be used. |
|
150 |
// @see https://www.drupal.org/node/2594243 |
|
151 |
// @see https://www.drupal.org/node/2315295 |
|
152 |
this.$context = context && $(context) || $(document); |
|
153 |
|
|
154 |
this.input = $input[0]; |
|
155 |
this.ariaLive = this.$context.find('#' + this.input.id + '-autocomplete-aria-live'); |
|
156 |
this.db = db; |
|
157 |
$input |
|
158 |
.keydown(function (event) { return ac.onkeydown(this, event); }) |
|
159 |
.keyup(function (event) { ac.onkeyup(this, event); }) |
|
160 |
.blur(function () { ac.hidePopup(); ac.db.cancel(); }); |
|
161 |
}; |
|
162 |
|
|
163 |
// Restore the previous prototype. |
|
164 |
Drupal.jsAC.prototype = oldPrototype; |
|
215 |
}; |
|
216 |
|
|
217 |
// Save the previous autocomplete prototype. |
|
218 |
var oldPrototype = Drupal.jsAC.prototype; |
|
219 |
|
|
220 |
/** |
|
221 |
* Override the autocomplete constructor. |
|
222 |
*/ |
|
223 |
Drupal.jsAC = function ($input, db, context) { |
|
224 |
var ac = this; |
|
225 |
|
|
226 |
// Context is normally passed by Drupal.behaviors.autocomplete above. However, |
|
227 |
// if a module has manually invoked this method they will likely not know |
|
228 |
// about this feature and a global fallback context to document must be used. |
|
229 |
// @see https://www.drupal.org/node/2594243 |
|
230 |
// @see https://www.drupal.org/node/2315295 |
|
231 |
this.$context = context && $(context) || $(document); |
|
232 |
|
|
233 |
this.input = $input[0]; |
|
234 |
this.ariaLive = this.$context.find('#' + this.input.id + '-autocomplete-aria-live'); |
|
235 |
this.db = db; |
|
236 |
$input |
|
237 |
.keydown(function (event) { |
|
238 |
return ac.onkeydown(this, event); |
|
239 |
}) |
|
240 |
.keyup(function (event) { |
|
241 |
ac.onkeyup(this, event); |
|
242 |
}) |
|
243 |
.blur(function () { |
|
244 |
ac.hidePopup(); |
|
245 |
ac.db.cancel(); |
|
246 |
}); |
|
247 |
}; |
|
248 |
|
|
249 |
// Restore the previous prototype. |
|
250 |
Drupal.jsAC.prototype = oldPrototype; |
|
165 | 251 |
|
166 | 252 |
})(jQuery); |
Formats disponibles : Unified diff
Weekly update of contrib modules