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):\/\/[[email protected]#\/%?=~_|!:,.;]*[[email protected]#\/%=~_|]/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):\/\/[[email protected]#\/%?=~_|!:,.;]*[[email protected]#\/%=~_|]/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 +