mention-completer v1.0.8
mention-completer
A UI-platform-independent module for managing mention-like completion
Introduction
This module implements an EventEmitter object which uses provided regexes to detect and replace @username- or #hashtag-like patterns in a (platform-independent) input field. The entity it interacts with must only have a value, a selection range, and presumably its own UI with which the user may select a completion.
It exists because I found myself working with React Native, implementing the gory details of mention detection and replacement. There's no shortage of HTML-based UI widgets that implement mention detection and completion, but all I needed was a platform-independent utility that would handle the dirty work, leaving me free to hook up the rest trivially.
Installation
$ npm install mention-completerExample
For a live HTML-based example, see here. Note that the code consists almost entirely of connecting the text field.
var MentionCompleter = require('mention-completer')
var completer = new MentionCompleter({
patterns: { handle: /(@[\w]+)\b/, hashtag: /(#[\w]+)\b/ },
getSelectionRange: ...,
setSelectionRange: ...,
getValue: ...,
setValue: ...
})
completer
.on('match', function(match) {
// Trigger a remote API lookup and expose a UI element here, perhaps.
// Returns, e.g.:
// match = { value:'@usern', type:'handle', range:{start: 7, end: 13} }
})
.on('nomatch', function() {
// Hook into this event to close the menu
})
// Trigger a check when an input is modified:
$('#my-input-field').on('keyup', completer.checkForMatch.bind(completer) )
// 1) User types "hello, @usern"
//
// 2) Your code exposes a UI completion selector and calls 'replaceMatch'
// based on user input, e.g.:
//
// completer.replaceMatch( match, '@username' )
//
// 3) If setValue and setSelectionRange are provided, they are triggered
// automatically with the inserted match. Otherwise you may use the
// 'replace' event to trigger them manually.API
Constructor
MentionCompleter(options)
Constructor for a new mention completer. Note that all get/set callbacks function in receive a callback with which they must return their result using the format callback(err, result). Option parameters are:
patterns: An associative array of pattern names and regexes. Recommended patterns are:
patterns: {
handle: /(@[\w]+)\b/,
hashtag: /(#[\w]+)\b/,
}getValue:function( callback(err,value) ): A callback that queries the current text field value. It may execute the callback either synchronously or asynchronously with its resulting value.setValue:function( value )(optional): A callback that inserts the result after replacement. If provided, is triggered automatically on eachreplaceevent.getSelectionRange:function( callback(err, {start, end}) ): A callback that queries the selection range and returns a range with format{start, end}.setSelectionRange:function( {start, end} )(optional): A callback that sets the selection range. If provided, is automatically called on eachreplaceevent.
Properties
.mostRecentMatch: the most recent match. If no match is present, equal tonull.
Methods
.checkForMatch()
Check for a completable match. Uses getSelectionRange and getValue to query the range and value. Emits a match event if a match is present and nomatch otherwise. You must hook this up automatically. A simple case is:
$('#input').on('change', completer.checkForMatch.bind(completer) ).replaceMatch( {string, range: {start,end}}, text )
Replaces a match with text. The format of the first argument matches the value provided with the match event. Note that for consistency, if replaceMatch is triggered before a check resulting from new input completes, the value of the text field at the time of the check will be used. In reality, the delay to get the value and selection range is expected to be extremely short (synchronous or very nearly so) compared to the time between input events (100ms?). A simple use-case would be:
var currentMatch
mention.on('match', function(match) {
currentMatch = match
})
// Result of user action:
mention.replaceMatch(currentMatch, '@suggestedname').on(eventName, callback(data))
Along with all other EventEmitter methods, on may be used to hook into any event. Note that these events are used internally so that .off may break functionality unless only a specific callback is detached.
Events
check: Triggered just before the field is checked for a match.datacontains{value, range:{start,end}}wherevalueis the queried value of the input andrangeis the queried selection range.match: Triggered when a completable match is detected.datacontains{string, value, type, range:{start,end}}wherestringis the matched string,valueis the match captured by the regex, type is the key of the pattern that was matched, andrangecontains the integer range ofvaluewithinstring.nomatch: Triggered when no completable match is detected. Perhaps a good place to trigger closing of a suggestion menu.replace: Triggered whenreplaceWithis explicitly called.datacontains the computed replacement,{text, selectionRange:{start,end}}wheretextcontains the text with replacement, andselectionRangecontains the post-replacement selection range. If provided,setSelectionRangeandsetValuewill update the input value.error: Triggered when something goes wrong.datacontains a string message.
Testing
This module uses Standard JS style. To test, run
$ npm run testBuilding
To bundle a browserified (output in dist/bundle.js), run
$ npm install -g browserify
$ npm run bundleLicense
ISC License, (c) 2015 Ricky Reusser
