2011-10-25 13:01:58 +00:00
/ * *
2014-12-20 14:21:31 +00:00
* Red people autocomplete
2011-10-25 13:01:58 +00:00
*
2014-12-20 14:21:31 +00:00
* require jQuery , jquery . textcomplete
2011-10-25 13:01:58 +00:00
* /
2015-01-21 10:38:55 +00:00
function contact _search ( term , callback , backend _url , type , extra _channels , spinelement ) {
2015-03-15 21:18:59 +00:00
if ( spinelement ) {
2015-01-21 10:38:55 +00:00
$ ( spinelement ) . spin ( 'tiny' ) ;
}
2015-01-07 21:07:11 +00:00
// Check if there is a cached result that contains the same information we would get with a full server-side search
2015-01-08 16:16:08 +00:00
var bt = backend _url + type ;
if ( ! ( bt in contact _search . cache ) ) contact _search . cache [ bt ] = { } ;
2015-01-08 15:06:37 +00:00
var lterm = term . toLowerCase ( ) ; // Ignore case
2015-03-15 21:18:59 +00:00
for ( var t in contact _search . cache [ bt ] ) {
2015-01-08 15:06:37 +00:00
if ( lterm . indexOf ( t ) >= 0 ) { // A more broad search has been performed already, so use those results
2015-01-21 10:38:55 +00:00
$ ( spinelement ) . spin ( false ) ;
2015-01-06 20:01:30 +00:00
// Filter old results locally
2015-03-15 21:18:59 +00:00
var matching = contact _search . cache [ bt ] [ t ] . filter ( function ( x ) { return ( x . name . toLowerCase ( ) . indexOf ( lterm ) >= 0 || ( typeof x . nick !== 'undefined' && x . nick . toLowerCase ( ) . indexOf ( lterm ) >= 0 ) ) ; } ) ; // Need to check that nick exists because groups don't have one
2015-01-08 15:06:37 +00:00
matching . unshift ( { taggable : false , text : term , replace : term } ) ;
2015-03-15 21:18:59 +00:00
setTimeout ( function ( ) { callback ( matching ) ; } , 1 ) ; // Use "pseudo-thread" to avoid some problems
2015-01-06 20:01:30 +00:00
return ;
}
}
2011-10-25 13:01:58 +00:00
var postdata = {
start : 0 ,
count : 100 ,
2014-12-20 14:21:31 +00:00
search : term ,
2015-01-07 18:39:50 +00:00
type : type ,
2015-03-15 21:18:59 +00:00
} ;
2015-01-04 11:54:23 +00:00
2015-01-07 18:39:50 +00:00
if ( typeof extra _channels !== 'undefined' && extra _channels )
2015-01-04 11:54:23 +00:00
postdata [ 'extra_channels[]' ] = extra _channels ;
2015-03-15 21:18:59 +00:00
2011-10-25 13:01:58 +00:00
$ . ajax ( {
type : 'POST' ,
2014-12-20 14:21:31 +00:00
url : backend _url ,
2011-10-25 13:01:58 +00:00
data : postdata ,
dataType : 'json' ,
2015-03-15 21:18:59 +00:00
success : function ( data ) {
2015-01-06 20:01:30 +00:00
// Cache results if we got them all (more information would not improve results)
// data.count represents the maximum number of items
2015-01-08 15:06:37 +00:00
if ( data . items . length - 1 < data . count ) {
2015-01-08 16:16:08 +00:00
contact _search . cache [ bt ] [ lterm ] = data . items ;
2015-01-06 20:01:30 +00:00
}
2015-01-08 15:06:37 +00:00
var items = data . items . slice ( 0 ) ;
items . unshift ( { taggable : false , text : term , replace : term } ) ;
callback ( items ) ;
2015-01-21 10:38:55 +00:00
$ ( spinelement ) . spin ( false ) ;
2014-12-20 14:21:31 +00:00
} ,
} ) . fail ( function ( ) { callback ( [ ] ) ; } ) ; // Callback must be invoked even if something went wrong.
2011-10-25 13:01:58 +00:00
}
2015-01-07 21:07:11 +00:00
contact _search . cache = { } ;
2011-10-25 13:01:58 +00:00
2015-01-08 15:06:37 +00:00
2015-01-07 17:57:16 +00:00
function contact _format ( item ) {
2015-01-08 16:16:08 +00:00
// Show contact information if not explicitly told to show something else
if ( typeof item . text === 'undefined' ) {
2015-03-15 21:18:59 +00:00
var desc = ( ( item . label ) ? item . nick + ' ' + item . label : item . nick ) ;
2015-01-17 12:16:22 +00:00
if ( typeof desc === 'undefined' ) desc = '' ;
2015-01-08 16:16:08 +00:00
if ( desc ) desc = ' (' + desc + ')' ;
2015-11-25 23:12:54 +00:00
return "<div class='{0}' title='{4}'><img class='dropdown-menu-img-sm' src='{1}'><span class='contactname'>{2}</span><span class='dropdown-sub-text'>{3}</span><div class='clear'></div></div>" . format ( item . taggable , item . photo , item . name , desc , item . link ) ;
2015-01-08 16:16:08 +00:00
}
2015-01-08 15:06:37 +00:00
else
2015-03-15 21:18:59 +00:00
return "<div>" + item . text + "</div>" ;
2011-10-25 13:01:58 +00:00
}
2015-01-07 17:57:16 +00:00
function editor _replace ( item ) {
2015-01-08 15:06:37 +00:00
if ( typeof item . replace !== 'undefined' ) {
2015-03-15 21:18:59 +00:00
return '$1$2' + item . replace ;
2015-01-08 15:06:37 +00:00
}
2014-12-20 14:21:31 +00:00
// $2 ensures that prefix (@,@!) is preserved
2015-01-04 11:54:23 +00:00
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 ) ;
2015-03-15 21:18:59 +00:00
return '$1$2' + item . nick . replace ( ' ' , '' ) + '+' + id + ' ' ;
2014-12-20 14:21:31 +00:00
}
2011-10-26 12:18:05 +00:00
2015-01-07 18:39:50 +00:00
function basic _replace ( item ) {
2015-01-08 15:06:37 +00:00
if ( typeof item . replace !== 'undefined' )
return '$1' + item . replace ;
2015-01-07 19:03:05 +00:00
return '$1' + item . name + ' ' ;
2015-01-07 18:39:50 +00:00
}
2015-10-03 01:12:09 +00:00
function trim _replace ( item ) {
if ( typeof item . replace !== 'undefined' )
return '$1' + item . replace ;
return '$1' + item . name ;
}
2015-01-07 20:32:17 +00:00
function submit _form ( e ) {
$ ( e ) . parents ( 'form' ) . submit ( ) ;
}
2011-10-25 13:01:58 +00:00
/ * *
2015-01-07 17:57:16 +00:00
* jQuery plugin 'editor_autocomplete'
2011-10-25 13:01:58 +00:00
* /
2015-03-15 21:18:59 +00:00
( function ( $ ) {
2015-01-07 17:57:16 +00:00
$ . fn . editor _autocomplete = function ( backend _url , extra _channels ) {
2015-03-15 21:18:59 +00:00
if ( typeof extra _channels === 'undefined' ) extra _channels = false ;
// Autocomplete contacts
contacts = {
match : /(^|\s)(@\!*)([^ \n]+)$/ ,
index : 3 ,
search : function ( term , callback ) { contact _search ( term , callback , backend _url , 'c' , extra _channels , spinelement = false ) ; } ,
replace : editor _replace ,
template : contact _format ,
} ;
smilies = {
match : /(^|\s)(:[a-z]{2,})$/ ,
index : 2 ,
search : function ( term , callback ) { $ . getJSON ( '/smilies/json' ) . done ( function ( data ) { callback ( $ . map ( data , function ( entry ) { return entry . text . indexOf ( term ) === 0 ? entry : null ; } ) ) ; } ) ; } ,
template : function ( item ) { return item . icon + item . text ; } ,
replace : function ( item ) { return "$1" + item . text + ' ' ; } ,
} ;
this . attr ( 'autocomplete' , 'off' ) ;
this . textcomplete ( [ contacts , smilies ] , { className : 'acpopup' , zIndex : 1020 } ) ;
} ;
2011-10-25 13:01:58 +00:00
} ) ( jQuery ) ;
2015-01-07 18:39:50 +00:00
/ * *
* jQuery plugin 'search_autocomplete'
* /
2015-03-15 21:18:59 +00:00
( function ( $ ) {
2015-01-07 18:39:50 +00:00
$ . fn . search _autocomplete = function ( backend _url ) {
2015-03-15 21:18:59 +00:00
// Autocomplete contacts
contacts = {
match : /(^@)([^\n]{2,})$/ ,
index : 2 ,
search : function ( term , callback ) { contact _search ( term , callback , backend _url , 'x' , [ ] , spinelement = '#nav-search-spinner' ) ; } ,
replace : basic _replace ,
template : contact _format ,
} ;
this . attr ( 'autocomplete' , 'off' ) ;
var a = this . textcomplete ( [ contacts ] , { className : 'acpopup' , maxCount : 100 , zIndex : 1020 , appendTo : 'nav' } ) ;
a . on ( 'textComplete:select' , function ( e , value , strategy ) { submit _form ( this ) ; } ) ;
} ;
2015-01-07 18:39:50 +00:00
} ) ( jQuery ) ;
2015-01-07 19:03:05 +00:00
2015-03-15 21:18:59 +00:00
( function ( $ ) {
2015-01-07 20:32:17 +00:00
$ . fn . contact _autocomplete = function ( backend _url , typ , autosubmit , onselect ) {
2015-03-15 21:18:59 +00:00
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 , [ ] , spinelement = false ) ; } ,
replace : basic _replace ,
template : contact _format ,
} ;
this . attr ( 'autocomplete' , 'off' ) ;
var a = this . textcomplete ( [ contacts ] , { className : 'acpopup' , zIndex : 1020 } ) ;
2015-10-03 01:12:09 +00:00
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 ) ;
( function ( $ ) {
$ . fn . name _autocomplete = function ( backend _url , typ , autosubmit , onselect ) {
if ( typeof typ === 'undefined' ) typ = '' ;
if ( typeof autosubmit === 'undefined' ) autosubmit = false ;
// Autocomplete contacts
names = {
match : /(^)([^\n]+)$/ ,
index : 2 ,
search : function ( term , callback ) { contact _search ( term , callback , backend _url , typ , [ ] , spinelement = false ) ; } ,
replace : trim _replace ,
template : contact _format ,
} ;
this . attr ( 'autocomplete' , 'off' ) ;
var a = this . textcomplete ( [ names ] , { className : 'acpopup' , zIndex : 1020 } ) ;
2015-03-15 21:18:59 +00:00
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 ) ; } ) ;
} ;
2016-01-14 22:23:12 +00:00
} ) ( jQuery ) ;