$(document).ready(function() { $(document).on("input", ".msg-textarea-input", function() { const msg_input = $(this); clearTimeout(msg_input.data('timer')); const timer = setTimeout(() => { const parentMsg = (isMobile) ? '.l-replyItem__main' : '.l-leaveMsg__msg'; const sendBtn = msg_input.closest(parentMsg).find('.send_msg, .send_edit_msg'); const currentTags = sendBtn.data('tags') || []; if (currentTags.length >= 10) { close_tag_user(); return; } const msg_input_val = msg_input.val(); const caretPos = msg_input[0].selectionStart; const match_tag = msg_input_val.substring(0, caretPos).match(/(?:^|\s)@([^@\s\r\t\n\f]*)$/); if (match_tag == null || match_tag[1].length > 60) { close_tag_user(); return; } const coordinates = get_CaretOffest(msg_input[0], caretPos); show_taguser_list(msg_input, coordinates, match_tag[1]); }, 500); msg_input.data('timer', timer); }); $(document).on("keydown", ".msg-textarea-input", function(e) { const msg_input = $(this); const caretPos = msg_input[0].selectionStart; if (msg_input[0].selectionStart != msg_input[0].selectionEnd) { return; } if (e.key === 'Escape' && ($('.msg_taguser_list.is-active, .search_all_user_list.is-active, .tag_search_box.is-active').length)) { close_tag_user(); return; } remove_tag_info(e, msg_input, caretPos); }) $(document).on('click', function(e) { const $target = $(e.target); const isInsideList = $target.closest('.msg_taguser_list.is-active, .search_all_user_list.is-active, .tag_search_box.is-active').length > 0; if (!isInsideList) { close_tag_user(); } }) $(document).on('click', '.msg_taguser_link', function() { $(".msg_taguser_list, .search_all_user_list").removeClass('is-active'); const $this = $(this); const uid = $this.data('id'); const uname = $this.data("uname"); const parentMsg = (isMobile) ? '.l-replyItem__main' : '.l-leaveMsg__msg'; const msg_input = $this.closest(parentMsg).find('.msg-textarea-input'); const sendBtn = $this.closest(parentMsg).find('.send_msg, .send_edit_msg'); const caretPos = msg_input[0].selectionStart; const currentValue = msg_input.val(); const match_tag = currentValue.substring(0, caretPos).match(/(?:^|\s)@([^@\s\r\t\n\f]*)$/); const insertText = `@${uname} `; msg_input.val(currentValue.substring(0, caretPos - (match_tag[1].length + 1)) + insertText + currentValue.substring(caretPos)); msg_input[0].setSelectionRange(caretPos - (match_tag[1].length + 1) + insertText.length, caretPos - (match_tag[1].length + 1) + insertText.length); msg_input.focus(); let currentTags = sendBtn.data('tags') || []; const isExist = currentTags.some(function(tag) { return tag.uid === uid; }); if (!isExist) { currentTags.push({ uid: uid, uname: uname }); sendBtn.data('tags', currentTags); } }); $(document).on('click', '.tag_search_box', function() { $(".tag_search_box").removeClass('is-active'); const msg_input = $(this).siblings('.msg-textarea-input'); const msg_input_val = msg_input.val(); const caretPos = msg_input[0].selectionStart; const match_tag = msg_input_val.substring(0, caretPos).match(/(?:^|\s)@([^@\s\r\t\n\f]*)$/); if (match_tag == null || match_tag[1].length > 60) { return; } const coordinates = get_CaretOffest(msg_input[0], caretPos); show_taguser_list(msg_input, coordinates, match_tag[1], true); msg_input.focus(); }); }); function remove_tag_info(event, msg_input, caretPos) { const msg_input_val = msg_input.val(); const parentSelector = (isMobile) ? '.l-replyItem__main' : '.l-leaveMsg__msg'; const sendBtn = msg_input.closest(parentSelector).find('.send_msg, .send_edit_msg'); let currentTags = sendBtn.data('tags') || []; if (currentTags.length === 0) return; let match = null; let newText = ''; let newCaretPos = caretPos; let deletedUname = null; if (event.key === 'Backspace' && caretPos > 0) { const beforeCaret = msg_input_val.substring(0, caretPos); for (let i = 0; i < currentTags.length; i++) { const tag = currentTags[i]; const escapedUname = tag.uname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regex = new RegExp(`@${escapedUname}\\s?$`); const m = beforeCaret.match(regex); if (m) { match = m; deletedUname = tag.uname; const matchLength = match[0].length; newText = msg_input_val.substring(0, caretPos - matchLength) + msg_input_val.substring(caretPos); newCaretPos = caretPos - matchLength; break; } } } else if (event.key === 'Delete' && caretPos < msg_input_val.length) { const afterCaret = msg_input_val.substring(caretPos); for (let i = 0; i < currentTags.length; i++) { const tag = currentTags[i]; const escapedUname = tag.uname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regex = new RegExp(`^@${escapedUname}\\s?`); const m = afterCaret.match(regex); if (m) { match = m; deletedUname = tag.uname; const matchLength = match[0].length; newText = msg_input_val.substring(0, caretPos) + msg_input_val.substring(caretPos + matchLength); break; } } } if (!match) return; event.preventDefault(); msg_input.val(newText); msg_input[0].setSelectionRange(newCaretPos, newCaretPos); const escapedDeletedUname = deletedUname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const stillExists = new RegExp(`@${escapedDeletedUname}(?:\\s|$)`).test(newText); if (!stillExists) { currentTags = currentTags.filter(function(tag) { return tag.uname !== deletedUname; }); sendBtn.data('tags', currentTags); } } async function show_taguser_list(msg_input, coordinates, match_name, search_all_user = false) { match_name = match_name.replace(/[\s\u00A0]/g, ' '); if (msg_input.siblings('.msg_taguser_list').length == 0 || search_all_user) { const post_obj = { 'pid' : msg_input.data('pid'), 'search_all_user' : (search_all_user) ? match_name : '', } const result = await $.post('/ajax/forum/message_users.php', post_obj, null, 'json'); if (result.status === 'success' && result.data.length > 0) { let list_class = 'msg_taguser_list'; if (search_all_user) { list_class = 'search_all_user_list'; $('.search_all_user_list').remove(); } renderTagUserList(msg_input, result.data, coordinates, list_class); } else if (search_all_user && result.status === 'no data') { showTagUserEmpty(msg_input, coordinates); return; } } else { msg_input.siblings('.msg_taguser_list').addClass('is-active').css({'margin-left' : ((coordinates.width_limit) ? coordinates.left - msg_input.siblings('.msg_taguser_list .c-group__options')[0].offsetWidth + 'px' : coordinates.left + 'px')}); } if (msg_input.siblings('.msg_taguser_list').length == 0 || search_all_user) return; $('.msg_taguser_list .c-group__options').scrollTop(0); if (search_match_name(msg_input, match_name) == 0) { $(".msg_taguser_list").removeClass('is-active'); if (match_name.trim().length <= 0 || match_name.trim().length > 60) return; showSearchBox(msg_input, coordinates); } } function get_CaretOffest(element, position) { let div = document.createElement('div'); div.id = 'input-textarea-position-div'; document.body.appendChild(div); const properties = [ 'font-family', 'font-size', 'font-weight', 'letter-spacing', 'line-height', 'text-transform', 'text-indent', 'text-align', 'direction', 'white-space', 'word-spacing', 'word-wrap', 'box-sizing', 'width', 'height', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width' ]; const style = div.style; const computed = window.getComputedStyle(element); properties.forEach(prop => style[prop] = computed[prop]); div.innerHTML = element.value.substring(0, position) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'") .replace(/\n$/g, '\n ') .replace(/\r\n|\r|\n/g, '
'); var span = document.createElement('span'); span.textContent = '.'; div.appendChild(span); var coordinates = { width_limit: div.clientWidth * 0.8 - span.offsetLeft < 0, left: span.offsetLeft, }; document.body.removeChild(div); return coordinates; } function renderTagUserList(msg_input, data, coordinates, list_class) { const items = data .map( (v) => ` ${v.uname} ${v.uname} ` ) .join(''); const html = `
${items}
`; msg_input.after(html); const list = msg_input.siblings('.' + list_class); list.css({ 'margin-left': coordinates.width_limit ? coordinates.left - list.find('.c-group__options')[0].offsetWidth + 'px' : coordinates.left + 'px', }); } function showTagUserEmpty(msg_input, coordinates) { const html = `
查無此會員
`; msg_input.after(html); const empty = msg_input.siblings('.taguser_empty'); empty.css({ 'margin-left': coordinates.width_limit ? coordinates.left - empty[0].offsetWidth + 'px' : coordinates.left + 'px', }); setTimeout(() => empty.remove(), 1000); } function showSearchBox(msg_input, coordinates) { if (msg_input.siblings('.tag_search_box').length === 0) { const html = `