getting jQuery ui autocomplete to work with #mentions only - javascript

I've had a look at a few questions, such as https://stackoverflow.com/a/7222592/2332251
I'm still having trouble reconciling it with the code I have.
At the moment the following works perfectly for searching a username as I start typing.
$(function() {
$("#appendedInputButton").autocomplete({
minLength: 2,
source: "searchusers.php"
});
});
The function in searchusers.php outputs the usernames from the database.
As I said, I'm having trouble making other #mention solutions work for me. I've tried copying over other solutions and swapping my details in but nothing seems to work.
So...
What do I need to do to my current autocomplete script to make it load only
when I initially type the '#' symbol?
I would really like to be able to have multiple #mentions in my posts
(optional) when autocomplete suggests usernames and when I select the username from the list I want it to appear in my post with the #symbol still appended to the front of the username e.g. "hello #john, the # symbol is still attached to your username"
If you need more info, please comment and I will provide more :)
Edit I'm just really unsure of the syntax to make it work. For example, using the example answer I posted above, I came up with (but it doesn't work):
function split(val) {
return val.split(/#\s*/);
}
function extractLast(term) {
return split(term).pop();
}
function getTags(term, callback) {
$.ajax({
url: "searchusers.php",
data: {
filter: term,
pagesize: 5
},
type: "POST",
success: callback,
jsonp: "jsonp",
dataType: "jsonp"
});
}
$(document).ready(function() {
$("#appendedInputButton")
// don't navigate away from the field on tab when selecting an item
.bind("keydown", function(event) {
if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active) {
event.preventDefault();
}
}).autocomplete({
source: function(request, response) {
if (request.term.indexOf("#") >= 0) {
$("#loading").show();
getTags(extractLast(request.term), function(data) {
response($.map(data.tags, function(el) {
return {
value: el.name,
count: el.count
}
}));
$("#loading").hide();
});
}
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
var terms = split(this.value);
// remove the current input
terms.pop();
// add the selected item
terms.push(ui.item.value);
// add placeholder to get the comma-and-space at the end
terms.push("");
this.value = terms.join("");
return false;
}
}).data("autocomplete")._renderItem = function(ul, item) {
return $("<li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + " <span class='count'>(" + item.count + ")</span></a>")
.appendTo(ul);
};
});
Where do I insert searchusers.php, #appendedInputButton and other specific info? I hope this makes sense.

I will form an answer based on my comments.
First of all lets review the list of requirements:
autocomplete usernames started with # symbol
prepend usernames with # symbol
multiple #mentions in a text
edit any #mention anywhere in a text
to implement the last requirement we need some magic functions that i found on stackoverflow:
getCaretPosition - https://stackoverflow.com/a/2897229/2335291
setCaretPosition - https://stackoverflow.com/a/512542/2335291
Also to detect a username somewhere in the text we need to define some constraints for usernames. I assume that it can have only letters and numbers and test it with \w+ pattern.
The live demo you can find here http://jsfiddle.net/AU92X/6/ It always returns 2 rows without filtering just to demonstrate the behavior. In the listing below i've put the original getTags function from the question as it looks fine for me. Although i have no idea how searchusers.php works.
function getCaretPosition (elem) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
elem.focus ();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange ();
// Move selection start to 0 position
oSel.moveStart ('character', -elem.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (elem.selectionStart || elem.selectionStart == '0')
iCaretPos = elem.selectionStart;
// Return results
return (iCaretPos);
}
function setCaretPosition(elem, caretPos) {
if(elem != null) {
if(elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
}
else {
if(elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else
elem.focus();
}
}
}
function getTags(term, callback) {
$.ajax({
url: "searchusers.php",
data: {
filter: term,
pagesize: 5
},
type: "POST",
success: callback,
jsonp: "jsonp",
dataType: "jsonp"
});
}
$(document).ready(function() {
$("#appendedInputButton").autocomplete({
source: function(request, response) {
var term = request.term;
var pos = getCaretPosition(this.element.get(0));
var substr = term.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
if (lastIndex >= 0){
var username = substr.substr(lastIndex + 1);
if (username.length && (/^\w+$/g).test(username)){
getTags(username, function(data) {
response($.map(data.tags, function(el) {
return {
value: el.name,
count: el.count
}
}));
});
return;
}
}
response({});
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
var pos = getCaretPosition(this);
var substr = this.value.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
if (lastIndex >= 0){
var prependStr = this.value.substring(0, lastIndex);
this.value = prependStr + '#' + ui.item.value + this.value.substr(pos);
setCaretPosition(this, prependStr.length + ui.item.value.length + 1);
}
return false;
}
}).data("ui-autocomplete")._renderItem = function(ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a>" + item.label + " <span class='count'>(" + item.count + ")</span></a>")
.appendTo(ul);
};
});

I cannot add a comment, so I'm just going to add this as an answer.
I tried the code snippet you've provided and it worked great. The only problem I had was while editing the mention. I decided to edit from the middle of the mention, the autocomplete showed and I selected an item successfully. Only - it didn't delete the rest of the previous mention, only the letters before the cursor's position.
So I added something extra:
select: function(event, ui) {
var pos = comments.init.getCaretPosition(this);
var substr = this.value.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
var afterPosString = this.value.substring(pos, this.value.length);
var leftovers = afterPosString.indexOf(' ');
if (leftovers == -1)
leftovers = afterPosString.length;
if (lastIndex >= 0){
var prependStr = this.value.substring(0, lastIndex);
this.value = prependStr + '#' + ui.item.value + this.value.substr(pos + leftovers);
comments.init.setCaretPosition(this, prependStr.length + ui.item.value.length + 1);
}
return false;
}
I changed the select function a bit to cover the leftovers. Now, it's searching for the next " " occurrence and adds the length of everything before it to the replaced value.
Hope this helps :)

Related

Filtering On Multiple Search Criteria With jQuery

I have a problem with my searching in JavaScript / jQuery. For example, if I choose "Two service" and "Online status" this function below returns all "Two service" and all "Online service".
The desired behavior has 3 parts:
1) For the different search criteria to be additive (i.e. ANDs instead of ORs).
2) Return all records when the search criteria is empty.
3) Make the data-name search from the #search input case insensitive
$(document).ready(function() {
$("#service").change(function(){ select(); });
$("#search").keyup(function(){ select(); });
$("#status").change(function(){ select(); });
select = function(){
var service = $("#service").val();
var search = $("#search").val();
var status = $("#status").val();
$(".box").hide();
$(".box[data-service='" + service + "']").show();
$(".box[data-search='" + search + "']").show();
$(".box[data-status='" + status + "']").show();
}
});
Example: https://jsfiddle.net/L7wyp13q/
You can try something like this :
$(document).ready(function() {
$("#service").change(function() {
select();
});
$("#search").keyup(function() {
select();
});
$("#status").change(function() {
select();
});
select = function() {
var service = $("#service").val();
var search = $("#search").val();
var status = $("#status").val();
$(".box").hide();
var boxes = $(".box").filter(function(index) {
return (service === 'all' || $(this).attr("data-service") === service) &&
(!search || $(this).attr("data-name").toLowerCase().indexOf(search.toLowerCase()) >= 0 ) &&
(status === 'all' || $(this).attr("data-status") === status);
});
console.log(boxes);
boxes.show();
}
});
fiddle demo : https://jsfiddle.net/xcrmyzgr/2/
The idea here is to build your selector dynamically based on the values of your filter criteria. I used an object to contain the filter values so that I could iterate over them and reuse the property names, but you can do it however you'd like.
Edit -- updated to return partial matches from search field, rather than only exact matches
Edit 2 -- added case insensitive searching
$(document).ready(function() {
$("#service, #status").change(function(){ select(); });
$("#search").keyup(function(){ select(); });
select = function(){
var selectorFilters = {
service: $("#service").val(),
status: $("#status").val()
};
$(".box").hide();
var selector = Object.keys(selectorFilters).reduce(function (sel, currentKey) {
var value = selectorFilters[currentKey];
if (value && value !== "" && value !== "all") {
sel += "[data-" + currentKey + "=" + value + "]";
}
return sel;
}, ".box"); // <-- start with .box and build from there
// will select even if search is partial match, rather than only exact match
$(selector).filter(function (){
var searchValue = $("#search").val().toLowerCase();
return (searchValue === "" || $(this).data("name").toLowerCase().indexOf(searchValue) > -1);
}).show();
}
});
Working DEMO

JQuery Autocomplete Widget - Up & Down Arrow Keys not working

I am new to Jquery and was going through a snippet of code of a larger application (which we have outsourced). This snippet is a jquery widget to autocomplete results.
On the HTML page, we have a search box. When the user enters some keystrokes, a search is performed (for places and events) on our database and the results are shown in an un-ordered list. The results show up fine. However, I was hoping to scroll through the results using the down and up arrow key which does not seem to work.
Opening the Developer Tools in Chrome, when I press the Down key the following error is reported
Uncaught TypeError: Cannot read property 'value' of undefined jquery-ui.min.js:8
The relevant Widget code is as follows
$.widget("custom.catcomplete", $.ui.autocomplete, {
_renderMenu: function(ul, items) {
ul.addClass('search-box');
var that = this;
var i = 0;
var j = 0;
var index = 0;
$.each(items, function(index, item) {
if (item.Space && i == 0) {
ul.append('<h4><i class="fa fa-car fa-fw"></i> Parking Space</h4>');
i++;
}
if (item.Event && j == 0) {
if (i > 0) {
ul.append('See All Result');
}
ul.append('<h4><i class="fa fa-calendar"></i> Venues</h4>');
j++
}
that._renderItemData(ul, item);
});
if (j == 0 && items.value == 'error') {
ul.append('See All Result');
}
}
});
$(function() {
// made on 01-07-2015
$("#search_new").catcomplete({
delay: 0,
//minLength: 2,
zIndex: 9999,
source: base_url + "searches/index.json",
messages: {
noResults: '',
results: function() {}
},
select: function(event, ui) {
window.location = (ui.item.url);
}
}).off('blur').on('blur', function() {
if(document.hasFocus()) {
$('ul.ui-autocomplete').show();
}
});
});
$.ui.autocomplete.prototype._renderItem = function(ul, item) {
if (item.Space) {
var space_body = '';
var address2 = (item.Space.address2 != null) ? item.Space.address2 : '';
space_body = space_body + "<article><strong><a class='search-name-link' href="+base_url+"spaces/spaceDetail/"+encodeURIComponent(Base64.encode(item.Space.id))+">"+item.Space.name+"</a> - "+item.City.name+"</strong></br>"+item.Space.flat_apartment_number+", "+item.Space.address1+", "+address2+" "+item.City.name+"</article>";
console.log("In _renderItem");
return $(ul).append(space_body)
.appendTo(ul);
}
if (item.Event) {
var event_body = '';
event_body = event_body + "<article><strong><a class='search-name-link' href="+base_url+"events/eventDetail/"+encodeURIComponent(Base64.encode(item.Event.id))+">"+item.Event.event_name+"</a></strong></br>"+item.EventAddress.address+" "+item.City.name+"</article>";
return $(ul).append(event_body)
.appendTo(ul);
}
if (!item.Space && !item.Event) {
return $(ul).append("<article class='no-search'>No records found. <b><a href='javascript:void(0)' class='search-not-found'>Click here</a></b> to get notification for your keyword.</article>")
.appendTo(ul);
}
}
From my limited understanding of JQuery Widgets :
For each result received we are appending to a ul and calling renderItemData which in turn calls the renderItem
I am unable to understand which 'value' is the code referring to.

