I was actually working on a prototype for displaying suggestions while you wrote text after the @ symbol, similar to nodebb. I put the document away for now, but this was the start of what I was working on :
- Code:
[panda=js]$(function(){$(function(){
if (!$.sceditor) return;
var faux = document.createElement('DIV'), l = document.createElement('DIV'), t = document.getElementById('text_editor_textarea'), sce = $(t).sceditor('instance'), txt = $('.sceditor-container textarea')[0];
// faux textarea
faux.id = 'faux-textarea';
// apply a few styles to the faux textarea so the text properties are identical
for (var style = ['margin:5px','z-index:-1','position:absolute','font-weight:normal','font-family:Verdana,Arial,Helvetica,sans-serif','font-size:13px','text-align:left','word-wrap:break-word','line-height:1.4em','visibility:hidden','overflow:auto','overflow-x:hidden'], i=0, j=style.length,p; i<j; i++) { p = style[i].split(':'); faux.style[p[0]] = p[1]; }
txt.style.wordBreak = 'break-all'; // makes line wrapping similar to the faux textarea
txt.parentNode.insertBefore(faux,txt);
// suggestion list
l.className = 'sceditor-dropdown sceditor-fontsize-picker';
l.style.height = '100px';
l.style.width = '150px';
l.style.overflow = 'auto';
l.style.overflowX = 'hidden';
l.style.display = 'none';
document.body.appendChild(l);
sce.keyUp(function(){ mentionSuggest() });
txt.onclick = mentionSuggest;
// use a named function so we can execute it on different events, such as when we click inside a mention
function mentionSuggest() {
var c = 0, v = sce.val(), s, m, pseudo, mention;
if (document.selection) {
s = document.selection.createRange();
s.moveStart('character', -txt.value.length);
c = s.text.length;
} else if (txt.selectionStart || txt.selectionStart == 0) c = txt.selectionStart;
v = v.slice(0,c) + '{FAUX_CARET}' + v.slice(c, v.length); // slice the message and insert the faux caret
// prevent HTML from formatting and replace breaks / spaces with their HTML equivalent
// also formats both the mentions and faux caret ( the mention regex needs improvements )
faux.innerHTML = v.replace(/</g,'<').replace(/>/g,'>').replace(/(@".*?"|@.*?\s|@.*?(\n|\r)|@.*?$)/g,'<a href="#">$1</a>').replace(/\n|\r/g,'<br>').replace(/\s/g,' ').replace(/<a href="#">/g,'<a href="#">').replace(/{FAUX_CARET}/,'<span id="faux_caret" style="position:absolute;margin-left:-3px;">|</span>');
faux.style.width = txt.style.width;
faux.style.height = txt.style.height;
faux.scrollTop = txt.scrollTop;
// find the faux caret's parent and check if it's an anchor
// since HTML isn't formatted it's the perfect way to identify mentions
m = document.getElementById('faux_caret').parentNode;
if (m.tagName == 'A') {
// clean the mention string so that we can use it for both replacement and queries
mention = m.innerHTML.replace(/<span.*?>\|<\/span>/,'').replace(/ /g,' ').replace(/<br>/g,''), pseudo = mention.slice(1).replace(/(^"|"$)/g,'').trim();
// sets the suggestion list position below where the mention is
l.style.left = $(m).offset().left + 'px';
l.style.top = ($(m).offset().top + 20) + 'px';
// submit a query to the memberlist page with the pseudo
pseudo.length && $.get('/memberlist?username='+encodeURIComponent(pseudo),function(d) {
var u = $('.avatar-mini a, a.gen',d);
if (!u.length) return;
l.innerHTML = '';
// loop through the results and form a list of username suggestions
for (var i=0,j=u.length,a; i<j; i++) {
a = document.createElement('A');
a.href = '#';
a.className = 'sceditor-fontsize-option';
a.innerHTML = $(u[i]).text().trim();
a.onclick = function() {
sce.focus();
// this is a little clunky at the moment, it globally replaces the mention variable with a's innerHTML
// ex : all @a will be replaced with @"Ange Tuteur"
sce.val(sce.val().replace(RegExp(mention,'g'),'@"'+$(this).text()+'"'));
l.style.display = 'none';
return false;
};
l.appendChild(a);
}
l.style.display = 'block';
});
} else l.style.display = 'none';
}
})});
It uses a faux textarea to mirror what's been written in the real textarea. I use it to format what matches a mention as an anchor so it's easy to know when the caret has entered it, and I can easily place the popup directly under the text.
It's the start of a project I haven't had time to finish, so there are no doubt a few bugs. The regexes need some improving and I haven't gotten around to adding a condition for sending AJAX requests. Anyway, it'll search the memberlist page for members who match what you've typed. If there's any matches it'll display a list like in the image I posted. Clicking any of the options will add the name to the editor, between quotes so there's no problems with mentioning members.
I originally suggested this when the mentions were first added, but no go. I figured it would be more user friendly, because honestly, Forumotion's mention system relies too much on the user knowing what a "valid" mention is.