Я работал над чем-то очень похожим на теги автозаполнения. У меня работает какой-то базовый код, но мне немного стыдно публиковать здесь, потому что это пограничная чушь. Это требует много очистки и рефакторинга, к которому я доберусь в течение следующих нескольких дней. Тем не менее, он делает то, что вам нужно, способом, аналогичным тому, что предлагает @Andrew.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>jQuery UI Example Page</title>
<link type="text/css" href="../css/smoothness/jquery-ui-1.8.7.custom.css" rel="stylesheet" />
<script type="text/javascript" src="../js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="../js/jquery-ui-1.8.7.custom.min.js"></script>
<script type="text/javascript">
$(function() {
var availableTags = [
"ActionScript", "AppleScript", "Asp", "BASIC", "C",
"C++", "Clojure", "COBOL", "ColdFusion", "Erlang",
"Fortran", "Groovy", "Haskell", "Java", "JavaScript", "Lisp",
"Perl", "PHP", "Python", "Ruby", "Scala", "Scheme"
];
function getCaretPosition(e) {
var p = -1;
if (document.selection) {
e.focus();
var s = document.selection.createRange();
s.moveStart('character', -e.value.length);
p = s.text.length;
} else if (e.selectionStart || e.selectionStart == '0') {
p = e.selectionStart;
}
return p;
}
function getPreviousCaretPosition(e) {
var s = e.value;
var i = getCaretPosition(e) - 1;
while (i >= 0 && s[i] != ' ') { i = i - 1; }
return i;
}
function getTerm(s, p) {
var i = p - 1;
while (i >= 0 && s[i] != ' ') { i = i - 1; }
return s.substring(i + 1, p);
}
$( "#tags" )
.bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
minLength: 2,
source: function(request, response) {
var t = getTerm(this.element[0].value, getCaretPosition(this.element[0]));
if (t[0] != '#') {
return false;
}
// delegate back to autocomplete, but extract the last term
response( $.ui.autocomplete.filter(
availableTags, t.substring(1, t.length) ) );
return true;
},
focus: function() {
return false;
},
search: function(event, ui) {
return true;
},
select: function(event, ui) {
var current = getCaretPosition(this);
var previous = getPreviousCaretPosition(this);
this.value = this.value.substring(0, previous) +
' #' + ui.item.value + ' ' + this.value.substring(current);
return false;
}
});
});
</script>
</head>
<body>
<div id="container">
<div id="content">
<div id="main">
<div class="item">
<div class="title">
<h2>hash-tag-autocomplete</h2>
</div>
</div>
<div class="item">
<form class="simpleform">
<p><textarea id="tags" rows="5" style="width:100%"></textarea><p>
<p><input type="submit"/><p>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
Я доберусь до этой функции в ближайшие пару дней и запакую ее как плагин jQuery. Я постараюсь опубликовать новую версию этого кода в качестве нового ответа.
ОБНОВЛЕНИЕ
Пытался получить что-нибудь чище. Вы можете использовать предпочитаемый способ получения и установки каретки вместо функций, которые я получил.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>jQuery UI Example Page</title>
<link type="text/css" href="../css/smoothness/jquery-ui-1.8.7.custom.css" rel="stylesheet" />
<script type="text/javascript" src="../js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="../js/jquery-ui-1.8.7.custom.min.js"></script>
<script type="text/javascript">
$(function() {
var availableTags = [
"ActionScript", "AppleScript", "Asp", "BASIC", "C", "C++",
"Clojure", "COBOL", "ColdFusion", "Erlang", "Fortran", "Groovy",
"Haskell", "Java", "JavaScript", "Lisp", "Perl", "PHP", "Python",
"Ruby", "Scala", "Scheme"
];
function getCaretPosition(e) {
if (typeof e.selectionStart == 'number') {
return e.selectionStart;
} else if (document.selection) {
var range = document.selection.createRange();
var rangeLength = range.text.length;
range.moveStart('character', -e.value.length);
return range.text.length - rangeLength;
}
};
function setCaretPosition(e, start, end) {
if (e.createTextRange) {
var r = e.createTextRange();
r.moveStart('character', start);
r.moveEnd('character', (end || start));
r.select();
} else if (e.selectionStart) {
e.focus();
e.setSelectionRange(start, (end || start));
}
};
function getWordBeforeCaretPosition(e) {
var s = e.value;
var i = getCaretPosition(e) - 1;
while (i >= 0 && s[i] != ' ') {
i = i - 1;
}
return i + 1;
};
function getWordBeforeCaret(e) {
var p = getWordBeforeCaretPosition(e);
var c = getCaretPosition(e);
return e.value.substring(p, c);
};
function replaceWordBeforeCaret(e, word) {
var p = getWordBeforeCaretPosition(e);
var c = getCaretPosition(e);
e.value = e.value.substring(0, p) + word + e.value.substring(c);
setCaretPosition(e, p + word.length);
};
$( "#tags" )
.bind("keydown", function(event) {
if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active ) {
event.preventDefault();
}
})
.autocomplete({
minLength: 0,
source: function(request, response) {
var w = getWordBeforeCaret(this.element[0]);
if (w[0] != '#') {
this.close();
return false;
}
response($.ui.autocomplete.filter(availableTags, w.substring(1, w.length)));
return true;
},
focus: function() {
return false;
},
search: function(event, ui) {
return true;
},
select: function(event, ui) {
replaceWordBeforeCaret(this, '#' + ui.item.value + ' ');
return false;
}
});
});
</script>
</head>
<body>
<h2>hash-tag-autocomplete</h2>
<form>
<p><textarea id="tags" rows="5" style="width:100%"></textarea><p/
<p><input type="submit"/><p>
</form>
</body>
</html>
Буду очень признателен за любые отзывы по этому поводу.