pidgin/nest
Clone
Summary
Browse
Changes
Graph
closing merged branch
help-weights
2019-08-23, Gary Kramlich
6af542ccd6f4
closing merged branch
/*
JavaScript autoComplete v1.0.4
Copyright (c) 2014 Simon Steinberger / Pixabay
GitHub: https://github.com/Pixabay/JavaScript-autoComplete
License: http://www.opensource.org/licenses/mit-license.php
*/
var
autoComplete
=
(
function
(){
// "use strict";
function
autoComplete
(
options
){
if
(
!
document
.
querySelector
)
return
;
// helpers
function
hasClass
(
el
,
className
){
return
el
.
classList
?
el
.
classList
.
contains
(
className
)
:
new
RegExp
(
'\\b'
+
className
+
'\\b'
).
test
(
el
.
className
);
}
function
addEvent
(
el
,
type
,
handler
){
if
(
el
.
attachEvent
)
el
.
attachEvent
(
'on'
+
type
,
handler
);
else
el
.
addEventListener
(
type
,
handler
);
}
function
removeEvent
(
el
,
type
,
handler
){
// if (el.removeEventListener) not working in IE11
if
(
el
.
detachEvent
)
el
.
detachEvent
(
'on'
+
type
,
handler
);
else
el
.
removeEventListener
(
type
,
handler
);
}
function
live
(
elClass
,
event
,
cb
,
context
){
addEvent
(
context
||
document
,
event
,
function
(
e
){
var
found
,
el
=
e
.
target
||
e
.
srcElement
;
while
(
el
&&
!
(
found
=
hasClass
(
el
,
elClass
)))
el
=
el
.
parentElement
;
if
(
found
)
cb
.
call
(
el
,
e
);
});
}
var
o
=
{
selector
:
0
,
source
:
0
,
minChars
:
3
,
delay
:
150
,
offsetLeft
:
0
,
offsetTop
:
1
,
cache
:
1
,
menuClass
:
''
,
renderItem
:
function
(
item
,
search
){
// escape special characters
search
=
search
.
replace
(
/[-\/\\^$*+?.()|[\]{}]/g
,
'\\$&'
);
var
re
=
new
RegExp
(
"("
+
search
.
split
(
' '
).
join
(
'|'
)
+
")"
,
"gi"
);
return
'<div class="autocomplete-suggestion" data-val="'
+
item
+
'">'
+
item
.
replace
(
re
,
"<b>$1</b>"
)
+
'</div>'
;
},
onSelect
:
function
(
e
,
term
,
item
){}
};
for
(
var
k
in
options
)
{
if
(
options
.
hasOwnProperty
(
k
))
o
[
k
]
=
options
[
k
];
}
// init
var
elems
=
typeof
o
.
selector
==
'object'
?
[
o
.
selector
]
:
document
.
querySelectorAll
(
o
.
selector
);
for
(
var
i
=
0
;
i
<
elems
.
length
;
i
++
)
{
var
that
=
elems
[
i
];
// create suggestions container "sc"
that
.
sc
=
document
.
createElement
(
'div'
);
that
.
sc
.
className
=
'autocomplete-suggestions '
+
o
.
menuClass
;
that
.
autocompleteAttr
=
that
.
getAttribute
(
'autocomplete'
);
that
.
setAttribute
(
'autocomplete'
,
'off'
);
that
.
cache
=
{};
that
.
last_val
=
''
;
that
.
updateSC
=
function
(
resize
,
next
){
var
rect
=
that
.
getBoundingClientRect
();
that
.
sc
.
style
.
left
=
Math
.
round
(
rect
.
left
+
(
window
.
pageXOffset
||
document
.
documentElement
.
scrollLeft
)
+
o
.
offsetLeft
)
+
'px'
;
that
.
sc
.
style
.
top
=
Math
.
round
(
rect
.
bottom
+
(
window
.
pageYOffset
||
document
.
documentElement
.
scrollTop
)
+
o
.
offsetTop
)
+
'px'
;
that
.
sc
.
style
.
width
=
Math
.
round
(
rect
.
right
-
rect
.
left
)
+
'px'
;
// outerWidth
if
(
!
resize
)
{
that
.
sc
.
style
.
display
=
'block'
;
if
(
!
that
.
sc
.
maxHeight
)
{
that
.
sc
.
maxHeight
=
parseInt
((
window
.
getComputedStyle
?
getComputedStyle
(
that
.
sc
,
null
)
:
that
.
sc
.
currentStyle
).
maxHeight
);
}
if
(
!
that
.
sc
.
suggestionHeight
)
that
.
sc
.
suggestionHeight
=
that
.
sc
.
querySelector
(
'.autocomplete-suggestion'
).
offsetHeight
;
if
(
that
.
sc
.
suggestionHeight
)
if
(
!
next
)
that
.
sc
.
scrollTop
=
0
;
else
{
var
scrTop
=
that
.
sc
.
scrollTop
,
selTop
=
next
.
getBoundingClientRect
().
top
-
that
.
sc
.
getBoundingClientRect
().
top
;
if
(
selTop
+
that
.
sc
.
suggestionHeight
-
that
.
sc
.
maxHeight
>
0
)
that
.
sc
.
scrollTop
=
selTop
+
that
.
sc
.
suggestionHeight
+
scrTop
-
that
.
sc
.
maxHeight
;
else
if
(
selTop
<
0
)
that
.
sc
.
scrollTop
=
selTop
+
scrTop
;
}
}
}
addEvent
(
window
,
'resize'
,
that
.
updateSC
);
document
.
body
.
appendChild
(
that
.
sc
);
live
(
'autocomplete-suggestion'
,
'mouseleave'
,
function
(
e
){
var
sel
=
that
.
sc
.
querySelector
(
'.autocomplete-suggestion.selected'
);
if
(
sel
)
setTimeout
(
function
(){
sel
.
className
=
sel
.
className
.
replace
(
'selected'
,
''
);
},
20
);
},
that
.
sc
);
live
(
'autocomplete-suggestion'
,
'mouseover'
,
function
(
e
){
var
sel
=
that
.
sc
.
querySelector
(
'.autocomplete-suggestion.selected'
);
if
(
sel
)
sel
.
className
=
sel
.
className
.
replace
(
'selected'
,
''
);
this
.
className
+=
' selected'
;
},
that
.
sc
);
live
(
'autocomplete-suggestion'
,
'mousedown'
,
function
(
e
){
if
(
hasClass
(
this
,
'autocomplete-suggestion'
))
{
// else outside click
var
v
=
this
.
getAttribute
(
'data-val'
);
that
.
value
=
v
;
o
.
onSelect
(
e
,
v
,
this
);
that
.
sc
.
style
.
display
=
'none'
;
}
},
that
.
sc
);
that
.
blurHandler
=
function
(){
try
{
var
over_sb
=
document
.
querySelector
(
'.autocomplete-suggestions:hover'
);
}
catch
(
e
){
var
over_sb
=
0
;
}
if
(
!
over_sb
)
{
that
.
last_val
=
that
.
value
;
that
.
sc
.
style
.
display
=
'none'
;
setTimeout
(
function
(){
that
.
sc
.
style
.
display
=
'none'
;
},
350
);
// hide suggestions on fast input
}
else
if
(
that
!==
document
.
activeElement
)
setTimeout
(
function
(){
that
.
focus
();
},
20
);
};
addEvent
(
that
,
'blur'
,
that
.
blurHandler
);
var
suggest
=
function
(
data
){
var
val
=
that
.
value
;
that
.
cache
[
val
]
=
data
;
if
(
data
.
length
&&
val
.
length
>=
o
.
minChars
)
{
var
s
=
''
;
for
(
var
i
=
0
;
i
<
data
.
length
;
i
++
)
s
+=
o
.
renderItem
(
data
[
i
],
val
);
that
.
sc
.
innerHTML
=
s
;
that
.
updateSC
(
0
);
}
else
that
.
sc
.
style
.
display
=
'none'
;
}
that
.
keydownHandler
=
function
(
e
){
var
key
=
window
.
event
?
e
.
keyCode
:
e
.
which
;
// down (40), up (38)
if
((
key
==
40
||
key
==
38
)
&&
that
.
sc
.
innerHTML
)
{
var
next
,
sel
=
that
.
sc
.
querySelector
(
'.autocomplete-suggestion.selected'
);
if
(
!
sel
)
{
next
=
(
key
==
40
)
?
that
.
sc
.
querySelector
(
'.autocomplete-suggestion'
)
:
that
.
sc
.
childNodes
[
that
.
sc
.
childNodes
.
length
-
1
];
// first : last
next
.
className
+=
' selected'
;
console
.
log
(
next
);
that
.
value
=
next
.
getAttribute
(
'data-val'
);
}
else
{
next
=
(
key
==
40
)
?
sel
.
nextSibling
:
sel
.
previousSibling
;
if
(
next
)
{
sel
.
className
=
sel
.
className
.
replace
(
'selected'
,
''
);
next
.
className
+=
' selected'
;
that
.
value
=
next
.
getAttribute
(
'data-val'
);
}
else
{
sel
.
className
=
sel
.
className
.
replace
(
'selected'
,
''
);
that
.
value
=
that
.
last_val
;
next
=
0
;
}
}
that
.
updateSC
(
0
,
next
);
return
false
;
}
// esc
else
if
(
key
==
27
)
{
that
.
value
=
that
.
last_val
;
that
.
sc
.
style
.
display
=
'none'
;
}
// enter
else
if
(
key
==
13
||
key
==
9
)
{
var
sel
=
that
.
sc
.
querySelector
(
'.autocomplete-suggestion.selected'
);
if
(
sel
&&
that
.
sc
.
style
.
display
!=
'none'
)
{
o
.
onSelect
(
e
,
sel
.
getAttribute
(
'data-val'
),
sel
);
setTimeout
(
function
(){
that
.
sc
.
style
.
display
=
'none'
;
},
20
);
}
}
};
addEvent
(
that
,
'keydown'
,
that
.
keydownHandler
);
that
.
keyupHandler
=
function
(
e
){
var
key
=
window
.
event
?
e
.
keyCode
:
e
.
which
;
if
(
!
key
||
(
key
<
35
||
key
>
40
)
&&
key
!=
13
&&
key
!=
27
)
{
var
val
=
that
.
value
;
if
(
val
.
length
>=
o
.
minChars
)
{
if
(
val
!=
that
.
last_val
)
{
that
.
last_val
=
val
;
clearTimeout
(
that
.
timer
);
if
(
o
.
cache
)
{
if
(
val
in
that
.
cache
)
{
suggest
(
that
.
cache
[
val
]);
return
;
}
// no requests if previous suggestions were empty
for
(
var
i
=
1
;
i
<
val
.
length
-
o
.
minChars
;
i
++
)
{
var
part
=
val
.
slice
(
0
,
val
.
length
-
i
);
if
(
part
in
that
.
cache
&&
!
that
.
cache
[
part
].
length
)
{
suggest
([]);
return
;
}
}
}
that
.
timer
=
setTimeout
(
function
(){
o
.
source
(
val
,
suggest
)
},
o
.
delay
);
}
}
else
{
that
.
last_val
=
val
;
that
.
sc
.
style
.
display
=
'none'
;
}
}
};
addEvent
(
that
,
'keyup'
,
that
.
keyupHandler
);
that
.
focusHandler
=
function
(
e
){
that
.
last_val
=
'\n'
;
that
.
keyupHandler
(
e
)
};
if
(
!
o
.
minChars
)
addEvent
(
that
,
'focus'
,
that
.
focusHandler
);
}
// public destroy method
this
.
destroy
=
function
(){
for
(
var
i
=
0
;
i
<
elems
.
length
;
i
++
)
{
var
that
=
elems
[
i
];
removeEvent
(
window
,
'resize'
,
that
.
updateSC
);
removeEvent
(
that
,
'blur'
,
that
.
blurHandler
);
removeEvent
(
that
,
'focus'
,
that
.
focusHandler
);
removeEvent
(
that
,
'keydown'
,
that
.
keydownHandler
);
removeEvent
(
that
,
'keyup'
,
that
.
keyupHandler
);
if
(
that
.
autocompleteAttr
)
that
.
setAttribute
(
'autocomplete'
,
that
.
autocompleteAttr
);
else
that
.
removeAttribute
(
'autocomplete'
);
document
.
body
.
removeChild
(
that
.
sc
);
that
=
null
;
}
};
}
return
autoComplete
;
})();
(
function
(){
if
(
typeof
define
===
'function'
&&
define
.
amd
)
define
(
'autoComplete'
,
function
()
{
return
autoComplete
;
});
else
if
(
typeof
module
!==
'undefined'
&&
module
.
exports
)
module
.
exports
=
autoComplete
;
else
window
.
autoComplete
=
autoComplete
;
})();