This commit is contained in:
Ilya Kantor 2014-10-26 22:10:13 +03:00
parent 06f61d8ce8
commit f301cb744d
2271 changed files with 103162 additions and 0 deletions

View file

@ -0,0 +1 @@
{"name":"autocomplete","plunk":"YfIrAQDnCNkb0mq3G5lS"}

View file

@ -0,0 +1,62 @@
function AutocompleteList(provider) {
var elem;
var filteredResults;
var currentIndex = 0;
this.render = function() {
elem = $('<ol/>');
return elem;
};
this.update = function(value) {
filteredResults = provider.filterByStart(value);
if (filteredResults.length) {
elem.html( '<li>' + filteredResults.join('</li><li>') + '</li>' );
} else {
elem.empty();
}
currentIndex = 0;
renderCurrent();
// это событие, как и всё обновление,
// может быть асинхронным (при получении списка с сервера)
$(this).triggerHandler({
type: 'update',
values: filteredResults
});
};
function renderCurrent() {
elem.children().eq(currentIndex).addClass('selected');
}
function clearCurrent() {
elem.children().eq(currentIndex).removeClass('selected');
}
this.get = function() {
return filteredResults[currentIndex];
};
this.down = function() {
if (currentIndex == filteredResults.length - 1) return;
clearCurrent();
currentIndex++;
renderCurrent();
};
this.up = function() {
if (currentIndex == 0) return;
clearCurrent();
currentIndex--;
renderCurrent();
};
this.clear = function() {
this.update('');
};
}

View file

@ -0,0 +1,51 @@
.autocomplete ol {
display: none;
margin: 0;
padding: 3px;
border: 1px solid gray;
list-style: none;
}
.autocomplete input {
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 1px 0 1px 3px;
width: 100%;
border: 1px solid blue;
border-radius: 3px;
-webkit-appearance: none;
font-size: 16px;
}
.autocomplete input:focus {
outline: none;
}
.autocomplete.open input {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.autocomplete.open ol {
display: block;
background: white;
z-index: 10000;
position: relative;
}
.autocomplete {
width: 400px;
height: 20px;
}
.autocomplete ol .selected {
background: blue;
}

View file

@ -0,0 +1,103 @@
function Autocomplete(options) {
var self = this;
var elem = options.elem;
var input = $('input', elem);
var list;
input.on({
focus: onInputFocus,
blur: onInputBlur,
keydown: onInputKeyDown
});
var inputCheckTimer;
// ------------------
function onInputKeyDown(e) {
var KEY_ARROW_UP = 38;
var KEY_ARROW_RIGHT = 39;
var KEY_ARROW_DOWN = 40;
var KEY_ENTER = 13;
var KEY_ESC = 27;
switch(e.keyCode) {
case KEY_ARROW_UP:
list.up();
return false;
break;
case KEY_ARROW_RIGHT:
if (list.get()) {
self.setValue( list.get(), true );
}
break;
case KEY_ENTER:
self.setValue( list.get() || input.val() );
input.blur();
break;
case KEY_ESC:
list.clear();
break;
case KEY_ARROW_DOWN:
list.down();
return false;
break;
}
}
function initList() {
list = new AutocompleteList(options.provider);
list.render().appendTo(elem);
$(list).on('update', onListUpdate);
}
function onListUpdate(e) {
if (e.values.length) {
elem.addClass('open');
} else {
elem.removeClass('open');
}
}
function onInputFocus() {
var inputValue = input.val();
function checkInput() {
if (inputValue != input.val()) {
if (!list) {
initList();
}
list.update(input.val());
inputValue = input.val();
}
}
inputCheckTimer = setInterval(checkInput, 30);
}
function onInputBlur() {
clearInterval(inputCheckTimer);
if (list) {
list.clear();
}
}
this.setValue = function(value, quiet) {
input.val(value);
if (!quiet) {
$(self).triggerHandler({
type: 'change',
value: value
});
}
}
}

View file

@ -0,0 +1 @@
{"name":"autocomplete","plunk":"YfIrAQDnCNkb0mq3G5lS"}

View file

@ -0,0 +1,62 @@
function AutocompleteList(provider) {
var elem;
var filteredResults;
var currentIndex = 0;
this.render = function() {
elem = $('<ol/>');
return elem;
};
this.update = function(value) {
filteredResults = provider.filterByStart(value);
if (filteredResults.length) {
elem.html( '<li>' + filteredResults.join('</li><li>') + '</li>' );
} else {
elem.empty();
}
currentIndex = 0;
renderCurrent();
// это событие, как и всё обновление,
// может быть асинхронным (при получении списка с сервера)
$(this).triggerHandler({
type: 'update',
values: filteredResults
});
};
function renderCurrent() {
elem.children().eq(currentIndex).addClass('selected');
}
function clearCurrent() {
elem.children().eq(currentIndex).removeClass('selected');
}
this.get = function() {
return filteredResults[currentIndex];
};
this.down = function() {
if (currentIndex == filteredResults.length - 1) return;
clearCurrent();
currentIndex++;
renderCurrent();
};
this.up = function() {
if (currentIndex == 0) return;
clearCurrent();
currentIndex--;
renderCurrent();
};
this.clear = function() {
this.update('');
};
}

View file

@ -0,0 +1,51 @@
.autocomplete ol {
display: none;
margin: 0;
padding: 3px;
border: 1px solid gray;
list-style: none;
}
.autocomplete input {
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 1px 0 1px 3px;
width: 100%;
border: 1px solid blue;
border-radius: 3px;
-webkit-appearance: none;
font-size: 16px;
}
.autocomplete input:focus {
outline: none;
}
.autocomplete.open input {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.autocomplete.open ol {
display: block;
background: white;
z-index: 10000;
position: relative;
}
.autocomplete {
width: 400px;
height: 20px;
}
.autocomplete ol .selected {
background: blue;
}

View file

@ -0,0 +1,103 @@
function Autocomplete(options) {
var self = this;
var elem = options.elem;
var input = $('input', elem);
var list;
input.on({
focus: onInputFocus,
blur: onInputBlur,
keydown: onInputKeyDown
});
var inputCheckTimer;
// ------------------
function onInputKeyDown(e) {
var KEY_ARROW_UP = 38;
var KEY_ARROW_RIGHT = 39;
var KEY_ARROW_DOWN = 40;
var KEY_ENTER = 13;
var KEY_ESC = 27;
switch(e.keyCode) {
case KEY_ARROW_UP:
list.up();
return false;
break;
case KEY_ARROW_RIGHT:
if (list.get()) {
self.setValue( list.get(), true );
}
break;
case KEY_ENTER:
self.setValue( list.get() || input.val() );
input.blur();
break;
case KEY_ESC:
list.clear();
break;
case KEY_ARROW_DOWN:
list.down();
return false;
break;
}
}
function initList() {
list = new AutocompleteList(options.provider);
list.render().appendTo(elem);
$(list).on('update', onListUpdate);
}
function onListUpdate(e) {
if (e.values.length) {
elem.addClass('open');
} else {
elem.removeClass('open');
}
}
function onInputFocus() {
var inputValue = input.val();
function checkInput() {
if (inputValue != input.val()) {
if (!list) {
initList();
}
list.update(input.val());
inputValue = input.val();
}
}
inputCheckTimer = setInterval(checkInput, 30);
}
function onInputBlur() {
clearInterval(inputCheckTimer);
if (list) {
list.clear();
}
}
this.setValue = function(value, quiet) {
input.val(value);
if (!quiet) {
$(self).triggerHandler({
type: 'change',
value: value
});
}
}
}

View file

@ -0,0 +1,20 @@
function FilteringListProvider(strings) {
this.get = function(index) {
return strings[index];
};
this.filterByStart = function(stringStart) {
if (stringStart.length < 2) return [];
var stringStartLC = stringStart.toLowerCase();
return strings.filter(function(str) {
var strLC = str.toLowerCase();
return strLC.slice(0, stringStartLC.length) == stringStartLC && strLC != stringStartLC;
});
}
}

View file

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="autocomplete.css">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="autocomplete.js"></script>
<script src="filtering-list-provider.js"></script>
<script src="autocomplete-list.js"></script>
</head>
<body>
<div class="autocomplete" id="search">
<input type="text" autocomplete="off">
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam explicabo nostrum eum placeat aliquid voluptatem nihil modi libero nulla tempore dolore itaque accusamus distinctio veniam quae voluptatibus suscipit provident quas quaerat tempora sequi magnam.</div>
<script>
var dataProvider = new FilteringListProvider([
'Человек',
'Чело',
'Че Гевара',
'Яблоко',
'Ноутбук',
'Но Пасаран!'
]);
var autocomplete = new Autocomplete({
elem: $('#search'),
provider: dataProvider
});
$(autocomplete).on('change', function(e) {
$('#search').next().html(e.value);
});
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
function FilteringListProvider(strings) {
this.get = function(index) {
return strings[index];
};
this.filterByStart = function(stringStart) {
if (stringStart.length < 2) return [];
var stringStartLC = stringStart.toLowerCase();
return strings.filter(function(str) {
var strLC = str.toLowerCase();
return strLC.slice(0, stringStartLC.length) == stringStartLC && strLC != stringStartLC;
});
}
}

View file

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="autocomplete.css">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="autocomplete.js"></script>
<script src="filtering-list-provider.js"></script>
<script src="autocomplete-list.js"></script>
</head>
<body>
<div class="autocomplete" id="search">
<input type="text" autocomplete="off">
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam explicabo nostrum eum placeat aliquid voluptatem nihil modi libero nulla tempore dolore itaque accusamus distinctio veniam quae voluptatibus suscipit provident quas quaerat tempora sequi magnam.</div>
<script>
var dataProvider = new FilteringListProvider([
'Человек',
'Чело',
'Че Гевара',
'Яблоко',
'Ноутбук',
'Но Пасаран!'
]);
var autocomplete = new Autocomplete({
elem: $('#search'),
provider: dataProvider
});
$(autocomplete).on('change', function(e) {
$('#search').next().html(e.value);
});
</script>
</body>
</html>