Jquery autocomplete with multiple values from remote JSON

I want to select multiple values by using the autocomplete()-plugin. The values I do receive from a remote JSON file. So far I can get 1 value but after that it fails. My goal is to select multiple values and store the ID, so I can post the values later on.
So far I have:
<input type="text" id="featured" autocomplete="on"></input>
<input type="hidden" value="" name="artist_id">
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$("#featured").bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB && $( this ).autocomplete( "instance" ).menu.active ) {
event.preventDefault();
}}).autocomplete({
minLength: 0,
source: function( request, response ) {
$.ajax({
url: App.APIO+'/i/search/artist?name='+request.term+'&featured=true',
dataType: "json",
success: function(data) {
var result = $.map(data.data, function(artist) {
return {value: artist.name, label: artist.name, artist_id: artist.artist_id};
});
response( result );
}
});
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
var item = split( this.value );
// remove the current input
item.pop();
// add the selected item
item.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
item.push( "" );
this.value = item.join( ", " );
return false;
$('[name="artist_id"]').val(ui.item.artist_id); // somehow insert the artist_id here
}
});
Right now I can only enter 1 value and select it, so that it for example displays "Lady Gaga, " but after that I cant enter anything e.g nothing happens. I can see in my network tab that it tries to load
/artist?name=ladygaga%20%b&featured=true
if I forexample type "b" after selecting the first value...
So what am I doing wrong and can someone help me out please...
//At first, Fill in the variable "sourceList" with the json data
var sourceList = $.ajax //to fetch the data
//Create a global variable for accessing the selected values
var selectedItems= [];
//Define the multiselect autocomplete textbox as below :
$("#inputID")
.bind("keydown", function(event) {// don't navigate away from the field on tab when selecting an item
if (event.keyCode === $.ui.keyCode.TAB && $(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
})
.bind("blur", function(event) {
//var $autoCompleteInstance = $(this).autocomplete("instance");
var selectedObjects = [], currentText = $(this).html();
//if ($autoCompleteInstance.term !== undefined && $autoCompleteInstance.term !== "") {
if (currentText !== undefined && currentText !== "") {
$.each(currentText.split(","), function(index, currentValue) {
var temp = $.grep(sourceList, function(current) {
return current.name === currentValue.trim();
});
$.merge(selectedObjects, temp);
});
selectedItems = selectedObjects;
var valueField = [], textField = [];
$.each(selectedItems, function(i, e) { valueField.push(e.valueField) }); //Resource_Id
$.each(selectedItems, function(i, e) { textField.push(e.textField) });
this.value = valueField.join(", ");
$(this).attr("value", valueField.join(", "));
this.innerHTML = textField.length > 0 ? textField.join(", ") + ", " : "";
}
else {
this.innerHTML = this.value = ""; $(this).attr("value", "");
selectedItems = [];
}
})
.autocomplete({
minLength: 0,
source: function(request, response) {
// delegate back to autocomplete, but extract the last term
response($.ui.autocomplete.filter(sourceList, extractLast(request.term)));
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
selectedItems.push(ui.item);
var valueField = [], textField = [];
$.each(selectedItems, function(i, e) { valueField.push(e.valueField) }); //Resource_Id
$.each(selectedItems, function(i, e) { textField.push(e.textField) });
this.value = valueField.join(", ");
$(this).attr("value", valueField.join(", "));
this.innerHTML = textField.join(", ") + ", ";
event.preventDefault();
$(this).focus();
placeCaretAtEnd(document.getElementById("attendees"));
//return false;
}
})
.data("ui-autocomplete")._renderItem = function(ul, value) {
return $("<li></li>").data("item.autocomplete", value).append('<span value=' + value.ValueField + '>' + value.TextField + '</span>').appendTo(ul); //Resource_Id
};
Hope this helps :)

Lost in a sea of nodes

I have a function that is supposed to duplicate a form and clear it out. It's clearing everything except checkboxes. Why is this? http://jsfiddle.net/GM2GN/1/
function addForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
// You can only submit a maximum of 10 todo items
if (formCount < 100) {
// Clone a form (without event handlers) from the first form
var row = $(".item:first").clone(false).get(0);
// Insert it after the last form
$(row).removeAttr('id').hide().insertAfter(".item:last").slideDown(300);
// Remove the bits we don't want in the new row/form
// e.g. error messages
$(".errorlist", row).remove();
$(row).children().removeClass("error");
// Relabel or rename all the relevant bits
$(row).children().children().children().children().each(function () {
updateElementIndex(this, prefix, formCount);
$(this).val("");
});
// Add an event handler for the delete item/form link
$(row).find(".delete").click(function () {
return deleteForm(this, prefix);
});
// Update the total form count
$("#id_" + prefix + "-TOTAL_FORMS").val(formCount + 1);
} // End if
else {
alert("Sorry, you can only enter a maximum of 100 items.");
}
return false;
}
// Register the click event handlers
$("#add").click(function () {
return addForm(this, "form");
});
Different from other input elements like text input, changing the checkbox value does not change the 'checked' status. The val() only change the value of the checkbox that submits to server. to change the checked status:
checkBoxes.prop("checked", false);
Above is the complete modified code..
just check if the actual input you're resetting is a checkbox, in that case, $(this).val('') will set its value to an empty string, yet this does not remove it's "checked" property.
I've just added this check after $(this).val('') :
if ($(this).is('input[type="checkbox"]')) {
$(this).removeAttr("checked");
}
modified code:
$(document).ready(function () {
// Code adapted from http://djangosnippets.org/snippets/1389/
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+-)');
var replacement = prefix + '-' + ndx + '-';
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex,
replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function deleteForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (formCount > 1) {
$(btn).parents('.item').remove();
var forms = $('.item'); // Get all the forms
// Update the total number of forms (1 less than before)
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
var i = 0;
// Go through the forms and set their indices, names and IDs
for (formCount = forms.length; i < formCount; i++) {
$(forms.get(i)).children().children().children().children().each(function () {
if ($(this).attr('type') == 'text') updateElementIndex(this, prefix, i);
});
}
} // End if
else {
alert("You have to enter at least one student!");
}
return false;
}
function addForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
// You can only submit a maximum of 10 todo items
if (formCount < 100) {
// Clone a form (without event handlers) from the first form
var row = $(".item:first").clone(false).get(0);
// Insert it after the last form
$(row).removeAttr('id').hide().insertAfter(".item:last").slideDown(300);
// Remove the bits we don't want in the new row/form
// e.g. error messages
$(".errorlist", row).remove();
$(row).children().removeClass("error");
// Relabel or rename all the relevant bits
$(row).children().children().children().children().each(function () {
updateElementIndex(this, prefix, formCount);
$(this).val("");
if ($(this).is('input[type="checkbox"]')) {
$(this).removeAttr("checked");
}
});
// Add an event handler for the delete item/form link
$(row).find(".delete").click(function () {
return deleteForm(this, prefix);
});
// Update the total form count
$("#id_" + prefix + "-TOTAL_FORMS").val(formCount + 1);
} // End if
else {
alert("Sorry, you can only enter a maximum of 100 items.");
}
return false;
}
// Register the click event handlers
$("#add").click(function () {
return addForm(this, "form");
});
$(".delete").click(function () {
return deleteForm(this, "form");
});
});

Multiple jQuery UI mentions autocomplete on the one page

I am having trouble getting multiple mentions autocomplete to work #mention - similar to FB etc.
I have looked on SO and found some good examples on doing a basic mentions autocomplete and have based mine on one, namely:
https://stackoverflow.com/a/17048788/2981412
I am however needing to get it to work across MULTIPLE (....infinite) textareas on the one page rather than just the one (which the above answer does well).
When I add it to more than one (using class selector, rather than ID) the additional ones do not display properly.
See my basic example with dummy data in this fiddle:
http://jsfiddle.net/yv8mn/3/
The top most textarea works fine, but the others show an empty drop down autocomplete menu.
Any ideas?
The JS...
function getCaretPosition (elem) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
elem.focus ();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange ();
// Move selection start to 0 position
oSel.moveStart ('character', -elem.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (elem.selectionStart || elem.selectionStart == '0')
iCaretPos = elem.selectionStart;
// Return results
return (iCaretPos);
}
function setCaretPosition(elem, caretPos) {
if(elem != null) {
if(elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
}
else {
if(elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else
elem.focus();
}
}
}
function getTags(term, callback) {
var data = {
tags: [
{username: 'john', count: 1}, {username: 'michael', count: 1}
]
};
callback(data);
}
$(document).ready(function() {
$(".appendedInputButton").autocomplete({
source: function(request, response) {
var term = request.term;
var pos = getCaretPosition(this.element.get(0));
var substr = term.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
if (lastIndex >= 0){
var username = substr.substr(lastIndex + 1);
if (username.length && (/^\w+$/g).test(username)){
getTags(username, function(data) {
response($.map(data.tags, function(el) {
return {
username: el.username,
count: el.count
}
}));
});
return;
}
}
response({});
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
var pos = getCaretPosition(this);
var substr = this.value.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
if (lastIndex >= 0){
var prependStr = this.value.substring(0, lastIndex);
this.value = prependStr + '#' + ui.item.username + this.value.substr(pos);
setCaretPosition(this, prependStr.length + ui.item.username.length + 1);
}
return false;
}
}).data("ui-autocomplete")._renderItem = function(ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a>" + item.username+" ("+ item.count+")</a>")
.appendTo(ul);
};
});
The dropdown menus are actually not empty, the list items are just very, very thin. Try clicking on one and you'll see that the information is inserted into the textarea.
So it seems everything works alright, except the styling for some reason.
I found the solution to my problem.
It firstly involved removing the following part of my code from the question:
.data("ui-autocomplete")._renderItem = function(ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a>" + item.username+" ("+ item.count+")</a>")
.appendTo(ul);
}
and replacing it with EITHER of these 2 solutions (both fixed it):
$.each($( "ui-autocomplete" ), function(index, item) {
$(item).data("ui-autocomplete")._renderItem = function (ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a>" + item.username+" ("+ item.count+")</a>")
.appendTo(ul);
};
});
OR
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a>" + item.username+" ("+ item.count+")</a>")
.appendTo(ul);
};
}
Which would then result in the following code (if using the initial solution):
function getCaretPosition (elem) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
elem.focus ();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange ();
// Move selection start to 0 position
oSel.moveStart ('character', -elem.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (elem.selectionStart || elem.selectionStart == '0')
iCaretPos = elem.selectionStart;
// Return results
return (iCaretPos);
}
function setCaretPosition(elem, caretPos) {
if(elem != null) {
if(elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
}
else {
if(elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else
elem.focus();
}
}
}
function getTags(term, callback) {
var data = {
tags: [
{username: 'john', count: 1}, {username: 'michael', count: 1}
]
};
callback(data);
}
$(document).ready(function() {
$(".appendedInputButton").autocomplete({
source: function(request, response) {
var term = request.term;
var pos = getCaretPosition(this.element.get(0));
var substr = term.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
if (lastIndex >= 0){
var username = substr.substr(lastIndex + 1);
if (username.length && (/^\w+$/g).test(username)){
getTags(username, function(data) {
response($.map(data.tags, function(el) {
return {
username: el.username,
count: el.count
}
}));
});
return;
}
}
response({});
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
var pos = getCaretPosition(this);
var substr = this.value.substring(0, pos);
var lastIndex = substr.lastIndexOf('#');
if (lastIndex >= 0){
var prependStr = this.value.substring(0, lastIndex);
this.value = prependStr + '#' + ui.item.username + this.value.substr(pos);
setCaretPosition(this, prependStr.length + ui.item.username.length + 1);
}
return false;
}
});
$.each($( "ui-autocomplete" ), function(index, item) {
$(item).data("ui-autocomplete")._renderItem = function (ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a>" + item.username+" ("+ item.count+")</a>")
.appendTo(ul);
};
});
});

Categories

Resources