Question Questionschatbot.js

Questions :question: place them in this section
Previous topicNext topic
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/src/Template.php on line 359: Array to string conversion
Array

Topic Author
dmzx
Founder
Founder
Status: Offline
User theme: Dark
Posts: 6485
Joined: Jan 13th, '14, 20:45
    Windows 10 Chrome

chatbot.js

Post by dmzx »

Open and replace all in styles\all\template\js\chatbot.js

Code: Select all

(function() {
	'use strict';

	var STORAGE_KEY_RESULTS = 'dmzx_chatbot_conv';
	var STORAGE_KEY_QUERY = 'dmzx_chatbot_last_query';
	var STORAGE_KEY_OPEN = 'dmzx_chatbot_open'; // '1' = open, '0' = minimized
	var STORAGE_KEY_SUGGESTIONS = 'dmzx_chatbot_suggestions_cache';
	var SUGGESTIONS_TTL = 60 * 60; // seconds (1 hour)
	var HISTORY_MAX = 3;
	if (typeof dmzx_chatbot !== 'undefined' && typeof dmzx_chatbot.lastsearch_limit !== 'undefined') {
		var parsedLimit = parseInt(dmzx_chatbot.lastsearch_limit, 10);
		if (!isNaN(parsedLimit) && parsedLimit >= 0) {
			HISTORY_MAX = parsedLimit;
		}
	}

	var typingTimers = {};

	if (typeof dmzx_chatbot !== 'undefined' && (parseInt(dmzx_chatbot.enabled, 10) === 0)) {
		return;
	}

	function saveConv(conv) {
		try {
			if (!conv || !conv.length) {
				sessionStorage.removeItem(STORAGE_KEY_RESULTS);
			} else {
				sessionStorage.setItem(STORAGE_KEY_RESULTS, JSON.stringify(conv));
			}
		} catch(e){}
	}

	function loadConv() {
		try {
			var raw = sessionStorage.getItem(STORAGE_KEY_RESULTS);
			if (raw) return JSON.parse(raw);
		} catch(e){}
		return [];
	}

	function saveHistory(query) {
		try {
			if (!query) return;
			if (typeof dmzx_chatbot !== 'undefined' && parseInt(dmzx_chatbot.lastsearch_enabled, 10) === 0) {
				return;
			}
			var key = 'dmzx_chatbot_history';
			var arr = JSON.parse(localStorage.getItem(key) || '[]');
			arr = arr.filter(function(q){ return q !== query; });
			arr.unshift(query);
			if (typeof HISTORY_MAX === 'number' && HISTORY_MAX >= 0 && arr.length > HISTORY_MAX) {
				arr = arr.slice(0, HISTORY_MAX);
			}
			localStorage.setItem(key, JSON.stringify(arr));
		} catch (e) {}
	}

	function loadHistory() {
		try {
			if (typeof dmzx_chatbot !== 'undefined' && parseInt(dmzx_chatbot.lastsearch_enabled, 10) === 0) {
				return [];
			}
			var raw = localStorage.getItem('dmzx_chatbot_history');
			if (!raw) return [];
			var arr = JSON.parse(raw);
			if (!Array.isArray(arr)) return [];
			if (typeof HISTORY_MAX === 'number' && HISTORY_MAX >= 0) {
				return arr.slice(0, HISTORY_MAX);
			}
			return arr;
		} catch (e) {
			return [];
		}
	}

	function saveSuggestionsCache(items) {
		try {
			var payload = { ts: Math.floor(Date.now()/1000), items: items };
			sessionStorage.setItem(STORAGE_KEY_SUGGESTIONS, JSON.stringify(payload));
		} catch (e) {}
	}

	function loadSuggestionsCache() {
		try {
			var raw = sessionStorage.getItem(STORAGE_KEY_SUGGESTIONS);
			if (!raw) return null;
			var p = JSON.parse(raw);
			if (!p || !p.ts || !p.items) return null;
			var now = Math.floor(Date.now()/1000);
			if (now - p.ts > SUGGESTIONS_TTL) {
				sessionStorage.removeItem(STORAGE_KEY_SUGGESTIONS);
				return null;
			}
			return p.items;
		} catch (e) {
			return null;
		}
	}

	function appendUserBubble($resultsEl, text) {
		var $row = $('<div/>').addClass('dmzx-chat-row user');
		var $b = $('<div/>').addClass('dmzx-chat-bubble user').text(text);
		$row.append($b);
		$resultsEl.append($row);
		$resultsEl.scrollTop($resultsEl.prop('scrollHeight'));
	}

	function createTypingIndicator() {
		var $wrap = $('<div/>').addClass('dmzx-typing');
		var $indicator = $('<div/>').addClass('typing-indicator').attr('aria-hidden', 'true');
		$indicator.append($('<span/>').addClass('typing-dot'));
		$indicator.append($('<span/>').addClass('typing-dot'));
		$indicator.append($('<span/>').addClass('typing-dot'));
		$wrap.append($indicator);
		$wrap.append($('<div/>').text(dmzx_chatbot.lang.loading).css({marginLeft:'8px', fontSize:'12px', color:'#666'}));
		return $wrap;
	}

	function appendBotBubble($resultsEl, id, htmlOrText, isTyping) {
		var $row = $('<div/>').addClass('dmzx-chat-row bot').attr('data-bubble-id', id);
		var $b = $('<div/>').addClass('dmzx-chat-bubble bot').html(htmlOrText);
		$row.append($b);
		if (isTyping) {
			var $t = createTypingIndicator();
			$row.append($t);

			var timer = setInterval(function() {
			}, 800);
			typingTimers[id] = {
				timer: timer,
				el: $t
			};
		}
		$resultsEl.append($row);
		$resultsEl.scrollTop($resultsEl.prop('scrollHeight'));
	}

	function replaceBotBubble($resultsEl, id, newHtml) {
		var $row = $resultsEl.find('[data-bubble-id="'+id+'"]');
		if ($row.length) {
			if (typingTimers[id]) {
				try { clearInterval(typingTimers[id].timer); } catch(e){}
				try { typingTimers[id].el.remove(); } catch(e){}
				delete typingTimers[id];
			}
			$row.empty();
			var $b = $('<div/>').addClass('dmzx-chat-bubble bot').html(newHtml);
			$row.append($b);
			$resultsEl.scrollTop($resultsEl.prop('scrollHeight'));
		}
	}

	function renderThreadResultsInto($container, threads) {
		if (!threads || !threads.length) {
			$container.append($('<div/>').addClass('dmzx-chatbot-empty').text(dmzx_chatbot.lang.no_results));
			return;
		}

		function decodeEntitiesInHtml(html) {
			var tmp = document.createElement('div');
			tmp.innerHTML = html;

			var walker = document.createTreeWalker(tmp, NodeFilter.SHOW_TEXT, null, false);
			var node;
			while ((node = walker.nextNode())) {
				node.nodeValue = decodeHtmlEntities(node.nodeValue);
			}
			return tmp.innerHTML;
		}

		threads.forEach(function(t){
			var $div = $('<div/>').addClass('dmzx-chatbot-thread');

			var $a = $('<a/>')
				.addClass('dmzx-chatbot-thread-title dmzx-chatbot-link')
				.attr({ href: t.url });

			if (t.title_html) {
				var safeHtml = decodeEntitiesInHtml(t.title_html);
				$a.html(safeHtml);
			} else {
				var title = decodeHtmlEntities(t.title || '');
				title = decodeHtmlEntities(title);
				$a.text(title);
			}

			$div.append($a);

			if (t.snippet_html) {
				var $s = $('<div/>').addClass('dmzx-chatbot-snippet').html(t.snippet_html);
				$div.append($s);
			}
			$container.append($div);
		});
	}

	function renderProfileInto($container, profileObj) {
		if (!profileObj || !profileObj.profile) {
			$container.append($('<div/>').addClass('dmzx-chatbot-empty').text(dmzx_chatbot.lang.user_not_found));
			return;
		}
		var profile = profileObj.profile;
		var posts = profileObj.recent_posts || [];

		var $card = $('<div/>').addClass('dmzx-chatbot-profile');
		$card.append($('<h3/>').text(profile.username));
		$card.append($('<div/>').addClass('meta').html('Joined: ' + profile.joined + ' &nbsp; • &nbsp; Posts: ' + profile.posts + (profile.last_seen ? (' &nbsp; • &nbsp; Last seen: ' + profile.last_seen) : '')));
		$card.append($('<div/>').append($('<a/>').attr({href: profile.profile_url, class: 'dmzx-chatbot-link'}).text(dmzx_chatbot.lang.view_profile).css({'color':'#007cba'})));

		if (posts.length) {
			$card.append($('<div/>').css({marginTop:'8px', marginBottom:'4px', fontSize:'13px'}).text(dmzx_chatbot.lang.recent_posts));
			var $ul = $('<ul/>').addClass('recent').css({paddingLeft:'18px', marginTop:'6px'});
			posts.forEach(function(p){
				var $li = $('<li/>');
				var $a = $('<a/>').attr({href: p.url, class: 'dmzx-chatbot-link'}).text(p.topic_title).css({'color':'#007cba'});
				$li.append($a);
				$li.append($('<div/>').css({fontSize:'12px', color:'#444'}).text(p.snippet));
				$ul.append($li);
			});
			$card.append($ul);
		}

		$container.append($card);
	}

	function makeBubbleId() {
		return 'b_' + Math.random().toString(36).slice(2,9);
	}
	
	function decodeHtmlEntities(str) {
		if (!str || typeof str !== 'string') return str;
		var txt = document.createElement('textarea');
		txt.innerHTML = str;
		return txt.value;
	}

	function ensureHistorySlot($container) {
		var $slot = $container.find('.dmzx-history-slot');
		if ($slot.length === 0) {
			$slot = $('<div/>').addClass('dmzx-history-slot').attr('aria-hidden', 'true');
			$container.append($slot);
		}
		return $slot;
	}

	function resolveBoardFile(filename) {
		try {
			var base = (typeof dmzx_chatbot !== 'undefined' && dmzx_chatbot.board_url) ? dmzx_chatbot.board_url : (window.location.protocol + '//' + window.location.host + '/');

			try {
				base = (new URL(base, window.location.href)).href;
			} catch (e) {

			}

			base = base.replace(/[#?].*$/, '');
			base = base.replace(/\/(?:app|index)\.php(?:\/)?$/i, '/');

			if (base.charAt(base.length - 1) !== '/') {
				base += '/';
			}

			return new URL(filename, base).href;
		} catch (e) {
			try {
				return new URL(filename, window.location.href).href;
			} catch (ee) {
				return filename;
			}
		}
	}

	function renderInitialGreeting($resultsEl) {
		var text = dmzx_chatbot.lang.welcome;
		$resultsEl.find('[data-initial]').remove();
		var $row = $('<div/>').addClass('dmzx-chat-row');
		var $b = $('<div/>').addClass('dmzx-chat-bubble bot').text(text);
		$row.append($b);
		$resultsEl.append($row);
		$resultsEl.scrollTop($resultsEl.prop('scrollHeight'));
	}

	function clearConversation($resultsEl) {
		try {
			sessionStorage.removeItem(STORAGE_KEY_RESULTS);
			sessionStorage.removeItem(STORAGE_KEY_QUERY);
		} catch (e) {}
		$resultsEl.empty();
		renderInitialGreeting($resultsEl);
		$('#dmzx-chatbot-query').val('').focus();
	}

	function renderDbSuggestions($container, suggestions) {
		$container.find('.dmzx-db-suggestion').remove();

		if (!suggestions || !suggestions.length) return;

		var limit = (typeof dmzx_chatbot !== 'undefined' && dmzx_chatbot.popular_limit) ? parseInt(dmzx_chatbot.popular_limit, 10) : 3;
		var limited = suggestions.slice(0, limit);

		var $slot = ensureHistorySlot($container);
		var $label = $('<div/>').addClass('dmzx-chat-suggestion dmzx-db-suggestion').css({'background':'#fff','border':'1px solid #eee','color':'#444','cursor':'default'}).text(dmzx_chatbot.lang.popular);

		$label.insertBefore($slot);

		limited.forEach(function(s) {
			var $chip = $('<div/>').addClass('dmzx-chat-suggestion dmzx-db-suggestion').text(decodeHtmlEntities(s));
			$chip.insertBefore($slot);
		});
	}

	function renderHistoryChips($container) {
		try {
			var $slot = ensureHistorySlot($container);
			$slot.empty();

			var history = loadHistory();
			if (!history || !history.length) return;

			var $wrap = $('<div/>').addClass('dmzx-history-wrapper').css({marginTop:'6px', marginBottom:'6px'});

			var $label = $('<div/>').addClass('dmzx-history-header').text(dmzx_chatbot.lang.recent_posts).css({marginBottom:'6px'});
			$wrap.append($label);

			var $row = $('<div/>').addClass('dmzx-history-row').css({display:'flex', gap:'6px', flexWrap:'wrap'});
			history.forEach(function(q) {
				var decoded = decodeHtmlEntities(q);
				var $chip = $('<div/>').addClass('dmzx-history-chip').text(decoded).attr('data-q', q);
				$row.append($chip);
			});
			$wrap.append($row);

			$slot.append($wrap);
		} catch (e) {

		}
	}

	function suggestionsUrl(route) {
		if (route && route !== '') {
			try {
				return route.replace(/\/search(\?.*)?$/i, '/suggestions');
			} catch (e) {}
		}
		return resolveBoardFile('chatbot/suggestions');
	}

	function feedbackUrl(route) {
		if (route && route !== '') {
			try {
				return route.replace(/\/search(\?.*)?$/i, '/feedback');
			} catch (e) {}
		}
		return resolveBoardFile('chatbot/feedback');
	}

	function loadSuggestions($container, route, force) {
		force = !!force;
		var cached = loadSuggestionsCache();
		if (!force && cached) {
			renderDbSuggestions($container, cached);
			return;
		}

		var $loading = $('<div/>').addClass('dmzx-chat-suggestion dmzx-db-suggestion').text(dmzx_chatbot.lang.loading).attr('data-loading','1');
		$container.append($loading);

		var url = suggestionsUrl(route);

		$.ajax({
			url: url,
			method: 'GET',
			dataType: 'json',
			timeout: 10000,
			headers: { 'X-Requested-With': 'XMLHttpRequest' }
		}).done(function(res) {
			$container.find('[data-loading="1"]').remove();
			if (res && Array.isArray(res.suggestions) && res.suggestions.length) {
				var staticTexts = [];
				$container.find('.dmzx-chat-suggestion[data-action]').each(function(){
					staticTexts.push($(this).text().trim());
				});
				var out = [];
				res.suggestions.forEach(function(s){
					var t = decodeHtmlEntities((s || '').trim());
					if (!t) return;
					if (staticTexts.indexOf(t) !== -1) return;
					if (out.indexOf(t) === -1) out.push(t);
				});
				saveSuggestionsCache(out);
				renderDbSuggestions($container, out);
			} else {
				$container.find('[data-loading="1"]').remove();
			}
		}).fail(function() {
			$container.find('[data-loading="1"]').remove();
		});
	}

	function appendFeedbackControls($resultsEl, bubbleId, logId, route) {
		if (!logId) return;
		var $bubble = $resultsEl.find('[data-bubble-id="'+bubbleId+'"] .dmzx-chat-bubble');
		if (!$bubble.length) return;

		if ($bubble.find('.dmzx-feedback').length) return;

		var $controls = $('<div/>').addClass('dmzx-feedback');
		var $hint = $('<div/>').text(dmzx_chatbot.lang.helpful_label).css({'margin-right':'8px'});
		var $up = $('<button/>').addClass('dmzx-feedback-up').attr('title','Yes').html('👍');
		var $down = $('<button/>').addClass('dmzx-feedback-down').attr('title','No').html('👎');

		$controls.append($hint).append($up).append($down);
		$bubble.append($controls);

		var fbUrl = feedbackUrl(route);

		function sendFeedback(value, $btn) {
			$controls.find('button').prop('disabled', true);
			$.ajax({
				url: fbUrl,
				method: 'POST',
				data: { log_id: logId, value: value },
				dataType: 'json',
				timeout: 10000,
				headers: { 'X-Requested-With': 'XMLHttpRequest' }
			}).done(function(res) {
				$controls.empty().append($('<div/>').addClass('thanks').text(dmzx_chatbot.lang.thanks_feedback));
				try { sessionStorage.removeItem('dmzx_chatbot_suggestions_cache'); } catch (e) {}
			}).fail(function() {
				$controls.empty().append($('<div/>').text('Feedback failed.').css({color:'#c0392b'}));
			});
		}

		$up.on('click', function(e) {
			e.preventDefault();
			sendFeedback(1, $(this));
		});
		$down.on('click', function(e) {
			e.preventDefault();
			sendFeedback(-1, $(this));
		});
	}

	function initChatbot($) {
		var $container = $('#dmzx-chatbot-widget-container');
		$(function() {
			var $widget = $('#dmzx-chatbot-widget');
			var $minBtn = $('#dmzx-chatbot-minimized');
			var $query = $('#dmzx-chatbot-query');
			var $results = $('#dmzx-chatbot-results');
			var $submit = $('#dmzx-chatbot-submit');
			var $suggestions = $('#dmzx-chatbot-suggestions');
			var $clearConvBtn = $('#dmzx-chatbot-clear-conv');

			var route = (typeof dmzx_chatbot !== 'undefined' && dmzx_chatbot.chatbot_search_url) ? dmzx_chatbot.chatbot_search_url : '{U_CHATBOT_SEARCH}';

			try { if (typeof dmzx_chatbot === 'undefined' || parseInt(dmzx_chatbot.popular_enabled,10) === 1) { loadSuggestions($suggestions, route, false); } } catch (e) {}

			try { if (typeof dmzx_chatbot === 'undefined' || parseInt(dmzx_chatbot.lastsearch_enabled,10) === 1) { renderHistoryChips($suggestions); } } catch (e) {}

			var openState = sessionStorage.getItem(STORAGE_KEY_OPEN);
			if (openState === null) {
				sessionStorage.setItem(STORAGE_KEY_OPEN, '0');
				openState = '0';
			}
			if (openState === '1') {
				$widget.show();
				$minBtn.hide();
			} else {
				$widget.hide();
				$minBtn.show();
			}

			var conv = loadConv();
			if (conv && conv.length) {
				$results.empty();
				conv.forEach(function(item){
					if (item.role === 'user') {
						appendUserBubble($results, item.text);
					} else {
						appendBotBubble($results, item.id || makeBubbleId(), item.html || item.text, false);
					}
				});
			} else {
				if ($results.children().length === 0) {
					renderInitialGreeting($results);
				}
			}

			$container.css('visibility', 'visible');

			$suggestions.on('click', '.dmzx-history-chip', function() {
				var q = $(this).attr('data-q') || $(this).text();
				$query.val(q).focus();
			});

			$suggestions.on('click', '.dmzx-chat-suggestion', function() {
				var action = $(this).data('action');
				if (!action) {
					$query.val($(this).text()).focus();
					return;
				}
				if (action === 'faq') {
					var faqUrl = resolveBoardFile('faq.php');
					var bubbleId = makeBubbleId();
					var html = '<div><strong>' + dmzx_chatbot.lang.suggest_faq + '</strong><div style="margin-top:6px;"><a class="dmzx-chatbot-link" href="' + faqUrl + '">' + faqUrl + '</a></div></div>';
					appendBotBubble($results, bubbleId, html, false);
					conv.push({ role: 'bot', id: bubbleId, html: html });
					saveConv(conv);
					return;
				}
				if (action === 'latest') {
					var latestUrl = resolveBoardFile('search.php?search_id=newposts');
					var bubbleId2 = makeBubbleId();
					var viewNewest = dmzx_chatbot.lang.view_newest;
					var html2 = '<div><strong>' + dmzx_chatbot.lang.suggest_latest + '</strong><div style="margin-top:6px;"><a class="dmzx-chatbot-link" href="' + latestUrl + '">' + viewNewest + '</a></div></div>';
					appendBotBubble($results, bubbleId2, html2, false);
					conv.push({ role: 'bot', id: bubbleId2, html: html2 });
					saveConv(conv);
					return;
				}
				if (action === 'compose_pm') {
					var composeId = makeBubbleId();
					var composeHtml = '<div><strong>' + dmzx_chatbot.lang.compose_title + '</strong><div style="margin-top:6px;"><input class="dmzx-compose-input" type="text" placeholder="' + dmzx_chatbot.lang.compose_placeholder + '" aria-label="' + dmzx_chatbot.lang.compose_placeholder + '" /> <button class="dmzx-compose-send">' + dmzx_chatbot.lang.compose_button + '</button></div><div style="margin-top:8px;font-size:12px;color:#666;">' + dmzx_chatbot.lang.compose_title + '</div></div>';
					appendBotBubble($results, composeId, composeHtml, false);
					conv.push({ role: 'bot', id: composeId, html: composeHtml });
					saveConv(conv);
					$results.find('[data-bubble-id="'+composeId+'"] .dmzx-compose-input').focus();
					return;
				}
				$query.val($(this).text()).focus();
			});

			$results.on('click', '.dmzx-compose-send', function(e) {
				e.preventDefault();
				var $btn = $(this);
				var $bubble = $btn.closest('[data-bubble-id]');
				if (!$bubble.length) return;
				var bid = $bubble.attr('data-bubble-id');
				var recipient = $bubble.find('.dmzx-compose-input').val() || '';
				recipient = recipient.trim();
				if (!recipient) {
					replaceBotBubble($results, bid, '<div>' + dmzx_chatbot.lang.please_enter + '</div>');
					return;
				}

				replaceBotBubble($results, bid, '<div><em>' + $('<div/>').text(recipient).html() + '…</em></div>', true);

				$.ajax({
					url: (typeof dmzx_chatbot !== 'undefined' && dmzx_chatbot.chatbot_search_url) ? dmzx_chatbot.chatbot_search_url.replace(/\/search(\?.*)?$/i, '/user') : resolveBoardFile('chatbot/user'),
					method: 'GET',
					data: { username: recipient },
					dataType: 'json',
					timeout: 15000,
					headers: { 'X-Requested-With': 'XMLHttpRequest' }
				}).done(function(res) {
					if (res && res.error) {
						replaceBotBubble($results, bid, '<div><strong>' + dmzx_chatbot.lang.error_label + '</strong> ' + $('<div/>').text(res.error).html() + '</div>');
						conv.push({ role: 'bot', id: bid, text: res.error });
						saveConv(conv);
						return;
					}
					if (!res.profile || !res.profile.user_id) {
						replaceBotBubble($results, bid, '<div>' + dmzx_chatbot.lang.user_not_found + '</div>');
						conv.push({ role: 'bot', id: bid, text: 'User not found.' });
						saveConv(conv);
						return;
					}

					var uid = res.profile.user_id;
					var uname = res.profile.username;
					var composeUrl = resolveBoardFile('ucp.php?i=pm&mode=compose&u=' + encodeURIComponent(uid) + '&username=' + encodeURIComponent(uname));

					var outHtml = '<div><strong>' + $('<div/>').text(uname).html() + '</strong>';
					outHtml += '<div style="margin-top:6px;"><a class="dmzx-chatbot-link" href="' + composeUrl + '">' + dmzx_chatbot.lang.compose_open + '</a></div>';
					outHtml += '<div style="margin-top:6px;font-size:12px;color:#666;">' + dmzx_chatbot.lang.compose_title + '</div>';
					outHtml += '</div>';

					replaceBotBubble($results, bid, outHtml);
					conv.push({ role: 'bot', id: bid, html: outHtml });
					saveConv(conv);
				}).fail(function(xhr) {
					var fallbackUrl = resolveBoardFile('memberlist.php?mode=search&username=' + encodeURIComponent(recipient));
					var errHtml = '<div>' + dmzx_chatbot.lang.lookup_failed.replace('%s', '<a class="dmzx-chatbot-link" href="' + fallbackUrl + '">' + dmzx_chatbot.lang.search_memberlist + '</a>') + '</div>';
					replaceBotBubble($results, bid, errHtml);
					conv.push({ role: 'bot', id: bid, html: errHtml });
					saveConv(conv);
				}).always(function(){
					$results.scrollTop($results.prop('scrollHeight'));
				});
			});

			$results.on('keydown', '.dmzx-compose-input', function(e) {
				if (e.key === 'Enter' && !e.shiftKey) {
					e.preventDefault();
					$(this).closest('[data-bubble-id]').find('.dmzx-compose-send').trigger('click');
				}
			});

			$clearConvBtn.on('click', function(e) {
				e.preventDefault();
				clearConversation($results);
			});

			$minBtn.on('click keypress', function(e) {
				if (e.type === 'keypress' && e.which !== 13 && e.which !== 32) return;
				$widget.show();
				$minBtn.hide();
				try { sessionStorage.setItem(STORAGE_KEY_OPEN, '1'); } catch(e){}
				setTimeout(function(){ $query.focus(); }, 50);
			});

			$('#dmzx-chatbot-close').on('click', function() {
				$widget.hide();
				$minBtn.show();
				try { sessionStorage.setItem(STORAGE_KEY_OPEN, '0'); } catch (e) {}
			});

			$query.on('keydown', function(e) {
				if (e.key === 'Enter' && !e.shiftKey) {
					e.preventDefault();
					$submit.trigger('click');
				}
			});

			$submit.on('click', function(e) {
				e.preventDefault();
				e.stopPropagation();

				var userMsg = $query.val().trim();
				if (!userMsg) {
					var hintId = makeBubbleId();
					appendBotBubble($results, hintId, dmzx_chatbot.lang.please_enter);
					setTimeout(function(){
						$results.find('[data-bubble-id="'+hintId+'"]').fadeOut(400, function(){ $(this).remove(); });
					}, 1800);
					return;
				}

				appendUserBubble($results, userMsg);
				conv.push({ role: 'user', text: userMsg });
				saveConv(conv);
				$query.val('').focus();

				try { saveHistory(userMsg); renderHistoryChips($suggestions); } catch (e) {}

				var um = userMsg.match(/^\s*(?:user:|u:)\s*(.+)$/i);
				var bubbleId = makeBubbleId();
				appendBotBubble($results, bubbleId, '<em>' + dmzx_chatbot.lang.searching + '</em>', true);

				if (um) {
					var username = um[1].trim();
					if (!username) {
						replaceBotBubble($results, bubbleId, dmzx_chatbot.lang.please_enter);
						return;
					}

					$.ajax({
						url: (typeof dmzx_chatbot !== 'undefined' && dmzx_chatbot.chatbot_search_url) ? dmzx_chatbot.chatbot_search_url.replace(/\/search(\?.*)?$/i, '/user') : resolveBoardFile('chatbot/user'),
						method: 'GET',
						data: { username: username },
						dataType: 'json',
						timeout: 12000,
						headers: { 'X-Requested-With': 'XMLHttpRequest' }
					}).done(function(res) {
						if (res && res.error) {
							replaceBotBubble($results, bubbleId, '<strong>' + dmzx_chatbot.lang.error_label + '</strong> ' + $('<div/>').text(res.error).html());
							return;
						}
						if (!res || !res.profile) {
							var fallbackUrl = resolveBoardFile('memberlist.php?mode=search&username=' + encodeURIComponent(username));
							var notFoundHtml = '<div>' + dmzx_chatbot.lang.user_not_found + ' Try <a class="dmzx-chatbot-link" href="' + fallbackUrl + '">' + dmzx_chatbot.lang.search_memberlist + '</a></div>';
							replaceBotBubble($results, bubbleId, notFoundHtml);
							conv.push({ role: 'bot', id: bubbleId, html: notFoundHtml });
							saveConv(conv);
							return;
						}

						var $tmp = $('<div/>');
						renderProfileInto($tmp, res);
						replaceBotBubble($results, bubbleId, $tmp.html());

						conv.push({ role: 'bot', id: bubbleId, html: $tmp.html() });
						saveConv(conv);
					}).fail(function(xhr, status) {
						var fallbackUrl = resolveBoardFile('memberlist.php?mode=search&username=' + encodeURIComponent(username));
						var errHtml = '<div>' + dmzx_chatbot.lang.lookup_failed.replace('%s', '<a class="dmzx-chatbot-link" href="' + fallbackUrl + '">' + dmzx_chatbot.lang.search_memberlist + '</a>') + '</div>';
						replaceBotBubble($results, bubbleId, errHtml);
						conv.push({ role: 'bot', id: bubbleId, html: errHtml });
						saveConv(conv);
					}).always(function(){
						$results.scrollTop($results.prop('scrollHeight'));
					});

					return;
				}

				var postUrl = (typeof dmzx_chatbot !== 'undefined' && dmzx_chatbot.chatbot_search_url) ? dmzx_chatbot.chatbot_search_url : '{U_CHATBOT_SEARCH}';

				replaceBotBubble($results, bubbleId, '<em>' + dmzx_chatbot.lang.searching + '</em>');

				$.ajax({
					url: postUrl,
					method: 'POST',
					data: { query: userMsg },
					dataType: 'text',
					timeout: 20000,
					headers: { 'X-Requested-With': 'XMLHttpRequest' }
				}).done(function(text) {
					var res;
					try {
						res = JSON.parse(text);
					} catch (e) {
						replaceBotBubble($results, bubbleId, dmzx_chatbot.lang.invalid_json);
						return;
					}

					if (res.error) {
						replaceBotBubble($results, bubbleId, '<strong>' + dmzx_chatbot.lang.error_label + '</strong> ' + $('<div/>').text(res.error).html());
						return;
					}

					if (res.threads && res.threads.length) {
						var $tmp = $('<div/>');
						renderThreadResultsInto($tmp, res.threads);

						var foundMsg = dmzx_chatbot.lang.i_found.replace('%d', res.threads.length);
						var lead = '<div style="margin-bottom:6px;font-size:13px;color:#444;">' + foundMsg + '</div>';
						replaceBotBubble($results, bubbleId, lead + $tmp.html());

						conv.push({ role: 'bot', id: bubbleId, html: lead + $tmp.html() });
						saveConv(conv);

						try {
							if (res.log_id) {
								appendFeedbackControls($results, bubbleId, res.log_id, route);
							}
						} catch (e) {}
						try { sessionStorage.removeItem('dmzx_chatbot_suggestions_cache'); } catch (e) {}
					} else {
						var html = '';
						if (res.message) {
							html += '<div>' + $('<div/>').text(res.message).html() + '</div>';
						} else {
							html += '<div>' + dmzx_chatbot.lang.no_results + '</div>';
						}

						if (res.suggestions && Array.isArray(res.suggestions) && res.suggestions.length) {
							html += '<div style="margin-top:8px;font-size:13px;color:#333;">';
							html += '<strong>' + dmzx_chatbot.lang.popular + '</strong>';
							html += '<ul style="margin:6px 0 0 16px;padding:0;font-size:13px;color:#444;">';
							res.suggestions.forEach(function(s) {
								var t = $('<div/>').text(s.text || '').html();
								var u = s.url || '#';
								html += '<li style="margin-bottom:6px;"><a class="dmzx-chatbot-link" href="' + u + '">' + t + '</a></li>';
							});
							html += '</ul></div>';
						}

						replaceBotBubble($results, bubbleId, html);
						conv.push({ role: 'bot', id: bubbleId, html: html });
						saveConv(conv);

						try {
							if (res.log_id) {
								appendFeedbackControls($results, bubbleId, res.log_id, route);
							}
						} catch (e) {}
					}
				}).fail(function(xhr, status) {
					var body = xhr && xhr.responseText ? xhr.responseText : null;
					if (body) {
						try {
							var parsed = JSON.parse(body);
							replaceBotBubble($results, bubbleId, parsed.error || parsed.message || dmzx_chatbot.lang.request_failed.replace('%s', status));
							return;
						} catch (e) {}
					}
					replaceBotBubble($results, bubbleId, dmzx_chatbot.lang.request_failed.replace('%s', (xhr && xhr.status ? xhr.status + ' ' + xhr.statusText : status)));
				}).always(function(){
					$results.scrollTop($results.prop('scrollHeight'));
				});
			});

			$results.on('click', 'a.dmzx-chatbot-link', function(e) {
				try {
					var curQuery = $query.val() || '';
					sessionStorage.setItem(STORAGE_KEY_QUERY, curQuery);
				} catch (err) {}

				try {
					if (window.innerWidth <= 520) {
						$widget.hide();
						$minBtn.show();
						try { sessionStorage.setItem(STORAGE_KEY_OPEN, '0'); } catch (ee) {}
						$minBtn.attr('aria-pressed', 'false');
					}
				} catch (e) {

				}

			});

			$suggestions.on('dblclick', function() {
				try { if (typeof dmzx_chatbot === 'undefined' || parseInt(dmzx_chatbot.popular_enabled,10) === 1) loadSuggestions($suggestions, route, true); } catch (e) {}
			});
		});
	}

	if (typeof require === 'function') {
		try {
			require(['jquery'], initChatbot);
		} catch (e) {
			if (window.jQuery) {
				initChatbot(window.jQuery);
			} else {
				var _pollCount = 0;
				var _poll = setInterval(function() {
					_pollCount++;
					if (window.jQuery) {
						clearInterval(_poll);
						initChatbot(window.jQuery);
					} else if (_pollCount > 50) {
						clearInterval(_poll);
					}
				}, 100);
			}
		}
	} else if (window.jQuery) {
		initChatbot(window.jQuery);
	} else {
		var pollCount = 0;
		var pollInterval = setInterval(function() {
			pollCount++;
			if (window.jQuery) {
				clearInterval(pollInterval);
				initChatbot(window.jQuery);
			} else if (pollCount > 50) {
				clearInterval(pollInterval);
			}
		}, 100);
	}
})();

Previous topicNext topic