1 /****************************************************************************** 2 * 3 * Copyright 2014-2017 Paphus Solutions Inc. 4 * 5 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.eclipse.org/legal/epl-v10.html 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /** 20 * Bot Libre open SDK. 21 * This JavaScript SDK lets you access chat bot, live chat, chatroom, forum, script, graphic, user services on 22 * the Bot Libre compatible websites, including: 23 * - Bot Libre! 24 * - Bot Libre for Business 25 * - Live Chat libre! 26 * - Forums libre! 27 * 28 * This JavaScript script can be used directly, or copied/modified on your own website. 29 * 30 * The SDK consist of two main class, SDKConnection and LiveChatConnection. 31 * 32 * SDKConnection uses AJAX calls to provide access to the libre REST API. 33 * This is used for chat bots, forums, user admin, and domains. 34 * 35 * LiveChatConnection uses web sockets to provide access to live chat and chatrooms. 36 * 37 * Version: 6.0.0-2017-10-16 38 */ 39 40 /** 41 * Static class for common util functions and static properties. 42 * @class 43 */ 44 var SDK = {}; 45 46 SDK.DOMAIN = "www.botlibre.com"; 47 SDK.NAME = "Bot Libre!"; 48 SDK.APP = ""; 49 50 SDK.DOMAIN = window.location.host; 51 SDK.APP = "/botlibre"; 52 53 SDK.PATH = "/rest/api"; 54 SDK.MAX_FILE_UPLOAD = 5000000; 55 56 SDK.host = SDK.DOMAIN; 57 SDK.app = SDK.APP; 58 SDK.scheme = 'https:' == document.location.protocol ? "https" : "http"; 59 SDK.url = SDK.scheme + "://" + SDK.DOMAIN + SDK.APP; 60 SDK.rest = SDK.url + SDK.PATH; 61 SDK.backlinkURL = SDK.url; 62 SDK.backlink = true; 63 SDK.commands = true; 64 65 /** 66 * You must set your application ID to use the SDK. 67 * You can obtain your application ID from your user page. 68 * @static 69 */ 70 SDK.applicationId = null; 71 72 /** 73 * Set the active language code. 74 * This is used for voice recognition. 75 */ 76 SDK.lang = "en"; 77 78 /** 79 * Enable debug logging. 80 * @static 81 */ 82 SDK.debug = false; 83 84 /** 85 * Escape and filter bot messages for HTML and JavaScript content for XSS security. 86 * This prevents bots sending advanced HTML and JavaScript in their messages. 87 * Set this to false to allow your bot to send JavaScript. 88 * @static 89 */ 90 SDK.secure = true; 91 92 /** 93 * Force avatars to enable or disable canvas for video (currently used only for Chrome and Firefox). 94 * @static 95 */ 96 SDK.useCanvas = null; 97 98 /** 99 * Force avatars to enable or disable video (currently disabled for Safari on iPhone). 100 * @static 101 */ 102 SDK.useVideo = null; 103 104 /** 105 * Attempt to fix grey mp4 video background (only used for Chrome). 106 * @static 107 */ 108 SDK.fixBrightness = null; 109 110 /** 111 * Attempt to fix an issue with Chrome not processing the CSS after correctly when the chat bubble resizes. 112 * @static 113 */ 114 SDK.fixChromeResizeCSS = true; 115 116 /** 117 * Set the error static field to trap or log any errors. 118 */ 119 SDK.error = function(message) { 120 console.log(message); 121 } 122 123 /** 124 * Allow our native speech API to use the third party ResponsiveVoice API. 125 * You must create an account with ResponsiveVoice to use their API, see https://responsivevoice.com 126 * @static 127 */ 128 SDK.responsiveVoice = false; 129 SDK.speechSynthesis = 'speechSynthesis' in window; 130 /** 131 * The speechRate can be set to change the native speech voice speed. 132 * It can range between 0.1 (lowest) and 10.0 (highest). 133 * 1.0 is the default rate for the current platform or voice. 134 * Other values act as a percentage relative to this, so for example 2.0 is twice as fast, 0.5 is half as fast. 135 */ 136 SDK.speechRate = null; 137 /** 138 * The speechPitch can be set to change the native speech voice pitch. 139 * It can range between 0.0 (lowest) and 2.0 (highest), with 1.0 being the default pitch for the current platform or voice. 140 */ 141 SDK.speechRate = null; 142 SDK.initResponsiveVoice = function() { 143 if (!('responsiveVoice' in window)) { 144 console.log("ResponsiveVoice missing, you must load its script first"); 145 return; 146 } 147 SDK.responsiveVoice = true; 148 SDK.speechSynthesis = true; 149 } 150 if (!('SpeechSynthesisUtterance' in window)) { 151 function SpeechSynthesisUtterance2(text) { 152 this.text = text; 153 } 154 } 155 156 SDK.currentAudio = null; 157 SDK.recognition = null; 158 SDK.recognitionActive = false; 159 SDK.backgroundAudio = null; 160 SDK.currentBackgroundAudio = null; 161 SDK.timers = {}; 162 /** 163 * Track if auto play of media is enabled in the browser (mobile Chrome/Safari) 164 * Enable or disable to force audio auto play. 165 */ 166 SDK.canPlayAudio = null; 167 /** 168 * Track if auto play of media is enabled in the browser (mobile Chrome/Safari) 169 * Enable or disable to force video auto play. 170 */ 171 SDK.canPlayVideo = true; 172 SDK.audio = null; 173 SDK.autoPlayActionAudio = null; 174 SDK.autoPlayBackgroundAudio = null; 175 SDK.autoPlayDelay = 2000; 176 /** 177 * Play the audio file given the url. 178 */ 179 SDK.play = function(file, channelaudio) { 180 SDK.pauseSpeechRecognition(); 181 var audio = null; 182 if (SDK.audio != null) { 183 audio = SDK.audio; 184 audio.pause(); 185 audio.onended = null; 186 audio.onpause = null; 187 audio.oncanplay = null; 188 audio.src = file; 189 } else { 190 audio = new Audio(file); 191 } 192 if (SDK.recognitionActive) { 193 audio.onended = function() { 194 SDK.startSpeechRecognition(); 195 if (channelaudio != false) { 196 SDK.currentAudio = null; 197 } 198 }; 199 } else if (channelaudio != false) { 200 audio.onended = function() { 201 SDK.currentAudio = null; 202 }; 203 } 204 if (SDK.canPlayAudio != true) { 205 if (!SDK.isMobile()) { 206 SDK.canPlayAudio = true; 207 } else { 208 audio.onplaying = function() { 209 SDK.canPlayAudio = true; 210 }; 211 } 212 } 213 if (channelaudio == false) { 214 audio.play(); 215 } else { 216 if (SDK.currentAudio != null && !SDK.currentAudio.ended && !SDK.currentAudio.paused) { 217 SDK.currentAudio.onpause = function() { 218 SDK.currentAudio = audio; 219 audio.play(); 220 }; 221 SDK.currentAudio.pause(); 222 } else { 223 SDK.currentAudio = audio; 224 audio.play(); 225 } 226 } 227 if (SDK.canPlayAudio == null) { 228 SDK.canPlayAudio = false; 229 /** 230 * This allows the audio to be initialized inside a button callback. 231 * This is require to auto play on mobile Chrome and Safari. 232 */ 233 setTimeout(function() { 234 if (SDK.canPlayAudio == false) { 235 SDK.initAudio = function() { 236 SDK.audio = new Audio(file); 237 SDK.currentAudio = SDK.audio; 238 SDK.currentAudio.onended = function() { 239 SDK.currentAudio = null; 240 }; 241 SDK.canPlayAudio = true; 242 SDK.audio.play(); 243 document.getElementById("sdkplaybutton").style.display = "none"; 244 } 245 var body = document.body || document.getElementsByTagName('body')[0]; 246 var playButton = document.createElement('div'); 247 var html = "<div id='sdkplaybutton' style='position:fixed;bottom:32px;left:32px;z-index:164;'><img onclick='SDK.initAudio()' width='64' src='" 248 + SDK.url + "/images/playsound.png'/></div>" 249 playButton.innerHTML = html; 250 body.appendChild(playButton); 251 setTimeout(function() { 252 document.getElementById("sdkplaybutton").style.display = "none"; 253 }, 10000); 254 } 255 }, SDK.autoPlayDelay); 256 } 257 return audio; 258 } 259 260 SDK.playChime = true; 261 /** 262 * Play the chime sound. 263 */ 264 SDK.chime = function() { 265 if (SDK.playChime) { 266 this.play(SDK.url + '/chime.mp3'); 267 SDK.playChime = false; 268 var timer = setInterval(function () { 269 SDK.playChime = true; 270 clearInterval(timer); 271 }, 1000); 272 } 273 } 274 275 /** 276 * Convert the text to speech and play it either using the browser native TTS support, or as server generated an audio file. 277 * The voice is optional and can be any voice supported by the server (see the voice page for a list of voices). 278 * For native voices a language code can be given. 279 * If the browser supports TTS the native voice will be used by default. 280 */ 281 SDK.tts = function(text, voice, native, lang, nativeVoice, mod) { 282 try { 283 if ((native || (native == null && voice == null)) && SDK.speechSynthesis) { 284 var utterance = null; 285 if ('SpeechSynthesisUtterance' in window) { 286 utterance = new SpeechSynthesisUtterance(text); 287 } else { 288 utterance = new SpeechSynthesisUtterance2(text); 289 } 290 SDK.nativeTTS(utterance, lang, nativeVoice); 291 } else { 292 var url = SDK.rest + '/form-speak?&text='; 293 url = url + encodeURIComponent(text); 294 if (voice != null) { 295 url = url + '&voice=' + voice; 296 } 297 if (mod != null) { 298 url = url + '&mod=' + mod; 299 } 300 if (SDK.applicationId != null) { 301 url = url + '&application=' + SDK.applicationId; 302 } 303 304 var request = new XMLHttpRequest(); 305 var self = this; 306 request.onreadystatechange = function() { 307 if (request.readyState != 4) return; 308 if (request.status != 200) { 309 console.log('Error: Speech web request failed'); 310 return; 311 } 312 self.play(SDK.url + "/" + request.responseText); 313 } 314 315 request.open('GET', url, true); 316 request.send(); 317 } 318 } catch (error) { 319 console.log('Error: Speech web request failed'); 320 } 321 } 322 323 /** 324 * Use the ResponsiveVoice API. 325 */ 326 SDK.responsiveVoiceTTS = function(utterance, lang, voice) { 327 var events = {}; 328 try { 329 SDK.pauseSpeechRecognition(); 330 if (voice == null || voice == "") { 331 voice = "US English Female"; 332 } 333 if (SDK.recognitionActive) { 334 events.onend = function() { 335 SDK.startSpeechRecognition(); 336 } 337 } 338 if (utterance.onend != null) { 339 events.onend = utterance.onend; 340 } 341 if (utterance.onstart != null) { 342 events.onstart = utterance.onstart; 343 } 344 responsiveVoice.speak(utterance.text, voice, events); 345 } catch (error) { 346 console.log(error); 347 } 348 } 349 350 /** 351 * Speak the native utterance first setting the voice and language. 352 */ 353 SDK.nativeTTS = function(utterance, lang, voice) { 354 if (SDK.speechRate != null) { 355 utterance.rate = SDK.speechRate; 356 } 357 if (SDK.speechPitch != null) { 358 utterance.pitch = SDK.speechPitch; 359 } 360 if (SDK.responsiveVoice) { 361 SDK.responsiveVoiceTTS(utterance, lang, voice); 362 return; 363 } 364 if (lang == null) { 365 lang = SDK.lang; 366 } 367 SDK.pauseSpeechRecognition(); 368 if (SDK.recognitionActive) { 369 utterance.addEventListener("end", function() { 370 SDK.startSpeechRecognition(); 371 }); 372 } 373 speechSynthesis.cancel(); 374 if (lang == null && voice == null) { 375 // Events don't always get fired unless this is done... 376 setTimeout(function() { 377 speechSynthesis.speak(utterance); 378 }, 100); 379 return; 380 } 381 var voices = speechSynthesis.getVoices(); 382 var foundVoice = null; 383 var foundLang = null; 384 var spoken = false; 385 if (voices.length == 0) { 386 speechSynthesis.onvoiceschanged = function() { 387 if (spoken) { 388 return; 389 } 390 voices = speechSynthesis.getVoices(); 391 for (i = 0; i < voices.length; i++) { 392 if (voice != null && (voice.length != 0) && voices[i].name.toLowerCase().indexOf(voice.toLowerCase()) != -1) { 393 if (foundVoice == null || voices[i].name == voice) { 394 foundVoice = voices[i]; 395 } 396 } else if (lang != null && (lang.length != 0) && voices[i].lang.toLowerCase().indexOf(lang.toLowerCase()) != -1) { 397 if (foundLang == null || voices[i].lang == lang) { 398 foundLang = voices[i]; 399 } 400 } 401 } 402 if (foundVoice != null) { 403 utterance.voice = foundVoice; 404 } else if (foundLang != null) { 405 utterance.voice = foundLang; 406 } 407 spoken = true; 408 setTimeout(function() { 409 speechSynthesis.speak(utterance); 410 },100); 411 }; 412 } else { 413 for (i = 0; i < voices.length; i++) { 414 if (voice != null && (voice.length != 0) && voices[i].name.toLowerCase().indexOf(voice.toLowerCase()) != -1) { 415 if (foundVoice == null || voices[i].name == voice) { 416 foundVoice = voices[i]; 417 } 418 } else if (lang != null && (lang.length != 0) && voices[i].lang.toLowerCase().indexOf(lang.toLowerCase()) != -1) { 419 if (foundLang == null || voices[i].lang == lang) { 420 foundLang = voices[i]; 421 } 422 } 423 } 424 if (foundVoice != null) { 425 utterance.voice = foundVoice; 426 } else if (foundLang != null) { 427 utterance.voice = foundLang; 428 } 429 setTimeout(function() { 430 speechSynthesis.speak(utterance); 431 },100); 432 } 433 } 434 435 /** 436 * Allow text to be translated into another language is the interface elements. 437 */ 438 SDK.translator = null; 439 SDK.translate = function(text) { 440 if (SDK.translator == null) { 441 SDK.translator = SDK.translators[SDK.lang]; 442 if (SDK.translator == null) { 443 SDK.translator = {}; 444 } 445 } 446 var translated = SDK.translator[text]; 447 if (translated != null) { 448 return translated; 449 } 450 return text 451 } 452 SDK.translators = { 453 "pt" : { 454 "Name" : "Nome", 455 "Phone" : "Telemóvel", 456 "Connect" : "Ligar" 457 } 458 } 459 460 /** 461 * Detect Chrome browser. 462 */ 463 SDK.isChrome = function() { 464 var agent = navigator.userAgent.toLowerCase() 465 return agent.indexOf('chrome') != -1 && agent.indexOf('edge') == -1; 466 } 467 468 /** 469 * Detect Firefox browser. 470 */ 471 SDK.isFirefox = function() { 472 return navigator.userAgent.toLowerCase().indexOf('firefox') != -1; 473 } 474 475 /** 476 * Detect Safari browser. 477 */ 478 SDK.isSafari = function() { 479 return navigator.userAgent.toLowerCase().indexOf('safari') != -1; 480 } 481 482 /** 483 * Detect mobile browser. 484 */ 485 SDK.isMobile = function() { 486 if (navigator.userAgent.match(/Android/i) 487 || navigator.userAgent.match(/webOS/i) 488 || navigator.userAgent.match(/iPhone/i) 489 || navigator.userAgent.match(/iPad/i) 490 || navigator.userAgent.match(/iPod/i) 491 || navigator.userAgent.match(/BlackBerry/i) 492 || navigator.userAgent.match(/Windows Phone/i)) { 493 return true; 494 } else { 495 return false; 496 } 497 } 498 499 /** 500 * Detect iPhone OS. 501 */ 502 SDK.isIPhone = function() { 503 if (navigator.userAgent.match(/iPhone/i)) { 504 return true; 505 } 506 return false; 507 } 508 509 /** 510 * Detect Mac OS. 511 */ 512 SDK.isMac = function() { 513 return navigator.platform.toLowerCase().indexOf('mac') != -1; 514 } 515 516 SDK.hd = false; 517 SDK.format = (SDK.isChrome() || SDK.isFirefox()) ? "webm" : "mp4"; 518 // Safari displays HTML5 video very poorly on iPhone. 519 if (SDK.isSafari() && SDK.isIPhone()) { 520 SDK.format = "img"; 521 } 522 523 /** 524 * Insert the text into the input field. 525 */ 526 SDK.insertAtCaret = function(element, text) { 527 if (document.selection) { 528 element.focus(); 529 var sel = document.selection.createRange(); 530 sel.text = text; 531 element.focus(); 532 } else if (element.selectionStart || element.selectionStart == 0) { 533 var startPos = element.selectionStart; 534 var endPos = element.selectionEnd; 535 var scrollTop = element.scrollTop; 536 element.value = element.value.substring(0, startPos) + text + element.value.substring(endPos, element.value.length); 537 element.focus(); 538 element.selectionStart = startPos + text.length; 539 element.selectionEnd = startPos + text.length; 540 element.scrollTop = scrollTop; 541 } else { 542 element.value += text; 543 element.focus(); 544 } 545 } 546 547 /** 548 * Fix innerHTML for IE and Safari. 549 */ 550 SDK.innerHTML = function(element) { 551 var html = element.innerHTML; 552 if (html == null) { 553 var serializer = new XMLSerializer(); 554 html = ""; 555 for (var index = 0; index < element.childNodes.length; index++) { 556 html = html + serializer.serializeToString(element.childNodes[index]); 557 } 558 } 559 var index = html.indexOf("<"); 560 var index2 = html.indexOf(">") 561 if (index != -1 && index2 > index) { 562 html = html.replace(/</g, "<"); 563 html = html.replace(/>/g, ">"); 564 } 565 if (html.indexOf("&") != -1) { 566 html = html.replace(/&/g, "&"); 567 } 568 return html; 569 } 570 571 /** 572 * Strip HTML tags from text. 573 * Return plain text. 574 */ 575 SDK.stripTags = function(html) { 576 var element = document.createElement("p"); 577 element.innerHTML = html; 578 SDK.removeTags(element); 579 return element.innerText || element.textContent; 580 } 581 582 SDK.removeTags = function(node) { 583 if (node.className == 'nospeech' || node.tagName == 'SCRIPT' || node.tagName == 'SELECT' || node.tagName == 'BUTTON' || node.tagName == 'OPTION') { 584 node.parentNode.removeChild(node); 585 } else { 586 var index = 0; 587 var childNodes = node.childNodes; 588 var children = []; 589 while (index < childNodes.length) { 590 children[index] = childNodes[index]; 591 index++; 592 } 593 var index = 0; 594 while (index < children.length) { 595 SDK.removeTags(children[index]); 596 index++; 597 } 598 } 599 return node; 600 } 601 602 /** 603 * Replace reserved HTML character with their HTML escape codes. 604 */ 605 SDK.escapeHTML = function(html) { 606 return html.replace(/&/g, "&") 607 .replace(/</g, "<") 608 .replace(/>/g, ">") 609 .replace(/"/g, """) 610 .replace(/'/g, "'"); 611 } 612 613 /** 614 * Replace URL and email references in the text with HTML links. 615 */ 616 SDK.linkURLs = function(text) { 617 var http = text.indexOf("http") != -1; 618 var www = text.indexOf("www.") != -1; 619 var email = text.indexOf("@") != -1; 620 if (!http && !www && !email) { 621 return text; 622 } 623 if (text.indexOf("<") != -1 && text.indexOf(">") != -1) { 624 return text; 625 } 626 if (http) { 627 var regex = /\b(?:https?|ftp|file):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim; 628 text = text.replace(regex, function(url, b, c) { 629 var lower = url.toLowerCase(); 630 if (lower.indexOf(".png") != -1 || lower.indexOf(".jpg") != -1 || lower.indexOf(".jpeg") != -1 || lower.indexOf(".gif") != -1) { 631 return '<a href="' + url + '" target="_blank"><img src="' + url + '" height="50"></a>'; 632 } else if (lower.indexOf(".mp4") != -1 || lower.indexOf(".webm") != -1 || lower.indexOf(".ogg") != -1) { 633 return '<a href="' + url + '" target="_blank"><video src="' + url + '" height="50"></a>'; 634 } else if (lower.indexOf(".wav") != -1 || lower.indexOf(".mp3") != -1) { 635 return '<a href="' + url + '" target="_blank"><audio src="' + url + '" controls>audio</a>'; 636 } else { 637 return '<a href="' + url + '" target="_blank">' + url + '</a>'; 638 } 639 }); 640 } else if (www) { 641 var regex = /((www\.)[^\s]+)/gim; 642 text = text.replace(regex, function(url, b, c) { 643 return '<a href="http://' + url + '" target="_blank">' + url + '</a>'; 644 }); 645 } 646 647 // http://, https://, ftp:// 648 //var urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim; 649 650 // www. 651 // var wwwPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim; 652 653 // [email protected] 654 if (email) { 655 var emailPattern = /(([a-zA-Z0-9_\-\.]+)@[a-zA-Z_]+?(?:\.[a-zA-Z]{2,6}))+/gim; 656 text = text.replace(emailPattern, '<a target="_blank" href="mailto:$1">$1</a>'); 657 } 658 return text; 659 } 660 661 /** 662 * Enable speech recognition if supported by the browser, and insert the voice to text to the input field. 663 * Optionally call click() on the button. 664 */ 665 SDK.registerSpeechRecognition = function(input, button) { 666 if (SDK.recognition == null) { 667 if ('webkitSpeechRecognition' in window) { 668 SDK.recognition = new webkitSpeechRecognition(); 669 if (SDK.lang != null) { 670 SDK.recognition.lang = SDK.lang; 671 } 672 SDK.recognition.continuous = true; 673 SDK.recognition.onresult = function (event) { 674 for (var i = event.resultIndex; i < event.results.length; ++i) { 675 if (event.results[i].isFinal) { 676 SDK.insertAtCaret(input, event.results[i][0].transcript); 677 } 678 } 679 if (button != null && button.click != null) { 680 button.click(); 681 } else if (button != null) { 682 button(); 683 } 684 }; 685 } else { 686 return; 687 } 688 } 689 } 690 691 SDK.startSpeechRecognition = function() { 692 if (SDK.recognition != null) { 693 if (SDK.lang != null) { 694 SDK.recognition.lang = SDK.lang; 695 } 696 SDK.recognition.start(); 697 SDK.recognitionActive = true; 698 } 699 } 700 701 SDK.pauseSpeechRecognition = function() { 702 if (SDK.recognition != null) { 703 SDK.recognition.stop(); 704 } 705 } 706 707 SDK.stopSpeechRecognition = function() { 708 if (SDK.recognition != null) { 709 SDK.recognition.stop(); 710 SDK.recognitionActive = false; 711 } 712 } 713 714 SDK.popupwindow = function(url, title, w, h) { 715 var left = (screen.width)-w-10; 716 var top = (screen.height)-h-100; 717 window.open(url, title, 'scrollbars=yes, resizable=yes, toolbar=no, location=no, directories=no, status=no, menubar=no, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left); 718 return false; 719 } 720 721 SDK.dataURLToBlob = function(dataURL) { 722 var marker = ';base64,'; 723 if (dataURL.indexOf(marker) == -1) { 724 var parts = dataURL.split(','); 725 var contentType = parts[0].split(':')[1]; 726 var raw = parts[1]; 727 728 return new Blob([raw], {type: contentType}); 729 } 730 731 var parts = dataURL.split(marker); 732 var contentType = parts[0].split(':')[1]; 733 var raw = window.atob(parts[1]); 734 var rawLength = raw.length; 735 736 var blobarray = new Uint8Array(rawLength); 737 738 for (var i = 0; i < rawLength; ++i) { 739 blobarray[i] = raw.charCodeAt(i); 740 } 741 742 return new Blob([blobarray], {type: contentType}); 743 } 744 745 SDK.uploadImage = function(fileInput, url, width, height, properties, onFinish) { 746 if (window.File && window.FileReader && window.FileList && window.Blob) { 747 var files = fileInput.files; 748 for (var i = 0; i < files.length; i++) { 749 SDK.resizeAndUploadImage(files[i], url, width, height, properties, ((i == (files.length - 1) ? onFinish : null))) 750 } 751 return false; 752 } else { 753 alert('The File APIs are not fully supported in this browser.'); 754 return false; 755 } 756 } 757 758 SDK.resizeAndUploadImage = function(file, url, width, height, properties, onFinish) { 759 var reader = new FileReader(); 760 reader.onloadend = function() { 761 var tempImg = new Image(); 762 tempImg.src = reader.result; 763 tempImg.onload = function() { 764 var MAX_WIDTH = width; 765 var MAX_HEIGHT = height; 766 if (width == null) { 767 MAX_WIDTH = tempImg.width; 768 } 769 if (height == null) { 770 MAX_HEIGHT = tempImg.height; 771 } 772 var tempW = tempImg.width; 773 var tempH = tempImg.height; 774 if (tempW > MAX_WIDTH) { 775 tempH *= MAX_WIDTH / tempW; 776 tempW = MAX_WIDTH; 777 } 778 if (tempH > MAX_HEIGHT) { 779 tempW *= MAX_HEIGHT / tempH; 780 tempH = MAX_HEIGHT; 781 } 782 var canvas = document.createElement('canvas'); 783 canvas.width = tempW; 784 canvas.height = tempH; 785 var ctx = canvas.getContext("2d"); 786 ctx.fillStyle = '#fff'; 787 ctx.fillRect(0, 0, canvas.width, canvas.height); 788 ctx.drawImage(this, 0, 0, tempW, tempH); 789 var dataUrl = canvas.toDataURL('image/jpeg'); 790 var blob = SDK.dataURLToBlob(dataUrl); 791 var formData = new FormData(); 792 if (properties != null) { 793 for (property in properties) { 794 formData.append(property, properties[property]); 795 } 796 } 797 formData.append('file', blob, file.name); 798 var request = new XMLHttpRequest(); 799 request.onreadystatechange = function() { 800 if (request.readyState != 4) { 801 return; 802 } 803 if (onFinish != null) { 804 onFinish(); 805 } 806 } 807 request.open("POST", url); 808 request.send(formData); 809 } 810 811 } 812 reader.readAsDataURL(file); 813 } 814 815 /** 816 * Open a JQuery error message dialog. 817 */ 818 SDK.showError = function(message, title) { 819 if (title == null) { 820 title = "Error"; 821 } 822 $("<div></div>").html(message).dialog({ 823 title: title, 824 resizable: false, 825 modal: true, 826 buttons: { 827 "Ok": function() { 828 $(this).dialog("close"); 829 } 830 } 831 }); 832 } 833 834 /** 835 * Open a JQuery confirm dialog. 836 */ 837 SDK.showConfirm = function(message, title, onYes, onNo) { 838 if (title == null) { 839 title = "Confirm"; 840 } 841 $("<div></div>").html(message).dialog({ 842 title: title, 843 resizable: false, 844 modal: true, 845 buttons: { 846 "Yes": function() { 847 onYes(); 848 $(this).dialog("close"); 849 }, 850 "No": function() { 851 onNo(); 852 $(this).dialog("close"); 853 } 854 } 855 }); 856 } 857 858 /** 859 * Evaluate any script tags in the node's descendants. 860 * This is required when innerHtml contains script nodes as they are not evaluated. 861 */ 862 SDK.evalScripts = function(node) { 863 if (node.tagName == 'SCRIPT') { 864 var script = document.createElement("script"); 865 script.text = node.innerHTML; 866 for (var index = node.attributes.length-1; index >= 0; i--) { 867 script.setAttribute(node.attributes[index].name, node.attributes[index].value); 868 } 869 node.parentNode.replaceChild(script, node); 870 } else { 871 var index = 0; 872 var children = node.childNodes; 873 while (index < children.length) { 874 SDK.evalScripts(children[index]); 875 index++; 876 } 877 } 878 return node; 879 } 880 881 /** 882 * Remove any script tags from the node. 883 */ 884 SDK.removeScripts = function(node) { 885 if (node.tagName == 'SCRIPT') { 886 node.parentNode.removeChild(node); 887 } else { 888 var index = 0; 889 var children = node.childNodes; 890 while (index < children.length) { 891 SDK.removeScripts(children[index]); 892 index++; 893 } 894 } 895 return node; 896 } 897 898 /** 899 * Add a stylesheet link to the page. 900 */ 901 SDK.addStylesheet = function(fileName) { 902 var head = document.head; 903 var link = document.createElement('link'); 904 link.type = 'text/css'; 905 link.rel = 'stylesheet'; 906 link.href = fileName; 907 head.appendChild(link); 908 } 909 910 /** 911 * Add a style tag to the page. 912 */ 913 SDK.addStyle = function(css) { 914 var body = document.body || document.getElementsByTagName('body')[0]; 915 var style = document.createElement('style'); 916 style.type = 'text/css'; 917 if (style.styleSheet) { 918 style.styleSheet.cssText = css; 919 } else { 920 style.appendChild(document.createTextNode(css)); 921 } 922 body.appendChild(style); 923 } 924 925 /** 926 * Graphics upload dialog and shared repositry browser. 927 * This provides a generic media upload dialog with many features: 928 * <ul> 929 * <li>Upload dialog UI 930 * <li>Locally resize images before upload 931 * <li>Upload from a web URL 932 * <li>Upload a media file from a shared graphics repository 933 * </ul> 934 * @class 935 */ 936 function GraphicsUploader() { 937 this.id = "graphics-browser"; 938 this.title = "Media Browser"; 939 this.browserClass = "dialog"; 940 this.dialogId = "graphics-uploader"; 941 this.dialogTitle = "Upload Media"; 942 this.dialogClass = "dialog"; 943 this.uploadURL = "upload-media"; 944 this.uploadFormProperties; 945 this.reloadOnSubmit = true; 946 this.fileInput; 947 this.urlInput; 948 this.prefix = "uploader-"; 949 this.renderedDialog = false; 950 this.submit = true; 951 this.showFile = true; 952 this.showURL = true; 953 this.showBrowse = true; 954 this.sdk = null; 955 this.url; 956 957 /** 958 * Open JQyery upload dialog. 959 */ 960 this.openUploadDialog = function() { 961 if (!this.renderedDialog) { 962 this.renderUploadDialog(); 963 } 964 $( '#' + this.dialogId ).dialog("open"); 965 } 966 967 /** 968 * Open JQyery browser dialog. 969 */ 970 this.openBrowser = function() { 971 var browser = document.getElementById(this.id); 972 if (browser != null) { 973 $( '#' + this.id ).remove(); 974 } 975 this.renderBrowser(); 976 $( '#' + this.id ).dialog("open"); 977 this.fetchMedia(); 978 } 979 980 /** 981 * Render JQyery upload dialog. 982 */ 983 this.renderUploadDialog = function() { 984 var uploadDialog = document.createElement('div'); 985 uploadDialog.setAttribute('id', this.dialogId); 986 uploadDialog.setAttribute('title', this.dialogTitle); 987 uploadDialog.setAttribute('class', this.dialogClass); 988 uploadDialog.style.display = "none"; 989 var html = 990 "<style>\n" 991 + "." + this.prefix + "button { text-decoration:none; padding: 12px 2px 12px 2px; }\n" 992 + "." + this.prefix + "dialog-div { margin-top: 10px;margin-bottom: 10px; }\n" 993 + "</style>\n"; 994 if (this.showBrowse) { 995 html = html 996 + "<div class='" + this.prefix + "dialog-div'>\n" 997 + "<a id='" + this.prefix + "browse-library' onclick='return false;' href='#' class='" + this.prefix + "button' title='Browse our shared media library'>\n" 998 + "<img src='images/importr.png' style='vertical-align: middle'>\n" 999 + "Browse media library\n" 1000 + "</a>\n" 1001 + "</div>\n"; 1002 } 1003 if (this.showFile) { 1004 if (this.showBrowse) { 1005 html = html + "<hr>\n"; 1006 } 1007 html = html 1008 + "<div class='" + this.prefix + "dialog-div'>\n" 1009 + "<a id='" + this.prefix + "upload-media' onclick='return false;' href='#' class='" + this.prefix + "button' title='Upload an image or media file from your computer or device'>\n" 1010 + "<img src='images/upload.png' style='vertical-align: middle'>\n" 1011 + "Upload from computer or device</a>\n" 1012 + "</div>\n" 1013 + "<div class='" + this.prefix + "dialog-div'>\n" 1014 + "<input id='" + this.prefix + "file-input' style='display:none' type='file' name='file' style='display:none'/>\n" 1015 + "<input id='" + this.prefix + "resize' type='checkbox' title='Resize the image file locally to the max pixel width, to srink large images, and save upload bandwidth (only use on image files)'>\n" 1016 + "Resize to <input id='" + this.prefix + "resize-width' type='number' value='300' style='width:50px;height:25px' title='Image resize width in pixels'> pixels\n" 1017 + "</div>\n"; 1018 } 1019 if (this.showURL) { 1020 if (this.showFile || this.showBrowse) { 1021 html = html + "<hr>\n"; 1022 } 1023 html = html 1024 + "<div class='" + this.prefix + "dialog-div'>\n" 1025 + "<a id='" + this.prefix + "upload-url' onclick='return false;' href='#' class='" + this.prefix + "button' title='Import an image or media file from the web URL'>\n" 1026 + "<img src='images/importr.png' style='vertical-align: middle'>\n" 1027 + "Import from web URL\n" 1028 + "</a>\n" 1029 + "</div>\n" 1030 + "<input id='" + this.prefix + "url-input' type='text' style='width:100%'>\n"; 1031 } 1032 uploadDialog.innerHTML = html; 1033 document.body.appendChild(uploadDialog); 1034 1035 var self = this; 1036 var element = document.getElementById(this.prefix + "upload-media"); 1037 if (element != null) { 1038 element.addEventListener("click", function(event) { 1039 if (document.getElementById(self.prefix + 'resize').checked) { 1040 document.getElementById(self.prefix + 'file-input').click(); 1041 } else { 1042 self.fileInput.click(); 1043 } 1044 return false; 1045 }); 1046 } 1047 element = document.getElementById(this.prefix + "file-input"); 1048 if (element != null) { 1049 element.addEventListener("change", function(event) { 1050 var width = parseInt(document.getElementById(self.prefix + 'resize-width').value); 1051 SDK.uploadImage( 1052 document.getElementById(self.prefix + 'file-input'), 1053 self.uploadURL, 1054 width, 1055 null, 1056 self.uploadFormProperties, 1057 function() { 1058 if (self.reloadOnSubmit) { 1059 location.reload(); 1060 } 1061 }); 1062 return false; 1063 }); 1064 } 1065 element = document.getElementById(this.prefix + "upload-url"); 1066 if (element != null) { 1067 element.addEventListener("click", function(event) { 1068 self.urlInput.value = document.getElementById(self.prefix + "url-input").value; 1069 if (self.submit) { 1070 self.urlInput.form.submit(); 1071 } 1072 return false; 1073 }); 1074 } 1075 element = document.getElementById(this.prefix + "browse-library"); 1076 if (element != null) { 1077 element.addEventListener("click", function(event) { 1078 self.openBrowser(function(url) { 1079 if (url == null) { 1080 return false; 1081 } 1082 self.urlInput.value = url; 1083 if (self.submit) { 1084 self.urlInput.form.submit(); 1085 } 1086 }); 1087 return false; 1088 }); 1089 } 1090 1091 $( '#' + this.dialogId ).dialog({ 1092 autoOpen: false, 1093 modal: true, 1094 buttons: { 1095 "Cancel": function() { 1096 $(this).dialog("close"); 1097 } 1098 } 1099 }); 1100 this.renderedDialog = true; 1101 } 1102 1103 /** 1104 * Render JQyery browser dialog. 1105 */ 1106 this.renderBrowser = function() { 1107 var browser = document.createElement('div'); 1108 browser.setAttribute('id', this.id); 1109 browser.setAttribute('title', this.title); 1110 browser.setAttribute('class', this.browserClass); 1111 browser.style.display = "none"; 1112 1113 var self = this; 1114 GraphicsUploader.updateSearch = function() { 1115 self.fetchMedia(); 1116 } 1117 var height = window.innerHeight - (window.innerHeight * 0.2); 1118 var width = window.innerWidth - (window.innerWidth * 0.2); 1119 var html = 1120 "<style>\n" 1121 + "." + this.prefix + "button { text-decoration:none; padding: 12px 2px 12px 2px; }\n" 1122 + "." + this.prefix + "browser-div { }\n" 1123 + "." + this.prefix + "search-div { width:264px;margin:2px;display:inline-block;font-size:13px; }\n" 1124 + "." + this.prefix + "search-span { display:inline-block;width:78px; }\n" 1125 + "." + this.prefix + "browse-categories, ." + this.prefix + "browse-tags, , ." + this.prefix + "browse-filter { width:150px; }\n" 1126 + "." + this.prefix + "browse-sort { width:150px; }\n" 1127 + "." + this.prefix + "browse-div { display:inline-block;margin:2px;vertical-align:top; }\n" 1128 + "." + this.prefix + "browse-details { font-size:12px;color:grey; }\n" 1129 + "." + this.prefix + "browse-img { max-width:100px;max-height:100px; }\n" 1130 + "." + this.prefix + "browse-span div { position:absolute;margin:-1px 0 0 0;padding:3px 3px 3px 3px;background:#fff;border-style:solid;border-color:black;border-width:1px;max-width:300px;min-width:100px;z-index:152;visibility:hidden;opacity:0;transition:visibility 0s linear 0.3s, opacity 0.3s linear; } \n" 1131 + "." + this.prefix + "browse-span:hover div { display:inline;visibility:visible;opacity:1;transition-delay:0.5s; }\n" 1132 + "</style>\n" 1133 + "<div><div class='" + this.prefix + "search-div'><span class='" + this.prefix + "search-span'>Categories</span><input id='" + this.prefix + "browse-categories' type='text'/></div>" 1134 + " <div class='" + this.prefix + "search-div'><span class='" + this.prefix + "search-span'>Tags</span><input id='" + this.prefix + "browse-tags' type='text'/></div>" 1135 + " <div class='" + this.prefix + "search-div'><span class='" + this.prefix + "search-span'>Filter</span><input id='" + this.prefix + "browse-filter' type='text'/></div>" 1136 + " <div class='" + this.prefix + "search-div'><span class='" + this.prefix + "search-span'>Sort</span><select id='" + this.prefix + "browse-sort' onchange='GraphicsUploader.updateSearch()'><option value='name'>name</option><option value='Date'>date</option><option value='thumbs up'>thumbs up</option>\n" 1137 + "<option value='thumbs down'>thumbs down</option><option value='Stars'>stars</option><option value='connects'>connects</option></select>\n" 1138 + "<a href='#' onclick='GraphicsUploader.updateSearch()' title='Search'><img src='images/inspect.png' style='vertical-align: middle'></a></div>\n" 1139 + "</div>\n" 1140 + "<div id='" + this.prefix + "browser-div' class='" + this.prefix + "browser-div'>\n" 1141 + "</div>\n"; 1142 browser.innerHTML = html; 1143 document.body.appendChild(browser); 1144 1145 var self = this; 1146 SDK.debug = true; 1147 if (this.sdk == null) { 1148 this.sdk = new SDKConnection(); 1149 } 1150 var autocompleteEvent = function(event) { 1151 var self = this; 1152 $(self).autocomplete('search', ''); 1153 } 1154 if (GraphicsUploader.tags.length == 0) { 1155 var contentConfig = new ContentConfig(); 1156 contentConfig.type = "Graphic"; 1157 this.sdk.fetchTags(contentConfig, function(results) { 1158 GraphicsUploader.tags = results; 1159 $( "#" + self.prefix + "browse-tags" ).autocomplete({ source: GraphicsUploader.tags, minLength: 0, appendTo: $("#" + self.prefix + "browse-tags").parent() }).on('focus', autocompleteEvent); 1160 }); 1161 } else { 1162 $( "#" + this.prefix + "browse-tags" ).autocomplete({ source: GraphicsUploader.tags, minLength: 0, appendTo: $("#" + self.prefix + "browse-tags").parent() }).on('focus', autocompleteEvent); 1163 } 1164 if (GraphicsUploader.categories.length == 0) { 1165 var contentConfig = new ContentConfig(); 1166 contentConfig.type = "Graphic"; 1167 this.sdk.fetchCategories(contentConfig, function(results) { 1168 GraphicsUploader.categories = results; 1169 $( "#" + self.prefix + "browse-categories" ).autocomplete({ source: GraphicsUploader.categories, minLength: 0, appendTo: $("#" + self.prefix + "browse-categories").parent() }).on('focus', autocompleteEvent); 1170 }); 1171 } else { 1172 $( "#" + this.prefix + "browse-categories" ).autocomplete({ source: GraphicsUploader.categories, minLength: 0, appendTo: $("#" + self.prefix + "browse-categories").parent() }).on('focus', autocompleteEvent); 1173 } 1174 var keyPressed = function search(e) { 1175 if (e.keyCode == 13) { 1176 self.fetchMedia(); 1177 } 1178 } 1179 $( "#" + this.prefix + "browse-tags" ).on("keydown", keyPressed); 1180 $( "#" + this.prefix + "browse-categories" ).on("keydown", keyPressed); 1181 $( "#" + this.prefix + "browse-filter" ).on("keydown", keyPressed); 1182 1183 $( '#' + this.id ).dialog({ 1184 autoOpen: false, 1185 modal: true, 1186 height: height, 1187 width: width, 1188 buttons: { 1189 "Cancel": function() { 1190 $(this).dialog("close"); 1191 } 1192 } 1193 }); 1194 } 1195 1196 /** 1197 * Query and display graphics. 1198 */ 1199 this.fetchMedia = function() { 1200 var browseConfig = new BrowseConfig(); 1201 browseConfig.type = "Graphic"; 1202 browseConfig.category = document.getElementById(this.prefix + 'browse-categories').value; 1203 browseConfig.tag = document.getElementById(this.prefix + 'browse-tags').value; 1204 browseConfig.filter = document.getElementById(this.prefix + 'browse-filter').value; 1205 browseConfig.sort = document.getElementById(this.prefix + 'browse-sort').value; 1206 var self = this; 1207 var urlprefix = self.sdk.credentials.url + "/"; 1208 GraphicsUploader.chooseMedia = function(id) { 1209 var config = new GraphicConfig(); 1210 config.id = id; 1211 self.sdk.fetch(config, function(result) { 1212 self.url = urlprefix + result.media; 1213 if (self.urlInput != null) { 1214 self.urlInput.value = self.url; 1215 if (self.submit) { 1216 self.urlInput.form.submit(); 1217 } 1218 } 1219 }); 1220 } 1221 this.sdk.browse(browseConfig, function(results) { 1222 var div = document.getElementById(self.prefix + "browser-div"); 1223 while (div.firstChild) { 1224 div.removeChild(div.firstChild); 1225 } 1226 for (var index = 0; index < results.length; index++) { 1227 var result = results[index]; 1228 var graphicDiv = document.createElement('div'); 1229 graphicDiv.setAttribute('id', self.prefix + 'browse-div'); 1230 graphicDiv.setAttribute('class', self.prefix + 'browse-div'); 1231 var html = 1232 "<span id='" + self.prefix + "browse-span' class='" + self.prefix + "browse-span'>" 1233 + "<table style='border-style:solid;border-color:grey;border-width:1px'><tr><td style='height:100px;width:100px;' align='center' valign='middle'>" 1234 + "<a href='#' onclick='GraphicsUploader.chooseMedia(" + result.id + ")'><img id='" + self.prefix + "browse-img' class='" + self.prefix + "browse-img' src='" + urlprefix + result.avatar + "'></a>\n" 1235 + "</td></tr></table>" 1236 + "<div>" 1237 + "<span><b>" + result.name + "</b><br/>" + result.description + "</span><br/>" 1238 + "<span id='" + self.prefix + "browse-details' class='" + self.prefix + "browse-details'>"; 1239 if (result.categories != null && result.categories != "") { 1240 html = html + "Categories: " + result.categories + "<br/>"; 1241 } 1242 if (result.tags != null && result.tags != "") { 1243 html = html + "Tags: " + result.tags + "<br/>"; 1244 } 1245 if (result.license != null && result.license != "") { 1246 html = html + "License: " + result.license + "<br/>"; 1247 } 1248 html = html 1249 + "</div>" 1250 + "</span>\n" 1251 + "<div style='max-width:100px'><a href='#' style='text-decoration:none;' onclick='GraphicsUploader.chooseMedia(" + result.id + ")'><span id='" + self.prefix + "browse-details' class='" + self.prefix + "browse-details'>" + result.name + "</span></div></a>\n"; 1252 graphicDiv.innerHTML = html; 1253 var img = document.createElement('img'); 1254 img.setAttribute('src', urlprefix + result.avatar); 1255 div.appendChild(graphicDiv); 1256 } 1257 }); 1258 } 1259 } 1260 1261 GraphicsUploader.map = {}; 1262 1263 GraphicsUploader.tags = []; 1264 GraphicsUploader.categories = []; 1265 1266 /** 1267 * Open a media uploader dialog initialized with a form. 1268 * The dialog will use the form's action to upload media as 'file' for a file, or 'upload-url' for a URL. 1269 * The form should define an ID if to be used on multiple forms in the same document. 1270 * This can be used on the onclick on an input element to open the dialog i.e. <input type="submit" onclick="return GraphicsUploader.openUploadDialog(this.form)" value="Upload"> 1271 * This will create a hidden input of type file ('file'), and a hidden input of type text ('upload-url'), these will be passed to your server when the dialog submits the form. 1272 */ 1273 GraphicsUploader.openUploadDialog = function(form, title, showFile, showURL, showBrowse) { 1274 var id = form.getAttribute('id'); 1275 var prefix = "uploader-"; 1276 var dialogId = "graphics-uploader"; 1277 var browserId = "graphics-browser"; 1278 if (id == null) { 1279 id = "uploader"; 1280 } else { 1281 prefix = id + '-' + prefix; 1282 dialogId = id + '-' + dialogId; 1283 browserId = id + '-' + browserId; 1284 } 1285 var uploader = GraphicsUploader.map[id]; 1286 if (uploader == null) { 1287 uploader = new GraphicsUploader(); 1288 GraphicsUploader.map[id] = uploader; 1289 var div = document.createElement('div'); 1290 var html = 1291 "<input id='" + id + "file-input' style='display:none' onchange='this.form.submit()' type='file' name='file'/>\n" 1292 + "<input id='" + id + "url-input' style='display:none' name='upload-url' type='text'>"; 1293 div.innerHTML = html; 1294 form.appendChild(div); 1295 if (title != null) { 1296 uploader.dialogTitle = title; 1297 } 1298 if (showFile != null) { 1299 uploader.showFile = showFile; 1300 } 1301 if (showURL != null) { 1302 uploader.showURL = showURL; 1303 } 1304 if (showBrowse != null) { 1305 uploader.showBrowse = showBrowse; 1306 } 1307 uploader.prefix = prefix; 1308 uploader.dialogId = dialogId; 1309 uploader.id= browserId; 1310 uploader.fileInput = document.getElementById(id + 'file-input'); 1311 uploader.urlInput = document.getElementById(id + 'url-input'); 1312 uploader.uploadURL = form.action; 1313 } 1314 uploader.openUploadDialog(); 1315 return false; 1316 } 1317 1318 /** 1319 * Credentials used to establish a connection. 1320 * Defines the url, host, app, rest, which are all defaulted and should not need to be changed, 1321 * Requires an application id. 1322 * You can obtain your application id from your user details page on the hosting website. 1323 * @class 1324 */ 1325 function Credentials() { 1326 this.host = SDK.host; 1327 this.app = SDK.app; 1328 this.url = SDK.url; 1329 this.rest = SDK.rest; 1330 this.applicationId = SDK.applicationId; 1331 } 1332 1333 /** 1334 * Credentials for use with hosted services on the BOT libre website, a free bot hosting service. 1335 * http://www.botlibre.com 1336 * @class 1337 */ 1338 function BOTlibreCredentials() { 1339 this.DOMAIN = "www.botlibre.com"; 1340 this.APP = ""; 1341 this.PATH = "/rest/api"; 1342 1343 this.host = this.DOMAIN; 1344 this.app = this.APP; 1345 this.url = "http://" + this.DOMAIN + this.APP; 1346 this.rest = this.url + this.PATH; 1347 this.applicationId = SDK.applicationId; 1348 } 1349 1350 /** 1351 * Credentials for use with hosted services on the Bot Libre for Business website, 1352 * a commercial bot, live chat, chatroom, and forum, hosting service. 1353 * https://www.botlibre.biz 1354 * @class 1355 */ 1356 function PaphusCredentials() { 1357 this.DOMAIN = "www.botlibre.biz"; 1358 this.APP = ""; 1359 this.PATH = "/rest/api"; 1360 1361 this.host = this.DOMAIN; 1362 this.app = this.APP; 1363 this.url = "http://" + this.DOMAIN + this.APP; 1364 this.rest = this.url + this.PATH; 1365 this.applicationId = SDK.applicationId; 1366 } 1367 1368 /** 1369 * Credentials for use with hosted services on the LIVE CHAT libre website, a free live chat, chatrooms, forum, and chat bots that learn. 1370 * http://www.livechatlibre.com 1371 * @class 1372 */ 1373 function LIVECHATlibreCredentials() { 1374 this.DOMAIN = "www.livechatlibre.com"; 1375 this.APP = ""; 1376 this.PATH = "/rest/api"; 1377 1378 this.host = this.DOMAIN; 1379 this.app = this.APP; 1380 this.url = "http://" + this.DOMAIN + this.APP; 1381 this.rest = this.url + this.PATH; 1382 this.applicationId = SDK.applicationId; 1383 } 1384 1385 /** 1386 * Credentials for use with hosted services on the FORUMS libre website, a free embeddable forum hosting service. 1387 * http://www.forumslibre.com 1388 * @class 1389 */ 1390 function FORUMSlibreCredentials() { 1391 this.DOMAIN = "www.forumslibre.com"; 1392 this.APP = ""; 1393 this.PATH = "/rest/api"; 1394 1395 this.host = this.DOMAIN; 1396 this.app = this.APP; 1397 this.url = "http://" + this.DOMAIN + this.APP; 1398 this.rest = this.url + this.PATH; 1399 this.applicationId = SDK.applicationId; 1400 } 1401 1402 /** 1403 * Listener interface for a LiveChatConnection. 1404 * This gives asynchronous notification when a channel receives a message, or notice. 1405 * @class 1406 */ 1407 function LiveChatListener() { 1408 /** 1409 * A user message was received from the channel. 1410 */ 1411 this.message = function(message) {}; 1412 1413 /** 1414 * An informational message was received from the channel. 1415 * Such as a new user joined, private request, etc. 1416 */ 1417 this.info = function(message) {}; 1418 1419 /** 1420 * An error message was received from the channel. 1421 * This could be an access error, or message failure. 1422 */ 1423 this.error = function(message) {}; 1424 1425 /** 1426 * Notification that the connection was closed. 1427 */ 1428 this.closed = function() {}; 1429 1430 /** 1431 * The channels users changed (user joined, left, etc.) 1432 * This contains a comma separated values (CSV) list of the current channel users. 1433 * It can be passed to the SDKConnection.getUsers() API to obtain the UserConfig info for the users. 1434 */ 1435 this.updateUsers = function(usersCSV) {}; 1436 1437 /** 1438 * The channels users changed (user joined, left, etc.) 1439 * This contains a HTML list of the current channel users. 1440 * It can be inserted into an HTML document to display the users. 1441 */ 1442 this.updateUsersXML = function(usersXML) {}; 1443 } 1444 1445 /** 1446 * The WebLiveChatListener provides an integration between a LiveChatConnection and an HTML document. 1447 * It updates the document to message received from the connection, and sends messages from the document's form. 1448 * The HTML document requires the following elements: 1449 * - chat - <input type='text'> chat text input for sending messages 1450 * - send - <input type='submit'> button for sending chat input 1451 * - response - <p> paragraph for last chat message 1452 * - console - <table> table for chat log, and user log 1453 * - scroller - <div> div for chat log scroll pane 1454 * - online - <table> table for chat user list 1455 * @class 1456 */ 1457 function WebLiveChatListener() { 1458 /** Set the caption for the button bar button. */ 1459 this.caption = null; 1460 this.switchText = true; 1461 this.playChime = true; 1462 this.speak = false; 1463 this.voice = null; 1464 this.nativeVoice = null; 1465 this.nativeVoiceName = null; 1466 this.lang = null; 1467 this.nick = ""; 1468 this.connection = null; 1469 this.sdk = null; 1470 /** Configure if chat should be given focus after message. */ 1471 this.focus = true; 1472 /** Element id and class prefix. Can be used to have multiple avatars in the same page, or avoid naming collisions. */ 1473 this.prefix = ""; 1474 /** Allow the chat box button color to be set. */ 1475 this.color = "#009900"; 1476 /** Allow the user to modify style sheets. */ 1477 this.version = null; 1478 /** Allow the chat box hover button color to be set. */ 1479 this.hoverColor = "grey"; 1480 /** Allow the chat box background color to be set. */ 1481 this.background = null; 1482 /** Chat box width. */ 1483 this.width = 300; 1484 /** Chat box height. */ 1485 this.height = 320; 1486 /** Chat box offset from side. */ 1487 this.offset = 30; 1488 /** Chat Button Vertial Offset*/ 1489 this.verticalOffset = 0; 1490 /** Print response in chat bubble. */ 1491 this.bubble = false; 1492 /** Set the location of the button and box, one of "bottom-right", "bottom-left", "top-right", "top-left". */ 1493 this.boxLocation = "bottom-right"; 1494 /** Set styles explicitly to avoid inheriting page styles. Disable this to be able to override styles. */ 1495 this.forceStyles = true; 1496 /** Override the URL used in the chat box popup. */ 1497 this.popupURL = null; 1498 /** Set if the box chat log should be shown. */ 1499 this.chatLog = true; 1500 /** Box chat loading message to display. */ 1501 this.loading = "loading..."; 1502 /** Box chat show online users option. */ 1503 this.online = false; 1504 /** Link to online user list users to their profile page. */ 1505 this.linkUsers = true; 1506 /** Configure message log format (table or log). */ 1507 this.chatLogType = "log"; 1508 /** Configure the chat to auto accept a bot after waiting */ 1509 this.autoAccept = null; 1510 /** Prompt for name/email before connecting. */ 1511 this.promptContactInfo = false; 1512 this.hasContactInfo = false; 1513 /** Set if the back link should be displayed. */ 1514 this.backlink = SDK.backlink; 1515 this.contactName = null; 1516 this.contactEmail = null; 1517 this.contactPhone = null; 1518 this.contactInfo = ""; 1519 /** Allow the close button on the box button bar to be removed, and maximize on any click to the button bar. */ 1520 this.showClose = true; 1521 /** Provide an email chat log menu item. */ 1522 this.emailChatLog = false; 1523 /** Ask the user if they want an email of the chat log on close. */ 1524 this.promptEmailChatLog = false; 1525 this.windowTitle = document.title; 1526 this.isActive = true; 1527 /** Variables used to get the user and bot images. */ 1528 this.botThumb = {}; 1529 this.userThumb = {}; 1530 self = this; 1531 /** JSON object of all currently logged in users in the chat room take from updateUsersXML. */ 1532 this.users = {}; 1533 /** Box chat chat room option. */ 1534 this.chatroom = false; 1535 /** Show and hides menu bar */ 1536 this.showMenubar = true; 1537 /** Show Box Max */ 1538 this.showBoxmax = true; 1539 /** Show Send Image */ 1540 this.showSendImage = true; 1541 1542 /** 1543 * Create an embedding bar and div in the current web page. 1544 */ 1545 this.createBox = function() { 1546 if (this.prefix == "" && this.elementPrefix != null) { 1547 this.prefix = this.elementPrefix; 1548 } 1549 if (this.caption == null) { 1550 this.caption = this.instanceName; 1551 } 1552 var backgroundstyle = ""; 1553 var buttonstyle = ""; 1554 var buttonHoverStyle = ""; 1555 var hidden = "hidden"; 1556 var border = ""; 1557 if (this.backgroundIfNotChrome && SDK.isChrome()) { 1558 this.background = null; 1559 } 1560 if (this.background != null) { 1561 backgroundstyle = " style='background-color:" + this.background + "'"; 1562 hidden = "visible"; 1563 border = "border:1px;border-style:solid;border-color:black;"; 1564 } 1565 if (this.color != null) { 1566 buttonstyle = "background-color:" + this.color + ";"; 1567 } 1568 if (this.hoverColor != null) { 1569 buttonHoverStyle = "background-color:" + this.hoverColor + ";"; 1570 } 1571 1572 var minWidth = ""; 1573 var divWidth = ""; 1574 var background = ""; 1575 var minHeight = ""; 1576 var divHeight = ""; 1577 var maxDivWidth = ""; 1578 if (this.width != null) { 1579 minWidth = "width:" + this.width + "px;"; 1580 background = "background-size:" + this.width + "px auto;"; 1581 divWidth = minWidth; 1582 divHeight = "min-height:" + this.width + "px;"; 1583 responseWidth = "width:" + (this.width - 32) + "px;"; 1584 maxDivWidth = "max-width:" + (this.width - 50) + "px;"; 1585 } 1586 if (this.height != null) { 1587 minHeight = "height:" + this.height + "px;"; 1588 divHeight = minHeight; 1589 if (this.width != null) { 1590 background = "background-size:" + this.width + "px " + this.height + "px;"; 1591 } else { 1592 background = "background-size: auto " + this.height + "px;"; 1593 divWidth = "min-width:" + this.height + "px;"; 1594 } 1595 } 1596 var boxloc = "bottom:10px;right:10px"; 1597 if (this.boxLocation == "top-left") { 1598 boxloc = "top:10px;left:10px"; 1599 } else if (this.boxLocation == "top-right") { 1600 boxloc = "top:10px;right:10px"; 1601 } else if (this.boxLocation == "bottom-left") { 1602 boxloc = "bottom:10px;left:10px"; 1603 } else if (this.boxLocation == "bottom-right") { 1604 boxloc = "bottom:10px;right:10px"; 1605 } 1606 var locationBottom = 20; 1607 if (this.version < 6.0 || this.prefix != "botplatformchat") { 1608 locationBottom = 2; 1609 } 1610 var boxbarloc = "bottom:" + (locationBottom + this.verticalOffset) + "px;right:" + this.offset + "px"; 1611 if (this.boxLocation == "top-left") { 1612 boxbarloc = "top:" + (locationBottom + this.verticalOffset) + "px;left:" + this.offset + "px"; 1613 } else if (this.boxLocation == "top-right") { 1614 boxbarloc = "top:" + (locationBottom + this.verticalOffset) + "px;right:" + this.offset + "px"; 1615 } else if (this.boxLocation == "bottom-left") { 1616 boxbarloc = "bottom:" + (locationBottom + this.verticalOffset) + "px;left:" + this.offset + "px"; 1617 } else if (this.boxLocation == "bottom-right") { 1618 boxbarloc = "bottom:" + (locationBottom + this.verticalOffset) + "px;right:" + this.offset + "px"; 1619 } 1620 var box = document.createElement('div'); 1621 var html = 1622 "<style>\n" 1623 + "." + this.prefix + "box { position:fixed;" + boxloc + ";z-index:152;margin:2px;display:none;" + border + " }\n" 1624 + "." + this.prefix + "boxmenu { visibility:" + hidden + "; }\n" //margin-bottom:12px; 1625 + (this.forceStyles ? "#" : ".") + "" + this.prefix + "boxbarmax { font-size:18px;margin:2px;padding:0px;text-decoration:none; }\n" 1626 + "." + this.prefix + "boxbar { position:fixed;" + boxbarloc + ";z-index:152;margin:0;padding:6px;" + buttonstyle + " }\n" 1627 + "." + this.prefix + "boxbar:hover { " + buttonHoverStyle + " }\n" 1628 + "#" + this.prefix + "emailchatlogdialog { " + minWidth + " }\n" 1629 + "#" + this.prefix + "contactinfo { " + minHeight + minWidth + " }\n" 1630 + "." + this.prefix + "contactconnect { margin:4px;padding:8px;color:white;text-decoration:none;" + buttonstyle + " }\n" 1631 + "." + this.prefix + "no-bubble-text { " + responseWidth + "; max-height:100px; overflow:auto; }\n" 1632 + "." + this.prefix + "bubble-text { " + responseWidth + "; margin:4px; max-height:100px; overflow:auto; }\n" 1633 + (this.forceStyles ? "#" : ".") + this.prefix + "chat { width:99%;min-height:22px; }\n" 1634 + "." + this.prefix + "chat-1-div { " + maxDivWidth + "}\n" 1635 + "." + this.prefix + "chat-2-div { " + maxDivWidth + "}\n" 1636 + "." + this.prefix + "online-div { " + minWidth + " overflow-x: auto; overflow-y: hidden; white-space: nowrap; }\n" 1637 + "." + this.prefix + "scroller { overflow-x:hidden;" + minHeight + minWidth + " }\n" 1638 + "." + this.prefix + "box:hover ." + this.prefix + "boxmenu { visibility:visible; }\n"; 1639 if (this.version < 6.0 || this.prefix != "botplatformchat") { 1640 html = html 1641 + "." + this.prefix + "box img { display:inline; }\n" 1642 + "." + this.prefix + "boxbar img { display:inline; }\n" 1643 + "." + this.prefix + "box:hover { border:1px;border-style:solid;border-color:black; }\n" 1644 + "." + this.prefix + "box:hover ." + this.prefix + "boxmenu { visibility:visible; }\n" 1645 + "." + this.prefix + "boxclose, ." + this.prefix + "boxmin, ." + this.prefix + "boxmax { font-size:22px;margin:2px;padding:0px;text-decoration:none; }\n" 1646 + "." + this.prefix + "boxclose:hover, ." + this.prefix + "boxmin:hover, ." + this.prefix + "boxmax:hover { color: #fff;background: grey; }\n" 1647 + "#" + this.prefix + "emailchatlogdialog span { margin-left:0px;margin-top:4px; }\n" 1648 + "#" + this.prefix + "emailchatlogdialog input { margin:4px;font-size:13px;height:33px;width:90%;border:1px solid #d5d5d5; }\n" 1649 + "." + this.prefix + "emailconfirm { margin:4px;padding:8px;color:white;background-color:grey;text-decoration:none; }\n" 1650 + "#" + this.prefix + "contactinfo span { margin-left:4px;margin-top:4px; }\n" 1651 + "#" + this.prefix + "contactinfo input { margin:4px;font-size:13px;height:33px;width:90%;border:1px solid #d5d5d5; }\n" 1652 + "." + this.prefix + "no-bubble { margin:4px; padding:8px; border:1px; border-style:solid; border-color:black; background-color:white; color:black; }\n" 1653 + "." + this.prefix + "boxbutton { width:20px;height:20px;margin:2px; }\n" 1654 + "." + this.prefix + "bubble-div { padding-bottom:15px;position:relative; }\n" 1655 + "." + this.prefix + "no-bubble-plain { margin:4px; padding:8px; border:1px; }\n" 1656 + "." + this.prefix + "bubble { margin:4px; padding:8px; border:1px; border-style:solid; border-color:black; border-radius:10px; background-color:white; color:black; }\n" 1657 + "." + this.prefix + "bubble:before { content:''; position:absolute; bottom:0px; left:40px; border-width:20px 0 0 20px; border-style:solid; border-color:black transparent; display:block; width:0;}\n" 1658 + "." + this.prefix + "bubble:after { content:''; position:absolute; bottom:3px; left:42px; border-width:18px 0 0 16px; border-style:solid; border-color:white transparent; display:block; width:0;}\n" 1659 + "." + this.prefix + "box-input-span { display:block; overflow:hidden; margin:4px; padding-right:4px; }\n" 1660 + "a." + this.prefix + "menuitem { text-decoration: none;display: block;color: #585858; }\n" 1661 + "a." + this.prefix + "menuitem:hover { color: #fff;background: grey; }\n" 1662 + "tr." + this.prefix + "menuitem:hover { background: grey; }\n" 1663 + "." + this.prefix + "powered { margin:4px;font-size:10px; }\n" 1664 + "img." + this.prefix + "menu { width: 24px;height: 24px;margin: 2px;cursor: pointer;vertical-align: middle; }\n" 1665 + "span." + this.prefix + "menu { color: #818181;font-size: 12px; }\n" 1666 + "img." + this.prefix + "toolbar { width: 25px;height: 25px;margin: 1px;padding: 1px;cursor: pointer;vertical-align: middle;border-style: solid;border-width: 1px;border-color: #fff; }\n" 1667 + "td." + this.prefix + "toolbar { width: 36px;height: 36px }\n" 1668 /*+ "." + this.prefix + "online { height: 97px;width: 300px;overflow-x: auto;overflow-y: hidden;white-space: nowrap; }\n"*/ 1669 + "." + this.prefix + "menupopup div { position:absolute;margin: -1px 0 0 0;padding: 3px 3px 3px 3px;background: #fff;border-style:solid;border-color:black;border-width:1px;width:160px;max-width:300px;z-index:152;visibility:hidden;opacity:0;transition:visibility 0s linear 0.3s, opacity 0.3s linear; }\n" 1670 + "." + this.prefix + "menupopup:hover div { display:inline;visibility:visible;opacity:1;transition-delay:0.5s; }\n" 1671 + "img.chat-user-thumb { height: 50px; }\n" 1672 + "a.user { text-decoration: none; }\n" 1673 + "td." + this.prefix + "chat-1 { width:100%;background-color: #d5d5d5;}\n" 1674 + "span." + this.prefix + "chat-1 { color:#333;}\n" 1675 + "span." + this.prefix + "chat-user { color:grey;font-size:small; }\n" 1676 + "." + this.prefix + "console { width:100%; }\n" 1677 + "." + this.prefix + "online-div { display: none; }\n" 1678 + "." + this.prefix + "-channel-title { display: none; }\n" 1679 + "#" + this.prefix + "boxtable { background:none; border:none; margin:0; }\n" 1680 + "#" + this.prefix + "boxbar3 { display:none; }\n" 1681 + "#" + this.prefix + "boxbarmax { color: white; }\n"; 1682 } 1683 html = html 1684 + "</style>\n" 1685 + "<div id='" + this.prefix + "box' class='" + this.prefix + "box' " + backgroundstyle + ">" 1686 + "<div class='" + this.prefix + "boxmenu'>" 1687 + (this.backlink ? "<span class='" + this.prefix + "powered'>powered by <a href='" + SDK.backlinkURL + "' target='_blank'>" + SDK.NAME + "</a></span>" : "") 1688 + "<span class=" + this.prefix + "-channel-title>" + this.instanceName + "</span>" 1689 + "<span style='float:right'><a id='" + this.prefix + "boxmin' class='" + this.prefix + "boxmin' onclick='return false;' href='#'><img src='" + SDK.url + "/images/minimize.png'></a>"; 1690 if (this.showBoxmax) { 1691 html = html + "<a id='" + this.prefix + "boxmax' class='" + this.prefix + "boxmax' onclick='return false;' href='#'><img src='" + SDK.url + "/images/open.png'></a></span><br/>"; 1692 } else { 1693 html = html + "</span><br/>"; 1694 } 1695 html = html + "</div>"; 1696 if (this.online) { 1697 html = html 1698 + "<div id='" + this.prefix + "online-div' class='" + this.prefix + "online-div'>" 1699 + "<div id='" + this.prefix + "online' class='" + this.prefix + "online'" + "style='display:none;'>" 1700 + "<table></table>" 1701 + "</div>" 1702 + "</div>"; 1703 } 1704 if (this.chatLog) { 1705 html = html 1706 + "<div id='" + this.prefix + "scroller' class='" + this.prefix + "scroller'>" 1707 + "<table id='" + this.prefix + "console' class='" + this.prefix + "console' width=100% cellspacing=2></table>" 1708 + "</div>" 1709 } 1710 var urlprefix = this.sdk.credentials.url + "/"; 1711 html = html 1712 + "<div>\n" 1713 + "<div " + (this.bubble ? "id='" + this.prefix + "bubble-div' class='" + this.prefix + "bubble-div'" : "") + ">" 1714 + "<div " 1715 + "id='" + this.prefix + (this.bubble ? "bubble" : (this.background == null ? "no-bubble" : "no-bubble-plain") ) 1716 + "' class='" + this.prefix + (this.bubble ? "bubble" : (this.background == null ? "no-bubble" : "no-bubble-plain") ) 1717 + "'><div id='" + this.prefix + (this.bubble ? "bubble-text" : "no-bubble-text" ) + "' " 1718 + "class='" + this.prefix + (this.bubble ? "bubble-text" : "no-bubble-text" ) + "'>" 1719 + "<span id='" + this.prefix + "response'>" + this.loading + "</span><br/>" 1720 + "</div></div></div>\n"; 1721 html = html 1722 + "<table id='" + this.prefix + "boxtable' class='" + this.prefix + "boxtable' style='width:100%'><tr>\n"; 1723 if (this.showMenubar) { 1724 html = html 1725 + "<td class='" + this.prefix + "toolbar'><span class='" + this.prefix + "menu'>\n" 1726 + "<div style='inline-block;position:relative'>\n" 1727 + "<span id='" + this.prefix + "menupopup' class='" + this.prefix + "menupopup'>\n" 1728 + "<div style='text-align:left;bottom:30px'>\n" 1729 + "<table>\n" 1730 + "<tr class='" + this.prefix + "menuitem'>" 1731 + "<td><a id='" + this.prefix + "ping' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/empty.png' title='" + SDK.translate("Verify your connection to the server") + "'> " + SDK.translate("Ping server") + "</a></td>" 1732 + "</tr>\n"; 1733 if (this.chatroom) { 1734 html = html 1735 + "<tr class='" + this.prefix + "menuitem'>" 1736 + "<td><a id='" + this.prefix + "flag' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/flag2.png' title='" + SDK.translate("Flag a user for offensive content") + "'> " + SDK.translate("Flag user") + "</a></td>" 1737 + "</tr>\n" 1738 + "<tr class='" + this.prefix + "menuitem'>" 1739 + "<td><a id='" + this.prefix + "whisper' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/whisper.png' title='" + SDK.translate("Send a private message to another user") + "'> " + SDK.translate("Whisper user") + "</a></td>" 1740 + "</tr>\n" 1741 + "<tr class='" + this.prefix + "menuitem'>" 1742 + "<td><a id='" + this.prefix + "pvt' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/accept.png' title='" + SDK.translate("Invite another user to a private channel") + "'> " + SDK.translate("Request private") + "</a></td>" 1743 + "</tr>\n" 1744 } 1745 html = html 1746 + "<tr class='" + this.prefix + "menuitem'>" 1747 + "<td><a id='" + this.prefix + "clear' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/empty.png' title='" + SDK.translate("Clear the local chat log") + "'> " + SDK.translate("Clear log") + "</a></td>" 1748 + "</tr>\n" 1749 + "<tr class='" + this.prefix + "menuitem'>" 1750 + "<td><a id='" + this.prefix + "accept' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/accept.png' title='" + SDK.translate("Accept a private request from an operator, bot, or another user") + "'> " + SDK.translate("Accept private") + "</a></td>" 1751 + "</tr>\n"; 1752 if (this.showSendImage) { 1753 html = html 1754 + "<tr class='" + this.prefix + "menuitem'>" 1755 + "<td><a id='" + this.prefix + "sendImage' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/image.png' title='" + SDK.translate("Resize and send an image attachment") + "'> " + SDK.translate("Send image") + "</a></td>" 1756 + "</tr>\n" 1757 + "<tr class='" + this.prefix + "menuitem'>" 1758 + "<td><a id='" + this.prefix + "sendAttachment' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/attach.png' title='" + SDK.translate("Send an image or file attachment") + "'> " + SDK.translate("Send file") + "</a></td>" 1759 + "</tr>\n"; 1760 } 1761 if (this.emailChatLog) { 1762 html = html 1763 + "<tr class='" + this.prefix + "menuitem'>" 1764 + "<td><a id='" + this.prefix + "emailChatLog' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img id='email' class='" + this.prefix + "menu' src='" + SDK.url + "/images/message.png' title='" + SDK.translate("Send yourself an email of the conversation log") + "'> " + SDK.translate("Email Chat Log") + "</a></td>" 1765 } 1766 html = html 1767 + "<tr class='" + this.prefix + "menuitem'>" 1768 + "<td><a id='" + this.prefix + "toggleChime' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img id='boxchime' class='" + this.prefix + "menu' src='" + SDK.url + "/images/sound.png' title='" + SDK.translate("Play a chime when a message is recieved") + "'> " + SDK.translate("Chime") + "</a></td>" 1769 + "</tr>\n" 1770 + "<tr class='" + this.prefix + "menuitem'>" 1771 + "<td><a id='" + this.prefix + "toggleSpeak' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img id='boxtalk' class='" + this.prefix + "menu' src='" + SDK.url + "/images/talkoff.png' title='" + SDK.translate("Speak each message using voice synthesis") + "'> " + SDK.translate("Text to speech") + "</a></td>" 1772 + "</tr>\n" 1773 + "<tr class='" + this.prefix + "menuitem'>" 1774 + "<td><a id='" + this.prefix + "toggleListen' class='" + this.prefix + "menuitem' onclick='return false;' href='#'>" 1775 + "<img id='boxmic' class='" + this.prefix + "menu' src='" + SDK.url + "/images/micoff.png' title='" + SDK.translate("Enable speech recognition (browser must support HTML5 speech recognition, such as Chrome)") + "'> " + SDK.translate("Speech recognition") + "</a>" 1776 + "</td>" 1777 + "</tr>\n" 1778 + "<tr class='" + this.prefix + "menuitem'>" 1779 + "<td><a id='" + this.prefix + "exit' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + SDK.url + "/images/quit.png' title='" + SDK.translate("Exit the channel or active private channel") + "'> " + SDK.translate("Quit private or channel") + "</a></td>" 1780 + "</tr>\n" 1781 + "</table>\n" 1782 + "</div>\n" 1783 + "<img class='" + this.prefix + "toolbar' src='" + SDK.url + "/images/menu.png'>\n" 1784 + "</span>\n" 1785 + "</div>\n" 1786 + "</span></td>\n"; 1787 } 1788 html = html 1789 + "<td><span class='" + this.prefix + "box-input-span'><input id='" + this.prefix 1790 + "chat' type='text' id='" + this.prefix + "box-input' " 1791 + "class='" + this.prefix + "box-input'/></span></td>" 1792 + "</tr></table>" 1793 + "</div>\n" 1794 + "</div>\n" 1795 + "<div id='" + this.prefix + "boxbar' class='" + this.prefix + "boxbar'>" 1796 + "<div id='" + this.prefix + "boxbar2' class='" + this.prefix + "boxbar2'>" 1797 + "<span><a id='" + this.prefix + "boxbarmax' class='" + this.prefix + "boxbarmax' " + " onclick='return false;' href='#'><img id='" + this.prefix + "boxbarmaximage' " + "src='" + SDK.url + "/images/maximizew.png'> " + this.caption + " </a>"; 1798 if (this.showClose) { 1799 html = html + " <a id='" + this.prefix + "boxclose' class='" + this.prefix + "boxclose' onclick='return false;' href='#'> <img src='" + SDK.url + "/images/closeg.png'></a>"; 1800 } 1801 html = html 1802 + "</span><br>" 1803 + "</div>\n" 1804 + "<div id='" + this.prefix + "boxbar3' class='" + this.prefix + "boxbar3'" + ">" 1805 + "<span><a id='" + this.prefix + "boxbarmax2' class='" + this.prefix + "boxbarmax2' " + (this.forceStyles ? "style='color:white' " : "") + " onclick='return false;' href='#'>" + "</a>" 1806 + "</span><br>"; 1807 if (this.showClose) { 1808 html = html + " <a id='" + this.prefix + "boxclose2' class='" + this.prefix + "boxclose2' onclick='return false;' href='#'> <img src='" + SDK.url + "/images/closeg.png'></a>"; 1809 } 1810 html = html 1811 + "</div>\n" 1812 + "</span>" 1813 + "</div>\n"; 1814 1815 if (this.promptContactInfo) { 1816 html = html 1817 + "<div id='" + this.prefix + "contactinfo' class='" + this.prefix + "box' " + backgroundstyle + ">" 1818 + "<div class='" + this.prefix + "boxmenu'>" 1819 + "<span style='float:right'><a id='" + this.prefix + "contactboxmin' class='" + this.prefix + "contactboxmin' onclick='return false;' href='#'><img src='" + SDK.url + "/images/minimize.png'></a>" 1820 + "</div>\n" 1821 + "<div style='margin:10px'>\n" 1822 + "<span>" + SDK.translate("Name") + "</span><br/><input id='" + this.prefix + "contactname' type='text' /><br/>\n" 1823 + "<span>" + SDK.translate("Email") + "</span><br/><input id='" + this.prefix + "contactemail' type='email' /><br/>\n" 1824 + "<span>" + SDK.translate("Phone") + "</span><br/><input id='" + this.prefix + "contactphone' type='text' /><br/>\n" 1825 + "<br/><a id='" + this.prefix + "contactconnect' class='" + this.prefix + "contactconnect' " + (this.forceStyles ? "style='color:white' " : "") + " onclick='return false;' href='#'>" + SDK.translate("Connect") + "</a>\n" 1826 + "</div>\n" 1827 + "</div>"; 1828 } 1829 if (this.promptEmailChatLog) { 1830 html = html 1831 + "<div id='" + this.prefix + "emailchatlogdialog' class='" + this.prefix + "box' " + backgroundstyle + ">" 1832 + "<div class='" + this.prefix + "boxmenu'>" 1833 + "<span style='float:right'><a id='" + this.prefix + "emailchatlogdialogmin' class='" + this.prefix + "boxmin' onclick='return false;' href='#'><img src='" + SDK.url + "/images/minimize.png'></a>" 1834 + "</div>\n" 1835 + "<div style='margin:10px;margin-bottom:20px;margin-top:20px;'>\n" 1836 + "<span>" + SDK.translate("Would you like a copy of the chat log sent to your email?") + "</span><br/><input id='" + this.prefix + "emailchatlogemail' type='email' /><br/>\n" 1837 + "<br/><a id='" + this.prefix + "emailchatlogdialogyes' class='" + this.prefix + "emailconfirm' " + (this.forceStyles ? "style='color:white' " : "") + " onclick='return false;' href='#'>" + SDK.translate("Yes") + "</a>\n" 1838 + " <a id='" + this.prefix + "emailchatlogdialogno' class='" + this.prefix + "emailconfirm' " + (this.forceStyles ? "style='color:white' " : "") + " onclick='return false;' href='#'>" + SDK.translate("No") + "</a>\n" 1839 + "</div>\n" 1840 + "</div>"; 1841 } 1842 1843 box.innerHTML = html; 1844 document.body.appendChild(box); 1845 1846 if (this.online && this.chatroom) { 1847 document.getElementById(this.prefix + "online").style.height = "95px"; 1848 } 1849 if (this.chatLog && !this.bubble) { 1850 var bubbleDiv = document.getElementById(this.prefix + 'bubble-div'); 1851 if (bubbleDiv != null) { 1852 bubbleDiv.style.display = "none"; 1853 } 1854 document.getElementById(this.prefix + 'no-bubble-plain').style.display = "none"; 1855 document.getElementById(this.prefix + 'response').style.display = "none"; 1856 } 1857 1858 var self = this; 1859 var listen = false; 1860 if (document.getElementById(this.prefix + "chat") != null) { 1861 document.getElementById(this.prefix + "chat").addEventListener("keypress", function(event) { 1862 if (event.keyCode == 13) { 1863 self.sendMessage(); 1864 return false; 1865 } 1866 }); 1867 } 1868 if (document.getElementById(this.prefix + "exit") != null) { 1869 document.getElementById(this.prefix + "exit").addEventListener("click", function() { 1870 self.exit(); 1871 return false; 1872 }); 1873 } 1874 if (document.getElementById(this.prefix + "ping")!= null) { 1875 document.getElementById(this.prefix + "ping").addEventListener("click", function() { 1876 self.ping(); 1877 return false; 1878 }); 1879 } 1880 if (document.getElementById(this.prefix + "clear") != null) { 1881 document.getElementById(this.prefix + "clear").addEventListener("click", function() { 1882 self.clear(); 1883 return false; 1884 }); 1885 } 1886 if (document.getElementById(this.prefix + "accept") != null) { 1887 document.getElementById(this.prefix + "accept").addEventListener("click", function() { 1888 self.accept(); 1889 return false; 1890 }); 1891 } 1892 if (document.getElementById(this.prefix + "sendImage") != null) { 1893 document.getElementById(this.prefix + "sendImage").addEventListener("click", function() { 1894 self.sendImage(); 1895 return false; 1896 }); 1897 } 1898 if (document.getElementById(this.prefix + "sendAttachment") != null) { 1899 document.getElementById(this.prefix + "sendAttachment").addEventListener("click", function() { 1900 self.sendAttachment(); 1901 return false; 1902 }); 1903 } 1904 if (this.emailChatLog) { 1905 if (document.getElementById(this.prefix + "emailChatLog") != null) { 1906 document.getElementById(this.prefix + "emailChatLog").addEventListener("click", function() { 1907 self.emailChatLog(); 1908 return false; 1909 }); 1910 } 1911 } 1912 if (this.promptEmailChatLog) { 1913 document.getElementById(this.prefix + "emailchatlogdialogyes").addEventListener("click", function() { 1914 self.sendEmailChatLogBox(); 1915 return false; 1916 }); 1917 document.getElementById(this.prefix + "emailchatlogdialogno").addEventListener("click", function() { 1918 self.minimizeEmailChatLogBox(); 1919 return false; 1920 }); 1921 document.getElementById(this.prefix + "emailchatlogdialogmin").addEventListener("click", function() { 1922 self.minimizeEmailChatLogBox(); 1923 return false; 1924 }); 1925 } 1926 var menu = document.getElementById(this.prefix + "flag"); 1927 if (menu != null) { 1928 menu.addEventListener("click", function() { 1929 self.flag(); 1930 return false; 1931 }); 1932 } 1933 menu = document.getElementById(this.prefix + "whisper"); 1934 if (menu != null) { 1935 menu.addEventListener("click", function() { 1936 self.whisper(); 1937 return false; 1938 }); 1939 } 1940 menu = document.getElementById(this.prefix + "pvt"); 1941 if (menu != null) { 1942 menu.addEventListener("click", function() { 1943 self.pvt(); 1944 return false; 1945 }); 1946 } 1947 if (document.getElementById(this.prefix + "toggleChime") != null) { 1948 document.getElementById(this.prefix + "toggleChime").addEventListener("click", function() { 1949 self.toggleChime(); 1950 if (self.playChime) { 1951 document.getElementById('boxchime').src = SDK.url + "/images/sound.png"; 1952 } else { 1953 document.getElementById('boxchime').src = SDK.url + "/images/mute.png"; 1954 } 1955 }); 1956 } 1957 if (document.getElementById(this.prefix + "toggleSpeak") != null) { 1958 document.getElementById(this.prefix + "toggleSpeak").addEventListener("click", function() { 1959 self.toggleSpeak(); 1960 if (self.speak) { 1961 document.getElementById('boxtalk').src = SDK.url + "/images/talk.png"; 1962 } else { 1963 document.getElementById('boxtalk').src = SDK.url + "/images/talkoff.png"; 1964 } 1965 return false; 1966 }); 1967 } 1968 if (document.getElementById(this.prefix + "toggleListen") != null) { 1969 document.getElementById(this.prefix + "toggleListen").addEventListener("click", function() { 1970 listen = !listen; 1971 if (listen) { 1972 SDK.startSpeechRecognition(); 1973 document.getElementById('boxmic').src = SDK.url + "/images/mic.png"; 1974 } else { 1975 SDK.stopSpeechRecognition(); 1976 document.getElementById('boxmic').src = SDK.url + "/images/micoff.png"; 1977 } 1978 return false; 1979 }); 1980 } 1981 document.getElementById(this.prefix + "boxmin").addEventListener("click", function() { 1982 self.minimizeBox(); 1983 return false; 1984 }); 1985 if (this.promptContactInfo) { 1986 document.getElementById(this.prefix + "contactboxmin").addEventListener("click", function() { 1987 self.minimizeContactInfoBox(); 1988 return false; 1989 }); 1990 document.getElementById(this.prefix + "contactconnect").addEventListener("click", function() { 1991 self.contactConnect(); 1992 return false; 1993 }); 1994 } 1995 if (document.getElementById(this.prefix + "boxmax") != null) { 1996 document.getElementById(this.prefix + "boxmax").addEventListener("click", function() { 1997 self.popup(); 1998 return false; 1999 }); 2000 } 2001 if (this.showClose) { 2002 document.getElementById(this.prefix + "boxclose").addEventListener("click", function() { 2003 self.closeBox(); 2004 return false; 2005 }); 2006 document.getElementById(this.prefix + "boxclose2").addEventListener("click", function() { 2007 self.closeBox(); 2008 return false; 2009 }); 2010 document.getElementById(this.prefix + "boxbarmax").addEventListener("click", function() { 2011 self.maximizeBox(); 2012 return false; 2013 }); 2014 document.getElementById(this.prefix + "boxbarmax2").addEventListener("click", function() { 2015 self.maximizeBox(); 2016 return false; 2017 }); 2018 } else { 2019 document.getElementById(this.prefix + "boxbar").addEventListener("click", function() { 2020 self.maximizeBox(); 2021 return false; 2022 }); 2023 } 2024 } 2025 2026 /** 2027 * Minimize the live chat embedding box. 2028 */ 2029 this.minimizeBox = function() { 2030 this.onlineBar = false; 2031 if (this.promptContactInfo) { 2032 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 2033 } 2034 document.getElementById(this.prefix + "box").style.display = 'none'; 2035 var onlineDiv = document.getElementById(this.prefix + "online"); 2036 if (onlineDiv != null) { 2037 onlineDiv.style.display = 'none'; 2038 } 2039 if (this.promptEmailChatLog) { 2040 document.getElementById(this.prefix + "emailchatlogemail").value = this.contactEmail; 2041 document.getElementById(this.prefix + "emailchatlogdialog").style.display = 'inline'; 2042 return false; 2043 } 2044 document.getElementById(this.prefix + "boxbar").style.display = 'inline'; 2045 if (this.prefix.indexOf("livechat") != -1) { 2046 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2047 if (chatbot != null) { 2048 chatbot.style.display = 'inline'; 2049 } 2050 } 2051 if (this.prefix.indexOf("chat") != -1) { 2052 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2053 if (chatbot != null) { 2054 chatbot.style.display = 'inline'; 2055 } 2056 } 2057 this.exit(); 2058 setTimeout(function() { 2059 self.exit(); 2060 }, 100); 2061 return false; 2062 } 2063 2064 /** 2065 * Minimize the email chat log confirm dialog. 2066 */ 2067 this.minimizeEmailChatLogBox = function() { 2068 if (this.promptContactInfo) { 2069 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 2070 } 2071 document.getElementById(this.prefix + "box").style.display = 'none'; 2072 document.getElementById(this.prefix + "emailchatlogdialog").style.display = 'none'; 2073 document.getElementById(this.prefix + "boxbar").style.display = 'inline'; 2074 if (this.prefix.indexOf("livechat") != -1) { 2075 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2076 if (chatbot != null) { 2077 chatbot.style.display = 'inline'; 2078 } 2079 } 2080 if (this.prefix.indexOf("chat") != -1) { 2081 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2082 if (chatbot != null) { 2083 chatbot.style.display = 'inline'; 2084 } 2085 } 2086 this.exit(); 2087 setTimeout(function() { 2088 self.exit(); 2089 }, 100); 2090 return false; 2091 } 2092 2093 /** 2094 * Minimize the email chat log confirm dialog. 2095 */ 2096 this.sendEmailChatLogBox = function() { 2097 this.contactEmail = document.getElementById(this.prefix + "emailchatlogemail").value; 2098 this.sendEmailChatLog(); 2099 if (this.promptContactInfo) { 2100 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 2101 } 2102 document.getElementById(this.prefix + "box").style.display = 'none'; 2103 document.getElementById(this.prefix + "emailchatlogdialog").style.display = 'none'; 2104 document.getElementById(this.prefix + "boxbar").style.display = 'inline'; 2105 if (this.prefix.indexOf("livechat") != -1) { 2106 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2107 if (chatbot != null) { 2108 chatbot.style.display = 'inline'; 2109 } 2110 } 2111 if (this.prefix.indexOf("chat") != -1) { 2112 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2113 if (chatbot != null) { 2114 chatbot.style.display = 'inline'; 2115 } 2116 } 2117 setTimeout(function() { 2118 self.exit(); 2119 }, 100); 2120 return false; 2121 } 2122 2123 /** 2124 * Minimize the contact info box. 2125 */ 2126 this.minimizeContactInfoBox = function() { 2127 if (this.promptContactInfo) { 2128 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 2129 } 2130 document.getElementById(this.prefix + "box").style.display = 'none'; 2131 document.getElementById(this.prefix + "boxbar").style.display = 'inline'; 2132 if (this.prefix.indexOf("livechat") != -1) { 2133 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2134 if (chatbot != null) { 2135 chatbot.style.display = 'inline'; 2136 } 2137 } 2138 if (this.prefix.indexOf("chat") != -1) { 2139 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2140 if (chatbot != null) { 2141 chatbot.style.display = 'inline'; 2142 } 2143 } 2144 return false; 2145 } 2146 2147 /** 2148 * Check contact info and connect. 2149 */ 2150 this.contactConnect = function() { 2151 this.hasContactInfo = true; 2152 this.contactName = document.getElementById(this.prefix + "contactname").value; 2153 var ok = true; 2154 if (this.contactName != null && this.contactName == "") { 2155 ok = false; 2156 document.getElementById(this.prefix + "contactname").style.borderColor = "red"; 2157 document.getElementById(this.prefix + "contactname").placeholder = SDK.translate("Enter name"); 2158 } 2159 this.contactEmail = document.getElementById(this.prefix + "contactemail").value; 2160 if (this.contactEmail != null && this.contactEmail.indexOf("@") == -1) { 2161 ok = false; 2162 document.getElementById(this.prefix + "contactemail").style.borderColor = "red"; 2163 document.getElementById(this.prefix + "contactemail").placeholder = SDK.translate("Enter valid email"); 2164 } 2165 this.contactPhone = document.getElementById(this.prefix + "contactphone").value; 2166 this.contactInfo = this.contactName + " " + this.contactEmail + " " + this.contactPhone; 2167 if (ok) { 2168 this.maximizeBox(); 2169 } 2170 } 2171 2172 /** 2173 * Maximize the embedding div in the current webpage. 2174 */ 2175 this.maximizeBox = function() { 2176 this.onlineBar = true; 2177 if (this.promptContactInfo && !this.hasContactInfo) { 2178 document.getElementById(this.prefix + "contactinfo").style.display = 'inline'; 2179 document.getElementById(this.prefix + "boxbar").style.display = 'none'; 2180 document.getElementById(this.prefix + "box").style.display = 'none'; 2181 if (this.prefix.indexOf("livechat") != -1) { 2182 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2183 if (chatbot != null) { 2184 chatbot.style.display = 'none'; 2185 } 2186 } 2187 if (this.prefix.indexOf("chat") != -1) { 2188 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2189 if (chatbot != null) { 2190 chatbot.style.display = 'none'; 2191 } 2192 } 2193 } else { 2194 if (this.promptContactInfo) { 2195 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 2196 } 2197 document.getElementById(this.prefix + "boxbar").style.display = 'none'; 2198 document.getElementById(this.prefix + "box").style.display = 'inline'; 2199 if (this.prefix.indexOf("livechat") != -1) { 2200 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2201 if (chatbot != null) { 2202 chatbot.style.display = 'none'; 2203 } 2204 } 2205 if (this.prefix.indexOf("chat") != -1) { 2206 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2207 if (chatbot != null) { 2208 chatbot.style.display = 'none'; 2209 } 2210 } 2211 var chat = new LiveChatConnection(); 2212 chat.sdk = this.sdk; 2213 if (this.contactInfo != null) { 2214 chat.contactInfo = this.contactInfo; 2215 } 2216 var channel = new ChannelConfig(); 2217 channel.id = this.instance; 2218 chat.listener = this; 2219 chat.connect(channel, this.sdk.user); 2220 var self = this; 2221 if (this.autoAccept != null) { 2222 setTimeout(function() { 2223 chat.accept(); 2224 }, self.autoAccept); 2225 } 2226 } 2227 return false; 2228 } 2229 2230 /** 2231 * Close the embedding div in the current webpage. 2232 */ 2233 this.closeBox = function() { 2234 if (this.promptContactInfo) { 2235 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 2236 } 2237 document.getElementById(this.prefix + "boxbar").style.display = 'none'; 2238 document.getElementById(this.prefix + "box").style.display = 'none'; 2239 if (this.prefix.indexOf("livechat") != -1) { 2240 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("livechat")) + "boxbar"); 2241 if (chatbot != null) { 2242 chatbot.style.display = 'none'; 2243 } 2244 } 2245 if (this.prefix.indexOf("chat") != -1) { 2246 var chatbot = document.getElementById(this.prefix.substring(0, this.prefix.indexOf("chat")) + "boxbar"); 2247 if (chatbot != null) { 2248 chatbot.style.display = 'none'; 2249 } 2250 } 2251 this.exit(); 2252 var self = this; 2253 setTimeout(function() { 2254 self.exit(); 2255 }, 100); 2256 return false; 2257 } 2258 2259 /** 2260 * Create a popup window live chat session. 2261 */ 2262 this.popup = function() { 2263 var box = document.getElementById(this.prefix + "box"); 2264 if (box != null) { 2265 box.style.display = 'none'; 2266 } 2267 if (this.popupURL != null) { 2268 var popupURL = this.popupURL; 2269 if (popupURL.indexOf("livechat?") != -1 && this.contactInfo != null && this.contactInfo != "") { 2270 popupURL = popupURL + "&info=" + encodeURI(this.contactInfo); 2271 } 2272 SDK.popupwindow(popupURL, 'child', 700, 520); 2273 } else { 2274 var form = document.createElement("form"); 2275 form.setAttribute("method", "post"); 2276 form.setAttribute("action", SDK.url + "/livechat"); 2277 form.setAttribute("target", 'child'); 2278 2279 var input = document.createElement('input'); 2280 input.type = "hidden"; 2281 input.name = "id"; 2282 input.value = this.instance; 2283 form.appendChild(input); 2284 2285 input = document.createElement('input'); 2286 input.type = "hidden"; 2287 input.name = "embedded"; 2288 input.value = "embedded"; 2289 form.appendChild(input); 2290 2291 input = document.createElement('input'); 2292 input.type = "hidden"; 2293 input.name = "chat"; 2294 input.value = "true"; 2295 form.appendChild(input); 2296 2297 input = document.createElement('input'); 2298 input.type = "hidden"; 2299 input.name = "application"; 2300 input.value = this.connection.credentials.applicationId; 2301 form.appendChild(input); 2302 2303 input = document.createElement('input'); 2304 input.type = "hidden"; 2305 input.name = "css"; 2306 input.value = this.css; 2307 form.appendChild(input); 2308 2309 input = document.createElement('input'); 2310 input.type = "hidden"; 2311 input.name = "info"; 2312 input.value = this.contactInfo; 2313 form.appendChild(input); 2314 2315 document.body.appendChild(form); 2316 2317 SDK.popupwindow('','child', 700, 520); 2318 2319 form.submit(); 2320 document.body.removeChild(form); 2321 } 2322 this.minimizeBox(); 2323 return false; 2324 } 2325 2326 window.onfocus = function() { 2327 self.isActive = true; 2328 if (document.title != self.windowTitle) { 2329 document.title = self.windowTitle; 2330 } 2331 }; 2332 2333 window.onblur = function() { 2334 self.isActive = false; 2335 }; 2336 2337 2338 /** 2339 * Search for link using <a href="chat:yes">... 2340 * Switch them to use an onclick to post the chat back to the chat. 2341 */ 2342 this.linkChatPostbacks = function(node) { 2343 var self = this; 2344 var links = node.getElementsByTagName("a"); 2345 for (var index = 0; index < links.length; index++) { 2346 var a = links[index]; 2347 var href = a.getAttribute("href"); 2348 if (href != null && href.indexOf("chat:") != -1) { 2349 var chat = href.substring("chat:".length, href.length).trim(); 2350 var temp = function(param, element) { 2351 element.onclick = function() { 2352 self.connection.sendMessage(param); 2353 return false; 2354 }; 2355 } 2356 temp(chat, a); 2357 } 2358 } 2359 var buttons = node.getElementsByTagName("button"); 2360 for (var index = 0; index < buttons.length; index++) { 2361 var button = buttons[index]; 2362 if (button.parentNode.nodeName == "A") { 2363 continue; 2364 } 2365 var chat = button.textContent; 2366 if (chat != null && chat.length > 0) { 2367 var temp = function(param, element) { 2368 element.onclick = function() { 2369 self.connection.sendMessage(param); 2370 return false; 2371 }; 2372 } 2373 temp(chat, button); 2374 } 2375 } 2376 var choices = node.getElementsByTagName("select"); 2377 for (var index = 0; index < choices.length; index++) { 2378 var choice = choices[index]; 2379 var temp = function(param) { 2380 param.addEventListener("change", function() { 2381 self.connection.sendMessage(param.value); 2382 return false; 2383 }); 2384 } 2385 temp(choice); 2386 } 2387 } 2388 2389 /** 2390 * A user message was received from the channel. 2391 */ 2392 this.message = function(message) { 2393 var index = message.indexOf(':'); 2394 var speaker = ''; 2395 if (index != -1) { 2396 speaker = message.substring(0, index + 1); 2397 responseText = message.substring(index + 2, message.length); 2398 } else { 2399 responseText = message; 2400 } 2401 if (speaker != (this.nick + ':')) { 2402 if (this.playChime) { 2403 SDK.chime(); 2404 } 2405 if (this.speak) { 2406 SDK.tts(SDK.stripTags(responseText), this.voice, this.nativeVoice, this.lang, this.nativeVoiceName); 2407 } 2408 document.getElementById(this.prefix + 'response').innerHTML = SDK.linkURLs(responseText); 2409 this.linkChatPostbacks(document.getElementById(this.prefix + 'response')); 2410 // Fix Chrome bug, 2411 if (SDK.fixChromeResizeCSS && SDK.isChrome()) { 2412 var padding = document.getElementById(this.prefix + 'response').parentNode.parentNode.style.padding; 2413 document.getElementById(this.prefix + 'response').parentNode.parentNode.style.padding = "7px"; 2414 var self = this; 2415 setTimeout(function() { 2416 document.getElementById(self.prefix + 'response').parentNode.parentNode.style.padding = padding; 2417 }, 10); 2418 } 2419 this.switchText = false; 2420 } else { 2421 this.switchText = true; 2422 } 2423 var scroller = document.getElementById(this.prefix + 'scroller'); 2424 var consolepane = document.getElementById(this.prefix + 'console'); 2425 if (scroller == null || consolepane == null) { 2426 return; 2427 } 2428 if (this.chatLog) { 2429 var tr = document.createElement('tr'); 2430 tr.style.verticalAlign = "top"; 2431 var td = document.createElement('td'); 2432 var td2 = document.createElement('td'); 2433 var div = document.createElement('div'); 2434 var span = document.createElement('span'); 2435 var br = document.createElement('br'); 2436 var span2 = document.createElement('span'); 2437 var div2 = document.createElement('div'); 2438 var chatClass = this.prefix + 'chat-1'; 2439 div.className = this.prefix + 'chat-1-div'; 2440 div2.className = this.prefix + 'chat-1-div-2'; 2441 span.className = this.prefix + 'chat-user-1'; 2442 td.className = this.prefix + 'chat-user-1'; 2443 if (this.switchText) { 2444 td.className = this.prefix + 'chat-user-2'; 2445 chatClass = this.prefix + 'chat-2'; 2446 div.className = this.prefix + 'chat-2-div'; 2447 div2.className = this.prefix + 'chat-2-div-2'; 2448 span.className = this.prefix + 'chat-user-2'; 2449 } 2450 var userImg = document.createElement('img'); 2451 userImg.className = this.prefix + 'chat-user'; 2452 var speakerName = speaker.slice(0, -1); 2453 if (speakerName != "Info" && speakerName != "Error") { 2454 for(var key in this.users) { 2455 if (key === speakerName) { 2456 userImg.setAttribute('alt', speakerName); 2457 userImg.setAttribute('src', this.users[key]); 2458 break; 2459 } 2460 } 2461 } 2462 td.appendChild(userImg); 2463 td.setAttribute('nowrap', 'nowrap'); 2464 td2.className = chatClass; 2465 td2.setAttribute('align', 'left'); 2466 td2.setAttribute('width', '100%'); 2467 2468 var date = new Date(); 2469 var time = date.getHours() + ":" + ((date.getMinutes() < 10)? "0" : "") + date.getMinutes() + ":" + ((date.getSeconds() < 10)? "0" : "") + date.getSeconds(); 2470 span.innerHTML = speaker + " <small>" + time + "</small>"; 2471 span2.className = chatClass; 2472 span2.innerHTML = SDK.linkURLs(responseText); 2473 this.linkChatPostbacks(span2); 2474 consolepane.appendChild(tr); 2475 2476 tr.appendChild(td); 2477 tr.appendChild(td2); 2478 div.appendChild(span); 2479 div.appendChild(br); 2480 div.appendChild(div2); 2481 td2.appendChild(div); 2482 div2.appendChild(span2); 2483 } 2484 this.switchText = !this.switchText; 2485 while (consolepane.childNodes.length > 500) { 2486 consolepane.removeChild(consolepane.firstChild); 2487 } 2488 scroller.scrollTop = scroller.scrollHeight; 2489 if (this.focus) { 2490 document.getElementById(this.prefix + 'chat').focus(); 2491 } 2492 if (!this.isActive) { 2493 document.title = SDK.stripTags(responseText); 2494 } 2495 }; 2496 2497 /** 2498 * An informational message was received from the channel. 2499 * Such as a new user joined, private request, etc. 2500 */ 2501 this.info = function(message) { 2502 if (this.connection.nick != null && this.connection.nick != "") { 2503 this.nick = this.connection.nick; 2504 } 2505 this.message(message); 2506 }; 2507 2508 /** 2509 * An error message was received from the channel. 2510 * This could be an access error, or message failure. 2511 */ 2512 this.error = function(message) { 2513 this.message(message); 2514 }; 2515 2516 /** 2517 * Notification that the connection was closed. 2518 */ 2519 this.closed = function() {}; 2520 2521 /** 2522 * The channels users changed (user joined, left, etc.) 2523 * This contains a comma separated values (CSV) list of the current channel users. 2524 * It can be passed to the SDKConnection.getUsers() API to obtain the UserConfig info for the users. 2525 */ 2526 this.updateUsers = function(usersCSV) {}; 2527 2528 /** 2529 * The channels users changed (user joined, left, etc.) 2530 * This contains a HTML list of the current channel users. 2531 * It can be inserted into an HTML document to display the users. 2532 */ 2533 this.updateUsersXML = function(usersXML) { 2534 if (!this.linkUsers) { 2535 usersXML = usersXML.split('<a').join('<span'); 2536 usersXML = usersXML.split('</a>').join('</span>'); 2537 } 2538 var onlineList = document.getElementById(this.prefix + 'online'); 2539 if (onlineList == null) { 2540 return; 2541 } 2542 if (!this.chatLog) { 2543 onlineList.style.height = "60px"; 2544 } 2545 var div = document.createElement('div'); 2546 div.innerHTML = usersXML; 2547 var children = div.childNodes[0].childNodes; 2548 var usersArray = {}; 2549 var size = children.length; 2550 for(var i = 0; i < size; i++) { 2551 var userName = children[i].innerText; 2552 var child = children[i].childNodes; 2553 var imageSrc = child[0].getAttribute('src'); 2554 usersArray[userName] = imageSrc; 2555 } 2556 this.users = usersArray; 2557 if (this.onlineBar) { 2558 var onlineBar = onlineList; 2559 onlineBar.innerHTML = ''; 2560 if (this.chatroom || this.isFrame) { // displaying list of users on top 2561 var count = 0; 2562 var ids = {}; 2563 var length = children.length; 2564 for (var i = 0; i < length; i++) { 2565 var child = children[i - count]; 2566 ids[child.id] = child.id; 2567 if (document.getElementById(child.id) == null) { 2568 onlineList.appendChild(child); 2569 count++; 2570 } 2571 } 2572 onlineList.style.margin = "0"; 2573 onlineList.style.display = 'inline'; 2574 } 2575 else { // displaying only single bot on top 2576 var length = children.length; 2577 var child = children[length - 1]; 2578 var keys = []; 2579 for(var keyItem in this.users) { 2580 keys.push(keyItem); 2581 } 2582 var botName = keys[keys.length - 1]; 2583 var botImageSrc = this.users[botName]; 2584 if (typeof botName === 'undefined' || typeof botImageSrc === 'undefined') { 2585 return; 2586 } 2587 var botImage = document.createElement('img'); 2588 botImage.className = this.prefix + "-bot-image"; 2589 botImage.setAttribute('alt', botName); 2590 botImage.setAttribute('src', botImageSrc); 2591 var botSpan = document.createElement('span'); 2592 botSpan.className = this.prefix + "user-bot"; 2593 botSpan.innerHTML = botName; 2594 onlineBar.append(botImage); 2595 onlineBar.append(botSpan); 2596 if (!this.isFrame) { 2597 onlineList.style.display = 'block'; 2598 var line = document.createElement('hr'); 2599 var onlineDiv = document.getElementById(this.prefix + 'online-div'); 2600 onlineDiv.appendChild(line); 2601 } 2602 } 2603 return; 2604 } 2605 onlineList.innerHTML = ''; 2606 var div = document.createElement('div'); 2607 div.innerHTML = usersXML; 2608 var children = div.childNodes[0].childNodes; 2609 var count = 0; 2610 var length = children.length; 2611 var ids = {}; 2612 // Add missing user 2613 for (var i = 0; i < length; i++) { 2614 var child = children[i - count]; 2615 ids[child.id] = child.id; 2616 if (document.getElementById(child.id) == null) { 2617 onlineList.appendChild(child); 2618 count++; 2619 } 2620 } 2621 // Remove missing users 2622 var onlineDiv = document.getElementById(this.prefix + 'online-div'); 2623 if (onlineDiv == null) { 2624 return; 2625 } 2626 children = onlineDiv.childNodes; 2627 count = 0; 2628 length = children.length; 2629 for (var i = 0; i < length; i++) { 2630 var child = children[i - count]; 2631 if (child.id != (this.prefix + 'online') && ids[child.id] == null) { 2632 onlineDiv.removeChild(child); 2633 count++; 2634 } 2635 } 2636 }; 2637 2638 /** 2639 * Decrease the size of the video element for the userid. 2640 */ 2641 this.shrinkVideo = function(user) { 2642 var id = 'user-' + encodeURIComponent(user); 2643 var userdiv = document.getElementById(id); 2644 if (userdiv != null) { 2645 var media = userdiv.firstElementChild; 2646 if (media != null) { 2647 media.height = media.height / 1.5; 2648 } 2649 } 2650 }; 2651 2652 /** 2653 * Increase the size of the video element for the userid. 2654 */ 2655 this.expandVideo = function(user) { 2656 var id = 'user-' + encodeURIComponent(user); 2657 var userdiv = document.getElementById(id); 2658 if (userdiv != null) { 2659 var media = userdiv.firstElementChild; 2660 if (media != null) { 2661 media.height = media.height * 1.5; 2662 } 2663 } 2664 }; 2665 2666 /** 2667 * Mute the audio for the userid. 2668 */ 2669 this.muteAudio = function(user) { 2670 var id = 'user-' + encodeURIComponent(user); 2671 var userdiv = document.getElementById(id); 2672 if (userdiv != null) { 2673 var media = userdiv.firstElementChild; 2674 if (media != null) { 2675 if (media.muted) { 2676 if (user != this.nick) { 2677 media.muted = false; 2678 } 2679 } else { 2680 media.muted = true; 2681 } 2682 } 2683 } 2684 }; 2685 2686 /** 2687 * Mute the video for the userid. 2688 */ 2689 this.muteVideo = function(user) { 2690 var id = 'user-' + encodeURIComponent(user); 2691 var userdiv = document.getElementById(id); 2692 if (userdiv != null) { 2693 var media = userdiv.firstElementChild; 2694 if (media != null) { 2695 if (media.paused) { 2696 media.play(); 2697 media.style.opacity = 100; 2698 } else { 2699 media.pause(); 2700 media.style.opacity = 0; 2701 } 2702 } 2703 } 2704 }; 2705 2706 this.toggleChime = function() { 2707 this.playChime = !this.playChime; 2708 } 2709 2710 this.toggleSpeak = function() { 2711 this.speak = !this.speak; 2712 } 2713 2714 this.toggleKeepAlive = function() { 2715 this.connection.toggleKeepAlive(); 2716 } 2717 2718 this.sendMessage = function() { 2719 var message = document.getElementById(this.prefix + 'chat').value; 2720 if (message != '') { 2721 this.connection.sendMessage(message); 2722 document.getElementById(this.prefix + 'chat').value = ''; 2723 } 2724 return false; 2725 }; 2726 2727 this.sendImage = function() { 2728 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 2729 alert('The File APIs are not fully supported in this browser.'); 2730 return false; 2731 } 2732 var form = document.createElement("form"); 2733 form.enctype = "multipart/form-data"; 2734 form.method = "post"; 2735 form.name = "fileinfo"; 2736 var fileInput = document.createElement("input"); 2737 var self = this; 2738 fileInput.name = "file"; 2739 fileInput.type = "file"; 2740 form.appendChild(fileInput); 2741 fileInput.onchange = function() { 2742 var file = fileInput.files[0]; 2743 self.connection.sendAttachment(file, true, form); 2744 } 2745 fileInput.click(); 2746 return false; 2747 }; 2748 2749 this.sendAttachment = function() { 2750 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 2751 alert('The File APIs are not fully supported in this browser.'); 2752 return false; 2753 } 2754 var form = document.createElement("form"); 2755 form.enctype = "multipart/form-data"; 2756 form.method = "post"; 2757 form.name = "fileinfo"; 2758 var fileInput = document.createElement("input"); 2759 var self = this; 2760 fileInput.name = "file"; 2761 fileInput.type = "file"; 2762 form.appendChild(fileInput); 2763 fileInput.onchange = function() { 2764 var file = fileInput.files[0]; 2765 self.connection.sendAttachment(file, false, form); 2766 } 2767 fileInput.click(); 2768 return false; 2769 }; 2770 2771 this.ping = function() { 2772 this.connection.ping(); 2773 document.getElementById(this.prefix + 'chat').value = ''; 2774 return false; 2775 }; 2776 2777 this.accept = function() { 2778 this.connection.accept(); 2779 document.getElementById(this.prefix + 'chat').value = ''; 2780 return false; 2781 }; 2782 2783 this.exit = function() { 2784 if (this.connection != null) { 2785 this.connection.exit(); 2786 document.getElementById(this.prefix + 'chat').value = ''; 2787 } 2788 return false; 2789 }; 2790 2791 this.spyMode = function() { 2792 this.connection.spyMode(); 2793 document.getElementById(this.prefix + 'chat').value = ''; 2794 return false; 2795 }; 2796 2797 this.normalMode = function() { 2798 this.connection.normalMode(); 2799 document.getElementById(this.prefix + 'chat').value = ''; 2800 return false; 2801 }; 2802 2803 this.boot = function() { 2804 document.getElementById(this.prefix + 'chat').value = 'boot: user'; 2805 return false; 2806 }; 2807 2808 this.emailChatLog = function() { 2809 document.getElementById(this.prefix + 'chat').value = 'email: ' + (this.contactEmail == null ? '[email protected]' : this.contactEmail); 2810 return false; 2811 }; 2812 2813 this.sendEmailChatLog = function() { 2814 this.connection.sendMessage('email: ' + this.contactEmail); 2815 return false; 2816 }; 2817 2818 this.whisper = function(user) { 2819 if (user == null) { 2820 user = 'user'; 2821 } 2822 document.getElementById(this.prefix + 'chat').value = 'whisper: ' + user + ': message'; 2823 return false; 2824 }; 2825 2826 this.flag = function(user) { 2827 if (user != null) { 2828 document.getElementById(this.prefix + 'chat').value = 'flag: ' + user + ': reason'; 2829 return false; 2830 } 2831 document.getElementById(this.prefix + 'chat').value = 'flag: user: reason'; 2832 return false; 2833 }; 2834 2835 this.pvt = function(user) { 2836 if (user != null) { 2837 this.connection.pvt(user); 2838 return false; 2839 } 2840 document.getElementById(this.prefix + 'chat').value = 'private: user'; 2841 return false; 2842 }; 2843 2844 this.clear = function() { 2845 document.getElementById(this.prefix + 'response').innerHTML = ''; 2846 var console = document.getElementById(this.prefix + 'console'); 2847 if (console != null) { 2848 console.innerHTML = ''; 2849 } 2850 return false; 2851 }; 2852 } 2853 2854 /** 2855 * Shared method for updating an avatar image/video/audio from the chat response. 2856 */ 2857 SDK.updateAvatar = function(responseMessage, speak, urlprefix, elementPrefix, channelaudio, afterFunction, nativeVoice, lang, voice) { 2858 try { 2859 2860 var noMedia = false; 2861 if (SDK.canPlayVideo == null) { 2862 if (!SDK.isMobile()) { 2863 SDK.canPlayVideo = true; 2864 } else { 2865 SDK.canPlayVideo = false; 2866 SDK.canPlayAudio = true; 2867 // Check if auto play has been disable by the browser (mobile Chrome/Safari) 2868 setTimeout(function() { 2869 if (noMedia) { 2870 SDK.canPlayVideo = null; 2871 SDK.canPlayAudio = null; 2872 } else { 2873 if (SDK.canPlayVideo == false) { 2874 SDK.initVideo = function() { 2875 SDK.canPlayVideo = true; 2876 SDK.audio = new Audio(SDK.url + '/chime.mp3'); 2877 SDK.audio.load(); 2878 SDK.autoPlayActionAudio = new Audio(SDK.url + '/chime.mp3'); 2879 SDK.autoPlayActionAudio.load(); 2880 SDK.autoPlayBackgroundAudio = new Audio(SDK.url + '/chime.mp3'); 2881 SDK.autoPlayBackgroundAudio.load(); 2882 SDK.updateAvatar(responseMessage, speak, urlprefix, elementPrefix, channelaudio, afterFunction, nativeVoice, lang, voice); 2883 document.getElementById("sdkplaybutton2").style.display = "none"; 2884 }; 2885 var body = document.body || document.getElementsByTagName('body')[0]; 2886 var playButton = document.createElement('div'); 2887 var html = "<div id='sdkplaybutton2' style='position:fixed;bottom:32px;left:32px;z-index:164;'><img onclick='SDK.initVideo()' width='64' src='" 2888 + SDK.url + "/images/playsound.png'/></div>" 2889 playButton.innerHTML = html; 2890 body.appendChild(playButton); 2891 setTimeout(function() { 2892 document.getElementById("sdkplaybutton2").style.display = "none"; 2893 }, 10000); 2894 } 2895 } 2896 }, SDK.autoPlayDelay); 2897 } 2898 } 2899 nativeVoice = nativeVoice && SDK.speechSynthesis; 2900 if (elementPrefix == null) { 2901 elementPrefix = ""; 2902 } 2903 var avatarStatus = document.getElementById(elementPrefix + "avatar-status"); 2904 if (avatarStatus != null) { 2905 var status = ""; 2906 if (responseMessage.emote != null && responseMessage.emote != "" && responseMessage.emote != "NONE") { 2907 status = responseMessage.emote.toLowerCase(); 2908 } 2909 if (responseMessage.action != null && responseMessage.action != "") { 2910 if (status != "") { 2911 status = status + " : "; 2912 } 2913 status = status + responseMessage.action; 2914 } 2915 if (responseMessage.pose != null && responseMessage.pose != "") { 2916 if (status != "") { 2917 status = status + " : "; 2918 } 2919 status = status + responseMessage.pose; 2920 } 2921 avatarStatus.innerHTML = status; 2922 } 2923 if (responseMessage.avatarActionAudio != null && speak) { 2924 var audio = SDK.autoPlayActionAudio; 2925 if (audio == null) { 2926 audio = new Audio(urlprefix + responseMessage.avatarActionAudio); 2927 } else { 2928 audio.src = urlprefix + responseMessage.avatarActionAudio; 2929 } 2930 if (SDK.canPlayVideo == null) { 2931 audio.onplaying = new function() { 2932 SDK.canPlayVideo = true; 2933 } 2934 } 2935 audio.play(); 2936 } 2937 if (!speak || SDK.currentBackgroundAudio != responseMessage.avatarAudio) { 2938 // Only switch if different audio. 2939 if (SDK.backgroundAudio != null) { 2940 SDK.backgroundAudio.pause(); 2941 SDK.currentBackgroundAudio = null; 2942 } 2943 if (responseMessage.avatarAudio != null && speak) { 2944 SDK.currentBackgroundAudio = responseMessage.avatarAudio; 2945 SDK.backgroundAudio = SDK.autoPlayBackgroundAudio; 2946 if (SDK.backgroundAudio == null) { 2947 SDK.backgroundAudio = new Audio(urlprefix + responseMessage.avatarAudio); 2948 } else { 2949 SDK.backgroundAudio.src = urlprefix + responseMessage.avatarAudio; 2950 } 2951 SDK.backgroundAudio.loop = true; 2952 if (SDK.canPlayVideo == null) { 2953 SDK.backgroundAudio.onplaying = new function() { 2954 document.getElementById("native-voice-name").value = "onplaying-back"; 2955 SDK.canPlayVideo = true; 2956 } 2957 } 2958 SDK.backgroundAudio.play(); 2959 } 2960 } 2961 var video = document.getElementById(elementPrefix + "avatar-video"); 2962 var isVideo = responseMessage.avatarType != null && responseMessage.avatarType.indexOf("video") != -1; 2963 var useVideo = video != null && SDK.useVideo != false && (SDK.useVideo == true || !(SDK.isSafari() && SDK.isIPhone())); 2964 if (isVideo && useVideo) { 2965 var div = document.getElementById(elementPrefix + "avatar-image-div"); 2966 if (div != null) { 2967 div.style.display = "none"; 2968 } 2969 div = document.getElementById(elementPrefix + "avatar-game-div"); 2970 if (div != null) { 2971 div.style.display = "none"; 2972 } 2973 div = document.getElementById(elementPrefix + "avatar-video-div"); 2974 var canvas = null; 2975 if (div != null) { 2976 div.style.display = "inline-block"; 2977 if (responseMessage.avatarBackground != null) { 2978 div.style.backgroundImage = "url(" + urlprefix + responseMessage.avatarBackground + ")"; 2979 } 2980 var canvasDiv = document.getElementById(elementPrefix + "avatar-canvas-div"); 2981 if (((SDK.isChrome() && !SDK.isMobile()) || (SDK.isFirefox() && !SDK.isMac()) || SDK.useCanvas == true) && SDK.useCanvas != false && canvasDiv != null) { 2982 div.style.position = "fixed"; 2983 div.style.top = "-1000"; 2984 div.style.left = "-1000"; 2985 div.style.opacity = "0"; 2986 div.style.zIndex = "-1"; 2987 canvasDiv.style.display = "inline-block"; 2988 canvas = document.getElementById(elementPrefix + "avatar-canvas"); 2989 } 2990 } 2991 if (SDK.canPlayVideo == null) { 2992 video.onplaying = new function() { 2993 document.getElementById("native-voice-name").value = "onplaying-video"; 2994 SDK.canPlayVideo = true; 2995 } 2996 } 2997 if (responseMessage.avatar.indexOf("mp4") != -1 && (SDK.isChrome() || SDK.isFirefox() || SDK.fixBrightness != true) && SDK.fixBrightness != false) { 2998 // Hack to fix grey background in Chrome. 2999 if (SDK.isChrome()) { 3000 video.style.webkitFilter = "brightness(108.5%)"; 3001 } else { 3002 video.style["filter"] = "brightness(1.085)"; 3003 } 3004 if (canvas != null) { 3005 if (SDK.isChrome()) { 3006 canvas.style.webkitFilter = "brightness(108.5%)"; 3007 } else { 3008 video.style["filter"] = "brightness(1.085)"; 3009 } 3010 } 3011 } 3012 if (canvas == null) { 3013 if (responseMessage.avatarBackground != null) { 3014 video.poster = urlprefix + responseMessage.avatarBackground; 3015 } 3016 } 3017 var context = null; 3018 var drawCanvas = null; 3019 if (canvas != null) { 3020 context = canvas.getContext('2d'); 3021 if (SDK.timers[elementPrefix + "avatar-canvas"] == null) { 3022 drawCanvas = function() { 3023 if (!video.paused && !video.ended && video.currentTime > 0) { 3024 if (canvas.width != video.offsetWidth) { 3025 canvas.width = video.offsetWidth; 3026 } 3027 if (canvas.height != video.offsetHeight) { 3028 canvas.height = video.offsetHeight; 3029 } 3030 context.clearRect(0, 0, canvas.width, canvas.height); 3031 context.drawImage(video, 0, 0, video.offsetWidth, video.offsetHeight); 3032 } 3033 } 3034 SDK.timers[elementPrefix + "avatar-canvas"] = drawCanvas; 3035 setInterval(drawCanvas, 20); 3036 } 3037 } 3038 var end = function() { 3039 video.src = urlprefix + responseMessage.avatar; 3040 if (responseMessage.avatar2 == null) { 3041 video.loop = true; 3042 } else { 3043 video.loop = false; 3044 video.onended = function() { 3045 var index = Math.floor(Math.random() * 5); 3046 if (index == 4 && responseMessage.avatar5 != null) { 3047 video.src = urlprefix + responseMessage.avatar5; 3048 } else if (index == 3 && responseMessage.avatar4 != null) { 3049 video.src = urlprefix + responseMessage.avatar4; 3050 } else if (index == 2 && responseMessage.avatar3 != null) { 3051 video.src = urlprefix + responseMessage.avatar3; 3052 } else if (index == 1 && responseMessage.avatar2 != null) { 3053 video.src = urlprefix + responseMessage.avatar2; 3054 } else { 3055 video.src = urlprefix + responseMessage.avatar; 3056 } 3057 video.play(); 3058 } 3059 } 3060 video.play(); 3061 if (afterFunction != null) { 3062 afterFunction(); 3063 } 3064 } 3065 var talk = function() { 3066 if (responseMessage.message != null && responseMessage.message.length > 0) { 3067 if (responseMessage.avatarTalk != null) { 3068 if (speak) { 3069 if (responseMessage.speech == null && !nativeVoice) { 3070 end(); 3071 } else { 3072 video.src = urlprefix + responseMessage.avatar; 3073 video.loop = true; 3074 var playing = false; 3075 video.play(); 3076 3077 if (nativeVoice) { 3078 if ('SpeechSynthesisUtterance' in window) { 3079 utterance = new SpeechSynthesisUtterance(SDK.stripTags(responseMessage.message)); 3080 } else { 3081 utterance = new SpeechSynthesisUtterance2(SDK.stripTags(responseMessage.message)); 3082 } 3083 SDK.utterance = utterance; 3084 utterance.onstart = function() { 3085 if (playing) { 3086 return false; 3087 } 3088 if ('speechSynthesis' in window) { 3089 speechSynthesis.pause(); 3090 } 3091 video.src = urlprefix + responseMessage.avatarTalk; 3092 video.loop = true; 3093 video.oncanplay = function() { 3094 if (playing) { 3095 return false; 3096 } 3097 playing = true; 3098 if ('speechSynthesis' in window) { 3099 speechSynthesis.resume(); 3100 } 3101 } 3102 video.play(); 3103 } 3104 utterance.onerror = function() { 3105 console.log("error"); 3106 end(); 3107 } 3108 utterance.onend = function() { 3109 end(); 3110 } 3111 3112 SDK.nativeTTS(utterance, lang, voice); 3113 } else { 3114 //var audio = new Audio(urlprefix + responseMessage.speech, channelaudio); 3115 var audio = SDK.play(urlprefix + responseMessage.speech, channelaudio); 3116 //audio.onabort = function() {console.log("abort");} 3117 audio.oncanplay = function() { 3118 if (playing) { 3119 return false; 3120 } 3121 audio.pause(); 3122 video.src = urlprefix + responseMessage.avatarTalk; 3123 video.loop = true; 3124 video.oncanplay = function() { 3125 if (playing) { 3126 return false; 3127 } 3128 playing = true; 3129 audio.play(); 3130 } 3131 video.play(); 3132 } 3133 audio.onerror = function() { 3134 console.log("error"); 3135 end(); 3136 } 3137 //audio.onloadeddata = function() {console.log("loadeddata");} 3138 //audio.onloadedmetadata = function() {console.log("loadedmetadata");} 3139 //audio.onpause = function() {console.log("pause");} 3140 //audio.onplay = function() {console.log("play");} 3141 //audio.onplaying = function() {console.log("playing");} 3142 //audio.ontimeupdate = function() {console.log("timeupdate");} 3143 var onended = audio.onended; 3144 audio.onended = function() { 3145 if (onended != null) { 3146 onended(); 3147 } 3148 end(); 3149 } 3150 audio.play(); 3151 video.play(); 3152 } 3153 } 3154 } else { 3155 video.src = urlprefix + responseMessage.avatarTalk; 3156 video.loop = false; 3157 video.play(); 3158 var onended = video.onended; 3159 video.onended = function() { 3160 if (onended != null) { 3161 onended(); 3162 } 3163 end(); 3164 } 3165 } 3166 } else { 3167 video.src = urlprefix + responseMessage.avatar; 3168 video.loop = true; 3169 video.play(); 3170 if (speak) { 3171 if (nativeVoice) { 3172 if ('SpeechSynthesisUtterance' in window) { 3173 utterance = new SpeechSynthesisUtterance(SDK.stripTags(responseMessage.message)); 3174 } else { 3175 utterance = new SpeechSynthesisUtterance2(SDK.stripTags(responseMessage.message)); 3176 } 3177 utterance.onend = afterFunction; 3178 SDK.nativeTTS(utterance, lang, voice); 3179 } else { 3180 var audio = SDK.play(urlprefix + responseMessage.speech, channelaudio); 3181 var onended = audio.onended; 3182 audio.onended = function() { 3183 if (onended != null) { 3184 onended(); 3185 } 3186 if (afterFunction != null) { 3187 afterFunction(); 3188 } 3189 } 3190 } 3191 } else if (afterFunction != null) { 3192 afterFunction(); 3193 } 3194 } 3195 } else { 3196 end(); 3197 } 3198 } 3199 3200 if (responseMessage.avatarAction != null) { 3201 video.src = urlprefix + responseMessage.avatarAction; 3202 video.loop = false; 3203 video.play(); 3204 var onended = video.onended; 3205 video.onended = function() { 3206 if (onended != null) { 3207 onended(); 3208 } 3209 talk(); 3210 } 3211 } else { 3212 talk(); 3213 } 3214 } else { 3215 var div = document.getElementById(elementPrefix + "avatar-video-div"); 3216 if (div != null) { 3217 div.style.display = "none"; 3218 } 3219 div = document.getElementById(elementPrefix + "avatar-canvas-div"); 3220 if (div != null) { 3221 div.style.display = "none"; 3222 } 3223 div = document.getElementById(elementPrefix + "avatar-game-div"); 3224 if (div != null) { 3225 div.style.display = "none"; 3226 } 3227 div = document.getElementById(elementPrefix + "avatar-image-div"); 3228 if (div != null) { 3229 div.style.display = "inline-block"; 3230 } 3231 var img = document.getElementById(elementPrefix + 'avatar'); 3232 if (img != null) { 3233 if (isVideo) { 3234 img.src = urlprefix + responseMessage.avatarBackground; 3235 } else { 3236 img.src = urlprefix + responseMessage.avatar; 3237 } 3238 } 3239 img = document.getElementById(elementPrefix + 'avatar2'); 3240 if (img != null) { 3241 if (isVideo) { 3242 img.src = urlprefix + responseMessage.avatarBackground; 3243 } else { 3244 img.src = urlprefix + responseMessage.avatar; 3245 } 3246 } 3247 if (speak && responseMessage.message != null && responseMessage.message.length > 0) { 3248 if (nativeVoice) { 3249 noMedia = true; 3250 SDK.tts(SDK.stripTags(responseMessage.message), null, true, lang, voice); 3251 } else if (responseMessage.speech != null) { 3252 var audio = SDK.play(urlprefix + responseMessage.speech, channelaudio); 3253 var onended = audio.onended; 3254 audio.onended = function() { 3255 if (onended != null) { 3256 onended(); 3257 } 3258 if (afterFunction != null) { 3259 afterFunction(); 3260 } 3261 } 3262 } 3263 } else { 3264 noMedia = true; 3265 if (afterFunction != null) { 3266 afterFunction(); 3267 } 3268 } 3269 } 3270 3271 } catch(err) { 3272 } 3273 } 3274 3275 /** 3276 * The WebChatbotListener provides an integration between a chat bot conversation through a SDKConnection and an HTML document. 3277 * It updates the document to messages received from the connection, and sends messages from the document's form. 3278 * The HTML document requires the following elements: 3279 * <ul> 3280 * <li> chat - input (type='text') element for sending messages 3281 * <li> send - input (type='submit') button for sending chat input 3282 * <li> response - p element paragraph for last chat message 3283 * <li> console - table element for chat log, and avatar 3284 * <li> scroller - div element for chat log scroll pane 3285 * <li> avatar - img element for the bot's avatar (optional) 3286 * <li> avatar2 - img element hover img for the bot's avatar (optional) 3287 * <li> avatar-image-div - div element for the bot's image (optional) 3288 * <li> avatar-video - video element for the bot's video (optional) 3289 * <li> avatar-video-div - div element for the bot's video (optional) 3290 * <li> avatar-status - span element for the bot's current status (optional) 3291 * </ul> 3292 * If a prefix is set, these id will be prefixed by the prefix. 3293 * Or you can call createBox() to have the WebChatbotListener create its own components in the current page. 3294 * @class 3295 */ 3296 function WebChatbotListener() { 3297 /** Set the caption for the button bar button. */ 3298 this.caption = null; 3299 /** Disallow speech. */ 3300 this.allowSpeech = true; 3301 /** Disallow image/file upload menus and buttons. */ 3302 this.allowFiles = true; 3303 /** Add image/file upload buttons to toolbar. */ 3304 this.showFileButtons = false; 3305 /** Remove menubar. */ 3306 this.showMenubar = true; 3307 /** Show Box Max*/ 3308 this.showBoxmax = true; 3309 /** Show Send Image*/ 3310 this.showSendImage = true; 3311 /** Remove language choice. */ 3312 this.showChooseLanguage = true; 3313 /** Enable or disable speech. */ 3314 this.speak = true; 3315 /** Configure if the browser's native voice TTS should be used. */ 3316 this.nativeVoice = false; 3317 /** Set the voice name for the native voice. */ 3318 this.nativeVoiceName = null; 3319 /** Set the language for the native voice. */ 3320 this.lang = null; 3321 /** Translate between the user's language, and the bot's language. */ 3322 this.translate = false; 3323 /** Enable or disable avatar. */ 3324 this.avatar = true; 3325 /** Set the avatar. */ 3326 this.avatarId = null; 3327 /** Set if the avatar should request HD (high def) video/images. */ 3328 this.hd = null; 3329 /** Set if the avatar should request a specific video or image format. */ 3330 this.format = null; 3331 /** A SDK connection must be set, be sure to include your app id. */ 3332 this.connection = null; 3333 /** The id or name of the bot instance to connect to. */ 3334 this.instance = null; 3335 /** The name to display for the bot. */ 3336 this.instanceName = "Bot"; 3337 /** The name to display for the user. */ 3338 this.userName = "You"; 3339 /** Allow the button color to be set. */ 3340 this.color = "#009900"; 3341 /** Allow the different style sheet options */ 3342 this.version = null; 3343 /** Set if the box chat log should be shown. */ 3344 this.chatLog = true; 3345 /** Allow the hover button color to be set. */ 3346 this.hoverColor = "grey"; 3347 /** Allow the background color to be set. */ 3348 this.background = null; 3349 /** Avatar image/video width. */ 3350 this.width = 300; 3351 /** Avatar image/video height. */ 3352 this.height = null; 3353 /** Chat bar offest from side. */ 3354 this.offset = 30; 3355 /** Chat Button Vertial Offset*/ 3356 this.verticalOffset = 0; 3357 /** Only apply the background color if not Chrome. */ 3358 this.backgroundIfNotChrome = false; 3359 /** onresponse event is raised after a response is received. */ 3360 this.onresponse = null; 3361 /** Configure if chat should be given focus after response. */ 3362 this.focus = true; 3363 /** Override the URL used in the chat bot box popup. */ 3364 this.popupURL = null; 3365 /** Print response in chat bubble. */ 3366 this.bubble = false; 3367 /** Initial message to send to the bot. */ 3368 this.greetingMessage = null; 3369 /** Initial message to display from the bot. (it is normally better to set a greeting in the bot instead). */ 3370 this.greeting = null; 3371 /** Loading message to display. */ 3372 this.loading = "loading..."; 3373 /** Element id and class prefix. This allows an id and class prefix to avoid name collisions on the element names for the chat, response, console, and avatar elements.*/ 3374 this.prefix = ""; 3375 /** This can be used to keep the bot's chat bar in synch with a livechat bar. */ 3376 this.livechatPrefix = null; 3377 /** Allows the bot's thumbnail image to be set for chat log. */ 3378 this.botThumb = {}; 3379 /** Allows the user's thumbnail image to be set for chat log. */ 3380 this.userThumb = {}; 3381 /** Set styles explictly to avoid inheriting page styles. Disable this to be able to override styles. */ 3382 this.forceStyles = true; 3383 /** Add additional css style code. */ 3384 this.style = ""; 3385 /** Set the location of the button and box, one of "bottom-right", "bottom-left", "top-right", "top-left". */ 3386 this.boxLocation = "bottom-right"; 3387 /** Prompt for name/email before connecting. */ 3388 this.promptContactInfo = false; 3389 this.hasContactInfo = false; 3390 this.contactName = null; 3391 this.contactEmail = null; 3392 this.contactPhone = null; 3393 this.contactInfo = ""; 3394 /** Set if the backlink should be displayed. */ 3395 this.backlink = SDK.backlink; 3396 3397 /** Support connections to external bots through their web API. */ 3398 this.external = false; 3399 this.apiURL = null; 3400 this.apiPost = null; 3401 this.apiResponse = null; 3402 3403 this.switchText = true; 3404 this.big = false; 3405 this.conversation = null; 3406 this.voiceInit = null; 3407 this.listen = false; 3408 3409 /** 3410 * Create an embedding bar and div in the current webpage. 3411 */ 3412 this.createBox = function() { 3413 if (this.livechatPrefix == null) { 3414 if (this.version >= 6.0) { 3415 this.livechatPrefix = "chat"; 3416 } else { 3417 this.livechatPrefix = "livechat"; 3418 } 3419 } 3420 if (this.prefix == "" && this.elementPrefix != null) { 3421 this.prefix = this.elementPrefix; 3422 } 3423 if (this.caption == null) { 3424 this.caption = this.instanceName; 3425 } 3426 var backgroundstyle = ""; 3427 var buttonstyle = ""; 3428 var buttonHoverStyle = ""; 3429 var hidden = "hidden"; 3430 var border = ""; 3431 if (this.backgroundIfNotChrome && SDK.isChrome()) { 3432 this.background = null; 3433 } 3434 if (this.background != null) { 3435 backgroundstyle = " style='background-color:" + this.background + "'"; 3436 hidden = "visible"; 3437 border = "border:1px;border-style:solid;border-color:black;"; 3438 } 3439 if (this.color != null) { 3440 buttonstyle = "background-color:" + this.color + ";"; 3441 } 3442 if (this.hoverColor != null) { 3443 buttonHoverStyle = "background-color:" + this.hoverColor + ";"; 3444 } 3445 var minWidth = ""; 3446 var divWidth = ""; 3447 var background = ""; 3448 var minHeight = ""; 3449 var divHeight = ""; 3450 var maxDivWidth = ""; 3451 var maxHeight = null; 3452 var responseWidth = ""; 3453 var chatWidth = ""; 3454 var hideAvatar = ""; 3455 var avatarWidth = this.width; 3456 var minAvatarWidth = ""; 3457 var scrollerHeight = this.height; 3458 var scrollerMinHeight = ""; 3459 if (this.width != null) { 3460 if (typeof this.width === "string") { 3461 this.width = parseInt(width); 3462 } 3463 // Auto correct for a short window or screen (assuming square). 3464 // 250 is total box height minus avatar. 3465 if ((this.width + 250) > window.innerHeight) { 3466 avatarWidth = window.innerHeight - 250; 3467 if (avatarWidth < 100) { 3468 hideAvatar = "display:none"; 3469 } 3470 } 3471 minWidth = "width:" + this.width + "px;"; 3472 minAvatarWidth = "width:" + avatarWidth + "px;"; 3473 background = "background-size:" + avatarWidth + "px auto;"; 3474 divWidth = minWidth; 3475 divHeight = "min-height:" + avatarWidth + "px;"; 3476 responseWidth = "width:" + (this.width - 16) + "px;"; 3477 chatWidth = "width:" + this.width + "px;"; 3478 maxDivWidth = "max-width:" + (this.width - 50) + "px;"; 3479 scrollerHeight = avatarWidth; 3480 } 3481 if (this.height != null) { 3482 if (typeof this.height === "string") { 3483 this.height = parseInt(height); 3484 } 3485 minHeight = "height:" + this.height + "px;"; 3486 divHeight = minHeight; 3487 if (this.width != null) { 3488 background = "background-size:" + this.width + "px " + this.height + "px;"; 3489 } else { 3490 background = "background-size: auto " + this.height + "px;"; 3491 divWidth = "min-width:" + this.height + "px;"; 3492 responseWidth = "width:" + (this.height - 16) + "px;"; 3493 chatWidth = "width:" + this.height + "px;"; 3494 } 3495 } else { 3496 scrollerMinHeight = "height:" + scrollerHeight + "px;"; 3497 } 3498 var inputFont = ""; 3499 if (SDK.isMobile()) { 3500 inputFont = "font-size: 16px;"; 3501 } 3502 var boxloc = "bottom:10px;right:10px"; 3503 if (this.boxLocation == "top-left") { 3504 boxloc = "top:10px;left:10px"; 3505 } else if (this.boxLocation == "top-right") { 3506 boxloc = "top:10px;right:10px"; 3507 } else if (this.boxLocation == "bottom-left") { 3508 boxloc = "bottom:10px;left:10px"; 3509 } else if (this.boxLocation == "bottom-right") { 3510 boxloc = "bottom:10px;right:10px"; 3511 } 3512 var locationBottom = 20; 3513 if (this.version < 6.0 || this.prefix != "botplatform") { 3514 locationBottom = 2; 3515 } 3516 var boxbarloc = "bottom:" + (locationBottom + this.verticalOffset) + "px;right:" + this.offset + "px"; 3517 if (this.boxLocation == "top-left") { 3518 boxbarloc = "top:" + (locationBottom + this.verticalOffset) + "px;left:" + this.offset + "px"; 3519 } else if (this.boxLocation == "top-right") { 3520 boxbarloc = "top:" + (locationBottom + this.verticalOffset) + "px;right:" + this.offset + "px"; 3521 } else if (this.boxLocation == "bottom-left") { 3522 boxbarloc = "bottom:" + (locationBottom + this.verticalOffset) + "px;left:" + this.offset + "px"; 3523 } else if (this.boxLocation == "bottom-right") { 3524 boxbarloc = "bottom:" + (locationBottom + this.verticalOffset) + "px;right:" + this.offset + "px"; 3525 } 3526 var box = document.createElement('div'); 3527 var html = 3528 "<style>\n" 3529 + "." + this.prefix + "box { position:fixed;" + boxloc + ";z-index:152;margin:2px;display:none;" + border + " }\n" 3530 + "." + this.prefix + "boxmenu { visibility:" + hidden + "; }\n" 3531 + (this.forceStyles ? "#" : ".") + "" + this.prefix + "boxbarmax { font-size:18px;margin:2px;padding:0px;text-decoration:none; }\n" 3532 + "." + this.prefix + "boxbar { position:fixed;" + boxbarloc + ";z-index:152;margin:0;padding:6px;" + buttonstyle + " }\n" 3533 + "." + this.prefix + "boxbar:hover { " + buttonHoverStyle + " }\n" 3534 + "." + this.prefix + "no-bubble-text { " + responseWidth + "; max-height:100px; overflow:auto; }\n" 3535 + "#" + this.prefix + "contactinfo { " + minHeight + minWidth + " }\n" 3536 + "." + this.prefix + "contactconnect { margin:4px;padding:8px;color:white;text-decoration:none;" + buttonstyle + " }\n" 3537 + "." + this.prefix + "scroller { overflow-x:hidden;" + scrollerMinHeight + minWidth + " }\n" 3538 + "." + this.prefix + "bubble-text { " + responseWidth + "; max-height:100px; overflow:auto; }\n" 3539 + "." + this.prefix + "chatchat-1-div { " + maxDivWidth + "}\n" 3540 + "." + this.prefix + "chatchat-2-div { " + maxDivWidth + "}\n" 3541 + (this.forceStyles ? "#" : ".") + this.prefix + "chat { width:99%;min-height:22px; }\n" 3542 + "." + this.prefix + "box:hover ." + this.prefix + "boxmenu { visibility:visible; }\n"; 3543 if (this.version < 6.0 || this.prefix != "botplatform") { 3544 html = html 3545 + "." + this.prefix + "box:hover { border:1px;border-style:solid;border-color:black; }\n" 3546 + "." + this.prefix + "box:hover ." + this.prefix + "boxmenu { visibility:visible; }\n" 3547 + "." + this.prefix + "boxclose, ." + this.prefix + "boxmin, ." + this.prefix + "boxmax { font-size:22px;margin:2px;padding:0px;text-decoration:none; }\n" 3548 + "." + this.prefix + "boxclose:hover, ." + this.prefix + "boxmin:hover, ." + this.prefix + "boxmax:hover { color: #fff;background: grey; }\n" 3549 + "." + this.prefix + "no-bubble { margin:4px; padding:8px; border:1px; border-style:solid; border-color:black; background-color:white; color:#585858; }\n" 3550 + "." + this.prefix + "no-bubble-plain { margin:4px; padding:8px; border:1px; }\n" 3551 + "#" + this.prefix + "contactinfo span { margin-left:4px;margin-top:4px; }\n" 3552 + "#" + this.prefix + "contactinfo input { margin:4px;font-size:13px;height:33px;width:90%;border:1px solid #d5d5d5; }\n" 3553 + "." + this.prefix + "boxbutton { width:20px;height:20px;margin:4px; }\n" 3554 + "." + this.prefix + "menupopup div { position:absolute;margin: -1px 0 0 0;padding: 3px 3px 3px 3px;background: #fff;border-style:solid;border-color:black;border-width:1px;width:180px;max-width:300px;z-index:152;visibility:hidden;opacity:0;transition:visibility 0s linear 0.3s, opacity 0.3s linear; }\n" 3555 + "." + this.prefix + "menupopup:hover div { display:inline;visibility:visible;opacity:1;transition-delay:0.5s; }\n" 3556 + "a." + this.prefix + "menuitem { text-decoration: none;display: block;color: #585858; }\n" 3557 + "a." + this.prefix + "menuitem:hover { color: #fff;background: grey; }\n" 3558 + "tr." + this.prefix + "menuitem:hover { background: grey; }\n" 3559 + "." + this.prefix + "yandex { display:none; }\n" 3560 + "." + this.prefix + "chatpowered { margin:4px;color:grey;font-size:10px; }\n" 3561 + "img." + this.prefix + "menu { width: 24px;height: 24px;margin: 2px;cursor: pointer;vertical-align: middle; }\n" 3562 + "span." + this.prefix + "menu { color: #818181;font-size: 12px; }\n" 3563 + "." + this.prefix + "bubble-div { padding-bottom:15px;position:relative; }\n" 3564 + "." + this.prefix + "bubble { margin:4px; padding:8px; border:1px; border-style:solid; border-color:black; border-radius:10px; background-color:white; color:#585858; }\n" 3565 + "." + this.prefix + "bubble:before { content:''; position:absolute; bottom:0px; left:40px; border-width:20px 0 0 20px; border-style:solid; border-color:black transparent; display:block; width:0;}\n" 3566 + "." + this.prefix + "bubble:after { content:''; position:absolute; bottom:3px; left:42px; border-width:18px 0 0 16px; border-style:solid; border-color:white transparent; display:block; width:0;}\n" 3567 + "." + this.prefix + "box-input-span { display:block; overflow:hidden; margin:4px; padding-right:4px; }\n" 3568 + "#" + this.prefix + "boxtable { background:none; border:none; margin:0; }\n" 3569 + "#" + this.prefix + "showChatLog { display:none; }\n" 3570 + "#" + this.prefix + "showChatLogButton { display:none; }\n" 3571 + "#" + this.prefix + "boxbar3 { display:none; }\n" 3572 + "#" + this.prefix + "boxbarmax { color: white; }\n"; 3573 } 3574 html = html + this.style 3575 + "</style>\n" 3576 + "<div id='" + this.prefix + "box' class='" + this.prefix + "box' " + backgroundstyle + ">" 3577 + "<div class='" + this.prefix + "boxmenu'>" 3578 + (this.backlink ? "<span class='" + this.prefix + "chatpowered'>powered by <a href='" + SDK.backlinkURL + "' target='_blank'>" + SDK.NAME + "</a></span>" : "") 3579 + "<span style='float:right'><a id='" + this.prefix + "boxmin' class='" + this.prefix + "boxmin' onclick='return false;' href='#'><img src='" + SDK.url + "/images/minimize.png'></a> "; 3580 if (this.showBoxmax) { 3581 html = html + "<a id='" + this.prefix + "boxmax' class='" + this.prefix + "boxmax' onclick='return false;' href='#'><img src='" + SDK.url + "/images/open.png'> </a></span><br/>"; 3582 } else { 3583 html = html + "</span><br/>"; 3584 } 3585 html = html + "</div>"; 3586 html = html 3587 + "<div id='" + this.prefix + "online' class='" + this.prefix + "online'>" 3588 + "</div>" 3589 + "<div id='" + this.prefix + "scroller' class='" + this.prefix + "scroller'>" 3590 + "<table id='" + this.prefix + "console' class='" + this.prefix + "console' width=100% cellspacing=2></table>" 3591 + "</div>"; 3592 html = html 3593 + "<div id='" + this.prefix + "avatar-div' style='" + hideAvatar + "'>" 3594 + "<div id='" + this.prefix + "avatar-image-div' style='display:none;text-align:center;" + minHeight + minAvatarWidth + "'>" 3595 + "<img id='" + this.prefix + "avatar' style='" + minHeight + minAvatarWidth + "'/>" 3596 + "</div>" 3597 + "<div id='" + this.prefix + "avatar-video-div' style='display:none;text-align:center;" + divHeight + divWidth + background + "background-repeat: no-repeat;'>" 3598 + "<video id='" + this.prefix + "avatar-video' autoplay preload='auto' style='background:transparent;" + minHeight + minAvatarWidth + "'>" 3599 + "Video format not supported by your browser (try Chrome)" 3600 + "</video>" 3601 + "</div>" 3602 + "<div id='" + this.prefix + "avatar-canvas-div' style='display:none;text-align:center;" + divHeight + divWidth + "'>" 3603 + "<canvas id='" + this.prefix + "avatar-canvas' style='background:transparent;" + minHeight + minAvatarWidth + "'>" 3604 + "Canvas not supported by your browser (try Chrome)" 3605 + "</canvas>" 3606 + "</div>" 3607 + "<div id='" + this.prefix + "avatar-game-div' style='display:none;text-align:center;" + divHeight + divWidth + "'>" 3608 + "</div>" 3609 + "</div>"; 3610 3611 var urlprefix = this.connection.credentials.url + "/"; 3612 html = html 3613 + "<div>" 3614 + "<div " + (this.bubble ? "id='" + this.prefix + "bubble-div'" : "") + " " + (this.bubble ? "class='" + this.prefix + "bubble-div'" : "") + ">" 3615 + "<div class='" + this.prefix + "" + (this.bubble ? "bubble" : (this.background == null ? "no-bubble" : "no-bubble-plain") ) 3616 + "'><div class='" + this.prefix + (this.bubble ? "bubble-text" : "no-bubble-text" ) + "'>" 3617 + "<span id='" + this.prefix + "response'>" + (this.greeting == null ? this.loading : this.greeting) + "</span><br/>" 3618 + "</div></div></div>" 3619 + "<div><span class='" + this.prefix + "box-input-span'><input id='" + this.prefix + "chat' type='text' class='" + this.prefix + "box-input'/></span></div>"; 3620 if (this.showMenubar) { 3621 html = html 3622 + "<div>" 3623 + "<span class='" + this.prefix + "menu'>\n" 3624 + "<div style='inline-block;position:relative'>\n" 3625 + "<span class='" + this.prefix + "menupopup'>" 3626 + "<div style='text-align:left;bottom:30px'>" 3627 + "<table>\n"; 3628 if (this.showChooseLanguage) { 3629 html = html 3630 + "<tr class='" + this.prefix + "menuitem'>" 3631 + "<td><a id='" + this.prefix + "boxlanguagemenu' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + urlprefix + "images/language.png' title='Translate to and from your selected language'>" 3632 + " <select id='" + this.prefix + "chooselanguage'>" 3633 + "<option value='none'>Choose Language</option>" 3634 + "<option value='en'>English</option>" 3635 + "<option value='zh'>Chinese</option>" 3636 + "<option value='es'>Spanish</option>" 3637 + "<option value='pt'>Portuguese</option>" 3638 + "<option value='de'>German</option>" 3639 + "<option value='fr'>French</option>" 3640 + "<option value='ja'>Japanese</option>" 3641 + "<option value='ar'>Arabic</option>" 3642 + "<option value='none'>None</option>" 3643 + "<option value='none'></option>" 3644 + "<option value='af'>Afrikaans</option>" 3645 + "<option value='sq'>Albanian</option>" 3646 + "<option value='hy'>Armenian</option>" 3647 + "<option value='az'>Azerbaijani</option>" 3648 + "<option value='ba'>Bashkir</option>" 3649 + "<option value='eu'>Basque</option>" 3650 + "<option value='be'>Belarusian</option>" 3651 + "<option value='bn'>Bengali</option>" 3652 + "<option value='bs'>Bosnian</option>" 3653 + "<option value='bg'>Bulgarian</option>" 3654 + "<option value='ca'>Catalan</option>" 3655 + "<option value='za'>Chinese</option>" 3656 + "<option value='hr'>Croatian</option>" 3657 + "<option value='cs'>Czech</option>" 3658 + "<option value='da'>Danish</option>" 3659 + "<option value='nl'>Dutch</option>" 3660 + "<option value='en'>English</option>" 3661 + "<option value='et'>Estonian</option>" 3662 + "<option value='fi'>Finnish</option>" 3663 + "<option value='fr'>French</option>" 3664 + "<option value='gl'>Galician</option>" 3665 + "<option value='ka'>Georgian</option>" 3666 + "<option value='de'>German</option>" 3667 + "<option value='gu'>Gujarati</option>" 3668 + "<option value='ht'>Haitian</option>" 3669 + "<option value='he'>Hebrew</option>" 3670 + "<option value='hi'>Hindi</option>" 3671 + "<option value='hu'>Hungarian</option>" 3672 + "<option value='id'>Indonesian</option>" 3673 + "<option value='ga'>Irish</option>" 3674 + "<option value='it'>Italian</option>" 3675 + "<option value='ja'>Japanese</option>" 3676 + "<option value='kn'>Kannada</option>" 3677 + "<option value='kk'>Kazakh</option>" 3678 + "<option value='ky'>Kirghiz</option>" 3679 + "<option value='ko'>Korean</option>" 3680 + "<option value='la'>Latin</option>" 3681 + "<option value='lv'>Latvian</option>" 3682 + "<option value='lt'>Lithuanian</option>" 3683 + "<option value='mk'>Macedonian</option>" 3684 + "<option value='mg'>Malagasy</option>" 3685 + "<option value='ms'>Malay</option>" 3686 + "<option value='mt'>Maltese</option>" 3687 + "<option value='mn'>Mongolian</option>" 3688 + "<option value='no'>Norwegian</option>" 3689 + "<option value='fa'>Persian</option>" 3690 + "<option value='pl'>Polish</option>" 3691 + "<option value='pt'>Portuguese</option>" 3692 + "<option value='pa'>Punjabi</option>" 3693 + "<option value='ro'>Romanian</option>" 3694 + "<option value='ru'>Russian</option>" 3695 + "<option value='sr'>Serbian</option>" 3696 + "<option value='si'>Sinhalese</option>" 3697 + "<option value='sk'>Slovak</option>" 3698 + "<option value='es'>Spanish</option>" 3699 + "<option value='sw'>Swahili</option>" 3700 + "<option value='sv'>Swedish</option>" 3701 + "<option value='tl'>Tagalog</option>" 3702 + "<option value='tg'>Tajik</option>" 3703 + "<option value='ta'>Tamil</option>" 3704 + "<option value='tt'>Tatar</option>" 3705 + "<option value='th'>Thai</option>" 3706 + "<option value='tr'>Turkish</option>" 3707 + "<option value='uk'>Ukrainian</option>" 3708 + "<option value='ur'>Urdu</option>" 3709 + "<option value='uz'>Uzbek</option>" 3710 + "<option value='cy'>Welsh</option>" 3711 + "</select>" 3712 + "</a></td>" 3713 + "</tr>\n"; 3714 } 3715 if (this.allowFiles) { 3716 if (this.showSendImage) { 3717 html = html 3718 + "<tr class='" + this.prefix + "menuitem'>" 3719 + "<td><a id='" + this.prefix + "sendImage' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + urlprefix + "/images/image.png' title='Resize and send an image attachment'> Send image</a></td>" 3720 + "</tr>\n" 3721 + "<tr class='" + this.prefix + "menuitem'>" 3722 + "<td><a id='" + this.prefix + "sendAttachment' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + urlprefix + "/images/attach.png' title='Send an image or file attachment'> Send file</a></td>" 3723 + "</tr>\n"; 3724 } 3725 } 3726 html = html 3727 + "<tr id='" + this.prefix + "showChatLog' class='" + this.prefix + "menuitem'>" 3728 + "<td><a class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + urlprefix + "/images/chat_log.png' title='Chat log'> Chat Log</a></td>" 3729 + "</tr>\n" 3730 + "<tr id='" + this.prefix + "showAvatarBot' class='" + this.prefix + "menuitem' style='display:none;'>" 3731 + "<td><a class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img class='" + this.prefix + "menu' src='" + urlprefix + "/images/avatar-icon.png' title='Avatar Bot'> Show Avatar</a></td>" 3732 + "</tr>\n"; 3733 3734 if (this.allowSpeech) { 3735 html = html 3736 + "<tr class='" + this.prefix + "menuitem'>" 3737 + "<td><a id='" + this.prefix + "boxspeakmenu' class='" + this.prefix + "menuitem' onclick='return false;' href='#'><img id='" + this.prefix + "boxspeak2' class='" + this.prefix + "menu' src='" + urlprefix + (this.speak ? "images/sound.png": "images/mute.png") +"' title='Speech'> Speech</a></td>" 3738 + "</tr>\n"; 3739 if (SDK.isChrome()) { 3740 html = html 3741 + "<tr class='" + this.prefix + "menuitem'>" 3742 + "<td><a id='" + this.prefix + "boxspeakrecognitionmenu' class='" + this.prefix + "menuitem' onclick='return false;' href='#'>" 3743 + "<img id='" + this.prefix + "boxspeakrecognition2' class='" + this.prefix + "menu' src='" + urlprefix + "/images/micoff.png' title='Speech recognition (browser must support HTML5 speech recognition, such as Chrome)'> Speech Recognition</a>" 3744 + "</td>" 3745 + "</tr>\n" 3746 } 3747 } 3748 html = html 3749 + "</table>\n" 3750 + "</div>" 3751 + "<img id='" + this.prefix + "boxmenubutton' class='" + this.prefix + "boxbutton' src='" + urlprefix + "/images/menu.png'>"; 3752 if (this.showChooseLanguage) { 3753 html = html + "<img id='" + this.prefix + "boxlanguage' class='" + this.prefix + "boxbutton' src='" + urlprefix + "/images/language.png'>"; 3754 } 3755 html = html + "</span>"; 3756 if (this.allowSpeech) { 3757 html = html 3758 + "<a onclick='return false;' href='#' title='Speech'><img id='" + this.prefix + "boxspeak' class='" + this.prefix + "boxbutton' src='" 3759 + urlprefix 3760 + (this.speak ? "images/sound.png": "images/mute.png") +"'></a></td>" 3761 + (SDK.isChrome() ? 3762 ("<a onclick='return false;' href='#' title='Speech Recognition'><img id='" + this.prefix + "boxspeakrecognition' class='" + this.prefix + "boxbutton' src='" 3763 + urlprefix 3764 + "images/micoff.png'></a>") 3765 : ""); 3766 } 3767 html = html + "<a id='" + this.prefix + "showChatLogButton' onclick='return false;' href='#' title='Show chat log'>" 3768 + "<img class='" + this.prefix + "boxbutton' src='" + urlprefix + "/images/chat_log.png' title='Chat log'></a>" 3769 + "<a id='" + this.prefix + "showAvatarBotButton' style='display:none;' onclick='return false;' href='#' title='Show Avatar Bot'>" 3770 + "<img class='" + this.prefix + "boxbutton' src='" + urlprefix + "/images/avatar-icon.png' title='Avatar Bot'></a>"; 3771 } 3772 if (this.allowFiles && this.showFileButtons) { 3773 html = html 3774 + "<a id='" + this.prefix + "sendImageTool' onclick='return false;' href='#'><img class='" + this.prefix + "boxbutton' src='" + urlprefix + "/images/image.png' title='Resize and send an image attachment'></a>" 3775 + "<a id='" + this.prefix + "sendAttachmentTool' onclick='return false;' href='#'><img class='" + this.prefix + "boxbutton' src='" + urlprefix + "/images/attach.png' title='Send an image or file attachment'></a>"; 3776 } 3777 html = html 3778 + "</span>" 3779 + "</div>" 3780 + "</div>" 3781 + "<div id='" + this.prefix + "yandex' class='" + this.prefix + "yandex'><span>Powered by <a target='_blank' href='http://translate.yandex.com/'>Yandex.Translate</a></span></div>" 3782 + "</div>" 3783 + "</div>" 3784 + "<div id='" + this.prefix + "boxbar' class='" + this.prefix + "boxbar'>" 3785 + "<div id='" + this.prefix + "boxbar2' class='" + this.prefix + "boxbar2'>" 3786 + "<span><a id='" + this.prefix + "boxbarmax' class='" + this.prefix + "boxbarmax' " + " onclick='return false;' href='#'><img id='" + this.prefix + "boxbarmaximage' " + "src='" + SDK.url + "/images/maximizew.png'> " + this.caption + " </a>" 3787 + " <a id='" + this.prefix + "boxclose' class='" + this.prefix + "boxclose' onclick='return false;' onclick='return false;' href='#'> <img src='" + SDK.url + "/images/closeg.png'></a></span><br/>" 3788 + "</div>"; 3789 html = html 3790 + "<div id='" + this.prefix + "boxbar3' class='" + this.prefix + "boxbar3'" + ">" 3791 + "<span><a id='" + this.prefix + "boxbarmax2' class='" + this.prefix + "boxbarmax2' " + (this.forceStyles ? "style='color:white' " : "") + " onclick='return false;' href='#'>" + "</a></span><br>" 3792 + " <a id='" + this.prefix + "boxclose2' class='" + this.prefix + "boxclose2' onclick='return false;' onclick='return false;' href='#'> <img src='" + SDK.url + "/images/closeg.png'></a></span><br/>" 3793 + "</div>\n" 3794 + "</div>\n"; 3795 3796 if (this.promptContactInfo) { 3797 html = html 3798 + "<div id='" + this.prefix + "contactinfo' class='" + this.prefix + "box' " + backgroundstyle + ">" 3799 + "<div class='" + this.prefix + "boxmenu'>" 3800 + "<span style='float:right'><a id='" + this.prefix + "contactboxmin' class='" + this.prefix + "contactboxmin' onclick='return false;' href='#'><img src='" + SDK.url + "/images/minimize.png'></a>" 3801 + "</div>\n" 3802 + "<div style='margin:10px'>\n" 3803 + "<span>Name</span><br/><input id='" + this.prefix + "contactname' type='text' /><br/>\n" 3804 + "<span>Email</span><br/><input id='" + this.prefix + "contactemail' type='email' /><br/>\n" 3805 + "<span>Phone</span><br/><input id='" + this.prefix + "contactphone' type='text' /><br/>\n" 3806 + "<br/><a id='" + this.prefix + "contactconnect' class='" + this.prefix + "contactconnect' " + (this.forceStyles ? "style='color:white' " : "") + " onclick='return false;' href='#'>Connect</a>\n" 3807 + "<br/><br/></div>\n" 3808 + "</div>"; 3809 } 3810 3811 box.innerHTML = html; 3812 document.body.appendChild(box); 3813 3814 var self = this; 3815 document.getElementById(this.prefix + "chat").addEventListener("keypress", function(event) { 3816 if (event.keyCode == 13) { 3817 self.sendMessage(); 3818 return false; 3819 } 3820 }); 3821 document.getElementById(this.prefix + "boxclose").addEventListener("click", function() { 3822 self.closeBox(); 3823 return false; 3824 }); 3825 document.getElementById(this.prefix + "boxclose2").addEventListener("click", function() { 3826 self.closeBox(); 3827 return false; 3828 }); 3829 document.getElementById(this.prefix + "boxmin").addEventListener("click", function() { 3830 self.minimizeBox(); 3831 return false; 3832 }); 3833 if (this.promptContactInfo) { 3834 document.getElementById(this.prefix + "contactboxmin").addEventListener("click", function() { 3835 self.minimizeBox(); 3836 return false; 3837 }); 3838 document.getElementById(this.prefix + "contactconnect").addEventListener("click", function() { 3839 self.contactConnect(); 3840 return false; 3841 }); 3842 } 3843 if (document.getElementById(this.prefix + "boxmax") != null) { 3844 document.getElementById(this.prefix + "boxmax").addEventListener("click", function() { 3845 self.popup(); 3846 return false; 3847 }); 3848 } 3849 document.getElementById(this.prefix + "boxbarmax").addEventListener("click", function() { 3850 self.maximizeBox(); 3851 return false; 3852 }); 3853 3854 document.getElementById(this.prefix + "boxbarmax2").addEventListener("click", function() { 3855 self.maximizeBox(); 3856 return false; 3857 }); 3858 3859 var langOrig = null; 3860 var nativeVoiceOrig = null; 3861 var voiceOrig = null; 3862 if (document.getElementById(this.prefix + "chooselanguage") != null) { 3863 document.getElementById(this.prefix + "chooselanguage").addEventListener("change", function() { 3864 if (nativeVoiceOrig == null && langOrig == null) { 3865 langOrig = self.lang; 3866 nativeVoiceOrig = self.nativeVoice; 3867 voiceOrig = self.voice; 3868 } 3869 var element = document.getElementById(self.prefix + 'chooselanguage'); 3870 self.lang = element.value; 3871 if (self.lang != "none") { 3872 document.getElementById(self.prefix + 'yandex').style.display = "inline"; 3873 self.nativeVoice = true; 3874 self.translate = true; 3875 self.voice = null; 3876 } else { 3877 document.getElementById(self.prefix + 'yandex').style.display = "none"; 3878 self.translate = false; 3879 self.lang = langOrig; 3880 self.nativeVoice = nativeVoiceOrig; 3881 self.voice = voiceOrig; 3882 } 3883 }); 3884 } 3885 if (document.getElementById(this.prefix + "sendImage") != null) { 3886 document.getElementById(this.prefix + "sendImage").addEventListener("click", function() { 3887 self.sendImage(); 3888 return false; 3889 }); 3890 } 3891 if (document.getElementById(this.prefix + "sendAttachment") != null) { 3892 document.getElementById(this.prefix + "sendAttachment").addEventListener("click", function() { 3893 self.sendAttachment(); 3894 return false; 3895 }); 3896 } 3897 if (document.getElementById(this.prefix + "sendImageTool") != null) { 3898 document.getElementById(this.prefix + "sendImageTool").addEventListener("click", function() { 3899 self.sendImage(); 3900 return false; 3901 }); 3902 } 3903 if (document.getElementById(this.prefix + "sendAttachmentTool") != null) { 3904 document.getElementById(this.prefix + "sendAttachmentTool").addEventListener("click", function() { 3905 self.sendAttachment(); 3906 return false; 3907 }); 3908 } 3909 3910 3911 if (this.avatar && this.chatLog) { 3912 document.getElementById(this.prefix + "online").style.display = "none"; 3913 document.getElementById(this.prefix + "scroller").style.display = "none"; 3914 if (this.version >= 6.0 && this.prefix == "botplatform") { 3915 var chatLogDiv = document.getElementById(this.prefix + "showChatLog"); 3916 if (chatLogDiv != null) { 3917 chatLogDiv.style.display = "block"; 3918 } 3919 var chatLogButtonDiv = document.getElementById(this.prefix + "showChatLogButton"); 3920 if (chatLogButtonDiv != null) { 3921 chatLogButtonDiv.style.display = "inline-block"; 3922 } 3923 } 3924 } else if (this.avatar && !this.chatLog) { 3925 document.getElementById(this.prefix + "online").style.display = "none"; 3926 document.getElementById(this.prefix + "scroller").style.display = "none"; 3927 var chatLogDiv = document.getElementById(this.prefix + "showChatLog"); 3928 var chatLogButtonDiv = document.getElementById(this.prefix + "showChatLogButton"); 3929 if (chatLogDiv != null) { 3930 chatLogDiv.style.display = "none"; 3931 } 3932 if (chatLogButtonDiv != null) { 3933 chatLogButtonDiv.style.display = "none"; 3934 } 3935 } else if (!this.avatar && this.chatLog) { 3936 document.getElementById(this.prefix + "online").style.display = "inline"; 3937 document.getElementById(this.prefix + "scroller").style.display = "inline-block"; 3938 document.getElementById(this.prefix + "avatar-div").style.display = "none"; 3939 var chatLogDiv = document.getElementById(this.prefix + "showChatLog"); 3940 var chatLogButtonDiv = document.getElementById(this.prefix + "showChatLogButton"); 3941 if (chatLogDiv != null) { 3942 chatLogDiv.style.display = "none"; 3943 } 3944 if (chatLogButtonDiv != null) { 3945 chatLogButtonDiv.style.display = "none"; 3946 } 3947 var bubbleDiv = document.getElementById(this.prefix + "bubble-div"); 3948 if (bubbleDiv != null) { 3949 bubbleDiv.style.display = "none"; 3950 } 3951 var noBubblePlain = document.getElementsByClassName(this.prefix + "no-bubble-plain"); 3952 if (noBubblePlain != null && noBubblePlain.length != 0) { 3953 noBubblePlain[0].style.display = "none"; 3954 } 3955 } else { 3956 document.getElementById(this.prefix + "online").style.display = "none"; 3957 document.getElementById(this.prefix + "scroller").style.display = "none"; 3958 document.getElementById(this.prefix + "avatar-div").style.display = "none"; 3959 } 3960 3961 if (document.getElementById(this.prefix + "showChatLog") != null) { 3962 document.getElementById(this.prefix + "showChatLog").addEventListener("click", function() { 3963 self.showChatLog(); 3964 return false; 3965 }); 3966 } 3967 if (document.getElementById(this.prefix + "showChatLogButton") != null) { 3968 document.getElementById(this.prefix + "showChatLogButton").addEventListener("click", function() { 3969 self.showChatLog(); 3970 return false; 3971 }); 3972 } 3973 if (document.getElementById(this.prefix + "showAvatarBot") != null) { 3974 document.getElementById(this.prefix + "showAvatarBot").addEventListener("click", function() { 3975 self.showAvatarBot(); 3976 return false; 3977 }); 3978 } 3979 if (document.getElementById(this.prefix + "showAvatarBotButton") != null) { 3980 document.getElementById(this.prefix + "showAvatarBotButton").addEventListener("click", function() { 3981 self.showAvatarBot(); 3982 return false; 3983 }); 3984 } 3985 this.showChatLog = function() { 3986 document.getElementById(this.prefix + "avatar-div").style.display = "none"; 3987 document.getElementById(this.prefix + "online").style.display = "inline"; 3988 var bubbleDiv = document.getElementById(this.prefix + "bubble-div"); 3989 if (bubbleDiv != null) { 3990 bubbleDiv.style.display = "none"; 3991 } 3992 var noBubblePlain = document.getElementsByClassName(this.prefix + "no-bubble-plain"); 3993 if (noBubblePlain != null && noBubblePlain.length != 0) { 3994 noBubblePlain[0].style.display = "none"; 3995 } 3996 document.getElementById(this.prefix + "scroller").style.display = "inline-block"; 3997 if (this.version >= 6.0 && this.prefix == "botplatform") { 3998 document.getElementById(this.prefix + "showChatLog").style.display = "none"; 3999 document.getElementById(this.prefix + "showChatLogButton").style.display = "none"; 4000 document.getElementById(this.prefix + "showAvatarBot").style.display = "block"; 4001 document.getElementById(this.prefix + "showAvatarBotButton").style.display = "inline-block"; 4002 } 4003 } 4004 this.showAvatarBot = function() { 4005 document.getElementById(this.prefix + "online").style.display = "none"; 4006 document.getElementById(this.prefix + "scroller").style.display = "none"; 4007 document.getElementById(this.prefix + "avatar-div").style.display = "inline-block"; 4008 var bubbleDiv = document.getElementById(this.prefix + "bubble-div"); 4009 if (bubbleDiv != null) { 4010 bubbleDiv.style.display = "inherit"; 4011 } 4012 var noBubblePlain = document.getElementsByClassName(this.prefix + "no-bubble-plain"); 4013 if (noBubblePlain != null && noBubblePlain.length != 0) { 4014 noBubblePlain[0].style.display = "inherit"; 4015 } 4016 if (this.version >= 6.0 && this.prefix == "botplatform") { 4017 document.getElementById(this.prefix + "showChatLog").style.display = "block"; 4018 document.getElementById(this.prefix + "showChatLogButton").style.display = "inline-block"; 4019 document.getElementById(this.prefix + "showAvatarBot").style.display = "none"; 4020 document.getElementById(this.prefix + "showAvatarBotButton").style.display = "none"; 4021 } 4022 } 4023 4024 if (document.getElementById(this.prefix + "boxspeak") != null) { 4025 document.getElementById(this.prefix + "boxspeak").addEventListener("click", function() { 4026 self.speak = !self.speak; 4027 var urlprefix = self.connection.credentials.url + "/"; 4028 if (self.speak) { 4029 document.getElementById(self.prefix + "boxspeak").src = urlprefix + "images/sound.png"; 4030 document.getElementById(self.prefix + "boxspeak2").src = urlprefix + "images/sound.png"; 4031 } else { 4032 document.getElementById(self.prefix + "boxspeak").src = urlprefix + "images/mute.png"; 4033 document.getElementById(self.prefix + "boxspeak2").src = urlprefix + "images/mute.png"; 4034 } 4035 return false; 4036 }); 4037 document.getElementById(this.prefix + "boxspeakmenu").addEventListener("click", function() { 4038 self.speak = !self.speak; 4039 var urlprefix = self.connection.credentials.url + "/"; 4040 if (self.speak) { 4041 document.getElementById(self.prefix + "boxspeak").src = urlprefix + "images/sound.png"; 4042 document.getElementById(self.prefix + "boxspeak2").src = urlprefix + "images/sound.png"; 4043 } else { 4044 document.getElementById(self.prefix + "boxspeak").src = urlprefix + "images/mute.png"; 4045 document.getElementById(self.prefix + "boxspeak2").src = urlprefix + "images/mute.png"; 4046 } 4047 return false; 4048 }); 4049 } 4050 if (document.getElementById(this.prefix + "boxspeakrecognition") != null) { 4051 SDK.registerSpeechRecognition(document.getElementById(self.prefix + 'chat'), function() { 4052 self.sendMessage(); 4053 }); 4054 document.getElementById(this.prefix + "boxspeakrecognition").addEventListener("click", function() { 4055 self.listen = !self.listen; 4056 if (self.listen) { 4057 SDK.startSpeechRecognition(); 4058 document.getElementById(self.prefix + 'boxspeakrecognition').src = urlprefix + "images/mic.png"; 4059 document.getElementById(self.prefix + 'boxspeakrecognition2').src = urlprefix + "images/mic.png"; 4060 } else { 4061 SDK.stopSpeechRecognition(); 4062 document.getElementById(self.prefix + 'boxspeakrecognition').src = urlprefix + "images/micoff.png"; 4063 document.getElementById(self.prefix + 'boxspeakrecognition2').src = urlprefix + "images/micoff.png"; 4064 } 4065 }); 4066 document.getElementById(this.prefix + "boxspeakrecognitionmenu").addEventListener("click", function() { 4067 self.listen = !self.listen; 4068 if (self.listen) { 4069 SDK.startSpeechRecognition(); 4070 document.getElementById(self.prefix + 'boxspeakrecognition').src = urlprefix + "images/mic.png"; 4071 document.getElementById(self.prefix + 'boxspeakrecognition2').src = urlprefix + "images/mic.png"; 4072 } else { 4073 SDK.stopSpeechRecognition(); 4074 document.getElementById(self.prefix + 'boxspeakrecognition').src = urlprefix + "images/micoff.png"; 4075 document.getElementById(self.prefix + 'boxspeakrecognition2').src = urlprefix + "images/micoff.png"; 4076 } 4077 }); 4078 } 4079 } 4080 4081 /** 4082 * Create a live chat bar beside the bot bar. 4083 */ 4084 this.createLiveChatBox = function(channel, label, position) { 4085 var box = document.createElement('div'); 4086 var buttonstyle = ""; 4087 if (this.color != null) { 4088 buttonstyle = "background-color:" + this.color + ";"; 4089 } 4090 var buttonHoverStyle = ""; 4091 if (this.hoverColor != null) { 4092 buttonHoverStyle = "background-color:" + this.hoverColor + ";"; 4093 } 4094 if (label == null) { 4095 label = "Live Chat"; 4096 } 4097 if (position == null) { 4098 position = (this.caption.length + label.length) * 8; 4099 position = "right:" + position + "px"; 4100 } 4101 var html = 4102 "<style>\n" 4103 + "." + this.prefix + this.livechatPrefix + "boxbar { position:fixed;bottom:2px;" + position + ";z-index:152;margin:0;padding:6px;" + buttonstyle + " }\n" 4104 + "." + this.prefix + this.livechatPrefix + "boxbar:hover { " + buttonHoverStyle + " }\n" 4105 + (this.forceStyles ? "#" : ".") + this.prefix + this.livechatPrefix + "boxmax { color:white;font-size:18px;margin:2px;padding:0px;text-decoration:none; }\n" 4106 + "</style>\n" 4107 + "<div id='" + this.prefix + this.livechatPrefix + "boxbar' class='" + this.prefix + this.livechatPrefix + "boxbar'>" 4108 + "<span><a id='" + this.prefix + this.livechatPrefix + "boxmax' class='" + this.prefix + this.livechatPrefix + "boxmax' onclick='return false;' href='#'>" + label + "</a></span>" 4109 + "</div>"; 4110 4111 box.innerHTML = html; 4112 document.body.appendChild(box); 4113 4114 document.getElementById(this.prefix + this.livechatPrefix + "boxmax").addEventListener("click", function() { 4115 SDK.popupwindow(SDK.url + '/livechat?id=' + channel + '&embedded&chat','child', 700, 520); 4116 return false; 4117 }); 4118 } 4119 4120 /** 4121 * Minimize the embedding div in the current webpage. 4122 */ 4123 this.minimizeBox = function() { 4124 if (this.promptContactInfo) { 4125 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 4126 } 4127 document.getElementById(this.prefix + "box").style.display = 'none'; 4128 document.getElementById(this.prefix + "boxbar").style.display = 'inline'; 4129 var livechatbot = document.getElementById(this.prefix + this.livechatPrefix + "boxbar"); 4130 if (livechatbot != null) { 4131 livechatbot.style.display = 'inline'; 4132 } 4133 this.exit(); 4134 return false; 4135 } 4136 4137 /** 4138 * Check contact info and connect. 4139 */ 4140 this.contactConnect = function() { 4141 this.hasContactInfo = true; 4142 this.contactName = document.getElementById(this.prefix + "contactname").value; 4143 var ok = true; 4144 if (this.contactName != null && this.contactName == "") { 4145 ok = false; 4146 document.getElementById(this.prefix + "contactname").style.borderColor = "red"; 4147 document.getElementById(this.prefix + "contactname").placeholder = "Enter name"; 4148 } 4149 this.contactEmail = document.getElementById(this.prefix + "contactemail").value; 4150 if (this.contactEmail != null && this.contactEmail.indexOf("@") == -1) { 4151 ok = false; 4152 document.getElementById(this.prefix + "contactemail").style.borderColor = "red"; 4153 document.getElementById(this.prefix + "contactemail").placeholder = "Enter valid email"; 4154 } 4155 this.contactPhone = document.getElementById(this.prefix + "contactphone").value; 4156 this.contactInfo = this.contactName + " " + this.contactEmail + " " + this.contactPhone; 4157 if (ok) { 4158 this.maximizeBox(); 4159 } 4160 } 4161 4162 /** 4163 * Maximize the embedding div in the current webpage. 4164 */ 4165 this.maximizeBox = function() { 4166 if (this.promptContactInfo && !this.hasContactInfo) { 4167 document.getElementById(this.prefix + "contactinfo").style.display = 'inline'; 4168 document.getElementById(this.prefix + "boxbar").style.display = 'none'; 4169 document.getElementById(this.prefix + "box").style.display = 'none'; 4170 var livechatbot = document.getElementById(this.prefix + this.livechatPrefix + "boxbar"); 4171 if (livechatbot != null) { 4172 livechatbot.style.display = 'none'; 4173 } 4174 } else { 4175 if (this.promptContactInfo) { 4176 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 4177 } 4178 document.getElementById(this.prefix + "boxbar").style.display = 'none'; 4179 document.getElementById(this.prefix + "box").style.display = 'inline'; 4180 var livechatbot = document.getElementById(this.prefix + this.livechatPrefix + "boxbar"); 4181 if (livechatbot != null) { 4182 livechatbot.style.display = 'none'; 4183 } 4184 this.greet(); 4185 } 4186 return false; 4187 } 4188 4189 /** 4190 * Close the embedding div in the current webpage. 4191 */ 4192 this.closeBox = function() { 4193 if (this.promptContactInfo) { 4194 document.getElementById(this.prefix + "contactinfo").style.display = 'none'; 4195 } 4196 document.getElementById(this.prefix + "boxbar").style.display = 'none'; 4197 document.getElementById(this.prefix + "box").style.display = 'none'; 4198 var livechatbot = document.getElementById(this.prefix + this.livechatPrefix + "boxbar"); 4199 if (livechatbot != null) { 4200 livechatbot.style.display = 'none'; 4201 } 4202 this.exit(); 4203 return false; 4204 } 4205 4206 /** 4207 * Create a popup window chat session with the bot. 4208 */ 4209 this.popup = function() { 4210 var box = document.getElementById(this.prefix + "box"); 4211 if (box != null) { 4212 box.style.display = 'none'; 4213 } 4214 var speech = this.speak; 4215 if (!this.allowSpeech) { 4216 speech = "disable"; 4217 } 4218 var height = 520; 4219 if (!this.avatar && !this.chatLog) { 4220 height = 260; 4221 } 4222 if (this.popupURL != null) { 4223 var popupURL = this.popupURL; 4224 if (popupURL.indexOf("chat?") != -1 && this.contactInfo != null && this.contactInfo != "") { 4225 popupURL = popupURL + "&info=" + encodeURI(this.contactInfo); 4226 } 4227 SDK.popupwindow(popupURL, 'child', 700, height); 4228 } else { 4229 var form = document.createElement("form"); 4230 form.setAttribute("method", "post"); 4231 form.setAttribute("action", SDK.url + "/chat"); 4232 form.setAttribute("target", 'child'); 4233 4234 var input = document.createElement('input'); 4235 input.type = 'hidden'; 4236 input.name = "id"; 4237 input.value = this.instance; 4238 form.appendChild(input); 4239 4240 input = document.createElement('input'); 4241 input.type = 'hidden'; 4242 input.name = "embedded"; 4243 input.value = "embedded"; 4244 form.appendChild(input); 4245 4246 input = document.createElement('input'); 4247 input.type = 'hidden'; 4248 input.name = "speak"; 4249 input.value = speech; 4250 form.appendChild(input); 4251 4252 input = document.createElement('input'); 4253 input.type = 'hidden'; 4254 input.name = "avatar"; 4255 input.value = this.avatar; 4256 form.appendChild(input); 4257 4258 input = document.createElement('input'); 4259 input.type = "hidden"; 4260 input.name = "css"; 4261 input.value = this.css; 4262 form.appendChild(input); 4263 4264 input = document.createElement('input'); 4265 input.type = 'hidden'; 4266 input.name = "info"; 4267 input.value = this.contactInfo; 4268 form.appendChild(input); 4269 4270 input = document.createElement('input'); 4271 input.type = 'hidden'; 4272 input.name = "application"; 4273 input.value = this.connection.credentials.applicationId; 4274 form.appendChild(input); 4275 4276 document.body.appendChild(form); 4277 4278 SDK.popupwindow('','child', 700, height); 4279 4280 form.submit(); 4281 document.body.removeChild(form); 4282 } 4283 this.minimizeBox(); 4284 return false; 4285 } 4286 4287 this.sendImage = function() { 4288 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 4289 alert('The File APIs are not fully supported in this browser.'); 4290 return false; 4291 } 4292 var form = document.createElement("form"); 4293 form.enctype = "multipart/form-data"; 4294 form.method = "post"; 4295 form.name = "fileinfo"; 4296 var fileInput = document.createElement("input"); 4297 var self = this; 4298 fileInput.name = "file"; 4299 fileInput.type = "file"; 4300 form.appendChild(fileInput); 4301 fileInput.onchange = function() { 4302 var file = fileInput.files[0]; 4303 self.sendFileAttachment(file, true, form); 4304 } 4305 fileInput.click(); 4306 return false; 4307 }; 4308 4309 this.sendAttachment = function() { 4310 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 4311 alert('The File APIs are not fully supported in this browser.'); 4312 return false; 4313 } 4314 var form = document.createElement("form"); 4315 form.enctype = "multipart/form-data"; 4316 form.method = "post"; 4317 form.name = "fileinfo"; 4318 var fileInput = document.createElement("input"); 4319 var self = this; 4320 fileInput.name = "file"; 4321 fileInput.type = "file"; 4322 form.appendChild(fileInput); 4323 fileInput.onchange = function() { 4324 var file = fileInput.files[0]; 4325 self.sendFileAttachment(file, false, form); 4326 } 4327 fileInput.click(); 4328 return false; 4329 }; 4330 4331 this.sendFileAttachment = function(file, resize, form) { 4332 var self = this; 4333 var media = new MediaConfig(); 4334 if (this.instance == null) { 4335 this.connection.error("Missing instance property"); 4336 return false; 4337 } 4338 media.instance = this.instance; 4339 media.name = file.name; 4340 media.type = file.type; 4341 if (!resize && file.size > SDK.MAX_FILE_UPLOAD) { 4342 this.connection.error("File exceeds maximum upload size of " + (SDK.MAX_FILE_UPLOAD / 1000000) + "meg"); 4343 } else { 4344 this.connection.createBotAttachment(media, file, resize, form, function(media) { 4345 //var message = "file: " + file.name + " : " + file.type + " : " + self.connection.fetchLink(media.file); 4346 var message = self.connection.fetchLink(media.file); 4347 message = document.getElementById(self.prefix + 'chat').value + " " + message; 4348 document.getElementById(self.prefix + 'chat').value = message; 4349 //self.sendMessage(); 4350 }) 4351 } 4352 return false; 4353 }; 4354 4355 /** 4356 * Search for link using <a href="chat:yes">... 4357 * Switch them to use an onclick to post the chat back to the bot. 4358 */ 4359 this.linkChatPostbacks = function(node) { 4360 var self = this; 4361 var links = node.getElementsByTagName("a"); 4362 for (var index = 0; index < links.length; index++) { 4363 var a = links[index]; 4364 var href = a.getAttribute("href"); 4365 if (href != null && href.indexOf("chat:") != -1) { 4366 var chat = href.substring("chat:".length, href.length).trim(); 4367 var temp = function(param, element) { 4368 element.onclick = function() { 4369 self.sendMessage(param); 4370 return false; 4371 }; 4372 } 4373 temp(chat, a); 4374 } 4375 } 4376 var buttons = node.getElementsByTagName("button"); 4377 for (var index = 0; index < buttons.length; index++) { 4378 var button = buttons[index]; 4379 if (button.parentNode.nodeName == "A") { 4380 continue; 4381 } 4382 var chat = button.textContent; 4383 if (chat != null && chat.length > 0) { 4384 var temp = function(param, element) { 4385 element.onclick = function() { 4386 self.sendMessage(param); 4387 return false; 4388 }; 4389 } 4390 temp(chat, button); 4391 } 4392 } 4393 var choices = node.getElementsByTagName("select"); 4394 for (var index = 0; index < choices.length; index++) { 4395 var choice = choices[index]; 4396 var temp = function(param) { 4397 param.addEventListener("change", function() { 4398 self.sendMessage(param.value); 4399 return false; 4400 }); 4401 } 4402 temp(choice); 4403 } 4404 } 4405 4406 /** 4407 * A chat message was received from the bot. 4408 */ 4409 this.response = function(user, message) { 4410 var responseDiv = document.getElementById(this.prefix + 'response'); 4411 if (responseDiv != null) { 4412 responseDiv.innerHTML = SDK.linkURLs(message); 4413 this.linkChatPostbacks(responseDiv); 4414 if (!SDK.secure) { 4415 SDK.evalScripts(responseDiv); 4416 } 4417 this.message(user, message); 4418 if (this.focus) { 4419 var chat = document.getElementById(this.prefix + 'chat'); 4420 if (chat != null) { 4421 chat.focus(); 4422 } 4423 } 4424 } 4425 if (this.onresponse != null) { 4426 this.onresponse(message); 4427 } 4428 if (responseDiv != null) { 4429 var self = this; 4430 // Fix Chrome bug, 4431 if (SDK.fixChromeResizeCSS && SDK.isChrome()) { 4432 var padding = responseDiv.parentNode.parentNode.style.padding; 4433 responseDiv.parentNode.parentNode.style.padding = "7px"; 4434 setTimeout(function() { 4435 responseDiv.parentNode.parentNode.style.padding = padding; 4436 }, 10); 4437 } 4438 } 4439 } 4440 4441 /** 4442 * A chat message was received from the bot. 4443 */ 4444 this.message = function(user, message) { 4445 var speaker = user; 4446 var scroller = document.getElementById(this.prefix + 'scroller'); 4447 var chatconsole = document.getElementById(this.prefix + 'console'); 4448 if (scroller == null || chatconsole == null) { 4449 return; 4450 } 4451 var tr = document.createElement('tr'); 4452 tr.style.verticalAlign = "top"; 4453 var td = document.createElement('td'); 4454 var td2 = document.createElement('td'); 4455 var div = document.createElement('div'); 4456 var div2 = document.createElement('div'); 4457 var span = document.createElement('span'); 4458 var span2 = document.createElement('span'); 4459 var br = document.createElement('br'); 4460 var chatClass = this.prefix + 'chatchat-1'; 4461 div.className = this.prefix + 'chatchat-1-div'; 4462 div2.className = this.prefix + 'chatchat-1-div-2'; 4463 span.className = this.prefix + 'chatchat-user-1'; 4464 td.className = this.prefix + 'chat-user-1'; 4465 var userImg; 4466 if (speaker === this.botThumb.name) { 4467 userImg = document.createElement('img'); 4468 userImg.className = this.prefix + 'chat-user'; 4469 userImg.setAttribute('alt', this.botThumb.name); 4470 userImg.setAttribute('src', this.botThumb.avatar); 4471 td.appendChild(userImg); 4472 } else { 4473 td.className = this.prefix + 'chat-user-2'; 4474 chatClass = this.prefix + 'chatchat-2'; 4475 div.className = this.prefix + 'chatchat-2-div'; 4476 div2.className = this.prefix + 'chatchat-2-div-2'; 4477 span.className = this.prefix + 'chatchat-user-2'; 4478 userImg = document.createElement('img'); 4479 userImg.className = this.prefix + 'chat-user'; 4480 userImg.setAttribute('alt', this.userThumb.name); 4481 userImg.setAttribute('src', this.userThumb.avatar); 4482 td.appendChild(userImg); 4483 } 4484 td.setAttribute('nowrap', 'nowrap'); 4485 td2.className = chatClass; 4486 td2.setAttribute('align', 'left'); 4487 td2.setAttribute('width', '100%'); 4488 var date = new Date(); 4489 var time = date.getHours() + ":" + ((date.getMinutes() < 10)? "0" : "") + date.getMinutes() + ":" + ((date.getSeconds() < 10)? "0" : "") + date.getSeconds(); 4490 span.innerHTML = speaker + " <small>" + time + "</small>"; 4491 span2.className = chatClass; 4492 span2.innerHTML = SDK.linkURLs(message); 4493 this.linkChatPostbacks(span2); 4494 chatconsole.appendChild(tr); 4495 tr.appendChild(td); 4496 tr.appendChild(td2); 4497 div.appendChild(span); 4498 div.appendChild(br); 4499 div.appendChild(div2); 4500 td2.appendChild(div); 4501 div2.appendChild(span2); 4502 while (chatconsole.childNodes.length > 500) { 4503 chatconsole.removeChild(chatconsole.firstChild); 4504 } 4505 scroller.scrollTop = scroller.scrollHeight; 4506 }; 4507 4508 /** 4509 * Update the bot's avatar's image/video/audio from the chat response. 4510 */ 4511 this.updateAvatar = function(responseMessage) { 4512 var urlprefix = this.connection.credentials.url + "/"; 4513 SDK.updateAvatar(responseMessage, this.speak, urlprefix, this.prefix, null, null, this.nativeVoice, this.lang, this.nativeVoiceName); 4514 if (SDK.commands && responseMessage.command != null) { 4515 var command = JSON.parse(responseMessage.command); 4516 if (command.start != null) { 4517 this.game = new window [command.start](); 4518 this.initGame(this.game) 4519 } 4520 } 4521 if (this.game != null) { 4522 this.game.updateAvatar(responseMessage); 4523 } 4524 console.log(responseMessage); 4525 }; 4526 4527 this.initGame = function(game) { 4528 this.game = game; 4529 game.init(this); 4530 } 4531 4532 this.toggleSpeak = function() { 4533 this.speak = !this.speak; 4534 } 4535 4536 /** 4537 * Initialize the bot listener. 4538 */ 4539 this.start = function() { 4540 if (this.prefix == "" && this.elementPrefix != null) { 4541 this.prefix = this.elementPrefix; 4542 } 4543 var self = this; 4544 this.connection.error = function(message) { 4545 self.response("Error", message); 4546 } 4547 if (this.avatar) { 4548 var config = new ChatConfig(); 4549 config.instance = this.instance; 4550 if (this.translate) { 4551 config.language = this.lang; 4552 } 4553 if (this.format != null) { 4554 config.avatarFormat = this.format; 4555 } 4556 if (this.hd != null) { 4557 config.avatarHD = this.hd; 4558 } 4559 this.connection.initChat(config, function(responseMessage) { 4560 if (this.conversation == null) { 4561 self.updateAvatar(responseMessage); 4562 } 4563 }); 4564 } 4565 if (this.connection.user != null && this.connection.user.user != null) { 4566 this.connection.viewUser(this.connection.user, function(user) { 4567 var userName = user.user; 4568 var userAvatar = user.avatar; 4569 self.userThumb['name'] = userName; 4570 self.userThumb['avatar'] = userAvatar; 4571 }); 4572 } else { 4573 var urlprefix = this.connection.credentials.url + "/"; 4574 self.userThumb['name'] = "You:"; 4575 self.userThumb['avatar'] = urlprefix + "images/user-thumb.jpg"; 4576 } 4577 var instanceConfig = new InstanceConfig(); 4578 instanceConfig.id = this.instance; 4579 this.connection.fetch(instanceConfig, function(instanceConfig) { 4580 var botName = instanceConfig.name; 4581 var botAvatar = instanceConfig.avatar; 4582 self.botThumb['name'] = botName; 4583 self.botThumb['avatar'] = botAvatar; 4584 var onlineDiv = document.getElementById(self.prefix + 'online'); 4585 if (onlineDiv == null) { 4586 return; 4587 } 4588 if (!onlineDiv.hasChildNodes()) { 4589 var div = document.createElement('div'); 4590 div.className = "online-user"; 4591 var botImage = document.createElement('img'); 4592 botImage.className = self.prefix + "chat-bot"; 4593 botImage.setAttribute('alt', self.botThumb.name); 4594 botImage.setAttribute('src', self.botThumb.avatar); 4595 var span = document.createElement('span'); 4596 span.className = self.prefix + "user-bot"; 4597 span.innerHTML = self.botThumb.name; 4598 div.appendChild(botImage); 4599 div.appendChild(span); 4600 onlineDiv.appendChild(div); 4601 var line = document.createElement('hr'); 4602 onlineDiv.appendChild(line); 4603 } 4604 }); 4605 } 4606 4607 /** 4608 * Send the bot an empty message to let it greet the user. 4609 * This will have the bot respond with any defined greeting it has. 4610 */ 4611 this.greet = function() { 4612 this.start(); 4613 var chat = new ChatConfig(); 4614 chat.info = this.contactInfo; 4615 chat.instance = this.instance; 4616 if (this.greetingMessage != null) { 4617 chat.message = this.greetingMessage; 4618 } 4619 if (this.translate) { 4620 chat.language = this.lang; 4621 } 4622 if (this.avatarId != null) { 4623 chat.avatar = this.avatarId; 4624 } 4625 if (this.hd != null) { 4626 chat.avatarHD = this.hd; 4627 } else if ((this.width != null && this.width > 400) || (this.height != null && this.height > 400)) { 4628 chat.avatarHD = true; 4629 } 4630 if (this.format != null) { 4631 chat.avatarFormat = this.format; 4632 } 4633 if (this.nativeVoice && SDK.speechSynthesis) { 4634 chat.speak = false; 4635 } else { 4636 chat.speak = this.speak; 4637 } 4638 var self = this; 4639 if (this.external) { 4640 this.externalChat(chat); 4641 } else { 4642 this.connection.chat(chat, function(responseMessage) { 4643 self.conversation = responseMessage.conversation; 4644 self.updateAvatar(responseMessage); 4645 if (responseMessage.message != null && responseMessage.message != "") { 4646 self.response(self.instanceName, responseMessage.message); 4647 } else if (self.greeting == null) { 4648 document.getElementById(self.prefix + 'response').innerHTML = "Hi"; 4649 } 4650 }); 4651 } 4652 return false; 4653 }; 4654 4655 /** 4656 * Send the current text from the chat input as a message to the bot, and process the response. 4657 */ 4658 this.sendMessage = function(message) { 4659 if (message == null) { 4660 var chat = document.getElementById(this.prefix + 'chat'); 4661 if (chat != null) { 4662 message = chat.value; 4663 } 4664 } 4665 if (message != '') { 4666 this.message(this.userName, message); 4667 var chat = new ChatConfig(); 4668 chat.message = message; 4669 chat.instance = this.instance; 4670 if (this.translate) { 4671 chat.language = this.lang; 4672 } 4673 if (this.avatarId != null) { 4674 chat.avatar = this.avatarId; 4675 } 4676 if (this.hd != null) { 4677 chat.avatarHD = this.hd; 4678 } else if ((this.width != null && this.width > 400) || (this.height != null && this.height > 400)) { 4679 chat.avatarHD = true; 4680 } 4681 if (this.format != null) { 4682 chat.avatarFormat = this.format; 4683 } 4684 if (this.nativeVoice && SDK.speechSynthesis) { 4685 chat.speak = false; 4686 } else { 4687 chat.speak = this.speak; 4688 } 4689 chat.conversation = this.conversation; 4690 var correction = document.getElementById('correction'); 4691 if (correction != null && correction.checked) { 4692 chat.correction = true; 4693 correction.checked = false; 4694 } 4695 var learning = document.getElementById('learning'); 4696 if (learning != null && learning.style.display != "none") { 4697 chat.learn = learning.checked; 4698 } 4699 var debug = document.getElementById('debug'); 4700 if (debug != null && debug.checked) { 4701 chat.debug = true; 4702 var debugLevel = document.getElementById('debugLevel'); 4703 if (debugLevel != null) { 4704 chat.debugLevel = debugLevel.value; 4705 } 4706 } 4707 var offensive = document.getElementById('offensive'); 4708 if (offensive != null && offensive.checked) { 4709 chat.offensive = true; 4710 offensive.checked = false; 4711 } 4712 var emote = document.getElementById('emote'); 4713 if (emote != null && emote.value != null && emote.value != "" && emote.value != "NONE") { 4714 chat.emote = emote.value.toUpperCase(); 4715 emote.value = "NONE"; 4716 } 4717 var action = document.getElementById('action'); 4718 if (action != null && action.value != null && action.value != "") { 4719 chat.action = action.value; 4720 action.value = ""; 4721 } 4722 var responseDiv = document.getElementById(this.prefix + 'response'); 4723 if (responseDiv != null) { 4724 responseDiv.innerHTML = '<i>thinking</i>'; 4725 } 4726 var chatInput = document.getElementById(this.prefix + 'chat'); 4727 if (chatInput != null) { 4728 chatInput.value = ''; 4729 } 4730 var self = this; 4731 if (this.external) { 4732 this.externalChat(chat); 4733 } else { 4734 this.connection.chat(chat, function(responseMessage) { 4735 self.conversation = responseMessage.conversation; 4736 self.response(self.instanceName, responseMessage.message); 4737 self.updateAvatar(responseMessage); 4738 var log = document.getElementById('log'); 4739 var logText = responseMessage.log; 4740 if (log != null) { 4741 if (logText != null) { 4742 log.style.display = "inline"; 4743 log.innerHTML = logText; 4744 } else { 4745 log.innerHTML = ""; 4746 } 4747 } 4748 }); 4749 } 4750 } 4751 return false; 4752 }; 4753 4754 /** 4755 * Send the json command to the bot, and process the response. 4756 */ 4757 this.sendCommand = function(json, processor) { 4758 if (json != '') { 4759 var command = new CommandConfig(); 4760 command.command = json; 4761 command.instance = this.instance; 4762 if (this.translate) { 4763 command.language = this.lang; 4764 } 4765 if (this.avatarId != null) { 4766 command.avatar = this.avatarId; 4767 } 4768 if (this.hd != null) { 4769 command.avatarHD = this.hd; 4770 } else if ((this.width != null && this.width > 400) || (this.height != null && this.height > 400)) { 4771 command.avatarHD = true; 4772 } 4773 if (this.format != null) { 4774 command.avatarFormat = this.format; 4775 } 4776 if (this.nativeVoice && SDK.speechSynthesis) { 4777 command.speak = false; 4778 } else { 4779 command.speak = this.speak; 4780 } 4781 command.conversation = this.conversation; 4782 var correction = document.getElementById('correction'); 4783 if (correction != null && correction.checked) { 4784 command.correction = true; 4785 correction.checked = false; 4786 } 4787 var learning = document.getElementById('learning'); 4788 if (learning != null && learning.style.display != "none") { 4789 command.learn = learning.checked; 4790 } 4791 var debug = document.getElementById('debug'); 4792 if (debug != null && debug.checked) { 4793 command.debug = true; 4794 var debugLevel = document.getElementById('debugLevel'); 4795 if (debugLevel != null) { 4796 chat.debugLevel = debugLevel.value; 4797 } 4798 } 4799 var offensive = document.getElementById('offensive'); 4800 if (offensive != null && offensive.checked) { 4801 command.offensive = true; 4802 offensive.checked = false; 4803 } 4804 var emote = document.getElementById('emote'); 4805 if (emote != null && emote.value != null && emote.value != "" && emote.value != "NONE") { 4806 command.emote = emote.value.toUpperCase(); 4807 emote.value = "NONE"; 4808 } 4809 var action = document.getElementById('action'); 4810 if (action != null && action.value != null && action.value != "") { 4811 command.action = action.value; 4812 action.value = ""; 4813 } 4814 var responseDiv = document.getElementById(this.prefix + 'response'); 4815 if (responseDiv != null) { 4816 responseDiv.innerHTML = '<i>thinking</i>'; 4817 } 4818 var chatInput = document.getElementById(this.prefix + 'chat'); 4819 if (chatInput != null) { 4820 chatInput.value = ''; 4821 } 4822 var self = this; 4823 if (this.external) { 4824 return false; 4825 } else { 4826 this.connection.command(command, function(responseMessage) { 4827 self.conversation = responseMessage.conversation; 4828 self.response(self.instanceName, responseMessage.message); 4829 self.updateAvatar(responseMessage); 4830 var log = document.getElementById('log'); 4831 var logText = responseMessage.log; 4832 if (log != null) { 4833 if (logText != null) { 4834 log.style.display = "inline"; 4835 log.innerHTML = logText; 4836 } else { 4837 log.innerHTML = ""; 4838 } 4839 } 4840 processor(responseMessage.command); 4841 }); 4842 } 4843 } 4844 return false; 4845 }; 4846 4847 /** 4848 * Send an external API chat request. 4849 */ 4850 this.externalChat = function(chat) { 4851 var url = this.apiURL; 4852 if (chat.message == null) { 4853 url = url.replace(":message", ""); 4854 } else { 4855 url = url.replace(":message", encodeURIComponent(chat.message)); 4856 } 4857 if (chat.conversation == null) { 4858 url = url.replace(":conversation", ""); 4859 } else { 4860 url = url.replace(":conversation", encodeURIComponent(chat.conversation)); 4861 } 4862 if (chat.speak) { 4863 url = url.replace(":speak", "true"); 4864 } else { 4865 url = url.replace(":speak", ""); 4866 } 4867 var self = this; 4868 this.connection.GET(url, function(xml) { 4869 if (xml == null) { 4870 return null; 4871 } 4872 var responseMessage = new ChatResponse(); 4873 responseMessage.parseXML(xml); 4874 self.conversation = responseMessage.conversation; 4875 self.response(self.instanceName, responseMessage.message); 4876 var urlprefix = self.apiURL.substring(0, self.apiURL.indexOf("/rest/api/form-chat")) + "/"; 4877 SDK.updateAvatar(responseMessage, self.speak, urlprefix, self.prefix, null, null, self.nativeVoice, self.lang, self.nativeVoiceName); 4878 var log = document.getElementById('log'); 4879 var logText = responseMessage.log; 4880 if (log != null) { 4881 if (logText != null) { 4882 log.innerHTML = logText; 4883 } else { 4884 log.innerHTML = ""; 4885 } 4886 } 4887 }); 4888 } 4889 4890 /** 4891 * Exit the conversation. 4892 */ 4893 this.exit = function() { 4894 if (this.conversation == null || this.external) { 4895 return false; 4896 } 4897 var chat = new ChatConfig(); 4898 chat.disconnect = true; 4899 chat.instance = this.instance; 4900 chat.conversation = this.conversation; 4901 var self = this; 4902 this.connection.chat(chat, function(responseMessage) { 4903 self.conversation = null; 4904 }); 4905 return false; 4906 }; 4907 4908 /** 4909 * Clear the chat console. 4910 */ 4911 this.clear = function() { 4912 document.getElementById(this.prefix + 'response').innerHTML = ''; 4913 var console = document.getElementById(this.prefix + 'console'); 4914 if (console != null) { 4915 console.innerHTML = ''; 4916 } 4917 return false; 4918 }; 4919 4920 this.resizeAvatar = function () { 4921 var avatar = document.getElementById(this.prefix + "avatar"); 4922 var avatarDiv = document.getElementById(this.prefix + "avatar-image-div"); 4923 var avatarVideo = document.getElementById(this.prefix + "avatar-video"); 4924 var avatarVideoDiv = document.getElementById(this.prefix + "avatar-video-div"); 4925 var avatarCanvas = document.getElementById(this.prefix + "avatar-canvas"); 4926 var avatarCanvasDiv = document.getElementById(this.prefix + "avatar-canvas-div"); 4927 var scroller = document.getElementById(this.prefix + "scroller"); 4928 var chatBubbleDiv = document.getElementById(web.prefix + 'bubble-div'); 4929 var chatBubble = document.getElementById(this.prefix + 'bubble'); 4930 if (!this.big) { 4931 this.hd = true; 4932 if (avatar != null) { 4933 avatar.className = "avatar-big"; 4934 } 4935 if (avatarVideo != null) { 4936 avatarVideo.className = "avatar-video-big"; 4937 } 4938 if (avatarVideoDiv != null) { 4939 avatarVideoDiv.className = "avatar-video-div-big"; 4940 } 4941 if (avatarCanvas != null) { 4942 avatarCanvas.className = "avatar-canvas-big"; 4943 } 4944 if (avatarCanvasDiv != null) { 4945 avatarCanvasDiv.className = "avatar-canvas-div-big"; 4946 } 4947 if (scroller != null) { 4948 scroller.style.display = "none"; 4949 document.getElementById(this.prefix + 'response').style.display = "inline"; 4950 } 4951 if (chatBubbleDiv != null) { 4952 chatBubbleDiv.style.display = "block"; 4953 } 4954 if (chatBubble != null) { 4955 chatBubble.style.display = "inherit"; 4956 } 4957 this.big = true; 4958 } else { 4959 this.hd = false; 4960 if (avatar != null) { 4961 avatar.className = "avatar"; 4962 } 4963 if (avatarVideo != null) { 4964 avatarVideo.className = "avatar-video"; 4965 } 4966 if (avatarVideoDiv != null) { 4967 avatarVideoDiv.className = "avatar-video-div"; 4968 } 4969 if (avatarCanvas != null) { 4970 avatarCanvas.className = "avatar-canvas"; 4971 } 4972 if (avatarCanvasDiv != null) { 4973 avatarCanvasDiv.className = "avatar-canvas-div"; 4974 } 4975 if (scroller != null) { 4976 if (this.chatLog && window.innerWidth > 480) { 4977 scroller.style.display = "inline-block"; 4978 } else { 4979 scroller.style.display = "none"; 4980 } 4981 } 4982 if (chatBubbleDiv != null) { 4983 if (!this.chatLog || window.innerWidth < 480) { 4984 chatBubbleDiv.style.display = "block"; 4985 } else { 4986 chatBubbleDiv.style.display = "none"; 4987 } 4988 } 4989 if (chatBubble != null) { 4990 if (!this.chatLog || window.innerWidth < 480) { 4991 chatBubble.style.display = "block"; 4992 } else { 4993 chatBubble.style.display = "none"; 4994 } 4995 } 4996 this.big = false; 4997 } 4998 if (window.onresize != null) { 4999 setTimeout(window.onresize(), 100); 5000 } 5001 return false; 5002 } 5003 } 5004 5005 /** 5006 * The WebAvatar provides access to an avatar and binds it to elements in an HTML document. 5007 * It lets you use a bot avatar without having a bot. You can tell the avatar what to say, and what actions and poses to display. 5008 * The HTML document requires the following elements: 5009 * <ul> 5010 * <li> avatar - img element for the avatar 5011 * <li> avatar-image-div - div element for the avatar's image 5012 * <li> avatar-video - video element for the avatar's video 5013 * <li> avatar-video-div - div element for the avatar's video 5014 * </ul> 5015 * If a prefix is set, these id will be prefixed by the prefix. 5016 * Or you can call createBox() to have the WebAvatar create its own components in the current page. 5017 * @class 5018 */ 5019 function WebAvatar() { 5020 /** Enable or disable speech. */ 5021 this.speak = true; 5022 /** Configure if the browser's native voice TTS should be used. */ 5023 this.nativeVoice = false; 5024 /** Set the language for the native voice. */ 5025 this.lang = null; 5026 /** Set the voice for the native voice. */ 5027 this.nativeVoiceName = null; 5028 /** An SDK connection object must be set. */ 5029 this.connection = null; 5030 /** The id or name of the avatar object to use. */ 5031 this.avatar = null; 5032 /** The name of the voice to use. */ 5033 this.voice = null; 5034 /** The name of the voice mod to use. */ 5035 this.voiceMod = null; 5036 /** Allow the background color to be set. */ 5037 this.background = null; 5038 /** Avatar image/video width. */ 5039 this.width = 300; 5040 /** Avatar image/video height. */ 5041 this.height = null; 5042 /** Only apply the background color if not Chrome. */ 5043 this.backgroundIfNotChrome = false; 5044 /** An optional close event. */ 5045 this.onclose = null; 5046 /** Return if the avatar box is in a closed state. */ 5047 this.closed = true; 5048 /** Element id and class prefix. Can be used to have multiple avatars in the same page, or avoid naming collisions. */ 5049 this.prefix = "avatar-"; 5050 /** Store list of messages to output. */ 5051 this.messages = null; 5052 /** Function to invoke when processing all messages is complete. */ 5053 this.ended = null; 5054 /** Set if the avatar should request HD (high def) video/images. */ 5055 this.hd = null; 5056 /** Set if the avatar should request a specific video or image format. */ 5057 this.format = null; 5058 5059 /** 5060 * Create an embedding bar and div in the current webpage. 5061 */ 5062 this.createBox = function() { 5063 if (this.prefix == "" && this.elementPrefix != null) { 5064 this.prefix = this.elementPrefix; 5065 } 5066 var backgroundstyle = ""; 5067 var hidden = "hidden"; 5068 var border = ""; 5069 if ((this.background != null) && (!this.backgroundIfNotChrome || !SDK.isChrome())) { 5070 backgroundstyle = " style='background-color:" + this.background + "'"; 5071 hidden = "visible"; 5072 border = "border:1px;border-style:solid;border-color:black;"; 5073 } 5074 var box = document.createElement('div'); 5075 var minWidth = ""; 5076 var minHeight = ""; 5077 var divWidth = ""; 5078 var divHeight = ""; 5079 var background = ""; 5080 if (this.width != null) { 5081 minWidth = "width:" + this.width + "px;"; 5082 background = "background-size:" + this.width + "px;"; 5083 divWidth = minWidth; 5084 divHeight = "min-height:" + this.width + "px;"; 5085 } 5086 if (this.height != null) { 5087 minHeight = "height:" + this.height + "px;"; 5088 divHeight = minHeight; 5089 if (this.width != null) { 5090 background = "background-size:" + this.width + "px " + this.height + "px;"; 5091 } else { 5092 background = "background-size: auto " + this.height + "px;"; 5093 divWidth = "min-width:" + this.height + "px;"; 5094 } 5095 } 5096 var html = 5097 "<style>\n" 5098 + "." + this.prefix + "avatarbox { position:fixed;bottom:10px;left:10px;z-index:152;margin:2px;" + border + " }\n" 5099 + "." + this.prefix + "avatarbox:hover { border:1px;border-style:solid;border-color:black; }\n" 5100 + "." + this.prefix + "avatarbox ." + this.prefix + "avatarboxmenu { visibility:" + hidden + "; }\n" 5101 + "." + this.prefix + "avatarbox:hover ." + this.prefix + "avatarboxmenu { visibility:visible; }\n" 5102 + "img." + this.prefix + "avatarboxclose { margin:4px }\n" 5103 + "#" + this.prefix + "avatarboxclose { margin:0px;font-size:26px; }\n" 5104 + "#" + this.prefix + "avatarboxclose:hover { color: #fff;background: grey; }\n" 5105 + "</style>\n" 5106 + "<div id='" + this.prefix + "avatarbox' class='" + this.prefix + "avatarbox' " + backgroundstyle + ">" 5107 + "<div class='" + this.prefix + "avatarboxmenu'>" 5108 + "<span style='float:right'><a id='" + this.prefix + "avatarboxclose' onclick='return false;' href='#'><img class='" + this.prefix + "avatarboxclose' src='" + SDK.url + "/images/closeg.png'></a></span><br/>" 5109 + "</div>" 5110 + "<div id='" + this.prefix + "avatar-image-div' style='display:none;" + minWidth + minHeight + "'>" 5111 + "<img id='" + this.prefix + "avatar' style='" + minWidth + minHeight + "'/>" 5112 + "</div>" 5113 + "<div id='" + this.prefix + "avatar-video-div' style='display:none;" + divWidth + divHeight + background + "background-repeat: no-repeat;'>" 5114 + "<video id='" + this.prefix + "avatar-video' autoplay preload='auto' style='background:transparent;" + minWidth + minHeight + "'>" 5115 + "Video format not supported by your browser (try Chrome)" 5116 + "</video>" 5117 + "</div>" 5118 + "<div id='" + this.prefix + "avatar-canvas-div' style='display:none;" + divWidth + divHeight + "'>" 5119 + "<canvas id='" + this.prefix + "avatar-canvas' style='background:transparent;" + minWidth + minHeight + "'>" 5120 + "Canvas not supported by your browser (try Chrome)" 5121 + "</canvas>" 5122 + "</div>" 5123 + "</div>"; 5124 5125 box.innerHTML = html; 5126 document.body.appendChild(box); 5127 5128 var self = this; 5129 document.getElementById(this.prefix + "avatarboxclose").addEventListener("click", function() { 5130 self.closeBox(); 5131 return false; 5132 }); 5133 this.closed = false; 5134 } 5135 5136 /** 5137 * Open the embedding div in the current webpage. 5138 */ 5139 this.openBox = function() { 5140 document.getElementById(this.prefix + "avatarbox").style.display = 'inline'; 5141 this.speak = true; 5142 this.closed = false; 5143 return false; 5144 } 5145 5146 /** 5147 * Close the embedding div in the current webpage. 5148 */ 5149 this.closeBox = function() { 5150 document.getElementById(this.prefix + "avatarbox").style.display = 'none'; 5151 this.speak = false; 5152 if (this.onclose != null) { 5153 this.onclose(); 5154 } 5155 this.closed = true; 5156 return false; 5157 } 5158 5159 /** 5160 * Update the avatar's image/video/audio from the message response. 5161 */ 5162 this.updateAvatar = function(responseMessage, afterFunction) { 5163 var urlprefix = this.connection.credentials.url + "/"; 5164 SDK.updateAvatar(responseMessage, this.speak, urlprefix, this.prefix, false, afterFunction, this.nativeVoice, this.lang, this.nativeVoiceName); 5165 }; 5166 5167 /** 5168 * Add the message to the avatars message queue. 5169 * The messages will be spoken when processMessages() is called. 5170 */ 5171 this.addMessage = function(message, emote, action, pose) { 5172 var config = new AvatarMessage(); 5173 config.message = message; 5174 config.avatar = this.avatar; 5175 if (this.hd != null) { 5176 config.hd = this.hd; 5177 } else if ((this.width != null && this.width > 400) || (this.height != null && this.height > 400)) { 5178 config.hd = true; 5179 } 5180 if (this.format != null) { 5181 config.format = this.format; 5182 } 5183 if (this.nativeVoice && SDK.speechSynthesis) { 5184 config.speak = false; 5185 } else { 5186 config.speak = this.speak; 5187 config.voice = this.voice; 5188 config.voiceMod = this.voiceMod; 5189 } 5190 config.emote = emote; 5191 config.action = action; 5192 config.pose = pose; 5193 if (this.messages == null) { 5194 this.messages = []; 5195 } 5196 this.messages[this.messages.length] = config; 5197 return false; 5198 }; 5199 5200 /** 5201 * Add the message to the avatars message queue. 5202 * The messages will be spoken when runMessages() is called. 5203 */ 5204 this.processMessages = function(pause) { 5205 if (this.messages == null || this.messages.length == 0) { 5206 if (this.ended != null) { 5207 this.ended(); 5208 } 5209 return false; 5210 } 5211 if (pause == null) { 5212 pause = 500; 5213 } 5214 var self = this; 5215 var message = this.messages[0]; 5216 this.messages = this.messages.splice(1, this.messages.length); 5217 this.connection.avatarMessage(message, function(responseMessage) { 5218 self.updateAvatar(responseMessage, function() { 5219 setTimeout(function() { 5220 self.processMessages(pause); 5221 }, pause); 5222 }); 5223 }); 5224 return false; 5225 } 5226 5227 /** 5228 * Have the avatar speak the message with voice and animation. 5229 * The function will be called at the end of the speech. 5230 */ 5231 this.message = function(message, emote, action, pose, afterFunction) { 5232 var config = new AvatarMessage(); 5233 config.message = message; 5234 config.avatar = this.avatar; 5235 if (this.nativeVoice && SDK.speechSynthesis) { 5236 config.speak = false; 5237 } else { 5238 config.speak = this.speak; 5239 config.voice = this.voice; 5240 config.voiceMod = this.voiceMod; 5241 } 5242 config.emote = emote; 5243 config.action = action; 5244 config.pose = pose; 5245 var self = this; 5246 this.connection.avatarMessage(config, function(responseMessage) { 5247 self.updateAvatar(responseMessage, afterFunction); 5248 }); 5249 return false; 5250 }; 5251 } 5252 5253 /** 5254 * Connection class for a Live Chat, or chatroom connection. 5255 * A live chat connection is different than an SDKConnection as it is asynchronous, 5256 * and uses web sockets for communication. 5257 * @class 5258 * @property channel 5259 * @property user 5260 * @property credentials 5261 * @property listener 5262 * @property keepAlive 5263 * @property onMediaStream 5264 * @property onMediaStreamEnded 5265 * @property nick 5266 * @property channelToken 5267 * @property onNewChannel 5268 * @property nick 5269 */ 5270 function LiveChatConnection() { 5271 this.channel = null; 5272 this.user = null; 5273 this.contactInfo = null; 5274 this.credentials = new Credentials(); 5275 this.socket = null; 5276 this.listener = null; 5277 this.keepAlive = false; 5278 this.keepAliveInterval = null; 5279 this.mediaConnection = null; 5280 this.onMediaStream = null; 5281 this.onMediaStreamEnded = null; 5282 this.nick = null; 5283 this.channelToken = null; 5284 this.onNewChannel = null; 5285 this.onMessageCallbacks = {}; 5286 5287 /** 5288 * Connect to the live chat server channel. 5289 * Validate the user credentials. 5290 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5291 */ 5292 this.connect = function(channel, user) { 5293 if (this.credentials == null) { 5294 throw "Mising credentials"; 5295 } 5296 this.channel = channel; 5297 this.user = user; 5298 if (this.nick == null && this.user != null) { 5299 this.nick = this.user.user; 5300 } 5301 var host = null; 5302 if (SDK.scheme == "https") { 5303 host = "wss://" + this.credentials.host + this.credentials.app + "/live/chat"; 5304 } else { 5305 host = "ws://" + this.credentials.host + this.credentials.app + "/live/chat"; 5306 } 5307 if ('WebSocket' in window) { 5308 this.socket = new WebSocket(host); 5309 } else if ('MozWebSocket' in window) { 5310 this.socket = new MozWebSocket(host); 5311 } else { 5312 throw 'Error: WebSocket is not supported by this browser.'; 5313 } 5314 5315 this.listener.connection = this; 5316 var self = this; 5317 5318 this.socket.onopen = function () { 5319 if (self.channel != null) { 5320 var appId = self.credentials.applicationId; 5321 if (appId == null) { 5322 appId = ''; 5323 } 5324 var connectString = "connect " + self.channel.id; 5325 if (self.user == null) { 5326 connectString = connectString + " " + appId; 5327 } else if (user.token == null) { 5328 connectString = connectString + " " + self.user.user + " " + self.user.password + " " + appId; 5329 } else { 5330 connectString = connectString + " " + self.user.user + " " + self.user.token + " " + appId; 5331 } 5332 if (self.contactInfo != null) { 5333 connectString = connectString + " @info " + self.contactInfo; 5334 } 5335 self.socket.send(connectString); 5336 } 5337 self.setKeepAlive(this.keepAlive); 5338 }; 5339 5340 this.socket.onclose = function () { 5341 self.listener.message("Info: Closed"); 5342 self.listener.closed(); 5343 self.disconnectMedia(); 5344 }; 5345 5346 this.socket.onmessage = function (message) { 5347 user = ""; 5348 data = message.data; 5349 text = data; 5350 index = text.indexOf(':'); 5351 if (index != -1) { 5352 user = text.substring(0, index); 5353 data = text.substring(index + 2, text.length); 5354 } 5355 if (user == "Media") { 5356 data = JSON.parse(data); 5357 5358 if (data.sender == self.nick) { 5359 return; 5360 } 5361 if (data.channel != self.channelToken) { 5362 return; 5363 } 5364 5365 if (self.onMessageCallbacks[data.channel]) { 5366 self.onMessageCallbacks[data.channel](data.message); 5367 }; 5368 return; 5369 } 5370 if (user == "Online-xml") { 5371 self.listener.updateUsersXML(data); 5372 return; 5373 } 5374 if (user == "Online") { 5375 self.listener.updateUsers(data); 5376 return; 5377 } 5378 if (user == "Channel") { 5379 self.channelToken = data; 5380 if (self.onNewChannel != null) { 5381 self.onNewChannel(data); 5382 } 5383 return; 5384 } 5385 if (user == "Nick") { 5386 if (self.nick == null) { 5387 self.nick = data; 5388 } 5389 return; 5390 } 5391 5392 if (self.keepAlive && user == "Info" && text.contains("pong")) { 5393 return; 5394 } 5395 if (user == "Info") { 5396 self.listener.info(text); 5397 return; 5398 } 5399 if (user == "Error") { 5400 self.listener.error(text); 5401 return; 5402 } 5403 self.listener.message(text); 5404 }; 5405 }; 5406 5407 /** 5408 * Connect to the active channels media feed (video, audio). 5409 */ 5410 this.connectMedia = function(mediaChannel, shareAudio, shareVideo) { 5411 if (this.mediaConnection != null) { 5412 this.mediaConnection.leave(); 5413 } 5414 this.mediaConnection = new RTCMultiConnection(mediaChannel); 5415 var self = this; 5416 var open = false; 5417 this.mediaConnection.session = { 5418 audio: shareAudio, 5419 video: shareVideo 5420 }; 5421 /*this.mediaConnection.mediaConstraints.audio = { 5422 mandatory: {}, 5423 optional: [{ 5424 googEchoCancellation: true, 5425 googAutoGainControl: true, 5426 googNoiseSuppression: true, 5427 googHighpassFilter: true, 5428 googTypingNoiseDetection: true, 5429 googAudioMirroring: true 5430 }] 5431 };*/ 5432 /*this.mediaConnection.privileges = { 5433 canStopRemoteStream: true, 5434 canMuteRemoteStream: true 5435 };*/ 5436 5437 this.mediaConnection.openSignalingChannel = function (config) { 5438 var channel = config.channel || this.channel; 5439 self.onMessageCallbacks[channel] = config.onmessage; 5440 5441 if (config.onopen) { 5442 setTimeout(config.onopen, 1000); 5443 } 5444 5445 // directly returning socket object using "return" statement 5446 return { 5447 send: function (message) { 5448 self.socket.send("Media: " + JSON.stringify({ 5449 sender: self.nick, 5450 channel: channel, 5451 message: message 5452 })); 5453 }, 5454 channel: channel 5455 }; 5456 }; 5457 this.mediaConnection.onstream = function(stream) { 5458 open = true; 5459 if (self.onMediaStream != null) { 5460 self.onMediaStream(stream); 5461 } 5462 }; 5463 this.mediaConnection.onstreamended = function(stream) { 5464 if (self.onMediaStreamEnded != null) { 5465 self.onMediaStreamEnded(stream); 5466 } 5467 }; 5468 this.mediaConnection.onNewSession = function(session) { 5469 session.join({ 5470 audio: shareAudio, 5471 video: shareVideo 5472 }); 5473 }; 5474 if (this.nick != null) { 5475 this.mediaConnection.userid = this.nick; 5476 } 5477 //connection.log = false; 5478 this.mediaConnection.onerror = function(error) { 5479 SDK.error(error); 5480 } 5481 this.mediaConnection.onMediaError = function(error) { 5482 SDK.error(error); 5483 } 5484 this.mediaConnection.connect(); 5485 setTimeout(function() { 5486 if (!open) { 5487 self.mediaConnection.open("room"); 5488 } 5489 }, 5000); 5490 } 5491 5492 /** 5493 * Disconnect from the active channels media feed (video, audio). 5494 */ 5495 this.disconnectMedia = function() { 5496 if (this.mediaConnection != null) { 5497 this.mediaConnection.leave(); 5498 this.mediaConnection = null; 5499 } 5500 } 5501 5502 /** 5503 * Reset the media feed (audio, video). 5504 */ 5505 this.resetMedia = function(shareAudio, shareVideo) { 5506 this.mediaConnection.session = { 5507 audio: shareAudio, 5508 video: shareVideo 5509 }; 5510 for (var streamid in this.mediaConnection.localStreams) { 5511 var stream = this.mediaConnection.streams[streamid]; 5512 if (!shareAudio || !shareVideo) { 5513 stream.mute({ 5514 audio: !shareAudio, 5515 video: !shareVideo 5516 }); 5517 } 5518 if (shareAudio || shareVideo) { 5519 stream.unmute({ 5520 audio: shareAudio, 5521 video: shareVideo 5522 }); 5523 } 5524 } 5525 } 5526 5527 /** 5528 * Decrease the size of the video element for the userid. 5529 */ 5530 this.shrinkVideo = function(user) { 5531 var streams = this.mediaConnection.streams.selectAll({remote:true, local:true}); 5532 for (i = 0; i < streams.length; i++) { 5533 stream = streams[i]; 5534 if (stream.userid == user) { 5535 stream.mediaElement.height = stream.mediaElement.height / 1.5; 5536 } 5537 } 5538 }; 5539 5540 /** 5541 * Increase the size of the video element for the userid. 5542 */ 5543 this.expandVideo = function(user) { 5544 var streams = this.mediaConnection.streams.selectAll({remote:true, local:true}); 5545 for (i = 0; i < streams.length; i++) { 5546 stream = streams[i]; 5547 if (stream.userid == user) { 5548 stream.mediaElement.height = stream.mediaElement.height * 1.5; 5549 } 5550 } 5551 }; 5552 5553 /** 5554 * Mute the audio for the userid. 5555 */ 5556 this.muteAudio = function(user) { 5557 var streams = this.mediaConnection.streams.selectAll({remote:true, local:true}); 5558 for (i = 0; i < streams.length; i++) { 5559 stream = streams[i]; 5560 if (stream.userid == user) { 5561 stream.mute({ 5562 audio: true 5563 }); 5564 } 5565 } 5566 }; 5567 5568 /** 5569 * Mute the video for the userid. 5570 */ 5571 this.muteVideo = function(user) { 5572 var streams = this.mediaConnection.streams.selectAll({remote:true, local:true}); 5573 for (i = 0; i < streams.length; i++) { 5574 stream = streams[i]; 5575 if (stream.userid == user) { 5576 stream.mute({ 5577 video: true 5578 }); 5579 } 5580 } 5581 }; 5582 5583 /** 5584 * Sent a text message to the channel. 5585 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5586 * Note, the listener will receive its own messages. 5587 */ 5588 this.sendMessage = function(message) { 5589 this.checkSocket(); 5590 this.socket.send(message); 5591 }; 5592 5593 this.sendAttachment = function(file, resize, form) { 5594 var self = this; 5595 var media = new MediaConfig(); 5596 if (this.channel == null) { 5597 this.listener.error("Missing channel property"); 5598 return false; 5599 } 5600 media.instance = this.channel.id; 5601 media.name = file.name; 5602 media.type = file.type; 5603 if (!resize && file.size > SDK.MAX_FILE_UPLOAD) { 5604 this.listener.error("File exceeds maximum upload size of " + (SDK.MAX_FILE_UPLOAD / 1000000) + "meg"); 5605 } else { 5606 this.sdk.error = function(message) { 5607 self.listener.error(message); 5608 } 5609 this.sdk.createChannelAttachment(media, file, resize, form, function(media) { 5610 var message = "file: " + file.name + " : " + file.type + " : " + self.sdk.fetchLink(media.file); 5611 self.sendMessage(message); 5612 }) 5613 } 5614 return false; 5615 }; 5616 5617 /** 5618 * Accept a private request. 5619 * This is also used by an operator to accept the top of the waiting queue. 5620 * This can also be used by a user to chat with the channel bot. 5621 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5622 */ 5623 this.accept = function() { 5624 this.checkSocket(); 5625 this.socket.send("accept"); 5626 }; 5627 5628 /** 5629 * Test the connection. 5630 * A pong message will be returned, this message will not be broadcast to the channel. 5631 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5632 */ 5633 this.ping = function() { 5634 this.checkSocket(); 5635 this.socket.send("ping"); 5636 }; 5637 5638 /** 5639 * Exit from the current private channel. 5640 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5641 */ 5642 this.exit = function() { 5643 this.checkSocket(); 5644 this.socket.send("exit"); 5645 }; 5646 5647 /** 5648 * Change to spy mode. 5649 * This allows admins to monitor the entire channel. 5650 */ 5651 this.spyMode = function() { 5652 this.checkSocket(); 5653 this.socket.send("mode: spy"); 5654 }; 5655 5656 /** 5657 * Change to normal mode. 5658 */ 5659 this.normalMode = function() { 5660 this.checkSocket(); 5661 this.socket.send("mode: normal"); 5662 }; 5663 5664 /** 5665 * Request a private chat session with a user. 5666 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5667 */ 5668 this.pvt = function(user) { 5669 this.checkSocket(); 5670 this.socket.send("pvt: " + user); 5671 }; 5672 5673 /** 5674 * Boot a user from the channel. 5675 * You must be a channel administrator to boot a user. 5676 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5677 */ 5678 this.boot = function(user) { 5679 this.checkSocket(); 5680 this.socket.send("boot: " + user); 5681 }; 5682 5683 /** 5684 * Send a private message to a user. 5685 * This call is asynchronous, any error or success with be sent as a separate message to the listener. 5686 */ 5687 this.whisper = function(user, message) { 5688 this.checkSocket(); 5689 this.socket.send("whisper:" + user + ": " + message); 5690 }; 5691 5692 /** 5693 * Disconnect from the channel. 5694 */ 5695 this.disconnect = function() { 5696 this.setKeepAlive(false); 5697 if (this.socket != null) { 5698 this.socket.disconnect(); 5699 } 5700 disconnectMedia(); 5701 }; 5702 5703 this.checkSocket = function() { 5704 if (this.socket == null) { 5705 throw "Not connected"; 5706 } 5707 }; 5708 5709 this.toggleKeepAlive = function() { 5710 this.setKeepAlive(!this.keepAlive); 5711 } 5712 5713 this.setKeepAlive = function(keepAlive) { 5714 this.keepAlive = keepAlive; 5715 if (!keepAlive && this.keepAliveInterval != null) { 5716 clearInterval(this.keepAliveInterval); 5717 } else if (keepAlive && this.keepAliveInterval == null) { 5718 this.keepAliveInterval = setInterval( 5719 function() { 5720 this.ping() 5721 }, 5722 600000); 5723 } 5724 } 5725 } 5726 5727 /** 5728 * Connection class for a REST service connection. 5729 * The SDK connection gives you access to the Bot Libre services using a REST web API. 5730 * <p> 5731 * The services include: 5732 * <ul> 5733 * <li> User management (account creation, validation) 5734 * <li> Bot access, chat, and administration 5735 * <li> Forum access, posting, and administration 5736 * <li> Live chat access, chat, and administration 5737 * <li> Script, Graphic, and Domain access, and administration 5738 * </ul> 5739 * @class 5740 * @property user 5741 * @property domain 5742 * @property credentials 5743 * @property debug 5744 * @property error 5745 */ 5746 function SDKConnection() { 5747 this.user; 5748 this.domain; 5749 this.credentials = new Credentials(); 5750 this.debug = SDK.debug; 5751 this.error = SDK.error; 5752 5753 this.exception; 5754 5755 /** 5756 * Validate the user credentials (password, or token). 5757 * The user details are returned (with a connection token, password removed). 5758 * The user credentials are soted in the connection, and used on subsequent calls. 5759 * An SDKException is thrown if the connect failed. 5760 */ 5761 this.connect = function(config, processor) { 5762 var self = this; 5763 this.fetchUser(config, function(user) { 5764 self.user = user; 5765 processor(user); 5766 }); 5767 } 5768 5769 /** 5770 * Connect to the live chat channel and return a LiveChatConnection. 5771 * A LiveChatConnection is separate from an SDKConnection and uses web sockets for 5772 * asynchronous communication. 5773 * The listener will be notified of all messages. 5774 */ 5775 this.openLiveChat = function(channel, listener) { 5776 var connection = new LiveChatConnection(); 5777 connection.sdk = this; 5778 connection.credentials = this.credentials; 5779 connection.listener = listener; 5780 connection.connect(channel, this.user); 5781 return connection; 5782 } 5783 5784 /** 5785 * Connect to the domain. 5786 * A domain is an isolated content space. 5787 * Any browse or query request will be specific to the domain's content. 5788 */ 5789 this.switchDomain = function(config, processor) { 5790 var self = this; 5791 this.fetch(config, function(domain) { 5792 self.domain = domain; 5793 processor(domain); 5794 }); 5795 } 5796 5797 /** 5798 * Disconnect from the connection. 5799 * An SDKConnection does not keep a live connection, but this resets its connected user and domain. 5800 */ 5801 this.disconnect = function() { 5802 this.user = null; 5803 this.domain = null; 5804 } 5805 5806 /** 5807 * Fetch the user details for the user credentials. 5808 * A token or password is required to validate the user. 5809 */ 5810 this.fetchUser = function(config, processor) { 5811 config.addCredentials(this); 5812 this.POST(this.credentials.rest + "/check-user", config.toXML(), function(xml) { 5813 if (xml == null) { 5814 return; 5815 } 5816 var user = new UserConfig(); 5817 user.parseXML(xml); 5818 processor(user); 5819 }); 5820 } 5821 5822 /** 5823 * Fetch the user details for the user id. 5824 */ 5825 this.viewUser = function(config, processor) { 5826 config.addCredentials(this); 5827 this.POST(this.credentials.rest + "/view-user", config.toXML(), function(xml) { 5828 if (xml == null) { 5829 return; 5830 } 5831 var user = new UserConfig(); 5832 user.parseXML(xml); 5833 processor(user); 5834 }); 5835 } 5836 5837 /** 5838 * Fetch the URL for the image from the server. 5839 */ 5840 this.fetchImage = function(image) { 5841 return this.credentials.url + "/" + image; 5842 } 5843 5844 /** 5845 * Fetch the URL for the image from the server. 5846 */ 5847 this.fetchLink = function(image) { 5848 return this.credentials.url + "/" + image; 5849 } 5850 5851 /** 5852 * Fetch the forum post details for the forum post id. 5853 */ 5854 this.fetchForumPost = function(config, processor) { 5855 config.addCredentials(this); 5856 this.POST(this.credentials.rest + "/check-forum-post", config.toXML(), function(xml) { 5857 if (xml == null) { 5858 return; 5859 } 5860 var post = new ForumPostConfig(); 5861 post.parseXML(xml); 5862 processor(post); 5863 }); 5864 } 5865 5866 /** 5867 * Create a new user. 5868 */ 5869 this.createUser = function(config, processor) { 5870 config.addCredentials(this); 5871 this.POST(this.credentials.rest + "/create-user", config.toXML(), function(xml) { 5872 if (xml == null) { 5873 return null; 5874 } 5875 var user = new UserConfig(); 5876 user.parseXML(xml); 5877 this.user = user; 5878 processor(user); 5879 }); 5880 } 5881 5882 /** 5883 * Create a new file/image/media attachment for a chat channel. 5884 */ 5885 this.createChannelAttachment = function(config, file, resize, form, processor) { 5886 config.addCredentials(this); 5887 if (resize) { 5888 this.POST_IMAGE(this.credentials.rest + "/create-channel-attachment", file, form, config.toXML(), function(xml) { 5889 if (xml == null) { 5890 return null; 5891 } 5892 var media = new MediaConfig(); 5893 media.parseXML(xml); 5894 processor(media); 5895 }); 5896 } else { 5897 this.POST_FILE(this.credentials.rest + "/create-channel-attachment", form, config.toXML(), function(xml) { 5898 if (xml == null) { 5899 return null; 5900 } 5901 var media = new MediaConfig(); 5902 media.parseXML(xml); 5903 processor(media); 5904 }); 5905 } 5906 } 5907 5908 /** 5909 * Create a new file/image/media attachment for a bot. 5910 */ 5911 this.createBotAttachment = function(config, file, resize, form, processor) { 5912 config.addCredentials(this); 5913 if (resize) { 5914 this.POST_IMAGE(this.credentials.rest + "/create-bot-attachment", file, form, config.toXML(), function(xml) { 5915 if (xml == null) { 5916 return null; 5917 } 5918 var media = new MediaConfig(); 5919 media.parseXML(xml); 5920 processor(media); 5921 }); 5922 } else { 5923 this.POST_FILE(this.credentials.rest + "/create-bot-attachment", form, config.toXML(), function(xml) { 5924 if (xml == null) { 5925 return null; 5926 } 5927 var media = new MediaConfig(); 5928 media.parseXML(xml); 5929 processor(media); 5930 }); 5931 } 5932 } 5933 5934 /** 5935 * Create a new file/image/media attachment for a forum. 5936 */ 5937 this.createForumAttachment = function(config, file, resize, form, processor) { 5938 config.addCredentials(this); 5939 if (resize) { 5940 this.POST_IMAGE(this.credentials.rest + "/create-forum-attachment", file, form, config.toXML(), function(xml) { 5941 if (xml == null) { 5942 return null; 5943 } 5944 var media = new MediaConfig(); 5945 media.parseXML(xml); 5946 processor(media); 5947 }); 5948 } else { 5949 this.POST_FILE(this.credentials.rest + "/create-forum-attachment", form, config.toXML(), function(xml) { 5950 if (xml == null) { 5951 return null; 5952 } 5953 var media = new MediaConfig(); 5954 media.parseXML(xml); 5955 processor(media); 5956 }); 5957 } 5958 } 5959 5960 /** 5961 * Create a new file/image/media attachment for a forum and insert the http link into the textarea. 5962 */ 5963 this.uploadForumAttachment = function(forum, resize, processor) { 5964 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 5965 this.error('The File APIs are not fully supported in this browser.'); 5966 return false; 5967 } 5968 var form = document.createElement("form"); 5969 form.enctype = "multipart/form-data"; 5970 form.method = "post"; 5971 form.name = "fileinfo"; 5972 var fileInput = document.createElement("input"); 5973 var self = this; 5974 fileInput.name = "file"; 5975 fileInput.type = "file"; 5976 form.appendChild(fileInput); 5977 fileInput.onchange = function() { 5978 var file = fileInput.files[0]; 5979 self.uploadForumFile(file, forum, resize, form, processor); 5980 } 5981 fileInput.click(); 5982 }; 5983 5984 /** 5985 * Create a new file/image/media attachment for a forum. 5986 */ 5987 this.uploadForumFile = function(file, forum, resize, form, processor) { 5988 var self = this; 5989 var media = new MediaConfig(); 5990 media.instance = forum; 5991 media.name = file.name; 5992 media.type = file.type; 5993 if (!resize && file.size > SDK.MAX_FILE_UPLOAD) { 5994 this.error("File exceeds maximum upload size of " + (SDK.MAX_FILE_UPLOAD / 1000000) + "meg"); 5995 } else { 5996 this.createForumAttachment(media, file, resize, form, function(media) { 5997 var link = self.fetchLink(media.file); 5998 if (processor != null) { 5999 processor(link, file.name); 6000 } 6001 }) 6002 } 6003 }; 6004 6005 /** 6006 * Create a new forum post. 6007 * You must set the forum id for the post. 6008 */ 6009 this.createForumPost = function(config, processor) { 6010 config.addCredentials(this); 6011 var xml = POST(this.credentials.rest + "/create-forum-post", config.toXML(), function(xml) { 6012 if (xml == null) { 6013 return null; 6014 } 6015 var post = new ForumPostConfig(); 6016 post.parseXML(xml); 6017 processor(post); 6018 }); 6019 } 6020 6021 /** 6022 * Create a reply to a forum post. 6023 * You must set the parent id for the post replying to. 6024 */ 6025 this.createReply = function(config, processor) { 6026 config.addCredentials(this); 6027 var xml = POST(this.credentials.rest + "/create-reply", config.toXML(), function(xml) { 6028 if (xml == null) { 6029 return null; 6030 } 6031 var reply = new ForumPostConfig(); 6032 reply.parseXML(xml); 6033 processor(reply); 6034 }); 6035 } 6036 6037 /** 6038 * Fetch the content details from the server. 6039 * The id or name and domain of the object must be set. 6040 */ 6041 this.fetch = function(config, processor) { 6042 config.addCredentials(this); 6043 this.POST(this.credentials.rest + "/check-" + config.type, config.toXML(), function(xml) { 6044 if (xml == null) { 6045 return null; 6046 } 6047 var config2 = new config.constructor(); 6048 config2.parseXML(xml); 6049 processor(config2) 6050 }); 6051 } 6052 6053 /** 6054 * Update the forum post. 6055 */ 6056 this.updateForumPost = function(config, processor) { 6057 config.addCredentials(this); 6058 this.POST(this.credentials.rest + "/update-forum-post", config.toXML(), function(xml) { 6059 if (xml == null) { 6060 return null; 6061 } 6062 var config = new ForumPostConfig(); 6063 config.parseXML(xml); 6064 processor(config); 6065 }); 6066 } 6067 6068 /** 6069 * Update the user details. 6070 * The password must be passed to allow the update. 6071 */ 6072 this.updateUser = function(config) { 6073 config.addCredentials(this); 6074 this.POST(this.credentials.rest + "/update-user", config.toXML(), function(xml) { 6075 return; 6076 }); 6077 } 6078 6079 /** 6080 * Permanently delete the forum post with the id. 6081 */ 6082 this.deleteForumPost = function(config) { 6083 config.addCredentials(this); 6084 this.POST(this.credentials.rest + "/delete-forum-post", config.toXML(), function(xml) { 6085 return; 6086 }); 6087 } 6088 6089 /** 6090 * Flag the content as offensive, a reason is required. 6091 */ 6092 this.flag = function(config) { 6093 config.addCredentials(this); 6094 this.POST(this.credentials.rest + "/flag-" + config.getType(), config.toXML(), function(xml) { 6095 return; 6096 }); 6097 } 6098 6099 /** 6100 * Flag the forum post as offensive, a reason is required. 6101 */ 6102 this.flagForumPost = function(config) { 6103 config.addCredentials(this); 6104 this.POST(this.credentials.rest + "/flag-forum-post", config.toXML(), function(xml) { 6105 return; 6106 }); 6107 } 6108 6109 /** 6110 * Flag the user post as offensive, a reason is required. 6111 */ 6112 this.flagUser = function(config) { 6113 config.addCredentials(this); 6114 this.POST(this.credentials.rest + "/flag-user", config.toXML(), function(xml) { 6115 return; 6116 }); 6117 } 6118 6119 /** 6120 * Process the bot chat message and return the bot's response. 6121 * The ChatConfig should contain the conversation id if part of a conversation. 6122 * If a new conversation the conversation id is returned in the response. 6123 */ 6124 this.chat = function(config, processor) { 6125 config.addCredentials(this); 6126 this.POST(this.credentials.rest + "/chat", config.toXML(), function(xml) { 6127 if (xml == null) { 6128 return null; 6129 } 6130 var responseMessage = new ChatResponse(); 6131 responseMessage.parseXML(xml); 6132 processor(responseMessage); 6133 }); 6134 } 6135 6136 /** 6137 * Process the bot command message and return the bot's response. 6138 * The CommandConfig should contain the conversation id if part of a conversation. 6139 * If a new conversation the conversation id is returned in the response. 6140 */ 6141 this.command = function(config, processor) { 6142 config.addCredentials(this); 6143 this.POST(this.credentials.rest + "/command", config.toXML(), function(xml) { 6144 if (xml == null) { 6145 return null; 6146 } 6147 var responseMessage = new ChatResponse(); 6148 responseMessage.parseXML(xml); 6149 processor(responseMessage); 6150 }); 6151 } 6152 6153 /** 6154 * Process the avatar message and return the avatar's response. 6155 */ 6156 this.avatarMessage = function(config, processor) { 6157 config.addCredentials(this); 6158 this.POST(this.credentials.rest + "/avatar-message", config.toXML(), function(xml) { 6159 if (xml == null) { 6160 return null; 6161 } 6162 var responseMessage = new ChatResponse(); 6163 responseMessage.parseXML(xml); 6164 processor(responseMessage); 6165 }); 6166 } 6167 6168 /** 6169 * Return the list of user details for the comma separated values list of user ids. 6170 */ 6171 this.fetchAllUsers = function(usersCSV, processor) { 6172 var config = new UserConfig(); 6173 config.user = usersCSV; 6174 config.addCredentials(this); 6175 this.POST(this.credentials.rest + "/get-users", config.toXML(), function(xml) { 6176 var users = []; 6177 if (xml != null) { 6178 for (var index = 0; index < xml.childNodes.length; index++) { 6179 var child = xml.childNodes[index]; 6180 var userConfig = new UserConfig(); 6181 userConfig.parseXML(child); 6182 users[user.length] = userConfig; 6183 } 6184 } 6185 processor(users); 6186 }); 6187 } 6188 6189 /** 6190 * Return the list of forum posts for the forum browse criteria. 6191 */ 6192 this.fetchPosts = function(config, processor) { 6193 config.addCredentials(this); 6194 var xml = this.POST(this.credentials.rest + "/get-forum-posts", config.toXML(), function(xml) { 6195 var instances = []; 6196 if (xml != null) { 6197 for (var index = 0; index < xml.childNodes.length; index++) { 6198 var child = xml.childNodes[index]; 6199 var post = new ForumPostConfig(); 6200 post.parseXML(child); 6201 instances[instances.length] = post; 6202 } 6203 } 6204 processor(instances); 6205 }); 6206 } 6207 6208 /** 6209 * Return the list of categories for the type, and domain. 6210 */ 6211 this.fetchCategories = function(config, processor) { 6212 config.addCredentials(this); 6213 var xml = this.POST(this.credentials.rest + "/get-categories", config.toXML(), function(xml) { 6214 var categories = []; 6215 categories[0] = ""; 6216 if (xml != null) { 6217 for (var index = 0; index < xml.childNodes.length; index++) { 6218 categories[categories.length] = (xml.childNodes[index].getAttribute("name")); 6219 } 6220 } 6221 processor(categories); 6222 }); 6223 } 6224 6225 /** 6226 * Return the list of tags for the type, and domain. 6227 */ 6228 this.fetchTags = function(config, processor) { 6229 config.addCredentials(this); 6230 var xml = this.POST(this.credentials.rest + "/get-tags", config.toXML(), function(xml) { 6231 var tags = []; 6232 tags[0] = ""; 6233 if (xml != null) { 6234 for (var index = 0; index < xml.childNodes.length; index++) { 6235 tags[tags.length] = (xml.childNodes[index].getAttribute("name")); 6236 } 6237 } 6238 processor(tags); 6239 }); 6240 } 6241 6242 /** 6243 * Return the users for the content. 6244 */ 6245 this.fetchUsers = function(config, processor) { 6246 config.addCredentials(this); 6247 var xml = this.POST(this.credentials.rest + "/get-" + config.getType() + "-users", config.toXML(), function(xml) { 6248 var users = []; 6249 if (xml != null) { 6250 for (var index = 0; index < xml.childNodes.length; index++) { 6251 var user = new UserConfig(); 6252 user.parseXML(xml.childNodes[index]); 6253 users[users.length] = (user.user); 6254 } 6255 } 6256 processor(users); 6257 6258 }); 6259 } 6260 6261 /** 6262 * Initialize the bot's avatar for a chat session. 6263 * This can be done before processing the first message for a quick response. 6264 * @deprecated replaced by initChat() 6265 */ 6266 this.initAvatar = function(config, processor) { 6267 config.addCredentials(this); 6268 this.POST(this.credentials.rest + "/init-avatar", config.toXML(), function(xml) { 6269 if (xml == null) { 6270 return; 6271 } 6272 var response = new ChatResponse(); 6273 response.parseXML(xml); 6274 processor(response); 6275 }); 6276 } 6277 6278 /** 6279 * Initialize the bot's avatar for a chat session. 6280 * This can be done before processing the first message for a quick response. 6281 */ 6282 this.initChat = function(config, processor) { 6283 config.addCredentials(this); 6284 this.POST(this.credentials.rest + "/init-chat", config.toXML(), function(xml) { 6285 if (xml == null) { 6286 return; 6287 } 6288 var response = new ChatResponse(); 6289 response.parseXML(xml); 6290 processor(response); 6291 }); 6292 } 6293 6294 /** 6295 * Return the conversation's chat settings. 6296 */ 6297 this.chatSettings = function(config, processor) { 6298 config.addCredentials(this); 6299 this.POST(this.credentials.rest + "/chat-settings", config.toXML(), function(xml) { 6300 if (xml == null) { 6301 return; 6302 } 6303 var settings = new ChatSettings(); 6304 settings.parseXML(xml); 6305 processor(settings); 6306 }); 6307 } 6308 6309 /** 6310 * Return the bot's voice configuration. 6311 */ 6312 this.trainInstance = function(config) { 6313 config.addCredentials(this); 6314 this.POST(this.credentials.rest + "/train-instance", config.toXML(), function(xml) { 6315 return; 6316 }); 6317 } 6318 6319 /** 6320 * Return the bot's voice configuration. 6321 */ 6322 this.fetchVoice = function(config, processor) { 6323 config.addCredentials(this); 6324 this.POST(this.credentials.rest + "/get-voice", config.toXML(), function(xml) { 6325 if (xml == null) { 6326 return; 6327 } 6328 var voice = new VoiceConfig(); 6329 voice.parseXML(xml); 6330 processor(voice); 6331 }); 6332 } 6333 6334 /** 6335 * Return the list of content for the browse criteria. 6336 * The type defines the content type (one of Bot, Forum, Channel, Domain). 6337 */ 6338 this.browse = function(config, processor) { 6339 config.addCredentials(this); 6340 var type = ""; 6341 if (config.type == "Bot") { 6342 type = "/get-instances"; 6343 } else if (config.type == "Forum") { 6344 type = "/get-forums"; 6345 } else if (config.type == "Channel") { 6346 type = "/get-channels"; 6347 } else if (config.type == "Domain") { 6348 type = "/get-domains"; 6349 } else if (config.type == "Graphic") { 6350 type = "/get-graphics"; 6351 } else if (config.type == "Avatar") { 6352 type = "/get-avatars"; 6353 } else if (config.type == "Script") { 6354 type = "/get-scripts"; 6355 } 6356 this.POST(this.credentials.rest + type, config.toXML(), function(xml) { 6357 var instances = []; 6358 if (xml != null) { 6359 for (var index = 0; index < xml.childNodes.length; index++) { 6360 var instance = null; 6361 if (config.type == "Bot") { 6362 instance = new InstanceConfig(); 6363 } else if (config.type == "Forum") { 6364 instance = new ForumConfig(); 6365 } else if (config.type == "Channel") { 6366 instance = new ChannelConfig(); 6367 } else if (config.type == "Domain") { 6368 instance = new DomainConfig(); 6369 } else if (config.type == "Avatar") { 6370 instance = new AvatarConfig(); 6371 } else if (config.type == "Script") { 6372 instance = new ScriptConfig(); 6373 } else if (config.type == "Graphic") { 6374 instance = new GraphicConfig(); 6375 } 6376 instance.parseXML(xml.childNodes[index]); 6377 instances[instances.length] = (instance); 6378 } 6379 } 6380 processor(instances); 6381 }); 6382 } 6383 6384 this.GET = function(url, processor) { 6385 if (this.debug) { 6386 console.log("GET: " + url); 6387 } 6388 var xml = null; 6389 var request = new XMLHttpRequest(); 6390 var debug = this.debug; 6391 var self = this; 6392 request.onreadystatechange = function() { 6393 if (request.readyState != 4) return; 6394 if (request.status != 200) { 6395 console.log('Error: SDK GET web request failed'); 6396 if (debug) { 6397 console.log(request.statusText); 6398 console.log(request.responseText); 6399 console.log(request.responseXML); 6400 } 6401 if (request.statusText != null && request.responseText != null && request.responseText.indexOf("<html>") != -1) { 6402 self.error(request.statusText); 6403 } else { 6404 self.error(request.responseText); 6405 } 6406 return; 6407 } 6408 processor(request.responseXML.childNodes[0]); 6409 } 6410 6411 request.open('GET', url, true); 6412 request.send(); 6413 } 6414 6415 this.POST = function(url, xml, processor) { 6416 if (this.debug) { 6417 console.log("POST: " + url); 6418 console.log("XML: " + xml); 6419 } 6420 var request = new XMLHttpRequest(); 6421 var debug = this.debug; 6422 var self = this; 6423 request.onreadystatechange = function() { 6424 if (debug) { 6425 console.log(request.readyState); 6426 console.log(request.status); 6427 console.log(request.statusText); 6428 console.log(request.responseText); 6429 console.log(request.responseXML); 6430 } 6431 if (request.readyState != 4) return; 6432 if (request.status != 200 && request.status != 204) { 6433 console.log('Error: SDK POST web request failed'); 6434 if (debug) { 6435 console.log(request.statusText); 6436 console.log(request.responseText); 6437 console.log(request.responseXML); 6438 } 6439 if (request.statusText != null && request.responseText != null && request.responseText.indexOf("<html>") != -1) { 6440 self.error(request.statusText); 6441 } else { 6442 self.error(request.responseText); 6443 } 6444 return; 6445 } 6446 processor(request.responseXML.childNodes[0]); 6447 }; 6448 6449 request.open('POST', url, true); 6450 request.setRequestHeader("Content-Type", "application/xml"); 6451 request.send(xml); 6452 } 6453 6454 this.POST_FILE = function(url, form, xml, processor) { 6455 if (this.debug) { 6456 console.log("POST FILE: " + url); 6457 console.log("FORM: " + form); 6458 console.log("XML: " + xml); 6459 } 6460 var request = new XMLHttpRequest(); 6461 var formData = new FormData(form); 6462 formData.append("xml", xml); 6463 var debug = this.debug; 6464 var self = this; 6465 request.onreadystatechange = function() { 6466 if (debug) { 6467 console.log(request.readyState); 6468 console.log(request.status); 6469 console.log(request.statusText); 6470 console.log(request.responseText); 6471 console.log(request.responseXML); 6472 } 6473 if (request.readyState != 4) return; 6474 if (request.status != 200 && request.status != 204) { 6475 console.log('Error: SDK POST web request failed'); 6476 if (debug) { 6477 console.log(request.statusText); 6478 console.log(request.responseText); 6479 console.log(request.responseXML); 6480 } 6481 if (request.statusText != null && request.responseText != null && request.responseText.indexOf("<html>") != -1) { 6482 self.error(request.statusText); 6483 } else { 6484 self.error(request.responseText); 6485 } 6486 return; 6487 } 6488 processor(request.responseXML.childNodes[0]); 6489 }; 6490 6491 request.open('POST', url, true); 6492 //request.setRequestHeader("Content-Type", "multipart/form-data"); 6493 request.send(formData); 6494 } 6495 6496 this.POST_IMAGE = function(url, file, form, xml, processor) { 6497 var self = this; 6498 var debug = this.debug; 6499 var reader = new FileReader(); 6500 reader.onloadend = function() { 6501 var tempImg = new Image(); 6502 tempImg.src = reader.result; 6503 tempImg.onload = function() { 6504 var MAX_WIDTH = 300; 6505 var MAX_HEIGHT = 300; 6506 var tempW = tempImg.width; 6507 var tempH = tempImg.height; 6508 if (tempW > tempH) { 6509 if (tempW > MAX_WIDTH) { 6510 tempH *= MAX_WIDTH / tempW; 6511 tempW = MAX_WIDTH; 6512 } 6513 } else { 6514 if (tempH > MAX_HEIGHT) { 6515 tempW *= MAX_HEIGHT / tempH; 6516 tempH = MAX_HEIGHT; 6517 } 6518 } 6519 var canvas = document.createElement('canvas'); 6520 canvas.width = tempW; 6521 canvas.height = tempH; 6522 var ctx = canvas.getContext("2d"); 6523 ctx.fillStyle = '#fff'; 6524 ctx.fillRect(0, 0, canvas.width, canvas.height); 6525 ctx.drawImage(this, 0, 0, tempW, tempH); 6526 var dataUrl = canvas.toDataURL('image/jpeg'); 6527 var blob = SDK.dataURLToBlob(dataUrl); 6528 6529 var request = new XMLHttpRequest(); 6530 var formData = new FormData(); 6531 formData.append("xml", xml); 6532 formData.append('file', blob, file.name); 6533 request.onreadystatechange = function() { 6534 if (debug) { 6535 console.log(request.readyState); 6536 console.log(request.status); 6537 console.log(request.statusText); 6538 console.log(request.responseText); 6539 console.log(request.responseXML); 6540 } 6541 if (request.readyState != 4) return; 6542 if (request.status != 200 && request.status != 204) { 6543 console.log('Error: SDK POST web request failed'); 6544 if (debug) { 6545 console.log(request.statusText); 6546 console.log(request.responseText); 6547 console.log(request.responseXML); 6548 } 6549 if (request.statusText != null && request.responseText != null && request.responseText.indexOf("<html>") != -1) { 6550 self.error(request.statusText); 6551 } else { 6552 self.error(request.responseText); 6553 } 6554 return; 6555 } 6556 processor(request.responseXML.childNodes[0]); 6557 }; 6558 6559 request.open('POST', url, true); 6560 //request.setRequestHeader("Content-Type", "multipart/form-data"); 6561 request.send(formData); 6562 } 6563 } 6564 reader.readAsDataURL(file); 6565 } 6566 } 6567 6568 /** 6569 * Abstract root class for all web API message objects. 6570 * Defines the required application id, and common fields. 6571 * @class 6572 * @property application 6573 * @property domain 6574 * @property user 6575 * @property token 6576 * @property instance 6577 * @property type 6578 */ 6579 function Config() { 6580 /** The application ID. This is require to authenticate the API usage. You can obtain your application ID from your user page. */ 6581 this.application; 6582 /** Optional domain id, if object is not on the server's default domain. */ 6583 this.domain; 6584 /** User ID, required for content creation, secure content access, or to identify the user. */ 6585 this.user; 6586 /** User's access token, returned from connect web API, can be used in place of password in subsequent calls, and stored in a cookie. The user's password should never be stored. */ 6587 this.token; 6588 /** The id or name of the bot or content instance to access. */ 6589 this.instance; 6590 /** Type of instance to access, ("Bot", "Forum", "Channel", "Domain") */ 6591 this.type; 6592 6593 this.addCredentials = function(connection) { 6594 this.application = connection.credentials.applicationId; 6595 if (connection.user != null) { 6596 this.user = connection.user.user; 6597 this.token = connection.user.token; 6598 } 6599 if (connection.domain != null) { 6600 this.domain = connection.domain.id; 6601 } 6602 } 6603 6604 this.writeCredentials = function(xml) { 6605 if (this.user != null && this.user.length > 0) { 6606 xml = xml + (" user=\"" + this.user + "\""); 6607 } 6608 if (this.token != null && this.token.length > 0) { 6609 xml = xml + (" token=\"" + this.token + "\""); 6610 } 6611 if (this.type != null && this.type.length > 0) { 6612 xml = xml + (" type=\"" + this.type + "\""); 6613 } 6614 if (this.instance != null && this.instance.length > 0) { 6615 xml = xml + (" instance=\"" + this.instance + "\""); 6616 } 6617 if (this.application != null && this.application.length > 0) { 6618 xml = xml + (" application=\"" + this.application + "\""); 6619 } 6620 if (this.domain != null && this.domain.length > 0) { 6621 xml = xml + (" domain=\"" + this.domain + "\""); 6622 } 6623 return xml; 6624 } 6625 } 6626 6627 /** 6628 * This object models a user. 6629 * It can be used from a chat UI, or with the Libre Web API. 6630 * It can convert itself to/from XML for web API usage. 6631 * This can be used to connect, create, edit, or browse a user instance. 6632 * @class 6633 * @property password 6634 * @property newPassword 6635 * @property hint 6636 * @property name 6637 * @property showName 6638 * @property email 6639 * @property website 6640 * @property bio 6641 * @property over18 6642 * @property avatar 6643 * @property connects 6644 * @property bots 6645 * @property posts 6646 * @property messages 6647 * @property joined 6648 * @property lastConnect 6649 */ 6650 function UserConfig() { 6651 /** Password, require to connect a user, or create a user. */ 6652 this.password; 6653 /** New password for editting a user's password (password is old password). */ 6654 this.newPassword; 6655 /** Optional password hint, in case password is forgotten. */ 6656 this.hint; 6657 /** Optional real name of the user. */ 6658 this.name; 6659 /** The real name can be hidden from other users. */ 6660 this.showName; 6661 /** Email, required for message notification, and to reset password. */ 6662 this.email; 6663 /** Optional user's website. */ 6664 this.website; 6665 /** Optional user's bio. */ 6666 this.bio; 6667 this.over18; 6668 /** Read-only, server local URL for user's avatar image. */ 6669 this.avatar; 6670 this.avatarThumb; 6671 6672 /** Read-only, total user connects. */ 6673 this.connects; 6674 /** Read-only, total bots created. */ 6675 this.bots; 6676 /** Read-only, total forum posts. */ 6677 this.posts; 6678 /** Read-only, total chat messages. */ 6679 this.messages; 6680 /** Read-only, date user joined. */ 6681 this.joined; 6682 /** Read-only, date of user's last connect. */ 6683 this.lastConnect; 6684 6685 this.addCredentials = function(connection) { 6686 this.application = connection.credentials.applicationId; 6687 if (connection.domain != null) { 6688 this.domain = connection.domain.id; 6689 } 6690 } 6691 6692 this.parseXML = function(element) { 6693 this.user = element.getAttribute("user"); 6694 this.name = element.getAttribute("name"); 6695 this.showName = element.getAttribute("showName"); 6696 this.token = element.getAttribute("token"); 6697 this.email = element.getAttribute("email"); 6698 this.hint = element.getAttribute("hint"); 6699 this.website = element.getAttribute("website"); 6700 this.connects = element.getAttribute("connects"); 6701 this.bots = element.getAttribute("bots"); 6702 this.posts = element.getAttribute("posts"); 6703 this.messages = element.getAttribute("messages"); 6704 this.joined = element.getAttribute("joined"); 6705 this.lastConnect = element.getAttribute("lastConnect"); 6706 6707 var node = element.getElementsByTagName("bio")[0]; 6708 if (node != null) { 6709 this.bio = SDK.innerHTML(node); 6710 } 6711 node = element.getElementsByTagName("avatar")[0]; 6712 if (node != null) { 6713 this.avatar = SDK.innerHTML(node); 6714 } 6715 } 6716 6717 this.toXML = function() { 6718 var xml = "<user"; 6719 xml = this.writeCredentials(xml); 6720 if (this.password != null) { 6721 xml = xml + (" password=\"" + this.password + "\""); 6722 } 6723 if (this.newPassword != null) { 6724 xml = xml + (" newPassword=\"" + this.newPassword + "\""); 6725 } 6726 if (this.hint != null) { 6727 xml = xml + (" hint=\"" + this.hint + "\""); 6728 } 6729 if (this.name != null) { 6730 xml = xml + (" name=\"" + this.name + "\""); 6731 } 6732 if (this.showName) { 6733 xml = xml + (" showName=\"" + this.showName + "\""); 6734 } 6735 if (this.email != null) { 6736 xml = xml + (" email=\"" + this.email + "\""); 6737 } 6738 if (this.website != null) { 6739 xml = xml + (" website=\"" + this.website + "\""); 6740 } 6741 if (this.over18) { 6742 xml = xml + (" over18=\"" + this.over18 + "\""); 6743 } 6744 xml = xml + (">"); 6745 6746 if (this.bio != null) { 6747 xml = xml + ("<bio>"); 6748 xml = xml + (SDK.escapeHTML(this.bio)); 6749 xml = xml + ("</bio>"); 6750 } 6751 xml = xml + ("</user>"); 6752 return xml; 6753 } 6754 6755 } 6756 UserConfig.prototype = new Config(); 6757 UserConfig.prototype.constructor = UserConfig; 6758 UserConfig.constructor = UserConfig; 6759 6760 /** 6761 * This object models a chat message sent to a chat bot instance. 6762 * It can be used from a chat UI, or with the Libre Web API. 6763 * It can convert itself to XML for web API usage. 6764 * @class 6765 * @property conversation 6766 * @property speak 6767 * @property correction 6768 * @property offensive 6769 * @property disconnect 6770 * @property emote 6771 * @property action 6772 * @property message 6773 * @property debug 6774 * @property debugLevel 6775 * @property learn 6776 */ 6777 function ChatConfig() { 6778 /** The conversation id for the message. This will be returned from the first response, and must be used for all subsequent messages to maintain the conversational state. Without the conversation id, the bot has no context for the reply. */ 6779 this.conversation; 6780 /** Sets if the voice audio should be generated for the bot's response. */ 6781 this.speak; 6782 /** Sets the message to be a correction to the bot's last response. */ 6783 this.correction; 6784 /** Flags the bot's last response as offensive. */ 6785 this.offensive; 6786 /** Ends the conversation. Conversation should be terminated to converse server resources. The message can be blank. */ 6787 this.disconnect; 6788 /** 6789 * Attaches an emotion to the user's message, one of: 6790 * NONE, 6791 * LOVE, LIKE, DISLIKE, HATE, 6792 * RAGE, ANGER, CALM, SERENE, 6793 * ECSTATIC, HAPPY, SAD, CRYING, 6794 * PANIC, AFRAID, CONFIDENT, COURAGEOUS, 6795 * SURPRISE, BORED, 6796 * LAUGHTER, SERIOUS 6797 */ 6798 this.emote; 6799 /** Attaches an action to the user's messages, such as "laugh", "smile", "kiss". */ 6800 this.action; 6801 /** The user's message text. */ 6802 this.message; 6803 /** Include the message debug log in the response. */ 6804 this.debug; 6805 /** Set the debug level, one of: SEVER, WARNING, INFO, CONFIG, FINE, FINER. */ 6806 this.debugLevel; 6807 /** Enable or disable the bot's learning for this message. */ 6808 this.learn; 6809 /** Escape and filter the response message HTML content for XSS security. */ 6810 this.secure = SDK.secure; 6811 /** Strip any HTML tags from the response message. */ 6812 this.plainText; 6813 /** Send extra info with the message, such as the user's contact info (name email phone). */ 6814 this.info; 6815 /** Request a specific avatar (by ID). */ 6816 this.avatar; 6817 /** Request the response avatar media in HD. */ 6818 this.avatarHD = SDK.hd; 6819 /** Request the response avatar media in a video or image format. */ 6820 this.avatarFormat = SDK.format; 6821 /** Translate between the user's language and the bot's language. */ 6822 this.language; 6823 6824 this.toXML = function() { 6825 var xml = "<chat"; 6826 xml = this.writeCredentials(xml); 6827 if (this.conversation != null) { 6828 xml = xml + (" conversation=\"" + this.conversation + "\""); 6829 } 6830 if (this.emote != null) { 6831 xml = xml + (" emote=\"" + this.emote + "\""); 6832 } 6833 if (this.action != null) { 6834 xml = xml + (" action=\"" + this.action + "\""); 6835 } 6836 if (this.speak) { 6837 xml = xml + (" speak=\"" + this.speak + "\""); 6838 } 6839 if (this.language != null) { 6840 xml = xml + (" language=\"" + this.language + "\""); 6841 } 6842 if (this.avatarHD) { 6843 xml = xml + (" avatarHD=\"" + this.avatarHD + "\""); 6844 } 6845 if (this.avatarFormat != null) { 6846 xml = xml + (" avatarFormat=\"" + this.avatarFormat + "\""); 6847 } 6848 if (this.correction) { 6849 xml = xml + (" correction=\"" + this.correction + "\""); 6850 } 6851 if (this.offensive) { 6852 xml = xml + (" offensive=\"" + this.offensive + "\""); 6853 } 6854 if (this.learn != null) { 6855 xml = xml + (" learn=\"" + this.learn + "\""); 6856 } 6857 if (this.secure != null) { 6858 xml = xml + (" secure=\"" + this.secure + "\""); 6859 } 6860 if (this.plainText != null) { 6861 xml = xml + (" plainText=\"" + this.plainText + "\""); 6862 } 6863 if (this.debug) { 6864 xml = xml + (" debug=\"" + this.debug + "\""); 6865 } 6866 if (this.info) { 6867 xml = xml + (" info=\"" + SDK.escapeHTML(this.info) + "\""); 6868 } 6869 if (this.debugLevel != null) { 6870 xml = xml + (" debugLevel=\"" + this.debugLevel + "\""); 6871 } 6872 if (this.disconnect) { 6873 xml = xml + (" disconnect=\"" + this.disconnect + "\""); 6874 } 6875 xml = xml + (">"); 6876 6877 if (this.message != null) { 6878 xml = xml + ("<message>"); 6879 xml = xml + (SDK.escapeHTML(this.message)); 6880 xml = xml + ("</message>"); 6881 } 6882 xml = xml + ("</chat>"); 6883 return xml; 6884 } 6885 } 6886 ChatConfig.prototype = new Config(); 6887 ChatConfig.prototype.constructor = ChatConfig; 6888 ChatConfig.constructor = ChatConfig; 6889 6890 /** 6891 * This object models a command message sent to a bot instance. 6892 * It can be used to send JSON events and commands to the bot to process. 6893 * It can convert itself to XML for web API usage. 6894 * @class 6895 * @property conversation 6896 * @property speak 6897 * @property correction 6898 * @property offensive 6899 * @property disconnect 6900 * @property emote 6901 * @property action 6902 * @property message 6903 * @property debug 6904 * @property debugLevel 6905 * @property learn 6906 */ 6907 function CommandConfig() { 6908 /** The conversation id for the message. This will be returned from the first response, and must be used for all subsequent messages to maintain the conversational state. Without the conversation id, the bot has no context for the reply. */ 6909 this.conversation; 6910 /** Sets if the voice audio should be generated for the bot's response. */ 6911 this.speak; 6912 /** Sets the message to be a correction to the bot's last response. */ 6913 this.correction; 6914 /** Flags the bot's last response as offensive. */ 6915 this.offensive; 6916 /** Ends the conversation. Conversation should be terminated to converse server resources. The message can be blank. */ 6917 this.disconnect; 6918 /** 6919 * Attaches an emotion to the user's message, one of: 6920 * NONE, 6921 * LOVE, LIKE, DISLIKE, HATE, 6922 * RAGE, ANGER, CALM, SERENE, 6923 * ECSTATIC, HAPPY, SAD, CRYING, 6924 * PANIC, AFRAID, CONFIDENT, COURAGEOUS, 6925 * SURPRISE, BORED, 6926 * LAUGHTER, SERIOUS 6927 */ 6928 this.emote; 6929 /** Attaches an action to the user's messages, such as "laugh", "smile", "kiss". */ 6930 this.action; 6931 /** The json command. */ 6932 this.command; 6933 /** Include the message debug log in the response. */ 6934 this.debug; 6935 /** Set the debug level, one of: SEVER, WARNING, INFO, CONFIG, FINE, FINER. */ 6936 this.debugLevel; 6937 /** Enable or disable the bot's learning for this message. */ 6938 this.learn; 6939 /** Escape and filter the response message HTML content for XSS security. */ 6940 this.secure = SDK.secure; 6941 /** Strip any HTML tags from the response message. */ 6942 this.plainText; 6943 /** Send extra info with the message, such as the user's contact info (name email phone). */ 6944 this.info; 6945 /** Request a specific avatar (by ID). */ 6946 this.avatar; 6947 /** Request the response avatar media in HD. */ 6948 this.avatarHD = SDK.hd; 6949 /** Request the response avatar media in a video or image format. */ 6950 this.avatarFormat = SDK.format; 6951 /** Translate between the user's language and the bot's language. */ 6952 this.language; 6953 6954 this.toXML = function() { 6955 var xml = "<command"; 6956 xml = this.writeCredentials(xml); 6957 if (this.conversation != null) { 6958 xml = xml + (" conversation=\"" + this.conversation + "\""); 6959 } 6960 if (this.emote != null) { 6961 xml = xml + (" emote=\"" + this.emote + "\""); 6962 } 6963 if (this.action != null) { 6964 xml = xml + (" action=\"" + this.action + "\""); 6965 } 6966 if (this.speak) { 6967 xml = xml + (" speak=\"" + this.speak + "\""); 6968 } 6969 if (this.language != null) { 6970 xml = xml + (" language=\"" + this.language + "\""); 6971 } 6972 if (this.avatarHD) { 6973 xml = xml + (" avatarHD=\"" + this.avatarHD + "\""); 6974 } 6975 if (this.avatarFormat != null) { 6976 xml = xml + (" avatarFormat=\"" + this.avatarFormat + "\""); 6977 } 6978 if (this.correction) { 6979 xml = xml + (" correction=\"" + this.correction + "\""); 6980 } 6981 if (this.offensive) { 6982 xml = xml + (" offensive=\"" + this.offensive + "\""); 6983 } 6984 if (this.learn != null) { 6985 xml = xml + (" learn=\"" + this.learn + "\""); 6986 } 6987 if (this.secure != null) { 6988 xml = xml + (" secure=\"" + this.secure + "\""); 6989 } 6990 if (this.plainText != null) { 6991 xml = xml + (" plainText=\"" + this.plainText + "\""); 6992 } 6993 if (this.debug) { 6994 xml = xml + (" debug=\"" + this.debug + "\""); 6995 } 6996 if (this.info) { 6997 xml = xml + (" info=\"" + SDK.escapeHTML(this.info) + "\""); 6998 } 6999 if (this.debugLevel != null) { 7000 xml = xml + (" debugLevel=\"" + this.debugLevel + "\""); 7001 } 7002 if (this.disconnect) { 7003 xml = xml + (" disconnect=\"" + this.disconnect + "\""); 7004 } 7005 xml = xml + (">"); 7006 7007 if (this.command != null) { 7008 xml = xml + ("<command>"); 7009 xml = xml + (SDK.escapeHTML(this.command)); 7010 xml = xml + ("</command>"); 7011 } 7012 xml = xml + ("</command>"); 7013 return xml; 7014 } 7015 } 7016 CommandConfig.prototype = new Config(); 7017 CommandConfig.prototype.constructor = CommandConfig; 7018 CommandConfig.constructor = CommandConfig; 7019 7020 /** 7021 * This object models a chat message received from a chat bot instance. 7022 * It can be used from a chat UI, or with the Libre Web API. 7023 * It can convert itself from XML for web API usage. 7024 * @class 7025 * @property conversation 7026 * @property avatar 7027 * @property avatarType 7028 * @property avatarTalk 7029 * @property avatarTalkType 7030 * @property avatarAction 7031 * @property avatarActionType 7032 * @property avatarActionAudio 7033 * @property avatarActionAudioType 7034 * @property avatarAudio 7035 * @property avatarAudioType 7036 * @property avatarBackground 7037 * @property speech 7038 * @property message 7039 * @property question 7040 * @property emote 7041 * @property action 7042 * @property pose 7043 * @property command 7044 * @property log 7045 */ 7046 function ChatResponse() { 7047 /** The conversation id for the message. This will be returned from the first response, and must be used for all subsequent messages to maintain the conversational state. Without the conversation id, the bot has no context for the reply. */ 7048 this.conversation; 7049 /** Server relative URL for the avatar image or video. */ 7050 this.avatar; 7051 /** Second avatar animation. */ 7052 this.avatar2; 7053 /** Third avatar animation. */ 7054 this.avatar3; 7055 /** Forth avatar animation. */ 7056 this.avatar4; 7057 /** Fifth avatar animation. */ 7058 this.avatar5; 7059 /** Avatar MIME file type, (mpeg, webm, ogg, jpeg, png) */ 7060 this.avatarType; 7061 /** Server relative URL for the avatar talking image or video. */ 7062 this.avatarTalk; 7063 /** Avatar talk MIME file type, (mpeg, webm, ogg, jpeg, png) */ 7064 this.avatarTalkType; 7065 /** Server relative URL for the avatar action image or video. */ 7066 this.avatarAction; 7067 /** Avatar action MIME file type, (mpeg, webm, ogg, jpeg, png) */ 7068 this.avatarActionType; 7069 /** Server relative URL for the avatar action audio image or video. */ 7070 this.avatarActionAudio; 7071 /** Avatar action audio MIME file type, (mpeg, wav) */ 7072 this.avatarActionAudioType; 7073 /** Server relative URL for the avatar audio image or video. */ 7074 this.avatarAudio; 7075 /** Avatar audio MIME file type, (mpeg, wav) */ 7076 this.avatarAudioType; 7077 /** Server relative URL for the avatar background image. */ 7078 this.avatarBackground; 7079 /** Server relative URL for the avatar speech audio file. */ 7080 this.speech; 7081 /** The bot's message text. */ 7082 this.message; 7083 /** Optional text to the original question. */ 7084 this.question; 7085 /** 7086 * Emotion attached to the bot's message, one of: 7087 * NONE, 7088 * LOVE, LIKE, DISLIKE, HATE, 7089 * RAGE, ANGER, CALM, SERENE, 7090 * ECSTATIC, HAPPY, SAD, CRYING, 7091 * PANIC, AFRAID, CONFIDENT, COURAGEOUS, 7092 * SURPRISE, BORED, 7093 * LAUGHTER, SERIOUS 7094 */ 7095 this.emote; 7096 /** Action for the bot's messages, such as "laugh", "smile", "kiss", or mobile directive (for virtual assistants). */ 7097 this.action; 7098 /** Pose for the bot's messages, such as "dancing", "sitting", "sleeping". */ 7099 this.pose; 7100 /** JSON Command for the bot's message. This can be by the client for mobile virtual assistant functionality, games integration, or other uses. */ 7101 this.command; 7102 /** The debug log of processing the message. */ 7103 this.log; 7104 7105 this.parseXML = function(element) { 7106 this.conversation = element.getAttribute("conversation"); 7107 this.avatar = element.getAttribute("avatar"); 7108 this.avatar2 = element.getAttribute("avatar2"); 7109 this.avatar3 = element.getAttribute("avatar3"); 7110 this.avatar4 = element.getAttribute("avatar4"); 7111 this.avatar5 = element.getAttribute("avatar5"); 7112 this.avatarType = element.getAttribute("avatarType"); 7113 this.avatarTalk = element.getAttribute("avatarTalk"); 7114 this.avatarTalkType = element.getAttribute("avatarTalkType"); 7115 this.avatarAction = element.getAttribute("avatarAction"); 7116 this.avatarActionType = element.getAttribute("avatarActionType"); 7117 this.avatarActionAudio = element.getAttribute("avatarActionAudio"); 7118 this.avatarActionAudioType = element.getAttribute("avatarActionAudioType"); 7119 this.avatarAudio = element.getAttribute("avatarAudio"); 7120 this.avatarAudioType = element.getAttribute("avatarAudioType"); 7121 this.avatarBackground = element.getAttribute("avatarBackground"); 7122 this.emote = element.getAttribute("emote"); 7123 this.action = element.getAttribute("action"); 7124 this.pose = element.getAttribute("pose"); 7125 this.command = element.getAttribute("command"); 7126 this.speech = element.getAttribute("speech"); 7127 7128 var node = element.getElementsByTagName("message")[0]; 7129 if (node != null) { 7130 this.message = SDK.innerHTML(node); 7131 } 7132 7133 node = element.getElementsByTagName("log")[0]; 7134 if (node != null) { 7135 this.log = SDK.innerHTML(node); 7136 } 7137 } 7138 } 7139 ChatResponse.prototype = new Config(); 7140 ChatResponse.prototype.constructor = ChatResponse; 7141 ChatResponse.constructor = ChatResponse; 7142 7143 /** 7144 * This object is returned from the SDK chatSettings() API to retrieve a conversation's chat settings. 7145 * It can convert itself from XML for web API usage. 7146 * @class 7147 * @property conversation 7148 * @property allowEmotes 7149 * @property allowCorrection 7150 * @property allowLearning 7151 * @property learning 7152 */ 7153 function ChatSettings() { 7154 this.conversation; 7155 this.allowEmotes; 7156 this.allowCorrection; 7157 this.allowLearning; 7158 this.learning; 7159 7160 this.toXML = function() { 7161 var xml = "<chat-settings"; 7162 xml = this.writeCredentials(xml); 7163 if (this.conversation != null) { 7164 xml = xml + (" conversation=\"" + this.conversation + "\""); 7165 } 7166 xml = xml + ("/>"); 7167 return xml; 7168 } 7169 7170 this.parseXML = function(element) { 7171 this.allowEmotes = "true" == (element.getAttribute("allowEmotes")); 7172 this.allowCorrection = "true" == (element.getAttribute("allowCorrection")); 7173 this.allowLearning = "true" == (element.getAttribute("allowLearning")); 7174 this.learning = "true" == (element.getAttribute("learning")); 7175 } 7176 } 7177 ChatSettings.prototype = new Config(); 7178 ChatSettings.prototype.constructor = ChatSettings; 7179 ChatSettings.constructor = ChatSettings; 7180 7181 /** 7182 * DTO for XML avatar message config. 7183 * @class 7184 * @property avatar 7185 * @property speak 7186 * @property voice 7187 * @property message 7188 * @property emote 7189 * @property action 7190 * @property pose 7191 */ 7192 function AvatarMessage() { 7193 this.avatar; 7194 this.speak; 7195 this.voice; 7196 this.voiceMod; 7197 this.message; 7198 this.emote; 7199 this.action; 7200 this.pose; 7201 this.hd = SDK.hd; 7202 this.format = SDK.format; 7203 7204 this.toXML = function() { 7205 var xml = "<avatar-message"; 7206 xml = this.writeCredentials(xml); 7207 if (this.avatar != null) { 7208 xml = xml + (" avatar=\"" + this.avatar + "\""); 7209 } 7210 if (this.emote != null) { 7211 xml = xml + (" emote=\"" + this.emote + "\""); 7212 } 7213 if (this.action != null) { 7214 xml = xml + (" action=\"" + this.action + "\""); 7215 } 7216 if (this.pose != null) { 7217 xml = xml + (" pose=\"" + this.pose + "\""); 7218 } 7219 if (this.voice != null) { 7220 xml = xml + (" voice=\"" + this.voice + "\""); 7221 } 7222 if (this.voiceMod != null) { 7223 xml = xml + (" voiceMod=\"" + this.voiceMod + "\""); 7224 } 7225 if (this.format != null) { 7226 xml = xml + (" format=\"" + this.format + "\""); 7227 } 7228 if (this.speak) { 7229 xml = xml + (" speak=\"" + this.speak + "\""); 7230 } 7231 if (this.hd) { 7232 xml = xml + (" hd=\"" + this.hd + "\""); 7233 } 7234 xml = xml + (">"); 7235 7236 if (this.message != null) { 7237 xml = xml + ("<message>"); 7238 xml = xml + (SDK.escapeHTML(this.message)); 7239 xml = xml + ("</message>"); 7240 } 7241 xml = xml + ("</avatar-message>"); 7242 return xml; 7243 } 7244 } 7245 AvatarMessage.prototype = new Config(); 7246 AvatarMessage.prototype.constructor = AvatarMessage; 7247 AvatarMessage.constructor = AvatarMessage; 7248 7249 /** 7250 * This object models the web API browse operation. 7251 * It can be used to search a set of instances (bots, forums, or channels). 7252 * @class 7253 * @property type 7254 * @property typeFilter 7255 * @property category 7256 * @property tag 7257 * @property filter 7258 * @property sort 7259 */ 7260 function BrowseConfig() { 7261 /** Filters instances by access type, "Public", "Private", "Personal". */ 7262 this.typeFilter; 7263 /** Filters instances by categories (csv) */ 7264 this.category; 7265 /** Filters instances by tags (csv) */ 7266 this.tag; 7267 /** Filters instances by name */ 7268 this.filter; 7269 /** Sorts instances, "name", "date", "size", "stars", "thumbs up", "thumbs down", "last connect", "connects", "connects today", "connects this week ", "connects this month" */ 7270 this.sort; 7271 7272 this.toXML = function() { 7273 var xml = "<browse"; 7274 xml = this.writeCredentials(xml); 7275 if (this.typeFilter != null) { 7276 xml = xml + (" typeFilter=\"" + this.typeFilter + "\""); 7277 } 7278 if (this.sort != null) { 7279 xml = xml + (" sort=\"" + this.sort + "\""); 7280 } 7281 if ((this.category != null) && this.category != "") { 7282 xml = xml + (" category=\"" + this.category + "\""); 7283 } 7284 if ((this.tag != null) && this.tag != "") { 7285 xml = xml + (" tag=\"" + this.tag + "\""); 7286 } 7287 if ((this.filter != null) && this.filter != "") { 7288 xml = xml + (" filter=\"" + this.filter + "\""); 7289 } 7290 xml = xml + ("/>"); 7291 return xml; 7292 } 7293 } 7294 BrowseConfig.prototype = new Config(); 7295 BrowseConfig.prototype.constructor = BrowseConfig; 7296 BrowseConfig.constructor = BrowseConfig; 7297 7298 /** 7299 * Abstract content class. 7300 * This object models a content object such as a bot, forum, or channel. 7301 * It can be used from a chat UI, or with the Libre Web API. 7302 * It can convert itself to/from XML for web API usage. 7303 * This can be used to create, edit, or browse a content. 7304 * @class 7305 * @property id 7306 * @property name 7307 * @property isAdmin 7308 * @property isAdult 7309 * @property isPrivate 7310 * @property isHidden 7311 * @property accessMode 7312 * @property isFlagged 7313 * @property flaggedReason 7314 * @property isExternal 7315 * @property description 7316 * @property details 7317 * @property disclaimer 7318 * @property tags 7319 * @property categories 7320 * @property creator 7321 * @property creationDate 7322 * @property lastConnectedUser 7323 * @property website 7324 * @property license 7325 * @property avatar 7326 * @property connects 7327 * @property dailyConnects 7328 * @property weeklyConnects 7329 * @property monthlyConnects 7330 */ 7331 function WebMediumConfig() { 7332 /** Instance ID. */ 7333 this.id; 7334 /** Instance name. */ 7335 this.name; 7336 /** Read-only, returns if connected user is the content's admin. */ 7337 this.isAdmin; 7338 this.isAdult; 7339 /** Sets if the content is private to the creator, and its members. */ 7340 this.isPrivate; 7341 /** Sets if the conent will be visible and searchable in the content directory. */ 7342 this.isHidden; 7343 /** Sets the access mode for the content, ("Everyone", "Users", "Members", "Administrators"). */ 7344 this.accessMode; 7345 /** Returns if the content has been flagged, or used to flag content as offensive (reason required). */ 7346 this.isFlagged; 7347 /** Returns why the content has been flagged, or used to flag content as offensive. */ 7348 this.flaggedReason; 7349 /** Can be used to create a link to external content in the content directory. */ 7350 this.isExternal; 7351 /** Optional description of the content. */ 7352 this.description; 7353 /** Optional restrictions or details of the content. */ 7354 this.details; 7355 /** Optional warning or disclaimer of the content. */ 7356 this.disclaimer; 7357 /** Tags to classify the content (csv). */ 7358 this.tags; 7359 /** Categories to categorize the content under (csv). */ 7360 this.categories; 7361 /** Read-only, returns content's creator's user ID. */ 7362 this.creator; 7363 /** Read-only, returns content's creation date. */ 7364 this.creationDate; 7365 /** Read-only, returns last user to access content */ 7366 this.lastConnectedUser; 7367 /** Optional license to license the content under. */ 7368 this.license; 7369 /** Optional website related to the content. */ 7370 this.website = ""; 7371 /** Read-only, server local URL to content's avatar image. */ 7372 this.avatar; 7373 /** Read-only, returns content's toal connects. */ 7374 this.connects; 7375 /** Read-only, returns content's daily connects. */ 7376 this.dailyConnects; 7377 /** Read-only, returns content's weekly connects. */ 7378 this.weeklyConnects; 7379 /** Read-only, returns content's monthly connects. */ 7380 this.monthlyConnects; 7381 7382 this.writeWebMediumXML = function(xml) { 7383 xml = this.writeCredentials(xml); 7384 if (this.id != null) { 7385 xml = xml + (" id=\"" + this.id + "\""); 7386 } 7387 if (this.name != null) { 7388 xml = xml + (" name=\"" + this.name + "\""); 7389 } 7390 if (this.isPrivate) { 7391 xml = xml + (" isPrivate=\"true\""); 7392 } 7393 if (this.isHidden) { 7394 xml = xml + (" isHidden=\"true\""); 7395 } 7396 if (this.accessMode != null && this.accessMode != "") { 7397 xml = xml + (" accessMode=\"" + this.accessMode + "\""); 7398 } 7399 if (this.isAdult) { 7400 xml = xml + (" isAdult=\"true\""); 7401 } 7402 if (this.isFlagged) { 7403 xml = xml + (" isFlagged=\"true\""); 7404 } 7405 xml = xml + (">"); 7406 if (this.description != null) { 7407 xml = xml + ("<description>"); 7408 xml = xml + (SDK.escapeHTML(this.description)); 7409 xml = xml + ("</description>"); 7410 } 7411 if (this.details != null) { 7412 xml = xml + ("<details>"); 7413 xml = xml + (SDK.escapeHTML(this.details)); 7414 xml = xml + ("</details>"); 7415 } 7416 if (this.disclaimer != null) { 7417 xml = xml + ("<disclaimer>"); 7418 xml = xml + (SDK.escapeHTML(this.disclaimer)); 7419 xml = xml + ("</disclaimer>"); 7420 } 7421 if (this.categories != null) { 7422 xml = xml + ("<categories>"); 7423 xml = xml + (SDK.escapeHTML(this.categories)); 7424 xml = xml + ("</categories>"); 7425 } 7426 if (this.tags != null) { 7427 xml = xml + ("<tags>"); 7428 xml = xml + (SDK.escapeHTML(this.tags)); 7429 xml = xml + ("</tags>"); 7430 } 7431 if (this.license != null) { 7432 xml = xml + ("<license>"); 7433 xml = xml + (SDK.escapeHTML(this.license)); 7434 xml = xml + ("</license>"); 7435 } 7436 if (this.flaggedReason != null) { 7437 xml = xml + ("<flaggedReason>"); 7438 xml = xml + (SDK.escapeHTML(this.flaggedReason)); 7439 xml = xml + ("</flaggedReason>"); 7440 } 7441 return xml; 7442 } 7443 7444 this.parseWebMediumXML = function(element) { 7445 this.id = element.getAttribute("id"); 7446 this.name = element.getAttribute("name"); 7447 this.creationDate = element.getAttribute("creationDate"); 7448 this.isPrivate = element.getAttribute("isPrivate"); 7449 this.isHidden = element.getAttribute("isHidden"); 7450 this.accessMode = element.getAttribute("accessMode"); 7451 this.isAdmin = element.getAttribute("isAdmin"); 7452 this.isAdult = element.getAttribute("isAdult"); 7453 this.isFlagged = element.getAttribute("isFlagged"); 7454 this.creator = element.getAttribute("creator"); 7455 this.creationDate = element.getAttribute("creationDate"); 7456 this.connects = element.getAttribute("connects"); 7457 this.dailyConnects = element.getAttribute("dailyConnects"); 7458 this.weeklyConnects = element.getAttribute("weeklyConnects"); 7459 this.monthlyConnects = element.getAttribute("monthlyConnects"); 7460 7461 var node = element.getElementsByTagName("description")[0]; 7462 if (node != null) { 7463 this.description = SDK.innerHTML(node); 7464 } 7465 node = element.getElementsByTagName("details")[0]; 7466 if (node != null) { 7467 this.details = SDK.innerHTML(node); 7468 } 7469 node = element.getElementsByTagName("disclaimer")[0]; 7470 if (node != null) { 7471 this.disclaimer = SDK.innerHTML(node); 7472 } 7473 node = element.getElementsByTagName("categories")[0]; 7474 if (node != null) { 7475 this.categories = SDK.innerHTML(node); 7476 } 7477 node = element.getElementsByTagName("tags")[0]; 7478 if (node != null) { 7479 this.tags = SDK.innerHTML(node); 7480 } 7481 node = element.getElementsByTagName("flaggedReason")[0]; 7482 if (node != null) { 7483 this.flaggedReason = SDK.innerHTML(node); 7484 } 7485 node = element.getElementsByTagName("lastConnectedUser")[0]; 7486 if (node != null) { 7487 this.lastConnectedUser = SDK.innerHTML(node); 7488 } 7489 node = element.getElementsByTagName("license")[0]; 7490 if (node != null) { 7491 this.license = SDK.innerHTML(node); 7492 } 7493 node = element.getElementsByTagName("avatar")[0]; 7494 if (node != null) { 7495 this.avatar = SDK.innerHTML(node); 7496 } 7497 } 7498 } 7499 WebMediumConfig.prototype = new Config(); 7500 WebMediumConfig.prototype.constructor = WebMediumConfig; 7501 WebMediumConfig.constructor = WebMediumConfig; 7502 7503 /** 7504 * This object models a live chat channel or chatroom instance. 7505 * It can be used from a chat UI, or with the Libre Web API. 7506 * It can convert itself to/from XML for web API usage. 7507 * This can be used to create, edit, or browse a channel instance. 7508 * @class 7509 * @property type 7510 * @property messages 7511 * @property usersOnline 7512 * @property adminsOnline 7513 */ 7514 function ChannelConfig() { 7515 /** Sets type, "ChatRoom", "OneOnOne". */ 7516 this.type; 7517 /** Read-only: total number of messages. */ 7518 this.messages; 7519 /** Read-only: current users online. */ 7520 this.usersOnline; 7521 /** Read-only: current admins or operators online. */ 7522 this.adminsOnline; 7523 7524 this.type = "channel"; 7525 7526 this.credentials = function() { 7527 var config = new ChannelConfig(); 7528 config.id = this.id; 7529 return config; 7530 } 7531 7532 this.toXML = function() { 7533 var xml = "<channel"; 7534 if (this.type != null && this.type != "") { 7535 xml = xml + (" type=\"" + this.type + "\""); 7536 } 7537 xml = this.writeWebMediumXML(xml); 7538 xml = xml + ("</channel>"); 7539 return xml; 7540 } 7541 7542 this.parseXML = function(element) { 7543 this.parseWebMediumXML(element); 7544 this.type = element.getAttribute("type"); 7545 this.messages = element.getAttribute("messages"); 7546 this.usersOnline = element.getAttribute("usersOnline"); 7547 this.adminsOnline = element.getAttribute("adminsOnline"); 7548 } 7549 } 7550 ChannelConfig.prototype = new WebMediumConfig(); 7551 ChannelConfig.prototype.constructor = ChannelConfig; 7552 ChannelConfig.constructor = ChannelConfig; 7553 7554 /** 7555 * DTO to parse response of a list of names. 7556 * This is used for categories, tags, and templates. 7557 * @class 7558 * @property type 7559 */ 7560 function ContentConfig() { 7561 this.type; 7562 7563 this.parseXML = function(element) { 7564 this.type = element.getAttribute("type"); 7565 } 7566 7567 7568 this.toXML = function() { 7569 var xml = "<content"; 7570 xml = this.writeCredentials(xml); 7571 7572 xml = xml + ("/>"); 7573 return xml; 7574 } 7575 } 7576 ContentConfig.prototype = new Config(); 7577 ContentConfig.prototype.constructor = ContentConfig; 7578 ContentConfig.constructor = ContentConfig; 7579 7580 /** 7581 * This object models a domain. 7582 * It can be used from a chat UI, or with the Libre Web API. 7583 * A domain is an isolated content space to create bots and other content in (such as a commpany, project, or school). 7584 * It can convert itself to/from XML for web API usage. 7585 * This can be used to create, edit, or browse a domain instance. 7586 * @class 7587 * @property creationMode 7588 */ 7589 function DomainConfig() { 7590 this.creationMode; 7591 7592 this.type = "domain"; 7593 7594 this.credentials = function() { 7595 var config = new DomainConfig(); 7596 config.id = this.id; 7597 return config; 7598 } 7599 7600 this.toXML = function() { 7601 var xml = "<domain"; 7602 if (this.creationMode != null && this.creationMode != "") { 7603 xml = xml + (" creationMode=\"" + this.creationMode + "\""); 7604 } 7605 xml = this.writeWebMediumXML(xml); 7606 xml = xml + ("</domain>"); 7607 return xml; 7608 } 7609 7610 this.parseXML = function(element) { 7611 this.parseWebMediumXML(element); 7612 this.creationMode = element.getAttribute("creationMode"); 7613 } 7614 } 7615 DomainConfig.prototype = new WebMediumConfig(); 7616 DomainConfig.prototype.constructor = DomainConfig; 7617 DomainConfig.constructor = DomainConfig; 7618 7619 /** 7620 * This object models an avatar. 7621 * An avatar represents a bot's visual image, but can also be used independently with TTS. 7622 * It can convert itself to/from XML for web API usage. 7623 * This can be used to create, edit, or browse an avatar instance. 7624 * @class 7625 */ 7626 function AvatarConfig() { 7627 7628 this.type = "avatar"; 7629 7630 this.credentials = function() { 7631 var config = new AvatarConfig(); 7632 config.id = this.id; 7633 return config; 7634 } 7635 7636 this.toXML = function() { 7637 var xml = "<avatar"; 7638 xml = this.writeWebMediumXML(xml); 7639 xml = xml + ("</avatar>"); 7640 return xml; 7641 } 7642 7643 this.parseXML = function(element) { 7644 this.parseWebMediumXML(element); 7645 } 7646 } 7647 AvatarConfig.prototype = new WebMediumConfig(); 7648 AvatarConfig.prototype.constructor = AvatarConfig; 7649 AvatarConfig.constructor = AvatarConfig; 7650 7651 /** 7652 * This object models a script from the script library. 7653 * It can convert itself to/from XML for web API usage. 7654 * This can be used to create, edit, or browse an avatar instance. 7655 * @class 7656 */ 7657 function ScriptConfig() { 7658 7659 this.type = "script"; 7660 7661 this.credentials = function() { 7662 var config = new AvatarConfig(); 7663 config.id = this.id; 7664 return config; 7665 } 7666 7667 this.toXML = function() { 7668 var xml = "<script"; 7669 xml = this.writeWebMediumXML(xml); 7670 xml = xml + ("</script>"); 7671 return xml; 7672 } 7673 7674 this.parseXML = function(element) { 7675 this.parseWebMediumXML(element); 7676 } 7677 } 7678 ScriptConfig.prototype = new WebMediumConfig(); 7679 ScriptConfig.prototype.constructor = ScriptConfig; 7680 ScriptConfig.constructor = ScriptConfig; 7681 7682 /** 7683 * This object models a graphic from the graphics library. 7684 * It can convert itself to/from XML for web API usage. 7685 * This can be used to create, edit, or browse an avatar instance. 7686 * @class 7687 */ 7688 function GraphicConfig() { 7689 this.media; 7690 7691 this.type = "graphic"; 7692 7693 this.credentials = function() { 7694 var config = new AvatarConfig(); 7695 config.id = this.id; 7696 return config; 7697 } 7698 7699 this.toXML = function() { 7700 var xml = "<graphic"; 7701 xml = this.writeWebMediumXML(xml); 7702 xml = xml + ("</graphic>"); 7703 return xml; 7704 } 7705 7706 this.parseXML = function(element) { 7707 this.parseWebMediumXML(element); 7708 this.media = element.getAttribute("media"); 7709 } 7710 } 7711 GraphicConfig.prototype = new WebMediumConfig(); 7712 GraphicConfig.prototype.constructor = GraphicConfig; 7713 GraphicConfig.constructor = GraphicConfig; 7714 7715 /** 7716 * This object models a forum instance. 7717 * It can be used from a chat UI, or with the Libre Web API. 7718 * It can convert itself to/from XML for web API usage. 7719 * This can be used to create, edit, or browse a forum instance. 7720 * @class 7721 * @property replyAccessMode 7722 * @property postAccessMode 7723 * @property posts 7724 */ 7725 function ForumConfig() { 7726 /** Sets the access mode for forum post replies, ("Everyone", "Users", "Members", "Administrators"). */ 7727 this.replyAccessMode; 7728 /** Sets the access mode for forum posts, ("Everyone", "Users", "Members", "Administrators"). */ 7729 this.postAccessMode; 7730 /** Read-only property for the total number of posts to the forum. */ 7731 this.posts; 7732 7733 this.type = "forum"; 7734 7735 this.credentials = function() { 7736 var config = new ForumConfig(); 7737 config.id = this.id; 7738 return config; 7739 } 7740 7741 this.toXML = function() { 7742 var xml = xml + ("<forum"); 7743 if (this.replyAccessMode != null && !this.replyAccessMode == "") { 7744 xml = xml + (" replyAccessMode=\"" + this.replyAccessMode + "\""); 7745 } 7746 if (this.postAccessMode != null && !this.postAccessMode == "") { 7747 xml = xml + (" postAccessMode=\"" + this.postAccessMode + "\""); 7748 } 7749 xml = this.writeWebMediumXML(xml); 7750 xml = xml + ("</forum>"); 7751 return xml; 7752 } 7753 7754 this.parseXML = function(element) { 7755 this.parseWebMediumXML(element); 7756 this.replyAccessMode = element.getAttribute("replyAccessMode"); 7757 this.postAccessMode = element.getAttribute("postAccessMode"); 7758 this.posts = element.getAttribute("posts"); 7759 } 7760 } 7761 ForumConfig.prototype = new WebMediumConfig(); 7762 ForumConfig.prototype.constructor = ForumConfig; 7763 ForumConfig.constructor = ForumConfig; 7764 7765 /** 7766 * This object models a forum post. 7767 * It can be used from a forum UI, or with the Libre Web API. 7768 * It can convert itself to/from XML for web API usage. 7769 * You must set the forum id as the forum of the forum post. 7770 * A forum post that has a parent (parent forum post id) is a reply. 7771 * @class 7772 * @property id 7773 * @property topic 7774 * @property summary 7775 * @property details 7776 * @property detailsText 7777 * @property forum 7778 * @property tags 7779 * @property isAdmin 7780 * @property isFlagged 7781 * @property flaggedReason 7782 * @property isFeatured 7783 * @property creator 7784 * @property creationDate 7785 * @property views 7786 * @property dailyViews 7787 * @property weeklyViews 7788 * @property monthlyViews 7789 * @property replyCount 7790 * @property parent 7791 * @property replies 7792 */ 7793 function ForumPostConfig() { 7794 this.id; 7795 this.topic; 7796 this.summary; 7797 this.details; 7798 this.detailsText; 7799 this.forum; 7800 this.tags; 7801 this.isAdmin; 7802 this.isFlagged; 7803 this.flaggedReason; 7804 this.isFeatured; 7805 this.creator; 7806 this.creationDate; 7807 this.views; 7808 this.dailyViews; 7809 this.weeklyViews; 7810 this.monthlyViews; 7811 this.replyCount; 7812 this.parent; 7813 this.avatar; 7814 this.replies; 7815 7816 this.toXML = function() { 7817 var xml = "<forum-post"; 7818 xml = this.writeCredentials(xml); 7819 if (this.id != null) { 7820 xml = xml + (" id=\"" + this.id + "\""); 7821 } 7822 if (this.parent != null) { 7823 xml = xml + (" parent=\"" + this.parent + "\""); 7824 } 7825 if (this.forum != null) { 7826 xml = xml + (" forum=\"" + this.forum + "\""); 7827 } 7828 if (this.isFeatured) { 7829 xml = xml + (" isFeatured=\"true\""); 7830 } 7831 xml = xml + (">"); 7832 if (this.topic != null) { 7833 xml = xml + ("<topic>"); 7834 xml = xml + (SDK.escapeHTML(this.topic)); 7835 xml = xml + ("</topic>"); 7836 } 7837 if (this.details != null) { 7838 xml = xml + ("<details>"); 7839 xml = xml + (SDK.escapeHTML(this.details)); 7840 xml = xml + ("</details>"); 7841 } 7842 if (this.tags != null) { 7843 xml = xml + ("<tags>"); 7844 xml = xml + (SDK.escapeHTML(this.tags)); 7845 xml = xml + ("</tags>"); 7846 } 7847 xml = xml + ("</forum-post>"); 7848 } 7849 7850 this.parseXML = function(element) { 7851 this.id = element.getAttribute("id"); 7852 this.parent = element.getAttribute("parent"); 7853 this.forum = element.getAttribute("forum"); 7854 this.views = element.getAttribute("views"); 7855 this.dailyViews = element.getAttribute("dailyViews"); 7856 this.weeklyViews = element.getAttribute("weeklyViews"); 7857 this.monthlyViews = element.getAttribute("monthlyViews"); 7858 this.isAdmin = element.getAttribute("isAdmin"); 7859 this.replyCount = element.getAttribute("replyCount"); 7860 this.isFlagged = element.getAttribute("isFlagged"); 7861 this.isFeatured = element.getAttribute("isFeatured"); 7862 this.creator = element.getAttribute("creator"); 7863 this.creationDate = element.getAttribute("creationDate"); 7864 7865 var node = element.getElementsByTagName("summary")[0]; 7866 if (node != null) { 7867 this.summary = SDK.innerHTML(node); 7868 } 7869 node = element.getElementsByTagName("details")[0]; 7870 if (node != null) { 7871 this.details = SDK.innerHTML(node); 7872 } 7873 node = element.getElementsByTagName("detailsText")[0]; 7874 if (node != null) { 7875 this.detailsText = SDK.innerHTML(node); 7876 } 7877 node = element.getElementsByTagName("topic")[0]; 7878 if (node != null) { 7879 this.topic = SDK.innerHTML(node); 7880 } 7881 node = element.getElementsByTagName("tags")[0]; 7882 if (node != null) { 7883 this.tags = SDK.innerHTML(node); 7884 } 7885 node = element.getElementsByTagName("flaggedReason")[0]; 7886 if (node != null) { 7887 this.flaggedReason = SDK.innerHTML(node); 7888 } 7889 node = element.getElementsByTagName("avatar")[0]; 7890 if (node != null) { 7891 this.avatar = SDK.innerHTML(node); 7892 } 7893 var nodes = element.getElementsByTagName("replies"); 7894 if (nodes != null && nodes.length > 0) { 7895 this.replies = []; 7896 for (var index = 0; index < nodes.length; index++) { 7897 var reply = nodes[index]; 7898 var config = new ForumPostConfig(); 7899 config.parseXML(reply); 7900 this.replies[replies.length] = (config); 7901 } 7902 } 7903 } 7904 } 7905 ForumPostConfig.prototype = new Config(); 7906 ForumPostConfig.prototype.constructor = ForumPostConfig; 7907 ForumPostConfig.constructor = ForumPostConfig; 7908 7909 /** 7910 * The Instance config object defines the settings for a bot instance. 7911 * It is used to create, edit, and reference a bot. 7912 * It inherits from the WebMediumConfig class. 7913 * @see {@link WebMediumConfig} 7914 * @class 7915 * @property size 7916 * @property allowForking 7917 * @property template 7918 */ 7919 function InstanceConfig() { 7920 /** Read-only : the current size of the bot's knowledge base. **/ 7921 this.size; 7922 /** Sets if the bot can be forked. */ 7923 this.allowForking; 7924 /** Sets the name or id of a bot to clone to create a new bot. */ 7925 this.template; 7926 7927 this.type = "instance"; 7928 7929 this.credentials = function() { 7930 var config = new InstanceConfig(); 7931 config.id = this.id; 7932 return config; 7933 } 7934 7935 this.toXML = function() { 7936 var xml = "<instance"; 7937 if (this.allowForking) { 7938 xml = xml + (" allowForking=\"true\""); 7939 } 7940 xml = this.writeWebMediumXML(xml); 7941 if (this.template != null) { 7942 xml = xml + ("<template>"); 7943 xml = xml + (this.template); 7944 xml = xml + ("</template>"); 7945 } 7946 xml = xml + ("</instance>"); 7947 return xml; 7948 } 7949 7950 this.parseXML = function(element) { 7951 this.parseWebMediumXML(element); 7952 this.allowForking = element.getAttribute("allowForking"); 7953 this.size = element.getAttribute("size"); 7954 7955 var node = element.getElementsByTagName("template")[0]; 7956 if (node != null) { 7957 this.template = SDK.innerHTML(node); 7958 } 7959 } 7960 } 7961 InstanceConfig.prototype = new WebMediumConfig(); 7962 InstanceConfig.prototype.constructor = InstanceConfig; 7963 InstanceConfig.constructor = InstanceConfig; 7964 7965 /** 7966 * The Media config object is used the send and retrieve image, video, audio, and file attachments with the server. 7967 * Media and file attachments can be sent linked in chat messages or forum posts. 7968 * It inherits from the Config class. 7969 * @see {@link Config} 7970 * @class 7971 * @property id 7972 * @property name 7973 * @property type 7974 * @property file 7975 * @property key 7976 */ 7977 function MediaConfig() { 7978 this.id; 7979 this.name; 7980 this.type; 7981 this.file; 7982 this.key; 7983 7984 this.parseXML = function (element) { 7985 this.id = element.getAttribute("id"); 7986 this.name = element.getAttribute("name"); 7987 this.type = element.getAttribute("type"); 7988 this.file = element.getAttribute("file"); 7989 this.key = element.getAttribute("key"); 7990 } 7991 7992 this.toXML = function() { 7993 var xml = "<media"; 7994 xml = this.writeCredentials(xml); 7995 7996 if (this.id != null) { 7997 xml = xml + (" id=\"" + this.id + "\""); 7998 } 7999 if (this.name != null) { 8000 xml = xml + (" name=\"" + this.name + "\""); 8001 } 8002 if (this.file != null) { 8003 xml = xml + (" file=\"" + this.file + "\""); 8004 } 8005 if (this.key != null) { 8006 xml = xml + (" key=\"" + this.key + "\""); 8007 } 8008 8009 xml = xml + ("/>"); 8010 return xml; 8011 } 8012 } 8013 MediaConfig.prototype = new Config(); 8014 MediaConfig.prototype.constructor = MediaConfig; 8015 MediaConfig.constructor = MediaConfig; 8016 8017 /** 8018 * The Voice config object allows the bot's voice to be configured. 8019 * It inherits from the Config class. 8020 * @see {@link Config} Config 8021 * @class 8022 * @property language 8023 * @property pitch 8024 * @property speechRate 8025 */ 8026 function VoiceConfig() { 8027 /** Voice language code (en, fr, en_US, etc.) */ 8028 this.language; 8029 this.pitch; 8030 this.speechRate; 8031 8032 this.parseXML = function (element) { 8033 this.language = element.getAttribute("language"); 8034 this.pitch = element.getAttribute("pitch"); 8035 this.speechRate = element.getAttribute("speechRate"); 8036 } 8037 8038 8039 this.toXML = function() { 8040 var xml = "<voice"; 8041 xml = this.writeCredentials(xml); 8042 8043 if (this.language != null) { 8044 xml = xml + (" language=\"" + this.language + "\""); 8045 } 8046 if (this.pitch != null) { 8047 xml = xml + (" pitch=\"" + this.pitch + "\""); 8048 } 8049 if (this.speechRate != null) { 8050 xml = xml + (" speechRate=\"" + this.speechRate + "\""); 8051 } 8052 8053 xml = xml + ("/>"); 8054 return xml; 8055 } 8056 } 8057 VoiceConfig.prototype = new Config(); 8058 VoiceConfig.prototype.constructor = VoiceConfig; 8059 VoiceConfig.constructor = VoiceConfig; 8060 8061 /** 8062 * The Training config object allows new responses to be added to the bot. 8063 * It supports four operations, AddGreeting, RemoveGreeting, AddDefaultResponse, RemoveDefaultResponse, and AddResponse. 8064 * It inherits from the Config class. 8065 * @see {@link Config} Config 8066 * @class 8067 * @property operation 8068 * @property question 8069 * @property response 8070 */ 8071 function TrainingConfig() { 8072 /** Type of response ("Response", "Greeting", "DefaultResponse"). */ 8073 this.operation; 8074 /** The question phrase or pattern (i.e. "hello", "what is your name", "Pattern:^ help ^"). */ 8075 this.question; 8076 /** The response phrase or formula (i.e. "Hello there.", "Formula:"My name is {:target}."", "What would you like help with?"). */ 8077 this.response; 8078 8079 this.parseXML = function (element) { 8080 this.operation = element.getAttribute("operation"); 8081 var node = element.getElementsByTagName("question")[0]; 8082 if (node != null) { 8083 this.question = SDK.innerHTML(node); 8084 } 8085 node = element.getElementsByTagName("response")[0]; 8086 if (node != null) { 8087 this.response = SDK.innerHTML(node); 8088 } 8089 } 8090 8091 this.toXML = function() { 8092 var xml = "<training"; 8093 xml = this.writeCredentials(xml); 8094 8095 if (this.operation != null) { 8096 xml = xml + (" operation=\"" + this.operation + "\""); 8097 } 8098 xml = xml + (">"); 8099 if (this.question != null) { 8100 xml = xml + ("<question>"); 8101 xml = xml + (SDK.escapeHTML(this.question)); 8102 xml = xml + ("</question>"); 8103 } 8104 if (this.response != null) { 8105 xml = xml + ("<response>"); 8106 xml = xml + (SDK.escapeHTML(this.response)); 8107 xml = xml + ("</response>"); 8108 } 8109 xml = xml + ("</training>"); 8110 8111 xml = xml + ("/>"); 8112 return xml; 8113 } 8114 } 8115 TrainingConfig.prototype = new Config(); 8116 TrainingConfig.prototype.constructor = TrainingConfig; 8117 TrainingConfig.constructor = TrainingConfig; 8118 8119 /** 8120 * Allow async loading callback. 8121 */ 8122 if (typeof SDK_onLoaded !== 'undefined') { 8123 SDK_onLoaded(); 8124 } 8125 8126 /** 8127 * Allow for botlibre.SDK namespace. 8128 */ 8129 var botlibre = {}; 8130 botlibre.SDK = {}; 8131 for (var attr in SDK) { 8132 botlibre.SDK[attr] = SDK[attr]; 8133 } 8134