Browse files

Added demo using new jQuery UI autocomplete & menu.

  • Loading branch information...
1 parent a6de464 commit 3fd85bccde512af51ebb74022e1b107e65aad0cb Mark Gibson committed Dec 3, 2009
Showing with 173 additions and 1,038 deletions.
  1. +3 −2 Makefile
  2. +44 −0 css/ui.tokenlist.css
  3. +3 −0 demo/demo.css
  4. +79 −0 demo/demo.html
  5. +39 −0 demo/demo.js
  6. +1 −0 demo/jquery.js
  7. +1 −0 demo/ui-css
  8. +1 −0 demo/ui-src
  9. +1 −0 external/jquery
  10. +1 −0 external/jquery-ui
  11. +0 −762 src/jquery.autocomplete.js
  12. +0 −274 src/ui.tokenlist.js
View
5 Makefile
@@ -1,7 +1,8 @@
PACKAGE = jquery.ui-tokenlist
MODULES = \
- jquery.autocomplete.js \
- ui.tokenlist.js
+ jquery.ui.menu.js \
+ jquery.ui.autocomplete.js \
+ jquery.ui.tokenlist.js
include build/rules.mk
View
44 css/ui.tokenlist.css
@@ -0,0 +1,44 @@
+
+.ui-tokenlist {
+ padding: 1px;
+ margin: 0;
+ height: auto !important;
+ height: 1%;
+ list-style-position: outside;
+ list-style: none;
+}
+.ui-tokenlist .ui-tokenlist-item,
+.ui-tokenlist .ui-tokenlist-input {
+ float: left;
+ margin: 1px;
+ padding: 1px 2px 2px 5px;
+}
+.ui-tokenlist .ui-tokenlist-input {
+ padding-left: 4px;
+}
+.ui-tokenlist .ui-tokenlist-input input {
+ float: left;
+ padding: 1px;
+ border: none;
+ background: none;
+}
+.ui-tokenlist .ui-tokenlist-label {
+ float: left;
+}
+.ui-tokenlist .ui-tokenlist-remove {
+ float: right;
+ cursor: pointer;
+}
+
+/* IE fixes */
+/*
+body.msie .ui-tokenlist li {
+ padding-top: 0;
+ vertical-align: middle;
+}
+body.msie .ui-tokenlist li button {
+ float: none;
+ margin-left: 1ex;
+ margin-top: 2px;
+}
+*/
View
3 demo/demo.css
@@ -0,0 +1,3 @@
+@import url("ui-css/ui.all.css");
+@import url("../css/ui.tokenlist.css");
+
View
79 demo/demo.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>Token List Demo</title>
+
+ <link rel="stylesheet" href="demo.css" type="text/css" />
+
+ <script type="text/javascript" src="jquery.js"></script>
+ <script type="text/javascript" src="ui-src/jquery.ui.core.js"></script>
+ <script type="text/javascript" src="ui-src/jquery.ui.position.js"></script>
+ <script type="text/javascript" src="ui-src/jquery.ui.menu.js"></script>
+ <script type="text/javascript" src="ui-src/jquery.ui.autocomplete.js"></script>
+ <script type="text/javascript" src="../src/jquery.ui.tokenlist.js"></script>
+ <script type="text/javascript" src="demo.js"></script>
+</head>
+<body>
+ <h1>Token List Demo</h1>
+
+ <p>Convert a plain text field into a facebook style list builder:</p>
+
+ <button id="enhance">Enhance</button>
+ <button id="toggle" disabled="disabled">Toggle Original Input</button>
+
+ <hr/>
+
+ <label for="test1">With Autocomplete:</label>
+ <input id="test1" type="text" value="one, two, four" class="test autocomplete"/>
+
+ <hr/>
+
+ <label for="test2">Without:</label>
+ <input id="test2" type="text" value="six, three, zero" class="test"/>
+
+ <hr/>
+
+ <label for="test3">Using a UL in the markup:</label>
+ <ul id="test3" class="test autocomplete"></ul>
+
+ <hr/>
+
+ <label for="test4">Disabled:</label>
+ <input id="test4" type="text" value="eight, ten, four, six, nine" class="test" disabled="disabled"/>
+
+ <hr style="margin:1em 0;color:red"/>
+
+ <div style="font-size:small">
+ <p>Browser Compatibility Tests:</p>
+ <dl>
+ <dt>Linux - Ubuntu 8.10:</dt>
+ <dd><ul>
+ <li>Firefox 3.0.6 - ?</li>
+ <li>Opera 9.63 - ?</li>
+ <li>Konqueror 4.1.3 - ?</li>
+ </ul></dd>
+ <dt>Windows - XP sp3:</dt>
+ <dd><ul>
+ <li>IE 7 - ?</li>
+ <li>IE 6 - ?</li>
+ <li>Safari 3.1.2 - ?</li>
+ <li>Chrome 1.0.154.48 - ?</li>
+ </ul></dd>
+ <dt>UserAgent:</dt>
+ <dd><script type="text/javascript">document.write(window.navigator.userAgent);</script></dd>
+ </dl>
+ <p><a href="javascript:var firebug=document.createElement('script');firebug.setAttribute('src','http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js');document.body.appendChild(firebug);(function(){if(window.firebug.version){firebug.init();}else{setTimeout(arguments.callee);}})();void(firebug);">Firebug Lite</a></p>
+ </div>
+
+ <hr />
+
+ <p>
+ <a href="http://validator.w3.org/check?uri=referer"><img
+ src="http://www.w3.org/Icons/valid-xhtml10"
+ alt="Valid XHTML 1.0 Transitional" height="31" width="88" /></a>
+ </p>
+</body>
+</html>
+
View
39 demo/demo.js
@@ -0,0 +1,39 @@
+jQuery(function($) {
+
+ var data = ['one','two','three','four','five','six','seven','eight','nine','ten'];
+
+ $('#enhance').one('click', function() {
+ $('.test')
+ // Convert the element to a token list
+ .tokenlist({ validate: data })
+
+ .filter('.autocomplete')
+
+ .each(function() {
+ var items = $(this).tokenlist('items');
+
+ // Add the Autocomplete to the input field of the tokenlist
+ $(this)
+ .tokenlist('input')
+ .autocomplete({
+ source: function(request, response) {
+ // escape regex characters
+ var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
+ return $.grep(data, function(value) {
+ // also filter out existing items
+ return matcher.test(value) && $.inArray(value, items) < 0;
+ });
+ },
+ delay: 0,
+ change: function() {
+ $(this).trigger('change');
+ }
+ });
+ });
+
+ // Toggle the original input fields
+ $('#toggle').attr('disabled', false).bind('click', function() {
+ $('.test:text').toggle();
+ });
+ });
+});
View
1 demo/jquery.js
View
1 demo/ui-css
View
1 demo/ui-src
View
1 external/jquery
View
1 external/jquery-ui
View
762 src/jquery.autocomplete.js
@@ -1,762 +0,0 @@
-/*!
- * Autocomplete - jQuery plugin 1.0.2
- *
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
- *
- * With modifications:
- * 14/01/09 - Mark Gibson - Added ability to filter list before display
- */
-
-;(function($) {
-
-$.fn.extend({
- autocomplete: function(urlOrData, options) {
- var isUrl = typeof urlOrData == "string";
- options = $.extend({}, $.Autocompleter.defaults, {
- url: isUrl ? urlOrData : null,
- data: isUrl ? null : urlOrData,
- delay: isUrl ? $.Autocompleter.defaults.delay : 10,
- max: options && !options.scroll ? 10 : 150
- }, options);
-
- // if highlight is set to false, replace it with a do-nothing function
- options.highlight = options.highlight || function(value) { return value; };
-
- // if the formatMatch option is not specified, then use formatItem for backwards compatibility
- options.formatMatch = options.formatMatch || options.formatItem;
-
- return this.each(function() {
- new $.Autocompleter(this, options);
- });
- },
- result: function(handler) {
- return this.bind("result", handler);
- },
- search: function(handler) {
- return this.trigger("search", [handler]);
- },
- flushCache: function() {
- return this.trigger("flushCache");
- },
- setOptions: function(options){
- return this.trigger("setOptions", [options]);
- },
- unautocomplete: function() {
- return this.trigger("unautocomplete");
- }
-});
-
-$.Autocompleter = function(input, options) {
-
- var KEY = {
- UP: 38,
- DOWN: 40,
- DEL: 46,
- TAB: 9,
- RETURN: 13,
- ESC: 27,
- COMMA: 188,
- PAGEUP: 33,
- PAGEDOWN: 34,
- BACKSPACE: 8
- };
-
- // Create $ object for input element
- var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
-
- var timeout;
- var previousValue = "";
- var cache = $.Autocompleter.Cache(options);
- var hasFocus = 0;
- var lastKeyPressCode;
- var config = {
- mouseDownOnSelect: false
- };
- var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-
- var blockSubmit;
-
- // prevent form submit in opera when selecting with return key
- $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
- if (blockSubmit) {
- blockSubmit = false;
- return false;
- }
- });
-
- // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
- $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
- // track last key pressed
- lastKeyPressCode = event.keyCode;
- switch(event.keyCode) {
-
- case KEY.UP:
- event.preventDefault();
- if ( select.visible() ) {
- select.prev();
- } else {
- onChange(0, true);
- }
- break;
-
- case KEY.DOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.next();
- } else {
- onChange(0, true);
- }
- break;
-
- case KEY.PAGEUP:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageUp();
- } else {
- onChange(0, true);
- }
- break;
-
- case KEY.PAGEDOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageDown();
- } else {
- onChange(0, true);
- }
- break;
-
- // matches also semicolon
- case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
- case KEY.TAB:
- case KEY.RETURN:
- if( selectCurrent() ) {
- // stop default to prevent a form submit, Opera needs special handling
- event.preventDefault();
- blockSubmit = true;
- return false;
- }
- break;
-
- case KEY.ESC:
- select.hide();
- break;
-
- default:
- clearTimeout(timeout);
- timeout = setTimeout(onChange, options.delay);
- break;
- }
- }).focus(function(){
- // track whether the field has focus, we shouldn't process any
- // results if the field no longer has focus
- hasFocus++;
- }).blur(function() {
- hasFocus = 0;
- if (!config.mouseDownOnSelect) {
- hideResults();
- }
- }).click(function() {
- // show select when clicking in a focused field
- if ( hasFocus++ > 1 && !select.visible() ) {
- onChange(0, true);
- }
- }).bind("search", function() {
- // TODO why not just specifying both arguments?
- var fn = (arguments.length > 1) ? arguments[1] : null;
- function findValueCallback(q, data) {
- var result;
- if( data && data.length ) {
- for (var i=0; i < data.length; i++) {
- if( data[i].result.toLowerCase() == q.toLowerCase() ) {
- result = data[i];
- break;
- }
- }
- }
- if( typeof fn == "function" ) fn(result);
- else $input.trigger("result", result && [result.data, result.value]);
- }
- $.each(trimWords($input.val()), function(i, value) {
- request(value, findValueCallback, findValueCallback);
- });
- }).bind("flushCache", function() {
- cache.flush();
- }).bind("setOptions", function() {
- $.extend(options, arguments[1]);
- // if we've updated the data, repopulate
- if ( "data" in arguments[1] )
- cache.populate();
- }).bind("unautocomplete", function() {
- select.unbind();
- $input.unbind();
- $(input.form).unbind(".autocomplete");
- });
-
-
- function selectCurrent() {
- var selected = select.selected();
- if( !selected )
- return false;
-
- var v = selected.result;
- previousValue = v;
-
- if ( options.multiple ) {
- var words = trimWords($input.val());
- if ( words.length > 1 ) {
- v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
- }
- v += options.multipleSeparator;
- }
-
- $input.val(v);
- hideResultsNow();
- $input.trigger("result", [selected.data, selected.value]);
- return true;
- }
-
- function onChange(crap, skipPrevCheck) {
- if( lastKeyPressCode == KEY.DEL ) {
- select.hide();
- return;
- }
-
- var currentValue = $input.val();
-
- if ( !skipPrevCheck && currentValue == previousValue )
- return;
-
- previousValue = currentValue;
-
- currentValue = lastWord(currentValue);
- if ( currentValue.length >= options.minChars) {
- $input.addClass(options.loadingClass);
- if (!options.matchCase)
- currentValue = currentValue.toLowerCase();
- request(currentValue, receiveData, hideResultsNow);
- } else {
- stopLoading();
- select.hide();
- }
- };
-
- function trimWords(value) {
- if ( !value ) {
- return [""];
- }
- var words = value.split( options.multipleSeparator );
- var result = [];
- $.each(words, function(i, value) {
- if ( $.trim(value) )
- result[i] = $.trim(value);
- });
- return result;
- }
-
- function lastWord(value) {
- if ( !options.multiple )
- return value;
- var words = trimWords(value);
- return words[words.length - 1];
- }
-
- // fills in the input box w/the first match (assumed to be the best match)
- // q: the term entered
- // sValue: the first matching result
- function autoFill(q, sValue){
- // autofill in the complete box w/the first match as long as the user hasn't entered in more data
- // if the last user key pressed was backspace, don't autofill
- if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
- // fill in the value (keep the case the user has typed)
- $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
- // select the portion of the value not typed by the user (so the next character will erase)
- $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
- }
- };
-
- function hideResults() {
- clearTimeout(timeout);
- timeout = setTimeout(hideResultsNow, 200);
- };
-
- function hideResultsNow() {
- var wasVisible = select.visible();
- select.hide();
- clearTimeout(timeout);
- stopLoading();
- if (options.mustMatch) {
- // call search and run callback
- $input.search(
- function (result){
- // if no value found, clear the input box
- if( !result ) {
- if (options.multiple) {
- var words = trimWords($input.val()).slice(0, -1);
- $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
- }
- else
- $input.val( "" );
- }
- }
- );
- }
- if (wasVisible)
- // position cursor at end of input field
- $.Autocompleter.Selection(input, input.value.length, input.value.length);
- };
-
- function receiveData(q, data) {
- if ( data && data.length && hasFocus ) {
- stopLoading();
- select.display(data, q);
- autoFill(q, data[0].value);
- select.show();
- } else {
- hideResultsNow();
- }
- };
-
- function request(term, success, failure) {
- if (!options.matchCase)
- term = term.toLowerCase();
- var data = cache.load(term);
- // recieve the cached data
- if (data && data.length) {
- success(term, data);
- // if an AJAX url has been supplied, try loading the data now
- } else if( (typeof options.url == "string") && (options.url.length > 0) ){
-
- var extraParams = {
- timestamp: +new Date()
- };
- $.each(options.extraParams, function(key, param) {
- extraParams[key] = typeof param == "function" ? param() : param;
- });
-
- $.ajax({
- // try to leverage ajaxQueue plugin to abort previous requests
- mode: "abort",
- // limit abortion to this input
- port: "autocomplete" + input.name,
- dataType: options.dataType,
- url: options.url,
- data: $.extend({
- q: lastWord(term),
- limit: options.max
- }, extraParams),
- success: function(data) {
- var parsed = options.parse && options.parse(data) || parse(data);
- cache.add(term, parsed);
- success(term, parsed);
- }
- });
- } else {
- // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
- select.emptyList();
- failure(term);
- }
- };
-
- function parse(data) {
- var parsed = [];
- var rows = data.split("\n");
- for (var i=0; i < rows.length; i++) {
- var row = $.trim(rows[i]);
- if (row) {
- row = row.split("|");
- parsed[parsed.length] = {
- data: row,
- value: row[0],
- result: options.formatResult && options.formatResult(row, row[0]) || row[0]
- };
- }
- }
- return parsed;
- };
-
- function stopLoading() {
- $input.removeClass(options.loadingClass);
- };
-
-};
-
-$.Autocompleter.defaults = {
- inputClass: "ac_input",
- resultsClass: "ac_results",
- loadingClass: "ac_loading",
- minChars: 1,
- delay: 400,
- matchCase: false,
- matchSubset: true,
- matchContains: false,
- cacheLength: 10,
- max: 100,
- mustMatch: false,
- extraParams: {},
- selectFirst: true,
- formatItem: function(row) { return row[0]; },
- formatMatch: null,
- autoFill: false,
- width: 0,
- multiple: false,
- multipleSeparator: ", ",
- highlight: function(value, term) {
- return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
- },
- scroll: true,
- scrollHeight: 180,
- filter: function(data) { return data; }
-};
-
-$.Autocompleter.Cache = function(options) {
-
- var data = {};
- var length = 0;
-
- function matchSubset(s, sub) {
- if (!options.matchCase)
- s = s.toLowerCase();
- var i = s.indexOf(sub);
- if (i == -1) return false;
- return i == 0 || options.matchContains;
- };
-
- function add(q, value) {
- if (length > options.cacheLength){
- flush();
- }
- if (!data[q]){
- length++;
- }
- data[q] = value;
- }
-
- function populate(){
- if( !options.data ) return false;
- // track the matches
- var stMatchSets = {},
- nullData = 0;
-
- // no url was specified, we need to adjust the cache length to make sure it fits the local data store
- if( !options.url ) options.cacheLength = 1;
-
- // track all options for minChars = 0
- stMatchSets[""] = [];
-
- // loop through the array and create a lookup structure
- for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
- var rawValue = options.data[i];
- // if rawValue is a string, make an array otherwise just reference the array
- rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
-
- var value = options.formatMatch(rawValue, i+1, options.data.length);
- if ( value === false )
- continue;
-
- var firstChar = value.charAt(0).toLowerCase();
- // if no lookup array for this character exists, look it up now
- if( !stMatchSets[firstChar] )
- stMatchSets[firstChar] = [];
-
- // if the match is a string
- var row = {
- value: value,
- data: rawValue,
- result: options.formatResult && options.formatResult(rawValue) || value
- };
-
- // push the current match into the set list
- stMatchSets[firstChar].push(row);
-
- // keep track of minChars zero items
- if ( nullData++ < options.max ) {
- stMatchSets[""].push(row);
- }
- };
-
- // add the data items to the cache
- $.each(stMatchSets, function(i, value) {
- // increase the cache size
- options.cacheLength++;
- // add to the cache
- add(i, value);
- });
- }
-
- // populate any existing data
- setTimeout(populate, 25);
-
- function flush(){
- data = {};
- length = 0;
- }
-
- return {
- flush: flush,
- add: add,
- populate: populate,
- load: function(q) {
- if (!options.cacheLength || !length)
- return null;
- /*
- * if dealing w/local data and matchContains than we must make sure
- * to loop through all the data collections looking for matches
- */
- if( !options.url && options.matchContains ){
- // track all matches
- var csub = [];
- // loop through all the data grids for matches
- for( var k in data ){
- // don't search through the stMatchSets[""] (minChars: 0) cache
- // this prevents duplicates
- if( k.length > 0 ){
- var c = data[k];
- $.each(c, function(i, x) {
- // if we've got a match, add it to the array
- if (matchSubset(x.value, q)) {
- csub.push(x);
- }
- });
- }
- }
- return csub;
- } else
- // if the exact item exists, use it
- if (data[q]){
- return data[q];
- } else
- if (options.matchSubset) {
- for (var i = q.length - 1; i >= options.minChars; i--) {
- var c = data[q.substr(0, i)];
- if (c) {
- var csub = [];
- $.each(c, function(i, x) {
- if (matchSubset(x.value, q)) {
- csub[csub.length] = x;
- }
- });
- return csub;
- }
- }
- }
- return null;
- }
- };
-};
-
-$.Autocompleter.Select = function (options, input, select, config) {
- var CLASSES = {
- ACTIVE: "ac_over"
- };
-
- var listItems,
- active = -1,
- data,
- term = "",
- needsInit = true,
- element,
- list;
-
- // Create results
- function init() {
- if (!needsInit)
- return;
- element = $("<div/>")
- .hide()
- .addClass(options.resultsClass)
- .css("position", "absolute")
- .appendTo(document.body);
-
- list = $("<ul/>").appendTo(element).mouseover( function(event) {
- if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
- active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
- $(target(event)).addClass(CLASSES.ACTIVE);
- }
- }).click(function(event) {
- $(target(event)).addClass(CLASSES.ACTIVE);
- select();
- // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
- input.focus();
- return false;
- }).mousedown(function() {
- config.mouseDownOnSelect = true;
- }).mouseup(function() {
- config.mouseDownOnSelect = false;
- });
-
- if( options.width > 0 )
- element.css("width", options.width);
-
- needsInit = false;
- }
-
- function target(event) {
- var element = event.target;
- while(element && element.tagName != "LI")
- element = element.parentNode;
- // more fun with IE, sometimes event.target is empty, just ignore it then
- if(!element)
- return [];
- return element;
- }
-
- function moveSelect(step) {
- listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
- movePosition(step);
- var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
- if(options.scroll) {
- var offset = 0;
- listItems.slice(0, active).each(function() {
- offset += this.offsetHeight;
- });
- if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
- list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
- } else if(offset < list.scrollTop()) {
- list.scrollTop(offset);
- }
- }
- };
-
- function movePosition(step) {
- active += step;
- if (active < 0) {
- active = listItems.size() - 1;
- } else if (active >= listItems.size()) {
- active = 0;
- }
- }
-
- function limitNumberOfItems(available) {
- return options.max && options.max < available
- ? options.max
- : available;
- }
-
- function fillList() {
- list.empty();
- var max = limitNumberOfItems(data.length);
- for (var i=0; i < max; i++) {
- if (!data[i])
- continue;
- var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
- if ( formatted === false )
- continue;
- var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
- $.data(li, "ac_data", data[i]);
- }
- listItems = list.find("li");
- if ( options.selectFirst ) {
- listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
- active = 0;
- }
- // apply bgiframe if available
- if ( $.fn.bgiframe )
- list.bgiframe();
- }
-
- return {
- display: function(d, q) {
- init();
- data = options.filter.call(input, d, options);
- term = q;
- fillList();
- },
- next: function() {
- moveSelect(1);
- },
- prev: function() {
- moveSelect(-1);
- },
- pageUp: function() {
- if (active != 0 && active - 8 < 0) {
- moveSelect( -active );
- } else {
- moveSelect(-8);
- }
- },
- pageDown: function() {
- if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
- moveSelect( listItems.size() - 1 - active );
- } else {
- moveSelect(8);
- }
- },
- hide: function() {
- element && element.hide();
- listItems && listItems.removeClass(CLASSES.ACTIVE);
- active = -1;
- },
- visible : function() {
- return element && element.is(":visible");
- },
- current: function() {
- return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
- },
- show: function() {
- var offset = $(input).offset();
- element.css({
- width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
- top: offset.top + input.offsetHeight,
- left: offset.left
- }).show();
- if(options.scroll) {
- list.scrollTop(0);
- list.css({
- maxHeight: options.scrollHeight,
- overflow: 'auto'
- });
-
- if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
- var listHeight = 0;
- listItems.each(function() {
- listHeight += this.offsetHeight;
- });
- var scrollbarsVisible = listHeight > options.scrollHeight;
- list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
- if (!scrollbarsVisible) {
- // IE doesn't recalculate width when scrollbar disappears
- listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
- }
- }
-
- }
- },
- selected: function() {
- var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
- return selected && selected.length && $.data(selected[0], "ac_data");
- },
- emptyList: function (){
- list && list.empty();
- },
- unbind: function() {
- element && element.remove();
- }
- };
-};
-
-$.Autocompleter.Selection = function(field, start, end) {
- if( field.createTextRange ){
- var selRange = field.createTextRange();
- selRange.collapse(true);
- selRange.moveStart("character", start);
- selRange.moveEnd("character", end);
- selRange.select();
- } else if( field.setSelectionRange ){
- field.setSelectionRange(start, end);
- } else {
- if( field.selectionStart ){
- field.selectionStart = start;
- field.selectionEnd = end;
- }
- }
- field.focus();
-};
-
-})(jQuery);
View
274 src/ui.tokenlist.js
@@ -1,274 +0,0 @@
-/*!
- * jQuery UI Token List @VERSION
- *
- * Copyright (c) 2009 Adaptavist.com
- * Dual licensed under the MIT and GPL licenses.
- */
-/* Depends:
- * ui.core.js
- */
-(function($) {
-
-$.widget('ui.tokenlist', {
-
- _init: function() {
- var self = this, key = $.ui.keyCode;
-
- if (this.element.is(':text')) {
- this.textElem = this.element;
-
- this.textElem
- // Hide the original field
- .hide()
- // Update our list if the original field is changed
- .bind('change.' + this.widgetName, function() {
- self.value(self.textElem.val(), true);
- });
-
- // Generate a list element to replace the original field
- this.element =
- $('<ul/>')
- .insertAfter(this.textElem)
- // Allow the widget to also be accessed via the generated element
- .data(this.widgetName, this);
- }
-
- this.element
- .addClass(this.widgetBaseClass + ' ui-widget ui-widget-content ui-helper-clearfix')
-
- .bind('keydown.' + this.widgetName, function(ev) {
- var focus, disabled = self._getData('disabled');
-
- switch (ev.keyCode) {
- case key.LEFT:
- case key.UP:
- case key.BACKSPACE:
- focus = $(ev.target).closest('li').prev('li');
- break;
- case key.RIGHT:
- case key.DOWN:
- case key.DELETE:
- focus = $(ev.target).closest('li').next('li.'+self.widgetBaseClass+'-item');
- if (!focus.length && !disabled) {
- focus = self.inputElem;
- }
- break;
- case key.HOME:
- case key.PAGE_UP:
- focus = $(ev.target).closest('ul').find('>li:first');
- break;
- case key.END:
- case key.PAGE_DOWN:
- focus = self.inputElem;
- break;
- }
-
- switch (ev.keyCode) {
- case key.DELETE:
- case key.BACKSPACE:
- if (disabled) {
- focus = undefined;
- } else {
- self._removeItem(ev.target);
- }
- break;
- }
-
- if (focus && focus.length) {
- focus[0].focus();
- ev.stopPropagation();
- ev.preventDefault();
- }
- })
-
- // Delete the item if the button is clicked
- .bind('click.' + this.widgetName, function(ev) {
- if (!self._getData('disabled')) {
- if ($(ev.target).is('.'+self.widgetBaseClass+'-remove')) {
- self._removeItem(ev.target);
- }
- if (this === ev.target) {
- self.inputElem[0].focus();
- }
- }
- });
-
- this.inputElem =
- $('<input type="text"/>')
- .bind('keydown.' + this.widgetName, function(ev) {
- if (ev.keyCode === key.LEFT) {
- // If caret is at the far-left of the field, move focus to the last item
- var caret;
- if (this.selectionEnd !== undefined) {
- caret = this.selectionEnd;
- }
- if (caret === 0) {
- $(this).closest('li').prev('li').each(function() { this.focus(); });
- ev.preventDefault();
- }
- }
- ev.stopPropagation();
- })
- .bind('change.' + this.widgetName, function() {
- if (self.add($(this).val()).length) {
- $(this).val('');
- }
- });
-
- // Add the new item input field
- $('<li/>')
- .appendTo(this.element)
- .addClass(this.widgetBaseClass+'-input')
- .append(this.inputElem);
-
- if (this.textElem) {
- this.value(this.textElem.val());
-
- if (this.textElem[0].disabled) {
- this.disable();
- }
- } else {
- this.add(this.items());
- }
- },
-
- _setData: function(key, value) {
- $.widget.prototype._setData.apply(this, arguments);
-
- if (key === 'disabled') {
- this.inputElem[0].disabled = value;
- }
- },
-
- input: function() {
- return $(this.inputElem);
- },
-
- items: function() {
- return this._getData('items');
- },
-
- empty: function() {
- // Remove all existing items
- $('> li.'+this.widgetBaseClass+'-item', this.element).remove();
- this.options.items = [];
- return this;
- },
-
- value: function(newValue, noChange) {
- var value = this._stringify(this.items());
-
- if (arguments.length > 0) {
- var newItems = this._parse(newValue),
- newValue = this._stringify(newItems);
-
- if (newValue !== value) {
- this.empty().add(newItems, noChange);
- value = newValue;
- }
- }
-
- return value;
- },
-
- add: function(newItems, noChange) {
- var items = this.items(),
- unique = !this._getData('duplicates'),
- validate = this._getData('validate'),
- added = [],
- self = this;
-
- if (!$.isArray(newItems)) {
- newItems = [newItems];
- }
-
- $.each(newItems, function(i, item) {
- // Discard duplicate items if duplicates are not allowed
- if (unique && $.inArray(item, items) >= 0) { return; }
-
- // Validate the item
- if (validate) {
- if ($.isArray(validate)) {
- if ($.inArray(item, validate) < 0) { return; }
- } else if ($.isFunction(validate)) {
- if (!validate.apply(self, item)) { return; }
- }
- }
-
- added.push(item);
- items.push(item);
- self._addItemElem(item);
- });
-
- if (added.length && !noChange) {
- this._change();
- }
-
- return added;
- },
-
- _addItemElem: function(token) {
- var input = $('.'+this.widgetBaseClass+'-input', this.element),
- label =
- $('<span/>')
- .addClass(this.widgetBaseClass+'-label')
- .text(token),
- button =
- $('<span>x</span>')
- .addClass(this.widgetBaseClass+'-remove ui-icon ui-icon-close')
- .attr('alt', this._getData('removeTip'));
-
- return $('<li/>')
- .insertBefore(input)
- .addClass(this.widgetBaseClass+'-item ui-state-default ui-corner-all')
- .attr('tabindex','-1')
- .append(label)
- .append(button)
-
- // Apply/remove style for a focused item
- .bind('focus.' + this.widgetName, function() { $(this).addClass('ui-state-focus'); })
- .bind('blur.' + this.widgetName, function() { $(this).removeClass('ui-state-focus'); });
-
- // Fix focusing in IE when clicking within the item
-// .bind('click', function() { this.focus(); });
- },
-
- _removeItem: function(target) {
- var item = $(target).closest('li');
- this.items().splice($(item).prevAll('li').length, 1);
- item.remove();
- this._change();
- },
-
- _parse: function(value) {
- return (value || '').split(this._getData('split'));
- },
-
- _stringify: function(items) {
- return items.join(this._getData('join'));
- },
-
- _change: function() {
- if (this.textElem) {
- this.textElem.val(this._stringify(this.items()));
- }
- this.element.trigger('change');
- }
-});
-
-$.extend($.ui.tokenlist, {
- getter: "add input items value",
- version: "@VERSION",
-
- defaults: {
- split: /\s*,\s*/,
- join: ', ',
- removeTip: "Remove Item",
- duplicates: false,
- items: [],
- validate: false // Maybe false, an array of allowed values, or a validation function
- }
-});
-
-})(jQuery);
-

0 comments on commit 3fd85bc

Please sign in to comment.