Latest topics
» Forumactif Edge - Releases
by Ange Tuteur Tue 03 Sep 2019, 11:49
» GIFActif - Giphy Button for the Editor
by Ange Tuteur Wed 08 May 2019, 17:21
» Forum Closure
by Ange Tuteur Mon 01 Jan 2018, 01:28
» Chit Chat Thread
by Valoish Sun 31 Dec 2017, 19:15
» Font/Text background color.
by Valoish Sun 31 Dec 2017, 19:11
» Forumactif Messenger - Instant Message Application for Forumotion
by Wolfuryo Sun 31 Dec 2017, 18:24
» [GAME] Count to One Million!
by brandon_g Fri 29 Dec 2017, 18:58
» Post Cards
by manikbiradar Wed 20 Dec 2017, 07:50
» [GAME] Countdown from 200,000
by Valoish Wed 13 Dec 2017, 23:22
» GeekPolice Tech Support Forums - GeekPolice.net
by Dr Jay Mon 11 Dec 2017, 19:12
» Asking about some plugin for Forumotion
by Dr Jay Mon 11 Dec 2017, 19:10
» [GAME] What are you thinking right now?
by Van-Helsing Sat 09 Dec 2017, 14:51
» Widget : Similar topics
by ranbac Wed 06 Dec 2017, 18:11
» Change the Background of the Forum and put an image and how to make prefixs?
by Clement Wed 06 Dec 2017, 15:19
» Hello from Western Australia
by SarkZKalie Wed 06 Dec 2017, 05:34
by Ange Tuteur Tue 03 Sep 2019, 11:49
» GIFActif - Giphy Button for the Editor
by Ange Tuteur Wed 08 May 2019, 17:21
» Forum Closure
by Ange Tuteur Mon 01 Jan 2018, 01:28
» Chit Chat Thread
by Valoish Sun 31 Dec 2017, 19:15
» Font/Text background color.
by Valoish Sun 31 Dec 2017, 19:11
» Forumactif Messenger - Instant Message Application for Forumotion
by Wolfuryo Sun 31 Dec 2017, 18:24
» [GAME] Count to One Million!
by brandon_g Fri 29 Dec 2017, 18:58
» Post Cards
by manikbiradar Wed 20 Dec 2017, 07:50
» [GAME] Countdown from 200,000
by Valoish Wed 13 Dec 2017, 23:22
» GeekPolice Tech Support Forums - GeekPolice.net
by Dr Jay Mon 11 Dec 2017, 19:12
» Asking about some plugin for Forumotion
by Dr Jay Mon 11 Dec 2017, 19:10
» [GAME] What are you thinking right now?
by Van-Helsing Sat 09 Dec 2017, 14:51
» Widget : Similar topics
by ranbac Wed 06 Dec 2017, 18:11
» Change the Background of the Forum and put an image and how to make prefixs?
by Clement Wed 06 Dec 2017, 15:19
» Hello from Western Australia
by SarkZKalie Wed 06 Dec 2017, 05:34
Recent Tutorials
Top posting users this month
Top Achievers
Who is online?
In total there are 61 users online :: 0 Registered, 0 Hidden and 61 Guests :: 2 Bots
None
Most users ever online was 515 on Tue 14 Sep 2021, 15:24
None
Most users ever online was 515 on Tue 14 Sep 2021, 15:24
Auto-suggest @mentions as You Type
Page 2 of 4 • Share
Page 2 of 4 • 1, 2, 3, 4
First topic message reminder :
This plugin for the editor auto-suggests you usernames while you're typing a @handle ( mention ). Clicking the suggestions or pressing enter will automatically complete the @handle so you can save time typing ! Plus to make the mentioning system more user-friendly this plugin auto-inserts quotes, so you don't have to worry about failing to tag anyone ever again !
How does it work ?
This plugin is optimized for all existing forum versions, so if you like what you hear above then it's time to move on to the installation !
Note : If you've modified the memberlist_body templates this plugin may not work for you. Please leave a reply with a link to your forum if this is the case.
To install this plugin go to Admin Panel > Modules > JavaScript codes management and create a new script with the following settings.
Title : @Mention Auto-suggest
Placement : In all the pages
Paste the following code into the textarea :
When you're finished, save the script and the auto-suggest plugin for mentions will be installed, and typing "@" should now bring up suggestions in your editor !
If you want to make any modifications to this plugin please see the following section.
Below is a list of the modifications that can be made to this plugin.
1. suggest_delay
This variable determines the delay before the editor starts searching for suggestions after typing the @ symbol. By default the delay is 0.1 seconds, if you want to change it simply modify the delay time.
2. lang
If you want to change any of the texts that appear in this plugin, find the lang object :
3. color
The last modifiable portion in this plugin is the color object :
That's all the modifications that can be made ! If you have any feedback, suggestions, or a problem with this plugin, feel free to leave a reply below. I hope this plugin makes mentioning members more easy !
This plugin for the editor auto-suggests you usernames while you're typing a @handle ( mention ). Clicking the suggestions or pressing enter will automatically complete the @handle so you can save time typing ! Plus to make the mentioning system more user-friendly this plugin auto-inserts quotes, so you don't have to worry about failing to tag anyone ever again !
Click to view demo |
How does it work ?
- Typing only the at symbol "@" in the editor will bring up a list of the recently connected users.
- Typing "@" with a letter after the symbol such as "@a" will bring up a list of users who begin with the letter "a". As you continue typing the results will narrow down !
- When the suggestion list pops up, you can move through the suggestions using the UP and DOWN arrow keys, pressing ENTER will auto-complete the @handle. You can also select mentions with the mouse.
- To cancel the suggestion list simply press the SPACE bar.
This plugin is optimized for all existing forum versions, so if you like what you hear above then it's time to move on to the installation !
Note : If you've modified the memberlist_body templates this plugin may not work for you. Please leave a reply with a link to your forum if this is the case.
Installation
To install this plugin go to Admin Panel > Modules > JavaScript codes management and create a new script with the following settings.
Title : @Mention Auto-suggest
Placement : In all the pages
Paste the following code into the textarea :
- Code:
!window.fa_mentionner && !/\/privmsg|\/profile\?mode=editprofile&page_profil=signature/.test(window.location.href) && $(function(){$(function(){
var container = $('.sceditor-container')[0],
text_editor = document.getElementById('text_editor_textarea'),
frame,
instance;
if (container && text_editor) {
frame = $('iframe', container);
instance = $(text_editor).sceditor('instance');
window.fa_mentionner = {
suggest_delay : 100, // delay before suggestions show up (100ms)
// language presets
lang : {
placeholder : 'Searching...',
not_found : 'User not found'
},
// colors of the suggestion popup
color : {
font : '#333',
hover_font : '#FFF',
error_font : '#F00',
background : '#FFF',
hover_background : '#69C',
border : '#CCC',
shadow : 'rgba(0, 0, 0, 0.176)'
},
// sceditor instance and rangeHelper
instance : instance,
rangeHelper : instance.getRangeHelper(),
// cached nodes for listening and modifications
frame : frame[0],
body : frame.contents().find('body')[0],
textarea : $('textarea', container)[0],
// faux textarea and suggestion list
faux_textarea : $('<div id="faux_text_editor" />')[0], // helps us mirror the cursor position in source mode
list : $('<div id="fa_mention_suggestions" style="position:absolute;" />')[0],
// version specific selectors
selectors : $('.bodyline')[0] ? ['a.gen[href^="/u"]', '.avatar.mini a'] :
document.getElementById('ipbwrapper') ? ['.membername', '.mini-avatar'] :
null,
// adjusts the scroll position of the faux textarea so the caret stays in line
adjustScroll : function() {
fa_mentionner.faux_textarea.scrollTop = fa_mentionner.textarea.scrollTop;
},
// updates the content in the faux textarea
updateFauxTextarea : function(active, key) {
if (key == 16) { // 16 = SHIFT
return; // return when specific keys are pressed
}
// clear suggestion queue when suggestions aren't active
if (active != true) {
fa_mentionner.clearSuggestions();
} else {
return; // return when interactive keys are pressed while suggesting ; up, down, enter
}
// use another method if in WYSIWYG mode
if (!fa_mentionner.instance.inSourceMode()) {
key != 32 ? fa_mentionner.searchWYSIWYG() : fa_mentionner.clearSuggestions();
return;
}
var val = fa_mentionner.instance.val(),
range = 0,
selection,
faux_caret,
username;
// update the textarea height and width if it's not equal
if (fa_mentionner.faux_textarea.style.height != fa_mentionner.textarea.style.height || fa_mentionner.faux_textarea.style.width != fa_mentionner.textarea.style.width) {
fa_mentionner.faux_textarea.style.height = fa_mentionner.textarea.style.height;
fa_mentionner.faux_textarea.style.width = fa_mentionner.textarea.style.width;
}
// get the position of the caret
if (document.selection) {
selection = document.selection.createRange();
selection.moveStart('character', -fa_mentionner.textarea.length);
range = selection.text.length;
} else if (fa_mentionner.textarea.selectionStart || fa_mentionner.textarea.selectionStart == 0) {
range = fa_mentionner.textarea.selectionStart;
}
// set the position of the caret
val = val.slice(0, range) + '{FAUX_CARET}' + val.slice(range, val.length);
// parse and sanitize the faux textarea content
$(fa_mentionner.faux_textarea).html(
val.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/@"(.*?)"|@(.*?)(?:\s|\r|\n|$)/g, function(M, $1, $2) {
var lastChar = M.substr(-1),
name = ($1 || $2 || '').replace(/\{FAUX_CARET\}|"/g, '');
return '<a href="#' + name + '">' + (/\s|\r|\n/.test(M) ? M.slice(0, M.length - 1) + '</a>' + lastChar : M + '</a>');
})
.replace(/\{FAUX_CARET\}/, '<span id="faux_caret" style="position:absolute;margin-left:-3px;">|</span>')
);
faux_caret = document.getElementById('faux_caret');
// mentions are parsed as <a>nchors, so when the faux caret is inside one we'll show some suggestions
if (faux_caret && faux_caret.parentNode.tagName == 'A') {
fa_mentionner.value = val;
fa_mentionner.delay = window.setTimeout(function() {
fa_mentionner.suggest(faux_caret.parentNode.href.replace(/.*?#(.*)/, '$1'), $(faux_caret).offset());
}, fa_mentionner.suggest_delay);
}
fa_mentionner.adjustScroll();
},
// search for active mentions in wysiwyg mode
searchWYSIWYG : function() {
var selected = fa_mentionner.rangeHelper.cloneSelected(),
mentions = selected.startContainer.data && selected.startContainer.data.match(/(@".*?")|(@.*?)(?:\s|\r|\n|$)/g),
offset,
offset_marker,
hit,
i;
console.log(mentions);
if (mentions && mentions[0]) {
// clean up whitespace
for (i in mentions) {
mentions[i] = mentions[i].replace(/\s$/g, '');
}
// search for the mention that's currently being modified
for (i in mentions) {
if (!fa_mentionner.wysiwyg_mentions || (mentions[i] != fa_mentionner.wysiwyg_mentions[i])) {
hit = true;
fa_mentionner.delay = window.setTimeout(function() {
fa_mentionner.rangeHelper.insertMarkers(); // insert markers to help get the caret offset
offset = $(fa_mentionner.frame).offset();
offset_marker = $('#sceditor-end-marker', fa_mentionner.body).show().offset();
// add the marker offsets to the iframe offsets
offset.left += offset_marker.left;
offset.top += offset_marker.top - fa_mentionner.body.scrollTop;
fa_mentionner.suggest(mentions[i].slice(1).replace(/^"|"$/g, ''), offset, true);
fa_mentionner.wysiwyg_active = mentions[i]; // save the active mention for later use in finish()
}, fa_mentionner.suggest_delay);
break;
}
}
// hide the suggestion list if there's no newly modified mentions
if (!hit) {
fa_mentionner.list.style.display = 'none';
fa_mentionner.focused = null;
}
fa_mentionner.wysiwyg_mentions = mentions; // update the list of mentions
}
},
// suggest a list of users based on the passed username
suggest : function(username, offset, wysiwyg) {
// insert the suggestion list to show that it's searching
fa_mentionner.list.innerHTML = '<span class="fam-info">' + fa_mentionner.lang.placeholder + '</span>';
$(fa_mentionner.list).css({
left : offset.left + 'px',
top : offset.top + 'px',
display : 'block',
overflowY : 'auto'
});
document.body.appendChild(fa_mentionner.list);
// send a query request to the memeberlist to find users who match the typed username
fa_mentionner.request = $.get('/memberlist?username=' + username, function(d) {
fa_mentionner.request = null;
var suggestion = $(fa_mentionner.selectors ? fa_mentionner.selectors[0] : '.avatar-mini a', d),
ava = fa_mentionner.selectors ? $(fa_mentionner.selectors[1], d) : null,
i = 0,
j = suggestion.length,
name;
fa_mentionner.list.innerHTML = '';
if (j) {
for (; i < j; i++) {
name = $(suggestion[i]).text().replace(/^\s+|\s+$/g, '');
fa_mentionner.list.insertAdjacentHTML('beforeend',
'<a href="javascript:fa_mentionner.finish(\'' + name.replace(/'/g, '\\\'') + '\', ' + wysiwyg + ');" class="fa_mention_suggestion">'+
'<img class="fa_suggested_avatar" src="' + $(fa_mentionner.selectors ? ava[i] : suggestion[i]).find('img').attr('src') + '"/>'+
'<span class="fa_suggested_name">' + name + '</span>'+
'</a>'
);
}
// change overflowY property when it exceeds 7 suggestions -- prevents unsightly scroll bug
fa_mentionner.list.style.overflowY = j > 7 ? 'scroll' : 'auto';
// update the focused suggestion and scroll it into view
fa_mentionner.list.firstChild.className += ' fam-focus';
fa_mentionner.focused = fa_mentionner.list.firstChild;
fa_mentionner.scrollSuggestions();
} else {
fa_mentionner.list.innerHTML = '<span class="fam-info" style="color:' + fa_mentionner.color.error_font + ';">' + fa_mentionner.lang.not_found + '</span>';
}
});
},
// kill the suggestion timeout while typing persists
clearSuggestions : function() {
if (fa_mentionner.delay) {
window.clearTimeout(fa_mentionner.delay);
fa_mentionner.delay = null;
fa_mentionner.list.style.display = 'none';
fa_mentionner.focused = null;
}
if (fa_mentionner.request) {
fa_mentionner.request.abort();
fa_mentionner.request = null;
}
},
// finish the username
finish : function(username, wysiwyg) {
var mention, index, i;
// hide and clear suggestions
fa_mentionner.clearSuggestions();
fa_mentionner.focused = null;
fa_mentionner.list.style.display = 'none';
if (!wysiwyg) {
fa_mentionner.value = fa_mentionner.value.replace(/(?:@".[^"]*?\{FAUX_CARET\}.*?"|@\{FAUX_CARET\}.*?(\s|\n|\r|$)|@.[^"\s]*?\{FAUX_CARET\}.*?(\s|\n|\r|$))/, function(M, $1, $2) {
mention = '@"' + username + '"';
return '{MENTION_POSITION}' + ( $1 ? $1 : $2 ? $2 : '' );
});
// get the index where the mention should be
index = fa_mentionner.value.indexOf('{MENTION_POSITION}');
fa_mentionner.value = fa_mentionner.value.replace('{MENTION_POSITION}', '');
// save current scroll position for application after the value has been updated
fa_mentionner.scrollIndex = fa_mentionner.textarea.scrollTop;
// update the textarea with the completed mention
fa_mentionner.instance.val('');
fa_mentionner.instance.insert(fa_mentionner.value.slice(0, index) + mention, fa_mentionner.value.slice(index, fa_mentionner.value.length));
// restore the scroll position for the textareas
fa_mentionner.textarea.scrollTop = fa_mentionner.scrollIndex;
fa_mentionner.adjustScroll();
// update the fake textarea
fa_mentionner.updateFauxTextarea();
} else {
// save the caret range in WYSIWYG so we can restore it after replacing the HTML
fa_mentionner.rangeHelper.saveRange();
fa_mentionner.body.innerHTML = fa_mentionner.body.innerHTML.replace(new RegExp(fa_mentionner.wysiwyg_active.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + '(<span.*?id="sceditor-end-marker".*?>)'), '@"' + username + '"$1');
fa_mentionner.body.focus();
fa_mentionner.rangeHelper.restoreRange();
// update the wysiwyg mention array so no new suggestions appear
for (i in fa_mentionner.wysiwyg_mentions) {
if (fa_mentionner.wysiwyg_mentions[i] == fa_mentionner.wysiwyg_active) {
fa_mentionner.wysiwyg_mentions[i] = '@"' + username + '"';
break;
}
}
}
},
// scroll the selected suggestion into view
scrollSuggestions : function() {
$(fa_mentionner.list).scrollTop(
(
$(fa_mentionner.focused).offset().top -
$(fa_mentionner.list).offset().top +
$(fa_mentionner.list).scrollTop()
) -
(26 * 3) // 26 = the height of the suggestions, so display 3 suggestions above while scrolling
);
}
};
// get computed styles for the textarea and apply them to the faux textarea
for (var css = window.getComputedStyle(fa_mentionner.textarea, null), i = 0, j = css.length, str = ''; i < j; i++) {
str += css[i] + ':' + css.getPropertyValue(css[i]) + ';';
}
// add styles to the head
$('head').append('<style type="text/css">'+
'#faux_text_editor {' + str + '}'+
'#faux_text_editor { position:absolute; left:0; bottom:0; z-index:-1; visibility:hidden; display:block; overflow-y:auto; width:100%; }'+
'#fa_mention_suggestions { color:' + fa_mentionner.color.font + '; font-size:10px; font-family:arial, verdana, sans-serif; background:' + fa_mentionner.color.background + '; border:1px solid ' + fa_mentionner.color.border + '; margin-top:20px; z-index:999; max-height:182px; overflow-x:hidden; box-shadow:0 6px 12px ' + fa_mentionner.color.shadow + '; }'+
'a.fa_mention_suggestion, .fam-info { color:' + fa_mentionner.color.font + '; height:26px; line-height:26px; padding:0 3px; display:block; white-space:nowrap; cursor:pointer; }'+
'a.fa_mention_suggestion.fam-focus { color:' + fa_mentionner.color.hover_font + '; background:' + fa_mentionner.color.hover_background + '; }'+
'.fa_suggested_avatar { height:20px; width:20px; vertical-align:middle; margin-right:3px; }'+
'a.fa_mention_suggestion, .fa_suggested_name { transition:none; }'+ // override transitions, specifically on modernbb
'</style>');
// insert faux textarea into document
fa_mentionner.textarea.parentNode.insertBefore(fa_mentionner.faux_textarea, fa_mentionner.textarea);
// apply event handlers
fa_mentionner.textarea.onclick = fa_mentionner.updateFauxTextarea;
fa_mentionner.textarea.onscroll = fa_mentionner.adjustScroll;
// update the faux textarea on keyup
fa_mentionner.instance.keyUp(function(e) {
if (fa_mentionner.focused && e && (e.keyCode == 13 || e.keyCode == 38 || e.keyCode == 40)) {
fa_mentionner.updateFauxTextarea(true, e.keyCode);
return false;
} else {
fa_mentionner.updateFauxTextarea(false, e.keyCode);
}
});
// key events for the suggested mentions
$([document, fa_mentionner.body]).on('keydown', function(e) {
var that = e.target;
if (fa_mentionner.focused && e && e.keyCode && (that.tagName == 'TEXTAREA' || that.tagName == 'BODY')) {
// move selection down
if (e.keyCode == 40) {
var next = fa_mentionner.focused.nextSibling;
if (next) {
$(fa_mentionner.focused).removeClass('fam-focus');
next.className += ' fam-focus';
fa_mentionner.focused = next;
fa_mentionner.scrollSuggestions();
}
return false;
}
// move selection up
if (e.keyCode == 38) {
var prev = fa_mentionner.focused.previousSibling;
if (prev) {
$(fa_mentionner.focused).removeClass('fam-focus');
prev.className += ' fam-focus';
fa_mentionner.focused = prev;
fa_mentionner.scrollSuggestions();
}
return false;
}
// apply selection
if (e.keyCode == 13) {
fa_mentionner.focused.click();
return false;
}
}
});
// update focused suggestion on hover
$(document).on('mouseover', function(e) {
var that = e.target;
if (/fa_mention_suggestion/.test(that.className)) {
$(fa_mentionner.focused).removeClass('fam-focus');
that.className += ' fam-focus';
fa_mentionner.focused = that;
}
});
}
})});
When you're finished, save the script and the auto-suggest plugin for mentions will be installed, and typing "@" should now bring up suggestions in your editor !
If you want to make any modifications to this plugin please see the following section.
Modifications
Below is a list of the modifications that can be made to this plugin.
1. suggest_delay
This variable determines the delay before the editor starts searching for suggestions after typing the @ symbol. By default the delay is 0.1 seconds, if you want to change it simply modify the delay time.
- Code:
suggest_delay : 100, // delay before suggestions show up (100ms)
2. lang
If you want to change any of the texts that appear in this plugin, find the lang object :
- Code:
lang : {
placeholder : 'Searching...',
not_found : 'User not found'
},
3. color
The last modifiable portion in this plugin is the color object :
- Code:
color : {
font : '#333',
hover_font : '#FFF',
error_font : '#F00',
background : '#FFF',
hover_background : '#69C',
border : '#CCC',
shadow : 'rgba(0, 0, 0, 0.176)'
},
That's all the modifications that can be made ! If you have any feedback, suggestions, or a problem with this plugin, feel free to leave a reply below. I hope this plugin makes mentioning members more easy !
Notice |
Tutorial written by Ange Tuteur. Special thanks to the Beta Testers for testing this plugin. Reproduction not permitted without consent from the author. |
Last edited by Ange Tuteur on Thu 27 Sep 2018, 10:01; edited 6 times in total
- GuestGuest
No problem. Anytime.
aha I see! Not only is it technically challenging but from what I remember, the problem faced in the making of this extension for phpBB was slow downs.
Catching and storing the name and avatar of so many members is a challenging task.
Do you think this script will be able to handle a forum with say 30-50K members?
Catching and storing the name and avatar of so many members is a challenging task.
Do you think this script will be able to handle a forum with say 30-50K members?
@Rhino.Freak I believe there may be some minor slowdowns depending on how many results are displayed per page and maybe even member count. On this forum there's 50 results on the memberlist page so that no doubt is a bit slower. These are the results I gathered from a few forums using just the "@" symbol :
1. FM Design
Results : 50
Members : 223
Response time : about 800-1000ms
2. Demoactif
Results : 10
Members : 10
Response time : about 200ms
3. Forumotion Support Forum
Results : 30
Members : 100,000+
Response time : about 600-800ms
It doesn't seem like member count has too much of an impact, although I'm certain there's at least some margin of impact. The results perpage seems to have the highest impact from what I can tell, because reducing that number does reduce the response time by a few hundred milliseconds..
1. FM Design
Results : 50
Members : 223
Response time : about 800-1000ms
2. Demoactif
Results : 10
Members : 10
Response time : about 200ms
3. Forumotion Support Forum
Results : 30
Members : 100,000+
Response time : about 600-800ms
It doesn't seem like member count has too much of an impact, although I'm certain there's at least some margin of impact. The results perpage seems to have the highest impact from what I can tell, because reducing that number does reduce the response time by a few hundred milliseconds..
- GuestGuest
Seems like that's on mobile, right?
- GuestGuest
Odd. I'm using a laptop with nearly the same screen size. I don't see any issues:
Perhaps your window isn't full size?
Perhaps your window isn't full size?
- GuestGuest
omarpop23 wrote:it's full size, my minitor is 15 inch, that's the problem
and i have on my same the problem mobile
Alright. Then we need to wait for Ange...
@omarpop23 for RTL forums ( and small screens ), try adding this CSS rule to your stylesheet :
- Code:
@media (min-width:0px) and (max-width:768px) {
#fa_mention_suggestions {
margin-left:-100px;
}
}
@mrsrz have you modified the memberlist_body template ? If so, please provide an URL to your forum. This plugin is only for the SCEditor btw.
http://musicinstant.host-es.com/
oh... I delete the template but not work this tuto..
"
Sorry for my english hahaha"
oh... I delete the template but not work this tuto..
"
Sorry for my english hahaha"
@mrsrz thanks, try using this script :
- Code:
!window.fa_mentionner && !/\/privmsg|\/profile\?mode=editprofile&page_profil=signature/.test(window.location.href) && $(function(){$(function(){
'SCEDITOR @HANDLE AUTO-SUGGEST';
'DEVELOPED BY ANGE TUTEUR';
'NO DISTRIBUTION WITHOUT CONSENT OF THE AUTHOR';
'ORIGIN : http://fmdesign.forumotion.com/t943-auto-suggest-mentions-as-you-type#19157';
var container = $('.sceditor-container')[0],
text_editor = document.getElementById('text_editor_textarea'),
frame,
instance;
if (container && text_editor) {
frame = $('iframe', container);
instance = $(text_editor).sceditor('instance');
window.fa_mentionner = {
suggest_delay : 100, // delay before suggestions show up (100ms)
// language presets
lang : {
placeholder : 'Searching...',
not_found : 'User not found'
},
// colors of the suggestion popup
color : {
font : '#333',
hover_font : '#FFF',
error_font : '#F00',
background : '#FFF',
hover_background : '#69C',
border : '#CCC',
shadow : 'rgba(0, 0, 0, 0.176)'
},
// sceditor instance and rangeHelper
instance : instance,
rangeHelper : instance.getRangeHelper(),
// cached nodes for listening and modifications
frame : frame[0],
body : frame.contents().find('body')[0],
textarea : $('textarea', container)[0],
// faux textarea and suggestion list
faux_textarea : $('<div id="faux_text_editor" />')[0], // helps us mirror the cursor position in source mode
list : $('<div id="fa_mention_suggestions" style="position:absolute;" />')[0],
// version specific selectors
selectors : $('.bodyline')[0] ? ['a.gen[href^="/u"]', '.avatar.mini a'] :
document.getElementById('ipbwrapper') ? ['.membername', '.mini-avatar'] :
null,
// adjusts the scroll position of the faux textarea so the caret stays in line
adjustScroll : function() {
fa_mentionner.faux_textarea.scrollTop = fa_mentionner.textarea.scrollTop;
},
// updates the content in the faux textarea
updateFauxTextarea : function(active, key) {
if (key == 16) { // 16 = SHIFT
return; // return when specific keys are pressed
}
// clear suggestion queue when suggestions aren't active
if (active != true) {
fa_mentionner.clearSuggestions();
} else {
return; // return when interactive keys are pressed while suggesting ; up, down, enter
}
// use another method if in WYSIWYG mode
if (!fa_mentionner.instance.inSourceMode()) {
key != 32 ? fa_mentionner.searchWYSIWYG() : fa_mentionner.clearSuggestions();
return;
}
var val = fa_mentionner.instance.val(),
range = 0,
selection,
faux_caret,
username;
// get the position of the caret
if (document.selection) {
selection = document.selection.createRange();
selection.moveStart('character', -fa_mentionner.textarea.length);
range = selection.text.length;
} else if (fa_mentionner.textarea.selectionStart || fa_mentionner.textarea.selectionStart == 0) {
range = fa_mentionner.textarea.selectionStart;
}
// set the position of the caret
val = val.slice(0, range) + '{FAUX_CARET}' + val.slice(range, val.length);
// parse and sanitize the faux textarea content
$(fa_mentionner.faux_textarea).html(
val.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/@"(.*?)"|@(.*?)(?:\s|\r|\n|$)/g, function(M, $1, $2) {
var lastChar = M.substr(-1),
name = ($1 || $2 || '').replace(/\{FAUX_CARET\}|"/g, '');
return '<a href="#' + name + '">' + (/\s|\r|\n/.test(M) ? M.slice(0, M.length - 1) + '</a>' + lastChar : M + '</a>');
})
.replace(/\{FAUX_CARET\}/, '<span id="faux_caret" style="position:absolute;margin-left:-3px;">|</span>')
);
faux_caret = document.getElementById('faux_caret');
// mentions are parsed as <a>nchors, so when the faux caret is inside one we'll show some suggestions
if (faux_caret && faux_caret.parentNode.tagName == 'A') {
fa_mentionner.value = val;
fa_mentionner.delay = window.setTimeout(function() {
fa_mentionner.suggest(faux_caret.parentNode.href.replace(/.*?#(.*)/, '$1'), $(faux_caret).offset());
}, fa_mentionner.suggest_delay);
}
fa_mentionner.adjustScroll();
},
// search for active mentions in wysiwyg mode
searchWYSIWYG : function() {
var selected = fa_mentionner.rangeHelper.cloneSelected(),
mentions = selected.startContainer.data && selected.startContainer.data.match(/(@".*?")|(@.*?)(?:\s|\r|\n|$)/g),
offset,
offset_marker,
hit,
i;
console.log(mentions);
if (mentions && mentions[0]) {
// clean up whitespace
for (i in mentions) {
mentions[i] = mentions[i].replace(/\s$/g, '');
}
// search for the mention that's currently being modified
for (i in mentions) {
if (!fa_mentionner.wysiwyg_mentions || (mentions[i] != fa_mentionner.wysiwyg_mentions[i])) {
hit = true;
fa_mentionner.delay = window.setTimeout(function() {
fa_mentionner.rangeHelper.insertMarkers(); // insert markers to help get the caret offset
offset = $(fa_mentionner.frame).offset();
offset_marker = $('#sceditor-end-marker', fa_mentionner.body).show().offset();
// add the marker offsets to the iframe offsets
offset.left += offset_marker.left;
offset.top += offset_marker.top - fa_mentionner.body.scrollTop;
fa_mentionner.suggest(mentions[i].slice(1).replace(/^"|"$/g, ''), offset, true);
fa_mentionner.wysiwyg_active = mentions[i]; // save the active mention for later use in finish()
}, fa_mentionner.suggest_delay);
break;
}
}
// hide the suggestion list if there's no newly modified mentions
if (!hit) {
fa_mentionner.list.style.display = 'none';
fa_mentionner.focused = null;
}
fa_mentionner.wysiwyg_mentions = mentions; // update the list of mentions
}
},
// suggest a list of users based on the passed username
suggest : function(username, offset, wysiwyg) {
// insert the suggestion list to show that it's searching
fa_mentionner.list.innerHTML = '<span class="fam-info">' + fa_mentionner.lang.placeholder + '</span>';
$(fa_mentionner.list).css({
left : offset.left + 'px',
top : offset.top + 'px',
display : 'block',
overflowY : 'auto'
});
document.body.appendChild(fa_mentionner.list);
// send a query request to the memeberlist to find users who match the typed username
fa_mentionner.request = $.get('/memberlist?username=' + username, function(d) {
fa_mentionner.request = null;
var suggestion = $('.avatar-mini a', d),
i = 0,
j = suggestion.length,
name;
fa_mentionner.list.innerHTML = '';
if (j) {
for (; i < j; i++) {
name = $(suggestion[i]).text().replace(/^\s+|\s+$/g, '');
fa_mentionner.list.insertAdjacentHTML('beforeend',
'<a href="javascript:fa_mentionner.finish(\'' + name.replace(/'/g, '\\\'') + '\', ' + wysiwyg + ');" class="fa_mention_suggestion">'+
'<img class="fa_suggested_avatar" src="' + $(suggestion[i]).find('img').attr('src') + '"/>'+
'<span class="fa_suggested_name">' + name + '</span>'+
'</a>'
);
}
// change overflowY property when it exceeds 7 suggestions -- prevents unsightly scroll bug
fa_mentionner.list.style.overflowY = j > 7 ? 'scroll' : 'auto';
// update the focused suggestion and scroll it into view
fa_mentionner.list.firstChild.className += ' fam-focus';
fa_mentionner.focused = fa_mentionner.list.firstChild;
fa_mentionner.scrollSuggestions();
} else {
fa_mentionner.list.innerHTML = '<span class="fam-info" style="color:' + fa_mentionner.color.error_font + ';">' + fa_mentionner.lang.not_found + '</span>';
}
});
},
// kill the suggestion timeout while typing persists
clearSuggestions : function() {
if (fa_mentionner.delay) {
window.clearTimeout(fa_mentionner.delay);
fa_mentionner.delay = null;
fa_mentionner.list.style.display = 'none';
fa_mentionner.focused = null;
}
if (fa_mentionner.request) {
fa_mentionner.request.abort();
fa_mentionner.request = null;
}
},
// finish the username
finish : function(username, wysiwyg) {
var mention, index, i;
// hide and clear suggestions
fa_mentionner.clearSuggestions();
fa_mentionner.focused = null;
fa_mentionner.list.style.display = 'none';
if (!wysiwyg) {
fa_mentionner.value = fa_mentionner.value.replace(/(?:@".[^"]*?\{FAUX_CARET\}.*?"|@\{FAUX_CARET\}.*?(\s|\n|\r|$)|@.[^"\s]*?\{FAUX_CARET\}.*?(\s|\n|\r|$))/, function(M, $1, $2) {
mention = '@"' + username + '"';
return '{MENTION_POSITION}' + ( $1 ? $1 : $2 ? $2 : '' );
});
// get the index where the mention should be
index = fa_mentionner.value.indexOf('{MENTION_POSITION}');
fa_mentionner.value = fa_mentionner.value.replace('{MENTION_POSITION}', '');
// save current scroll position for application after the value has been updated
fa_mentionner.scrollIndex = fa_mentionner.textarea.scrollTop;
// update the textarea with the completed mention
fa_mentionner.instance.val('');
fa_mentionner.instance.insert(fa_mentionner.value.slice(0, index) + mention, fa_mentionner.value.slice(index, fa_mentionner.value.length));
// restore the scroll position for the textareas
fa_mentionner.textarea.scrollTop = fa_mentionner.scrollIndex;
fa_mentionner.adjustScroll();
// update the fake textarea
fa_mentionner.updateFauxTextarea();
} else {
// save the caret range in WYSIWYG so we can restore it after replacing the HTML
fa_mentionner.rangeHelper.saveRange();
fa_mentionner.body.innerHTML = fa_mentionner.body.innerHTML.replace(new RegExp(fa_mentionner.wysiwyg_active.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + '(<span.*?id="sceditor-end-marker".*?>)'), '@"' + username + '"$1');
fa_mentionner.body.focus();
fa_mentionner.rangeHelper.restoreRange();
// update the wysiwyg mention array so no new suggestions appear
for (i in fa_mentionner.wysiwyg_mentions) {
if (fa_mentionner.wysiwyg_mentions[i] == fa_mentionner.wysiwyg_active) {
fa_mentionner.wysiwyg_mentions[i] = '@"' + username + '"';
break;
}
}
}
},
// scroll the selected suggestion into view
scrollSuggestions : function() {
$(fa_mentionner.list).scrollTop(
(
$(fa_mentionner.focused).offset().top -
$(fa_mentionner.list).offset().top +
$(fa_mentionner.list).scrollTop()
) -
(26 * 3) // 26 = the height of the suggestions, so display 3 suggestions above while scrolling
);
}
};
// get computed styles for the textarea and apply them to the faux textarea
for (var css = window.getComputedStyle(fa_mentionner.textarea, null), i = 0, j = css.length, str = ''; i < j; i++) {
str += css[i] + ':' + css.getPropertyValue(css[i]) + ';';
}
// add styles to the head
$('head').append('<style type="text/css">'+
'#faux_text_editor {' + str + '}'+
'#faux_text_editor { position:absolute; left:0; bottom:0; z-index:-1; visibility:hidden; display:block; overflow-y:auto; }'+
'#fa_mention_suggestions { color:' + fa_mentionner.color.font + '; font-size:10px; font-family:arial, verdana, sans-serif; background:' + fa_mentionner.color.background + '; border:1px solid ' + fa_mentionner.color.border + '; margin-top:20px; z-index:999; max-height:182px; overflow-x:hidden; box-shadow:0 6px 12px ' + fa_mentionner.color.shadow + '; }'+
'a.fa_mention_suggestion, .fam-info { color:' + fa_mentionner.color.font + '; height:26px; line-height:26px; padding:0 3px; display:block; white-space:nowrap; cursor:pointer; }'+
'a.fa_mention_suggestion.fam-focus { color:' + fa_mentionner.color.hover_font + '; background:' + fa_mentionner.color.hover_background + '; }'+
'.fa_suggested_avatar { height:20px; width:20px; vertical-align:middle; margin-right:3px; }'+
'</style>');
// insert faux textarea into document
fa_mentionner.textarea.parentNode.insertBefore(fa_mentionner.faux_textarea, fa_mentionner.textarea);
// apply event handlers
fa_mentionner.textarea.onclick = fa_mentionner.updateFauxTextarea;
fa_mentionner.textarea.onscroll = fa_mentionner.adjustScroll;
// update the faux textarea on keyup
fa_mentionner.instance.keyUp(function(e) {
if (fa_mentionner.focused && e && (e.keyCode == 13 || e.keyCode == 38 || e.keyCode == 40)) {
fa_mentionner.updateFauxTextarea(true, e.keyCode);
return false;
} else {
fa_mentionner.updateFauxTextarea(false, e.keyCode);
}
});
// key events for the suggested mentions
$([document, fa_mentionner.body]).on('keydown', function(e) {
var that = e.target;
if (fa_mentionner.focused && e && e.keyCode && (that.tagName == 'TEXTAREA' || that.tagName == 'BODY')) {
// move selection down
if (e.keyCode == 40) {
var next = fa_mentionner.focused.nextSibling;
if (next) {
$(fa_mentionner.focused).removeClass('fam-focus');
next.className += ' fam-focus';
fa_mentionner.focused = next;
fa_mentionner.scrollSuggestions();
}
return false;
}
// move selection up
if (e.keyCode == 38) {
var prev = fa_mentionner.focused.previousSibling;
if (prev) {
$(fa_mentionner.focused).removeClass('fam-focus');
prev.className += ' fam-focus';
fa_mentionner.focused = prev;
fa_mentionner.scrollSuggestions();
}
return false;
}
// apply selection
if (e.keyCode == 13) {
fa_mentionner.focused.click();
return false;
}
}
});
// update focused suggestion on hover
$(document).on('mouseover', function(e) {
var that = e.target;
if (/fa_mention_suggestion/.test(that.className)) {
$(fa_mentionner.focused).removeClass('fam-focus');
that.className += ' fam-focus';
fa_mentionner.focused = that;
}
});
}
})});
- TroyEccles
- Gender :
Posts : 25
Points : 3057
Reputation : 1
Language : English
Browser : Forum Version :
Works perfectly on a computer.
Works perfectly in an iPad.
Doesn't work on android phone (although it works for me on THIS site).
What could be the cause of that???
www.bellsareringing.forumotion.com
phpBB3
Works perfectly in an iPad.
Doesn't work on android phone (although it works for me on THIS site).
What could be the cause of that???
www.bellsareringing.forumotion.com
phpBB3
- SarkZKalieMember
- Gender :
Age : 33
Posts : 24
Points : 3990
Reputation : 11
Language : English
Browser : Forum Version :
After installed this plugin, i got duplicated avatar and username, then i changed some line in my heavy modified memberlist_body template. It works perfect now! :3
Thank you @Ange Tuteur!
Thank you @Ange Tuteur!
Last edited by SarkZKalie on Mon 29 Aug 2016, 12:39; edited 1 time in total
- SarkZKalieMember
- Gender :
Age : 33
Posts : 24
Points : 3990
Reputation : 11
Language : English
Browser : Forum Version :
Wow thank you @Valoish now ya here too :3
@SarkZKalie Haha yeah xD SLGray introduced me to Ange's forum and I got really into the games on here LOL. Now it's just a part of my daily routine to check up on this forum~
- Sponsored content
Page 2 of 4 • 1, 2, 3, 4
Similar topics
Create an account or log in to leave a reply
You need to be a member in order to leave a reply.
Page 2 of 4
Permissions in this forum:
You cannot reply to topics in this forum