muck-engine 0.2.15 → 0.2.16
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/app/helpers/muck_engine_helper.rb +7 -0
- data/muck-engine.gemspec +13 -2
- data/public/javascripts/jquery/colorpicker.js +450 -0
- data/public/javascripts/jquery/jquery.autocomplete.js.readme +6 -0
- data/public/javascripts/jquery/jquery.autocomplete.min.js +15 -0
- data/public/javascripts/jquery/jquery.autocomplete.pack.js +767 -0
- data/public/javascripts/jquery/jquery.metadata.min.js +13 -0
- data/public/javascripts/jquery/jquery.queryString.js +33 -0
- data/public/javascripts/jquery/jquery.swapimage.js +66 -0
- data/public/javascripts/jquery/jquery.swapimage.min.js +11 -0
- data/public/javascripts/tree.js +107 -0
- data/public/stylesheets/jquery/jquery.autocomplete.css +15 -0
- metadata +12 -2
@@ -0,0 +1,6 @@
|
|
1
|
+
NOTE: the jquery.autocomplete.pack.js file is modified from the original to work with luvfoo. Specifically line
|
2
|
+
314 was changed from
|
3
|
+
if ( data && data.length && hasFocus ) {
|
4
|
+
to
|
5
|
+
if ( data && data.length ) {
|
6
|
+
For some reason the hasFocus value was always 0 which prevented the autocomplete from ever showing up.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* Autocomplete - jQuery plugin 1.0.2
|
3
|
+
*
|
4
|
+
* Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
|
5
|
+
*
|
6
|
+
* Dual licensed under the MIT and GPL licenses:
|
7
|
+
* http://www.opensource.org/licenses/mit-license.php
|
8
|
+
* http://www.gnu.org/licenses/gpl.html
|
9
|
+
*
|
10
|
+
* Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
|
11
|
+
*
|
12
|
+
*/;(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);options.highlight=options.highlight||function(value){return value;};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};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;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){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;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){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("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&¤tValue==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];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$.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){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else
|
13
|
+
$input.val("");}});}if(wasVisible)$.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);if(data&&data.length){success(term,data);}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({mode:"abort",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{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};$.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;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];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(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}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(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
|
14
|
+
if(data[q]){return data[q];}else
|
15
|
+
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;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();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;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;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;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){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);
|
@@ -0,0 +1,767 @@
|
|
1
|
+
/**********************************************************************************************
|
2
|
+
* NOTE: this version is modified from the original to work with luvfoo. Specifically line
|
3
|
+
* 314 was changed from
|
4
|
+
* if ( data && data.length && hasFocus ) {
|
5
|
+
* to
|
6
|
+
* if ( data && data.length ) {
|
7
|
+
* For some reason the hasFocus value was always 0 which prevented the autocomplete from ever showing up.
|
8
|
+
**********************************************************************************************
|
9
|
+
*
|
10
|
+
* Autocomplete - jQuery plugin 1.0.2
|
11
|
+
*
|
12
|
+
* Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
|
13
|
+
*
|
14
|
+
* Dual licensed under the MIT and GPL licenses:
|
15
|
+
* http://www.opensource.org/licenses/mit-license.php
|
16
|
+
* http://www.gnu.org/licenses/gpl.html
|
17
|
+
*
|
18
|
+
* Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
|
19
|
+
*
|
20
|
+
*/
|
21
|
+
|
22
|
+
;(function($) {
|
23
|
+
|
24
|
+
$.fn.extend({
|
25
|
+
autocomplete: function(urlOrData, options) {
|
26
|
+
var isUrl = typeof urlOrData == "string";
|
27
|
+
options = $.extend({}, $.Autocompleter.defaults, {
|
28
|
+
url: isUrl ? urlOrData : null,
|
29
|
+
data: isUrl ? null : urlOrData,
|
30
|
+
delay: isUrl ? $.Autocompleter.defaults.delay : 10,
|
31
|
+
max: options && !options.scroll ? 10 : 150
|
32
|
+
}, options);
|
33
|
+
|
34
|
+
// if highlight is set to false, replace it with a do-nothing function
|
35
|
+
options.highlight = options.highlight || function(value) { return value; };
|
36
|
+
|
37
|
+
// if the formatMatch option is not specified, then use formatItem for backwards compatibility
|
38
|
+
options.formatMatch = options.formatMatch || options.formatItem;
|
39
|
+
|
40
|
+
return this.each(function() {
|
41
|
+
new $.Autocompleter(this, options);
|
42
|
+
});
|
43
|
+
},
|
44
|
+
result: function(handler) {
|
45
|
+
return this.bind("result", handler);
|
46
|
+
},
|
47
|
+
search: function(handler) {
|
48
|
+
return this.trigger("search", [handler]);
|
49
|
+
},
|
50
|
+
flushCache: function() {
|
51
|
+
return this.trigger("flushCache");
|
52
|
+
},
|
53
|
+
setOptions: function(options){
|
54
|
+
return this.trigger("setOptions", [options]);
|
55
|
+
},
|
56
|
+
unautocomplete: function() {
|
57
|
+
return this.trigger("unautocomplete");
|
58
|
+
}
|
59
|
+
});
|
60
|
+
|
61
|
+
$.Autocompleter = function(input, options) {
|
62
|
+
|
63
|
+
var KEY = {
|
64
|
+
UP: 38,
|
65
|
+
DOWN: 40,
|
66
|
+
DEL: 46,
|
67
|
+
TAB: 9,
|
68
|
+
RETURN: 13,
|
69
|
+
ESC: 27,
|
70
|
+
COMMA: 188,
|
71
|
+
PAGEUP: 33,
|
72
|
+
PAGEDOWN: 34,
|
73
|
+
BACKSPACE: 8
|
74
|
+
};
|
75
|
+
|
76
|
+
// Create $ object for input element
|
77
|
+
var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
|
78
|
+
|
79
|
+
var timeout;
|
80
|
+
var previousValue = "";
|
81
|
+
var cache = $.Autocompleter.Cache(options);
|
82
|
+
var hasFocus = 0;
|
83
|
+
var lastKeyPressCode;
|
84
|
+
var config = {
|
85
|
+
mouseDownOnSelect: false
|
86
|
+
};
|
87
|
+
var select = $.Autocompleter.Select(options, input, selectCurrent, config);
|
88
|
+
|
89
|
+
var blockSubmit;
|
90
|
+
|
91
|
+
// prevent form submit in opera when selecting with return key
|
92
|
+
$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
|
93
|
+
if (blockSubmit) {
|
94
|
+
blockSubmit = false;
|
95
|
+
return false;
|
96
|
+
}
|
97
|
+
});
|
98
|
+
|
99
|
+
// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
|
100
|
+
$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
|
101
|
+
// track last key pressed
|
102
|
+
lastKeyPressCode = event.keyCode;
|
103
|
+
switch(event.keyCode) {
|
104
|
+
|
105
|
+
case KEY.UP:
|
106
|
+
event.preventDefault();
|
107
|
+
if ( select.visible() ) {
|
108
|
+
select.prev();
|
109
|
+
} else {
|
110
|
+
onChange(0, true);
|
111
|
+
}
|
112
|
+
break;
|
113
|
+
|
114
|
+
case KEY.DOWN:
|
115
|
+
event.preventDefault();
|
116
|
+
if ( select.visible() ) {
|
117
|
+
select.next();
|
118
|
+
} else {
|
119
|
+
onChange(0, true);
|
120
|
+
}
|
121
|
+
break;
|
122
|
+
|
123
|
+
case KEY.PAGEUP:
|
124
|
+
event.preventDefault();
|
125
|
+
if ( select.visible() ) {
|
126
|
+
select.pageUp();
|
127
|
+
} else {
|
128
|
+
onChange(0, true);
|
129
|
+
}
|
130
|
+
break;
|
131
|
+
|
132
|
+
case KEY.PAGEDOWN:
|
133
|
+
event.preventDefault();
|
134
|
+
if ( select.visible() ) {
|
135
|
+
select.pageDown();
|
136
|
+
} else {
|
137
|
+
onChange(0, true);
|
138
|
+
}
|
139
|
+
break;
|
140
|
+
|
141
|
+
// matches also semicolon
|
142
|
+
case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
|
143
|
+
case KEY.TAB:
|
144
|
+
case KEY.RETURN:
|
145
|
+
if( selectCurrent() ) {
|
146
|
+
// stop default to prevent a form submit, Opera needs special handling
|
147
|
+
event.preventDefault();
|
148
|
+
blockSubmit = true;
|
149
|
+
return false;
|
150
|
+
}
|
151
|
+
break;
|
152
|
+
|
153
|
+
case KEY.ESC:
|
154
|
+
select.hide();
|
155
|
+
break;
|
156
|
+
|
157
|
+
default:
|
158
|
+
clearTimeout(timeout);
|
159
|
+
timeout = setTimeout(onChange, options.delay);
|
160
|
+
break;
|
161
|
+
}
|
162
|
+
}).focus(function(){
|
163
|
+
// track whether the field has focus, we shouldn't process any
|
164
|
+
// results if the field no longer has focus
|
165
|
+
hasFocus++;
|
166
|
+
}).blur(function() {
|
167
|
+
hasFocus = 0;
|
168
|
+
if (!config.mouseDownOnSelect) {
|
169
|
+
hideResults();
|
170
|
+
}
|
171
|
+
}).click(function() {
|
172
|
+
// show select when clicking in a focused field
|
173
|
+
if ( hasFocus++ > 1 && !select.visible() ) {
|
174
|
+
onChange(0, true);
|
175
|
+
}
|
176
|
+
}).bind("search", function() {
|
177
|
+
// TODO why not just specifying both arguments?
|
178
|
+
var fn = (arguments.length > 1) ? arguments[1] : null;
|
179
|
+
function findValueCallback(q, data) {
|
180
|
+
var result;
|
181
|
+
if( data && data.length ) {
|
182
|
+
for (var i=0; i < data.length; i++) {
|
183
|
+
if( data[i].result.toLowerCase() == q.toLowerCase() ) {
|
184
|
+
result = data[i];
|
185
|
+
break;
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
if( typeof fn == "function" ) fn(result);
|
190
|
+
else $input.trigger("result", result && [result.data, result.value]);
|
191
|
+
}
|
192
|
+
$.each(trimWords($input.val()), function(i, value) {
|
193
|
+
request(value, findValueCallback, findValueCallback);
|
194
|
+
});
|
195
|
+
}).bind("flushCache", function() {
|
196
|
+
cache.flush();
|
197
|
+
}).bind("setOptions", function() {
|
198
|
+
$.extend(options, arguments[1]);
|
199
|
+
// if we've updated the data, repopulate
|
200
|
+
if ( "data" in arguments[1] )
|
201
|
+
cache.populate();
|
202
|
+
}).bind("unautocomplete", function() {
|
203
|
+
select.unbind();
|
204
|
+
$input.unbind();
|
205
|
+
$(input.form).unbind(".autocomplete");
|
206
|
+
});
|
207
|
+
|
208
|
+
|
209
|
+
function selectCurrent() {
|
210
|
+
var selected = select.selected();
|
211
|
+
if( !selected )
|
212
|
+
return false;
|
213
|
+
|
214
|
+
var v = selected.result;
|
215
|
+
previousValue = v;
|
216
|
+
|
217
|
+
if ( options.multiple ) {
|
218
|
+
var words = trimWords($input.val());
|
219
|
+
if ( words.length > 1 ) {
|
220
|
+
v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
|
221
|
+
}
|
222
|
+
v += options.multipleSeparator;
|
223
|
+
}
|
224
|
+
|
225
|
+
$input.val(v);
|
226
|
+
hideResultsNow();
|
227
|
+
$input.trigger("result", [selected.data, selected.value]);
|
228
|
+
return true;
|
229
|
+
}
|
230
|
+
|
231
|
+
function onChange(crap, skipPrevCheck) {
|
232
|
+
if( lastKeyPressCode == KEY.DEL ) {
|
233
|
+
select.hide();
|
234
|
+
return;
|
235
|
+
}
|
236
|
+
|
237
|
+
var currentValue = $input.val();
|
238
|
+
|
239
|
+
if ( !skipPrevCheck && currentValue == previousValue )
|
240
|
+
return;
|
241
|
+
|
242
|
+
previousValue = currentValue;
|
243
|
+
|
244
|
+
currentValue = lastWord(currentValue);
|
245
|
+
if ( currentValue.length >= options.minChars) {
|
246
|
+
$input.addClass(options.loadingClass);
|
247
|
+
if (!options.matchCase)
|
248
|
+
currentValue = currentValue.toLowerCase();
|
249
|
+
request(currentValue, receiveData, hideResultsNow);
|
250
|
+
} else {
|
251
|
+
stopLoading();
|
252
|
+
select.hide();
|
253
|
+
}
|
254
|
+
};
|
255
|
+
|
256
|
+
function trimWords(value) {
|
257
|
+
if ( !value ) {
|
258
|
+
return [""];
|
259
|
+
}
|
260
|
+
var words = value.split( options.multipleSeparator );
|
261
|
+
var result = [];
|
262
|
+
$.each(words, function(i, value) {
|
263
|
+
if ( $.trim(value) )
|
264
|
+
result[i] = $.trim(value);
|
265
|
+
});
|
266
|
+
return result;
|
267
|
+
}
|
268
|
+
|
269
|
+
function lastWord(value) {
|
270
|
+
if ( !options.multiple )
|
271
|
+
return value;
|
272
|
+
var words = trimWords(value);
|
273
|
+
return words[words.length - 1];
|
274
|
+
}
|
275
|
+
|
276
|
+
// fills in the input box w/the first match (assumed to be the best match)
|
277
|
+
// q: the term entered
|
278
|
+
// sValue: the first matching result
|
279
|
+
function autoFill(q, sValue){
|
280
|
+
// autofill in the complete box w/the first match as long as the user hasn't entered in more data
|
281
|
+
// if the last user key pressed was backspace, don't autofill
|
282
|
+
if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
|
283
|
+
// fill in the value (keep the case the user has typed)
|
284
|
+
$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
|
285
|
+
// select the portion of the value not typed by the user (so the next character will erase)
|
286
|
+
$.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
|
287
|
+
}
|
288
|
+
};
|
289
|
+
|
290
|
+
function hideResults() {
|
291
|
+
clearTimeout(timeout);
|
292
|
+
timeout = setTimeout(hideResultsNow, 200);
|
293
|
+
};
|
294
|
+
|
295
|
+
function hideResultsNow() {
|
296
|
+
var wasVisible = select.visible();
|
297
|
+
select.hide();
|
298
|
+
clearTimeout(timeout);
|
299
|
+
stopLoading();
|
300
|
+
if (options.mustMatch) {
|
301
|
+
// call search and run callback
|
302
|
+
$input.search(
|
303
|
+
function (result){
|
304
|
+
// if no value found, clear the input box
|
305
|
+
if( !result ) {
|
306
|
+
if (options.multiple) {
|
307
|
+
var words = trimWords($input.val()).slice(0, -1);
|
308
|
+
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
|
309
|
+
}
|
310
|
+
else
|
311
|
+
$input.val( "" );
|
312
|
+
}
|
313
|
+
}
|
314
|
+
);
|
315
|
+
}
|
316
|
+
if (wasVisible)
|
317
|
+
// position cursor at end of input field
|
318
|
+
$.Autocompleter.Selection(input, input.value.length, input.value.length);
|
319
|
+
};
|
320
|
+
|
321
|
+
function receiveData(q, data) {
|
322
|
+
if ( data && data.length ) {
|
323
|
+
stopLoading();
|
324
|
+
select.display(data, q);
|
325
|
+
autoFill(q, data[0].value);
|
326
|
+
select.show();
|
327
|
+
} else {
|
328
|
+
hideResultsNow();
|
329
|
+
}
|
330
|
+
};
|
331
|
+
|
332
|
+
function request(term, success, failure) {
|
333
|
+
if (!options.matchCase)
|
334
|
+
term = term.toLowerCase();
|
335
|
+
var data = cache.load(term);
|
336
|
+
// recieve the cached data
|
337
|
+
if (data && data.length) {
|
338
|
+
success(term, data);
|
339
|
+
// if an AJAX url has been supplied, try loading the data now
|
340
|
+
} else if( (typeof options.url == "string") && (options.url.length > 0) ){
|
341
|
+
|
342
|
+
var extraParams = {
|
343
|
+
timestamp: +new Date()
|
344
|
+
};
|
345
|
+
$.each(options.extraParams, function(key, param) {
|
346
|
+
extraParams[key] = typeof param == "function" ? param() : param;
|
347
|
+
});
|
348
|
+
|
349
|
+
$.ajax({
|
350
|
+
// try to leverage ajaxQueue plugin to abort previous requests
|
351
|
+
mode: "abort",
|
352
|
+
// limit abortion to this input
|
353
|
+
port: "autocomplete" + input.name,
|
354
|
+
dataType: options.dataType,
|
355
|
+
url: options.url,
|
356
|
+
data: $.extend({
|
357
|
+
q: lastWord(term),
|
358
|
+
limit: options.max
|
359
|
+
}, extraParams),
|
360
|
+
success: function(data) {
|
361
|
+
var parsed = options.parse && options.parse(data) || parse(data);
|
362
|
+
cache.add(term, parsed);
|
363
|
+
success(term, parsed);
|
364
|
+
}
|
365
|
+
});
|
366
|
+
} else {
|
367
|
+
// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
|
368
|
+
select.emptyList();
|
369
|
+
failure(term);
|
370
|
+
}
|
371
|
+
};
|
372
|
+
|
373
|
+
function parse(data) {
|
374
|
+
var parsed = [];
|
375
|
+
var rows = data.split("\n");
|
376
|
+
for (var i=0; i < rows.length; i++) {
|
377
|
+
var row = $.trim(rows[i]);
|
378
|
+
if (row) {
|
379
|
+
row = row.split("|");
|
380
|
+
parsed[parsed.length] = {
|
381
|
+
data: row,
|
382
|
+
value: row[0],
|
383
|
+
result: options.formatResult && options.formatResult(row, row[0]) || row[0]
|
384
|
+
};
|
385
|
+
}
|
386
|
+
}
|
387
|
+
return parsed;
|
388
|
+
};
|
389
|
+
|
390
|
+
function stopLoading() {
|
391
|
+
$input.removeClass(options.loadingClass);
|
392
|
+
};
|
393
|
+
|
394
|
+
};
|
395
|
+
|
396
|
+
$.Autocompleter.defaults = {
|
397
|
+
inputClass: "ac_input",
|
398
|
+
resultsClass: "ac_results",
|
399
|
+
loadingClass: "ac_loading",
|
400
|
+
minChars: 1,
|
401
|
+
delay: 400,
|
402
|
+
matchCase: false,
|
403
|
+
matchSubset: true,
|
404
|
+
matchContains: false,
|
405
|
+
cacheLength: 10,
|
406
|
+
max: 100,
|
407
|
+
mustMatch: false,
|
408
|
+
extraParams: {},
|
409
|
+
selectFirst: true,
|
410
|
+
formatItem: function(row) { return row[0]; },
|
411
|
+
formatMatch: null,
|
412
|
+
autoFill: false,
|
413
|
+
width: 0,
|
414
|
+
multiple: false,
|
415
|
+
multipleSeparator: ", ",
|
416
|
+
highlight: function(value, term) {
|
417
|
+
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
|
418
|
+
},
|
419
|
+
scroll: true,
|
420
|
+
scrollHeight: 180
|
421
|
+
};
|
422
|
+
|
423
|
+
$.Autocompleter.Cache = function(options) {
|
424
|
+
|
425
|
+
var data = {};
|
426
|
+
var length = 0;
|
427
|
+
|
428
|
+
function matchSubset(s, sub) {
|
429
|
+
if (!options.matchCase)
|
430
|
+
s = s.toLowerCase();
|
431
|
+
var i = s.indexOf(sub);
|
432
|
+
if (i == -1) return false;
|
433
|
+
return i == 0 || options.matchContains;
|
434
|
+
};
|
435
|
+
|
436
|
+
function add(q, value) {
|
437
|
+
if (length > options.cacheLength){
|
438
|
+
flush();
|
439
|
+
}
|
440
|
+
if (!data[q]){
|
441
|
+
length++;
|
442
|
+
}
|
443
|
+
data[q] = value;
|
444
|
+
}
|
445
|
+
|
446
|
+
function populate(){
|
447
|
+
if( !options.data ) return false;
|
448
|
+
// track the matches
|
449
|
+
var stMatchSets = {},
|
450
|
+
nullData = 0;
|
451
|
+
|
452
|
+
// no url was specified, we need to adjust the cache length to make sure it fits the local data store
|
453
|
+
if( !options.url ) options.cacheLength = 1;
|
454
|
+
|
455
|
+
// track all options for minChars = 0
|
456
|
+
stMatchSets[""] = [];
|
457
|
+
|
458
|
+
// loop through the array and create a lookup structure
|
459
|
+
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
|
460
|
+
var rawValue = options.data[i];
|
461
|
+
// if rawValue is a string, make an array otherwise just reference the array
|
462
|
+
rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
|
463
|
+
|
464
|
+
var value = options.formatMatch(rawValue, i+1, options.data.length);
|
465
|
+
if ( value === false )
|
466
|
+
continue;
|
467
|
+
|
468
|
+
var firstChar = value.charAt(0).toLowerCase();
|
469
|
+
// if no lookup array for this character exists, look it up now
|
470
|
+
if( !stMatchSets[firstChar] )
|
471
|
+
stMatchSets[firstChar] = [];
|
472
|
+
|
473
|
+
// if the match is a string
|
474
|
+
var row = {
|
475
|
+
value: value,
|
476
|
+
data: rawValue,
|
477
|
+
result: options.formatResult && options.formatResult(rawValue) || value
|
478
|
+
};
|
479
|
+
|
480
|
+
// push the current match into the set list
|
481
|
+
stMatchSets[firstChar].push(row);
|
482
|
+
|
483
|
+
// keep track of minChars zero items
|
484
|
+
if ( nullData++ < options.max ) {
|
485
|
+
stMatchSets[""].push(row);
|
486
|
+
}
|
487
|
+
};
|
488
|
+
|
489
|
+
// add the data items to the cache
|
490
|
+
$.each(stMatchSets, function(i, value) {
|
491
|
+
// increase the cache size
|
492
|
+
options.cacheLength++;
|
493
|
+
// add to the cache
|
494
|
+
add(i, value);
|
495
|
+
});
|
496
|
+
}
|
497
|
+
|
498
|
+
// populate any existing data
|
499
|
+
setTimeout(populate, 25);
|
500
|
+
|
501
|
+
function flush(){
|
502
|
+
data = {};
|
503
|
+
length = 0;
|
504
|
+
}
|
505
|
+
|
506
|
+
return {
|
507
|
+
flush: flush,
|
508
|
+
add: add,
|
509
|
+
populate: populate,
|
510
|
+
load: function(q) {
|
511
|
+
if (!options.cacheLength || !length)
|
512
|
+
return null;
|
513
|
+
/*
|
514
|
+
* if dealing w/local data and matchContains than we must make sure
|
515
|
+
* to loop through all the data collections looking for matches
|
516
|
+
*/
|
517
|
+
if( !options.url && options.matchContains ){
|
518
|
+
// track all matches
|
519
|
+
var csub = [];
|
520
|
+
// loop through all the data grids for matches
|
521
|
+
for( var k in data ){
|
522
|
+
// don't search through the stMatchSets[""] (minChars: 0) cache
|
523
|
+
// this prevents duplicates
|
524
|
+
if( k.length > 0 ){
|
525
|
+
var c = data[k];
|
526
|
+
$.each(c, function(i, x) {
|
527
|
+
// if we've got a match, add it to the array
|
528
|
+
if (matchSubset(x.value, q)) {
|
529
|
+
csub.push(x);
|
530
|
+
}
|
531
|
+
});
|
532
|
+
}
|
533
|
+
}
|
534
|
+
return csub;
|
535
|
+
} else
|
536
|
+
// if the exact item exists, use it
|
537
|
+
if (data[q]){
|
538
|
+
return data[q];
|
539
|
+
} else
|
540
|
+
if (options.matchSubset) {
|
541
|
+
for (var i = q.length - 1; i >= options.minChars; i--) {
|
542
|
+
var c = data[q.substr(0, i)];
|
543
|
+
if (c) {
|
544
|
+
var csub = [];
|
545
|
+
$.each(c, function(i, x) {
|
546
|
+
if (matchSubset(x.value, q)) {
|
547
|
+
csub[csub.length] = x;
|
548
|
+
}
|
549
|
+
});
|
550
|
+
return csub;
|
551
|
+
}
|
552
|
+
}
|
553
|
+
}
|
554
|
+
return null;
|
555
|
+
}
|
556
|
+
};
|
557
|
+
};
|
558
|
+
|
559
|
+
$.Autocompleter.Select = function (options, input, select, config) {
|
560
|
+
var CLASSES = {
|
561
|
+
ACTIVE: "ac_over"
|
562
|
+
};
|
563
|
+
|
564
|
+
var listItems,
|
565
|
+
active = -1,
|
566
|
+
data,
|
567
|
+
term = "",
|
568
|
+
needsInit = true,
|
569
|
+
element,
|
570
|
+
list;
|
571
|
+
|
572
|
+
// Create results
|
573
|
+
function init() {
|
574
|
+
if (!needsInit)
|
575
|
+
return;
|
576
|
+
element = $("<div/>")
|
577
|
+
.hide()
|
578
|
+
.addClass(options.resultsClass)
|
579
|
+
.css("position", "absolute")
|
580
|
+
.appendTo(document.body);
|
581
|
+
|
582
|
+
list = $("<ul/>").appendTo(element).mouseover( function(event) {
|
583
|
+
if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
|
584
|
+
active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
|
585
|
+
$(target(event)).addClass(CLASSES.ACTIVE);
|
586
|
+
}
|
587
|
+
}).click(function(event) {
|
588
|
+
$(target(event)).addClass(CLASSES.ACTIVE);
|
589
|
+
select();
|
590
|
+
// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
|
591
|
+
input.focus();
|
592
|
+
return false;
|
593
|
+
}).mousedown(function() {
|
594
|
+
config.mouseDownOnSelect = true;
|
595
|
+
}).mouseup(function() {
|
596
|
+
config.mouseDownOnSelect = false;
|
597
|
+
});
|
598
|
+
|
599
|
+
if( options.width > 0 )
|
600
|
+
element.css("width", options.width);
|
601
|
+
|
602
|
+
needsInit = false;
|
603
|
+
}
|
604
|
+
|
605
|
+
function target(event) {
|
606
|
+
var element = event.target;
|
607
|
+
while(element && element.tagName != "LI")
|
608
|
+
element = element.parentNode;
|
609
|
+
// more fun with IE, sometimes event.target is empty, just ignore it then
|
610
|
+
if(!element)
|
611
|
+
return [];
|
612
|
+
return element;
|
613
|
+
}
|
614
|
+
|
615
|
+
function moveSelect(step) {
|
616
|
+
listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
|
617
|
+
movePosition(step);
|
618
|
+
var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
|
619
|
+
if(options.scroll) {
|
620
|
+
var offset = 0;
|
621
|
+
listItems.slice(0, active).each(function() {
|
622
|
+
offset += this.offsetHeight;
|
623
|
+
});
|
624
|
+
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
|
625
|
+
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
|
626
|
+
} else if(offset < list.scrollTop()) {
|
627
|
+
list.scrollTop(offset);
|
628
|
+
}
|
629
|
+
}
|
630
|
+
};
|
631
|
+
|
632
|
+
function movePosition(step) {
|
633
|
+
active += step;
|
634
|
+
if (active < 0) {
|
635
|
+
active = listItems.size() - 1;
|
636
|
+
} else if (active >= listItems.size()) {
|
637
|
+
active = 0;
|
638
|
+
}
|
639
|
+
}
|
640
|
+
|
641
|
+
function limitNumberOfItems(available) {
|
642
|
+
return options.max && options.max < available
|
643
|
+
? options.max
|
644
|
+
: available;
|
645
|
+
}
|
646
|
+
|
647
|
+
function fillList() {
|
648
|
+
list.empty();
|
649
|
+
var max = limitNumberOfItems(data.length);
|
650
|
+
for (var i=0; i < max; i++) {
|
651
|
+
if (!data[i])
|
652
|
+
continue;
|
653
|
+
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
|
654
|
+
if ( formatted === false )
|
655
|
+
continue;
|
656
|
+
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
|
657
|
+
$.data(li, "ac_data", data[i]);
|
658
|
+
}
|
659
|
+
listItems = list.find("li");
|
660
|
+
if ( options.selectFirst ) {
|
661
|
+
listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
|
662
|
+
active = 0;
|
663
|
+
}
|
664
|
+
// apply bgiframe if available
|
665
|
+
if ( $.fn.bgiframe )
|
666
|
+
list.bgiframe();
|
667
|
+
}
|
668
|
+
|
669
|
+
return {
|
670
|
+
display: function(d, q) {
|
671
|
+
init();
|
672
|
+
data = d;
|
673
|
+
term = q;
|
674
|
+
fillList();
|
675
|
+
},
|
676
|
+
next: function() {
|
677
|
+
moveSelect(1);
|
678
|
+
},
|
679
|
+
prev: function() {
|
680
|
+
moveSelect(-1);
|
681
|
+
},
|
682
|
+
pageUp: function() {
|
683
|
+
if (active != 0 && active - 8 < 0) {
|
684
|
+
moveSelect( -active );
|
685
|
+
} else {
|
686
|
+
moveSelect(-8);
|
687
|
+
}
|
688
|
+
},
|
689
|
+
pageDown: function() {
|
690
|
+
if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
|
691
|
+
moveSelect( listItems.size() - 1 - active );
|
692
|
+
} else {
|
693
|
+
moveSelect(8);
|
694
|
+
}
|
695
|
+
},
|
696
|
+
hide: function() {
|
697
|
+
element && element.hide();
|
698
|
+
listItems && listItems.removeClass(CLASSES.ACTIVE);
|
699
|
+
active = -1;
|
700
|
+
},
|
701
|
+
visible : function() {
|
702
|
+
return element && element.is(":visible");
|
703
|
+
},
|
704
|
+
current: function() {
|
705
|
+
return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
|
706
|
+
},
|
707
|
+
show: function() {
|
708
|
+
var offset = $(input).offset();
|
709
|
+
element.css({
|
710
|
+
width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
|
711
|
+
top: offset.top + input.offsetHeight,
|
712
|
+
left: offset.left
|
713
|
+
}).show();
|
714
|
+
if(options.scroll) {
|
715
|
+
list.scrollTop(0);
|
716
|
+
list.css({
|
717
|
+
maxHeight: options.scrollHeight,
|
718
|
+
overflow: 'auto'
|
719
|
+
});
|
720
|
+
|
721
|
+
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
|
722
|
+
var listHeight = 0;
|
723
|
+
listItems.each(function() {
|
724
|
+
listHeight += this.offsetHeight;
|
725
|
+
});
|
726
|
+
var scrollbarsVisible = listHeight > options.scrollHeight;
|
727
|
+
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
|
728
|
+
if (!scrollbarsVisible) {
|
729
|
+
// IE doesn't recalculate width when scrollbar disappears
|
730
|
+
listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
|
731
|
+
}
|
732
|
+
}
|
733
|
+
|
734
|
+
}
|
735
|
+
},
|
736
|
+
selected: function() {
|
737
|
+
var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
|
738
|
+
return selected && selected.length && $.data(selected[0], "ac_data");
|
739
|
+
},
|
740
|
+
emptyList: function (){
|
741
|
+
list && list.empty();
|
742
|
+
},
|
743
|
+
unbind: function() {
|
744
|
+
element && element.remove();
|
745
|
+
}
|
746
|
+
};
|
747
|
+
};
|
748
|
+
|
749
|
+
$.Autocompleter.Selection = function(field, start, end) {
|
750
|
+
if( field.createTextRange ){
|
751
|
+
var selRange = field.createTextRange();
|
752
|
+
selRange.collapse(true);
|
753
|
+
selRange.moveStart("character", start);
|
754
|
+
selRange.moveEnd("character", end);
|
755
|
+
selRange.select();
|
756
|
+
} else if( field.setSelectionRange ){
|
757
|
+
field.setSelectionRange(start, end);
|
758
|
+
} else {
|
759
|
+
if( field.selectionStart ){
|
760
|
+
field.selectionStart = start;
|
761
|
+
field.selectionEnd = end;
|
762
|
+
}
|
763
|
+
}
|
764
|
+
field.focus();
|
765
|
+
};
|
766
|
+
|
767
|
+
})(jQuery);
|