📜 ⬆️ ⬇️

RTM Context Autocomplete Menu

Once I went to rememberthemilk.com and realized that I want the same contextual autocomplete menu in my project. The result is a small jquery plugin that I want to present in this post. Works in ie6 +, opera, safari, firefox, chrome (tested in the latest versions). In short, I will tell you the essence of the "contextual" menu in the RTM-style.

This menu joins an input element, but, unlike the usual autocomplete menu, it “pops up” not for entering the entire value of an element, but for some logical part of the input field. At the same time, the menu is positioned directly below the auto-completion text. Here's what it looks like:

image
')
Project license - MIT / beerware.
Download the library with examples here: js-context-autocomplete.googlecode.com/files/js-autocomplete-v5.tar
The latest revision is collected here: svn checkout js-context-autocomplete.googlecode.com/svn/trunk js-context-autocomplete-read-only
Who is interested in participating in the project - write in a personal.
Temporary online-demo (upd)

Under the cut interesting points of implementation, a description of the functionality, examples, a list of known bugs and features for implementation.


Examples of using


var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  1. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  2. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  3. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  4. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  5. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  6. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  7. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  8. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  9. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  10. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  11. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  12. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  13. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  14. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  15. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  16. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  17. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  18. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  19. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  20. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  21. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  22. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  23. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  24. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  25. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  26. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  27. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
  28. var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .
var $input = $( '#text_input' ); // ( ) $input.autocomplete([ '' , ' ' , '' , '' , '' ]); // : // , , // , // '^something(match)$' // ( RegExp) $input.autocomplete({ '^\\d+\\s+(.*)$' : categories, '^\\d+\\s+.*?\: (.+)$' : notes, '#' : habra_tags, // # - '@' : places, // @ '!' : [ '1' , '2' , '3' ] // ! }); // : // // regex items $input_with_suffix.autocomplete([ { regex: /^\d+[.,]?\d*\s+(.*)$/, items: categories, suffix: ': ' // }, { regex: /^\d+[.,]?\d*\s+.*?: (.+)$/, items: notes } ]); * This source code was highlighted with Source Code Highlighter .


Known bugs


1. after selecting a menu item, the cursor moves to the end of the whole text, it is expected to move to the end of the inserted fragment
2. after selecting a mouse click, the input field does not receive focus back
3. short entry field and long text - menu positioning error
4. blind belief that menu items are strings (add test and cast to string)
5. autocomplete = “off” is not enabled by default (must be enabled)
6. There is no limit on the number of items displayed at the same time for too long menus.

Features for later implementation


1. ajax-loading menu items
2. complex format of menu items (emulation), add. developments
3. ability to customize the style of each menu item
4. menu dependency on third-party data (in the same element or on the page)

Why is this all about?



How it works?



Initially, I was interested in RTM autocomplete how to get the distance in pixels from the beginning of the input field to the current cursor position. That is what pushed me to start work. It turns out that this problem can be solved quite simply: it is enough to calculate the width of the hidden div, filled with text with the same style as in the menu. Unfortunately, this solution generates bug number 3, but it doesn’t really bother me so far. Maybe someone can offer a better solution?

When do we pop up?


The next interesting point is the determination of the position for which the menu should pop up. For the native RTM menu, it is common to drop out immediately after entering key characters (@ for location, # for tag, for priority, etc.), but I didn’t want to limit myself to this behavior and give freedom to show the menu for any cases: at least for input of tags separated by commas, at least some more for complex formats. This is where regular expressions come to the rescue. For each set of elements, a regular expression is assigned to which the entered string must match. When the string matches the regular expression, we display the menu starting with the first matched character in the autocomplete string. And immediately an example to understand what I mean.

Suppose we want to enter the amount in rubles and the expense item where the money was spent in the input field. In this case, we want the menu to appear after the end of the input of numbers. We write the simplest regular expression for this behavior: /^\d+\s+(.*)$/. Now when we enter a number and a space, the menu will pop up.

Complicate the situation. Suppose we have already entered a value and the menu disappeared, but then changed our mind, deleted a few characters to select another menu item. We want the menu not to appear next to the cursor, but from the beginning of the word that we are changing. To do this, in our regular expression we “catch” a word using such a construct (. *). By the way, if we wanted the menu to pop up after the first character of the word that matched, this construct would obviously have to look like (. +). Thus, it is quite simple to customize arbitrarily complex ways of menu behavior.

For those who like to break the brain over regular expressions, the problem: how to write a regular expression that would match for tags, separated by commas. So far I have been solving this problem like this:

  1. $ input_just_for_tags.autocomplete ([
  2. {
  3. // first tag (from the beginning of the line)
  4. regex: / ^ ([^,] +) $ /,
  5. items: habra_tags
  6. },
  7. {
  8. // not the first tag (what's up to the last comma before the cursor)
  9. regex: /^.*,\s+([^,,+)$,
  10. items: habra_tags
  11. }
  12. ]);
* This source code was highlighted with Source Code Highlighter .


There are options how to get by with one regular expression and satisfy the requirement that the auto-completion tag be caught in the first matched fragment?

Routine


All of the above took very little time — one evening (two to three hours). After that, it worked in FF and somehow strangely in Opera, refused to listen to the up-down-enter-esc keys in msie and webkit. And to share with the fact that I would like to have with everyone. It was also suggested that in remember them everything works the same in all browsers. So what's the problem? Tezisno:

1. key events (keypress, keydown) - very much amused how different browsers work with keyboard events. It helps it and it (9: JavaScript Events)
2. selectionStart, selectionEnd - msie does not know about this. But there is also a createRange.
3. jquery.each turned out that this wonderful method works a little differently in ie and not ie. Trifle, but this is a topic for another conversation, because I wonder why this is so, but so far there has been no chance to figure it out.

Instead of a resume


Code review required;)

Source: https://habr.com/ru/post/79134/


All Articles