I have been trying to write a selector function for Autocompleter.Local that will show a predefined Array and will scroll automatically to the first match. I have had success with with getting my list to populate and show all of the choices, however I cannot get it to scroll to the first match. Since I build the JS Array I can know exactly how many items are in the list going into my selector, but I don''t ever know the offset for a single <li> to be able to set the scrolling height. I am fairly certain that the onShow method is not the place to try to do it, but I haven''t had any success with any of the methods that I have tried to override either. Any solutions/insights are welcome! Here is my work in progress: <style> #auto_complete { width: 355px; height: 150px; background: #fff; overflow: auto; } #auto_complete ul { border: 1px solid #888; margin:0; padding:0; width: 98%; list-style-type:none; } #auto_complete ul li { margin:0; padding:0; } #auto_complete ul li.selected { background-color: #ffb; } #auto_complete ul strong.highlight { color: #800; margin:0; padding:0; } </style> <div id="auto_complete" style="display: none;"></div> <script type="text/javascript" language="javascript" charset="utf-8"> opts = new Array(<%= @tags.sort_by{|t| t.display_name}.collect!{|t1| ''"'' + t1.display_name + ''",''} -%>''''); // <![CDATA[ box = new Autocompleter.Local(''article_keywords'',''auto_complete'', opts , { tokens: new Array('' '','','',''\n''), /* start selector */ selector: function(instance) { var ret = []; // Beginning matches var entry = instance.getToken (); var firstMatch= -1; for (var i = 0; i < instance.options.array.length; i++) { var wasMatch = false; var elem = instance.options.array[i]; var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf(entry); while (foundPos != -1) { if (foundPos == 0 && elem.length != entry.length) { wasMatch = true; if (firstMatch < 0){ firstMatch=i; } ret.push("<li class=\"selected\"><strong>" + elem.substr(0, entry.length) + "</strong>" + elem.substr(entry.length) + "</li>"); break; } foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : elem.indexOf(entry, foundPos + 1); } if(wasMatch==false){ ret.push("<li>" + elem + "</li>"); } } instance.options.picked=firstMatch; instance.index=firstMatch; return "<ul>" + ret.join('''') + "</ul>"; } //end }); // ]]> </script> I did try to make a function that would scroll outside of the Autocompleter, but it doesn''t work based on the fact the auto_complete <div> may not be showing yet: function scrollme(box) { var topItem = Position.cumulativeOffset(box.getEntry(0)); var selItem = Position.cumulativeOffset(box.getEntry (box.index)); box.update.scrollTop=selItem[1]-(topItem[1]+15); } scrollme(box); Please help me!!! Thanks, -Steve _______________________________________________ Rails-spinoffs mailing list Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
Steve Longdo
2006-Mar-18 21:11 UTC
Re: Autocompleter.Local problem/desparate plea for help...
I''ve cleaned this up a bit, but it is still not perfect. Posting this incase a JS guru stops by and wants to show me how it could be refactored to be more...script.aculo.us or prototyp-ical :-) new Autocompleter.Local(''article_keywords'',''auto_complete'', opts , { tokens: new Array('' '','','',''\n''), /* start selector */ selector: function(instance) { var ret = []; // Beginning matches var entry = instance.getToken(); var firstMatch= -1; for (var i = 0; i < instance.options.array.length; i++) { var wasMatch = false; var elem = instance.options.array[i]; var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf(entry); while (foundPos != -1) { if (foundPos == 0 && elem.length != entry.length) { wasMatch = true; if (firstMatch < 0){ firstMatch=i; this.index=i; ret.push("<li class=\"selected\"><strong>" + elem.substr(0, entry.length) + "</strong>" + elem.substr(entry.length) + "</li>"); } else { ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + elem.substr(entry.length) + "</li>"); } break; } foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : elem.indexOf(entry, foundPos + 1); } if(wasMatch==false){ ret.push("<li>" + elem + "</li>"); } } instance.options.picked=firstMatch; return "<ul>" + ret.join('''') + "</ul>"; } //end }); Autocompleter.Local.prototype.render = function() { if(this.entryCount > 0) { //This bit is necessary to make the up/down keys work can''t remove... for (var i = 0; i < this.entryCount; i++) this.index==i ? Element.addClassName(this.getEntry(i),"selected") : Element.removeClassName(this.getEntry(i),"selected"); if(this.hasFocus) { this.show(); this.active = true; //A bit wonky calculation here, couldn''t find a way to get the offsetHeight of the LI //inside of the updated DIV because it is absolutely positioned? so I picked the below //I should be able to do it with font size (em to pixels anyone?) this.update.scrollTop=(this.options.picked * 25) + 10; } else { this.active = false; this.hide(); } } }; Thanks again for any help, -Steve http://www.stevelongdo.com On 3/17/06, Steve Longdo <steve.longdo-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > I have been trying to write a selector function for Autocompleter.Localthat will show a predefined Array and will scroll automatically to the first > match. I have had success with with getting my list to populate and show > all of the choices, however I cannot get it to scroll to the first match. > > Since I build the JS Array I can know exactly how many items are in the > list going into my selector, but I don''t ever know the offset for a single > <li> to be able to set the scrolling height. > > I am fairly certain that the onShow method is not the place to try to do > it, but I haven''t had any success with any of the methods that I have tried > to override either. > > Any solutions/insights are welcome! > > Here is my work in progress: > <style> > #auto_complete { > width: 355px; > height: 150px; > background: #fff; > overflow: auto; > } > #auto_complete ul { > border: 1px solid #888; > margin:0; > padding:0; > width: 98%; > list-style-type:none; > } > #auto_complete ul li { > margin:0; > padding:0; > } > #auto_complete ul li.selected { > background-color: #ffb; > } > #auto_complete ul strong.highlight { > color: #800; > margin:0; > padding:0; > } > </style> > <div id="auto_complete" style="display: none;"></div> > <script type="text/javascript" language="javascript" charset="utf-8"> > opts = new Array(<%= @tags.sort_by{|t| t.display_name}.collect!{|t1| ''"'' > + t1.display_name + ''",''} -%>''''); > // <![CDATA[ > box = new Autocompleter.Local(''article_keywords'',''auto_complete'', opts > , { tokens: new Array('' '','','',''\n''), > /* start selector */ > selector: function(instance) { > var ret = []; // Beginning matches > var entry = instance.getToken (); > var firstMatch= -1; > for (var i = 0; i < instance.options.array.length; i++) { > var wasMatch = false; > var elem = instance.options.array[i]; > var foundPos = instance.options.ignoreCase ? > elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf > (entry); > > while (foundPos != -1) { > if (foundPos == 0 && elem.length != entry.length) { > wasMatch = true; > if (firstMatch < 0){ > firstMatch=i; > } > ret.push("<li class=\"selected\"><strong>" + elem.substr(0, > entry.length) + "</strong>" + > elem.substr(entry.length) + "</li>"); > break; > } > > foundPos = instance.options.ignoreCase ? > elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : > elem.indexOf(entry, foundPos + 1); > } > if(wasMatch==false){ > ret.push("<li>" + elem + "</li>"); > } > } > instance.options.picked=firstMatch; > instance.index=firstMatch; > return "<ul>" + ret.join('''') + "</ul>"; > } > //end > }); > > // ]]> > </script> > > I did try to make a function that would scroll outside of the > Autocompleter, but it doesn''t work based on the fact the auto_complete <div> > may not be showing yet: > > function scrollme(box) { > var topItem = Position.cumulativeOffset(box.getEntry(0)); > var selItem = Position.cumulativeOffset(box.getEntry (box.index)); > box.update.scrollTop=selItem[1]-(topItem[1]+15); > } > scrollme(box); > > > Please help me!!! > > Thanks, > -Steve > > >_______________________________________________ Rails-spinoffs mailing list Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs