init
This commit is contained in:
parent
06f61d8ce8
commit
f301cb744d
2271 changed files with 103162 additions and 0 deletions
1
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/.plnkr
Executable file
1
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/.plnkr
Executable file
|
@ -0,0 +1 @@
|
|||
{"name":"autocomplete","plunk":"YfIrAQDnCNkb0mq3G5lS"}
|
|
@ -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('');
|
||||
};
|
||||
}
|
51
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/autocomplete.css
Executable file
51
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/autocomplete.css
Executable 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;
|
||||
}
|
103
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/autocomplete.js
Executable file
103
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/autocomplete.js
Executable 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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"name":"autocomplete","plunk":"YfIrAQDnCNkb0mq3G5lS"}
|
|
@ -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('');
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
43
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/index.html
Executable file
43
02-ui/05-widgets/06-widget-tasks/08-autocomplete/solution/index.html
Executable 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>
|
Loading…
Add table
Add a link
Reference in a new issue