diff options
Diffstat (limited to 'view/js/autocomplete.js')
-rw-r--r-- | view/js/autocomplete.js | 132 |
1 files changed, 119 insertions, 13 deletions
diff --git a/view/js/autocomplete.js b/view/js/autocomplete.js index 7c3145769..40a9cd4c8 100644 --- a/view/js/autocomplete.js +++ b/view/js/autocomplete.js @@ -3,13 +3,32 @@ * * require jQuery, jquery.textcomplete */ -function mysearch(term, callback, backend_url) { +function contact_search(term, callback, backend_url, type, extra_channels) { + // Check if there is a cached result that contains the same information we would get with a full server-side search + + var bt = backend_url+type; + if(!(bt in contact_search.cache)) contact_search.cache[bt] = {}; + + var lterm = term.toLowerCase(); // Ignore case + for(t in contact_search.cache[bt]) { + if(lterm.indexOf(t) >= 0) { // A more broad search has been performed already, so use those results + // Filter old results locally + var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || x.nick.toLowerCase().indexOf(lterm) >= 0); }); + matching.unshift({taggable:false, text: term, replace: term}); + callback(matching); + return; + } + } + var postdata = { start:0, count:100, search:term, - type:'c', + type:type, } + + if(typeof extra_channels !== 'undefined' && extra_channels) + postdata['extra_channels[]'] = extra_channels; $.ajax({ type:'POST', @@ -17,33 +36,70 @@ function mysearch(term, callback, backend_url) { data: postdata, dataType: 'json', success:function(data){ - callback(data.items); + // Cache results if we got them all (more information would not improve results) + // data.count represents the maximum number of items + if(data.items.length -1 < data.count) { + contact_search.cache[bt][lterm] = data.items; + } + var items = data.items.slice(0); + items.unshift({taggable:false, text: term, replace: term}); + callback(items); }, }).fail(function () {callback([]); }); // Callback must be invoked even if something went wrong. } +contact_search.cache = {}; + -function format(item) { - return "<div class='{0}'><img src='{1}'>{2} ({3})</div>".format(item.taggable, item.photo, item.name, ((item.label) ? item.nick + ' ' + item.label : item.nick) ) +function contact_format(item) { + // Show contact information if not explicitly told to show something else + if(typeof item.text === 'undefined') { + var desc = ((item.label) ? item.nick + ' ' + item.label : item.nick) + if(desc) desc = ' ('+desc+')'; + return "<div class='{0}' title='{4}'><img src='{1}'>{2}{3}</div>".format(item.taggable, item.photo, item.name, desc, item.link) + } + else + return "<div>"+item.text+"</div>" } -function replace(item) { +function editor_replace(item) { + if(typeof item.replace !== 'undefined') { + return '$1$2'+item.replace; + } + // $2 ensures that prefix (@,@!) is preserved - return '$1$2'+item.nick.replace(' ','') + '+' + item.id; + var id = item.id; + // 16 chars of hash should be enough. Full hash could be used if it can be done in a visually appealing way. + // 16 chars is also the minimum length in the backend (otherwise it's interpreted as a local id). + if(id.length > 16) + id = item.id.substring(0,16); + return '$1$2'+item.nick.replace(' ','') + '+' + id; +} + +function basic_replace(item) { + if(typeof item.replace !== 'undefined') + return '$1'+item.replace; + + return '$1'+item.name+' '; +} + +function submit_form(e) { + $(e).parents('form').submit(); } /** - * jQuery plugin 'contact_autocomplete' + * jQuery plugin 'editor_autocomplete' */ (function( $ ){ - $.fn.contact_autocomplete = function(backend_url) { + $.fn.editor_autocomplete = function(backend_url, extra_channels) { + if (typeof extra_channels === 'undefined') extra_channels = false; // Autocomplete contacts contacts = { match: /(^|\s)(@\!*)([^ \n]+)$/, index: 3, - search: function(term, callback) { mysearch(term, callback, backend_url); }, - replace: replace, - template: format, + search: function(term, callback) { contact_search(term, callback, backend_url, 'c', extra_channels); }, + replace: editor_replace, + template: contact_format, } smilies = { @@ -53,6 +109,56 @@ function replace(item) { template: function(item) { return item['icon'] + item['text'] }, replace: function(item) { return "$1"+item['text'] + ' '; }, } - this.textcomplete([contacts,smilies],{className:'acpopup'}); + this.attr('autocomplete','off'); + this.textcomplete([contacts,smilies],{className:'acpopup',zIndex:1050}); }; })( jQuery ); + +/** + * jQuery plugin 'search_autocomplete' + */ +(function( $ ){ + $.fn.search_autocomplete = function(backend_url) { + + // Autocomplete contacts + contacts = { + match: /(^@)([^\n]{2,})$/, + index: 2, + search: function(term, callback) { contact_search(term, callback, backend_url, 'x',[]); }, + replace: basic_replace, + template: contact_format, + } + this.attr('autocomplete','off'); + var a = this.textcomplete([contacts],{className:'acpopup',maxCount:100,zIndex: 1050}); + + a.on('textComplete:select', function(e,value,strategy) { submit_form(this); }); + + }; +})( jQuery ); + +(function( $ ){ + $.fn.contact_autocomplete = function(backend_url, typ, autosubmit, onselect) { + + if(typeof typ === 'undefined') typ = ''; + if(typeof autosubmit === 'undefined') autosubmit = false; + + // Autocomplete contacts + contacts = { + match: /(^)([^\n]+)$/, + index: 2, + search: function(term, callback) { contact_search(term, callback, backend_url, typ,[]); }, + replace: basic_replace, + template: contact_format, + } + + this.attr('autocomplete','off'); + var a = this.textcomplete([contacts],{className:'acpopup',zIndex:1050}); + + if(autosubmit) + a.on('textComplete:select', function(e,value,strategy) { submit_form(this); }); + + if(typeof onselect !== 'undefined') + a.on('textComplete:select',function(e,value,strategy) { onselect(value); }); + }; +})( jQuery ); + |