mentions
by tnhu
HTML
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://unpkg.com/[email protected]/index.js"></script>
<input value="$hello} $$hello $hello${world $hello_world">
<textarea>
$hello} $$hello $hello${world $hello_world
$hello.world
${hello world}
${helloworld }
${helloworld}
${hello
$$$
$$$hello
$$${hello
${
$
$hello
abc
(\$\{?)?[_a-zA-Z][_a-zA-Z0-9.]*\}?
missing $:
\$?[{_a-zA-Z][_a-zA-Z0-9.]*\}?
with $
(\$?[{_a-zA-Z][_a-zA-Z0-9.]*\}?)|(\$)
$hello} $$hello $hello${world $hello_world
$hello.world
${hello world}
${helloworld }
</textarea>
<span id="caret"/>
CSS
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
padding: 10px;
overflow: hidden;
}
#caret {
display: inline-block;
position: absolute;
width: 5px;
height: 5px;
border-radius: 50%;
background: rgba(255, 0, 0, .4);
}
input,
textarea {
width: calc(100% - 40px);
display: block;
outline: none;
margin: 0;
padding: 4px 8px;
background: transparent;
}
textarea {
margin-top: 20px;
height: 200px;
}
JavaScript
const trigger = ['$', '${'].sort((a, b) => a.length > b.length ? -1 : 1) // Longer trigger goes first
const replacementRule = match => '${' + match + '}'
const triggerSet = new Set(trigger.join(''))
const MatchingRulesLeftRight = replacementRule('sample.text').split('sample.text')
const IdentifiersSet = /[A-Za-z0-9_.]/
var $caret = document.getElementById('caret')
function getTokens(value, atIndex) {
const valueLen = value.length
const triggerLen = trigger.length
let tokenIndex = atIndex
let tokenLen = 0
let token, word, wordLen, match = ''
while (tokenIndex--) {
const char = value[tokenIndex]
// If char is out of indentifier and trigger ranges, exit loop
if (!triggerSet.has(char) && !IdentifiersSet.test(char)) {
break
}
const copiedStr = value.substr(tokenIndex, ++tokenLen)
for (let i = 0; i < triggerLen; i++) {
if (copiedStr.indexOf(trigger[i]) === 0) {
token = copiedStr
break
}
}
if (token) {
wordLen = tokenLen
let index = tokenIndex + wordLen
while (index < valueLen) {
if (!IdentifiersSet.test(value[index])) {
if (MatchingRulesLeftRight.length === 2 && token.indexOf(MatchingRulesLeftRight[0]) === 0 && value.indexOf(MatchingRulesLeftRight[1], index) === index) {
wordLen += MatchingRulesLeftRight[1].length
}
break
}
wordLen++
index++
}
word = value.substr(tokenIndex, wordLen)
for (let i = 0; i < triggerLen; i++) {
if (word.indexOf(trigger[i]) === 0) {
match = token.substr(trigger[i].length)
break
}
}
break
}
}
return {
match,
token,
tokenIndex,
tokenLen,
word,
wordLen
}
}
function showSuggestions() {
console.log('Show suggestions...')
}
function hideSuggestions() {
console.log('Hide suggestions...')
}
function handler(e) {
const {
target: input
} = e
const nodeName...