Skip to content

Instantly share code, notes, and snippets.

@zhephree
Created August 17, 2011 05:02
Show Gist options
  • Save zhephree/1150840 to your computer and use it in GitHub Desktop.
Save zhephree/1150840 to your computer and use it in GitHub Desktop.
AutoComplete in webOS Enyo
/*
The CSS is pretty basic. The important part is to make sure your holder DIV has the exact same font family
and font size as your Input. We can't /actually/ calculate the width of a font, so we cheat. We do this by
copying whatever text is in the Input into a hidden DIV. That Div is set to expand its width as the content
changes. We can then guess about how wide the block of text is. I set a max-width on the DIV so that it won't
push the suggestions list too far off the screen, even though we account for that in the keypress function.
*/
.holder {
position: absolute;
left: 0;
top: 0;
visibility: hidden;
pointer-events: none;
font-size: .9rem;
width: auto;
max-width: 570px;
height: auto;
}
/************************
Autocomplete in Enyo. This is a guide, not a copy-pasta chunk of code. It's to illustrate how I did it. Teach
a man to fish, etc., etc. If you use this, that's cool. Just give me a shout out somewhere. Twitter, blog,
release notes, source code, whatever.
I doubt this is the best way, and it's definitely not the only way, but I figure there's some pointers that
could lead you to something cool.
************************/
/*
Add a plain old HtmlContent component to your app. It'll be hidden. We'll handle the CSS in the other file
*/
{name: "holder", kind:"HtmlContent",className:"holder"}
/*
Make sure you listen to the keypress event for your Input box. I'm watching for the @symbol for Twitter
accounts, but you could check against a space to start a new word.
You'll want a Popup component with a VirtualRepeater in it to display your results. Mine's named "autoCompleteBox"
and its VirtualRepeat is "autoCompleteList"
"publisherInput" is my Input, obviously.
*/
publisherInputKeyPress: function(inSender,event,value,d){
//handle autocomplete
var cursor=inSender.getSelection();
var leftChar=value.charAt(cursor.start); //get the character to the left of the cursor
if(leftChar=="@"){
//console.log("we're atin'");
this.atStart=cursor.start+1;
this.autoComplete=true;
}else{
if(leftChar==" " || value.indexOf("@")==-1){
//if we're starting a new word or the @ was removed, close the box
//console.log("hit a space");
this.atStart==-1;
this.autoComplete=false;
this.$.autoCompleteBox.close();
}
if(this.autoComplete){
//figure out the chunk of text to use as a search
var space=value.indexOf(" ",this.atStart);
if(space>this.atStart){
var end=space-this.atStart;
var searchString=value.substr(this.atStart,end);
}else{
var searchString=value.substr(this.atStart);
}
//console.log("search="+searchString);
var searchArray=[..]; //this would be the array of things to search. could be a DB even
//console.log(friends);
this.suggestions=[];
for(var f=0;f<searchArray.length;f++){
if(this.suggestions.length==5){
break;
}
if(searchArray.username.indexOf(searchString)>-1){ //change ">-1" to "==0" for startsWith search
this.suggestions.push(searchArray[f]);
}
}
if(this.suggestions.length>0){
//re-render the VirtualRepeater. You can figure this out
this.$.autoCompleteList.render();
//set the content of our hidden DIV to the same as our Input to measure the text width
this.$.holder.setContent(value);
//get the width of our hidden DIV
var textWidth=this.$.holder.getBounds().width;
//get the positions of our popup and the autocomplete suggestions popup
var pl=this.$.publisherPopup.getBounds();
var bl=this.$.autoCompleteBox.getBounds();
//calculate the left of the suggestions. fudge it a bit so it won't cover the cursor
var left=textWidth+pl.left+40;
var top=50;
//make sure the suggestions list stays on the screen
if((left+bl.width)>screen.width){
left=screen.width-bl.width-7;
top=100;
}
//open our suggestions list popup at the precise left
this.$.autoCompleteBox.openAtControl(inSender,{top: top,left: left});
//however, if the box is already open, we have to manually set its left
//this moves the box to the right a bit as we type
this.$.autoCompleteBox.applyStyle("left",left+"px");
}else{
//bail if autocomplete is unnecessary
this.$.autoCompleteBox.close();
}
}
}
},
//handle when an autocomplete item is tapped
suggestionSelect: function(inSender,inEvent){
var sug=inEvent.rowIndex;
var row=this.suggestions[sug];
//find the cursor position, the value of the Input, and the chunk of text we used for searching
var cursor=this.$.publisherInput.getSelection();
var value=this.$.publisherInput.getValue();
var partial=value.substring(this.atStart-1,cursor.start);
//quick and dirtily replace the @ and the chunk with the full item
this.$.publisherInput.setValue(value.replace(partial,"@"+row.username+" "));
//move the cursor to the end of the Input
var len=this.$.publisherInput.getValue().length;
this.$.publisherInput.setSelection({start:len,end:len});
//turn off autocomplete and close the list of suggestions
this.autoComplete=false;
this.$.autoCompleteBox.close();
},
@zhephree
Copy link
Author

Whoa! That's awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment