diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa5818d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore tunneling tool +/ngrok diff --git a/component/Bubbles.js b/component/Bubbles.js index be231e7..7b3a2e6 100644 --- a/component/Bubbles.js +++ b/component/Bubbles.js @@ -1,18 +1,52 @@ function Bubbles(container, self, options) { // options - options = typeof options !== "undefined" ? options : {}; + options = typeof options !== "undefined" ? options : {}; animationTime = options.animationTime || 200; // how long it takes to animate chat bubble, also set in CSS typeSpeed = options.typeSpeed || 5; // delay per character, to simulate the machine "typing" widerBy = options.widerBy || 2; // add a little extra width to bubbles to make sure they don't break sidePadding = options.sidePadding || 6; // padding on both sides of chat bubbles + inputCallbackFn = options.inputCallbackFn || (function(o){ return false }); // should we display an input field? + var standingAnswer = "ice"; // remember where to restart convo if interrupted + + + // set up the stage container.classList.add("bubble-container"); var bubbleWrap = document.createElement("div"); bubbleWrap.className = "bubble-wrap"; container.appendChild(bubbleWrap); + // install user input textfield + this.typeInput = function(callbackFn){ + var inputWrap = document.createElement("div"); + inputWrap.className = "input-wrap"; + var inputText = document.createElement("textarea"); + inputText.setAttribute("placeholder", "Type your question..."); + inputWrap.appendChild(inputText); + inputText.addEventListener("keypress", function(e){ // register user input + if(e.keyCode == 13){ + e.preventDefault(); + typeof bubbleQueue !== false ? clearTimeout(bubbleQueue) : false; // allow user to interrupt the bot + var lastBubble = document.querySelectorAll(".bubble.say"); lastBubble = lastBubble[lastBubble.length-1]; + lastBubble.classList.contains("reply") && !lastBubble.classList.contains("reply-freeform") ? lastBubble.classList.add("bubble-hidden") : false; + addBubble("" + this.value + "", function(){}, "reply reply-freeform"); + // callback + typeof callbackFn === "function" ? callbackFn({ + "input" : this.value, + "convo" : convo, + "standingAnswer": standingAnswer + }) : false; + this.value = ""; + } + }); + container.appendChild(inputWrap); + bubbleWrap.style.paddingBottom = "100px"; + } + inputCallbackFn ? this.typeInput(inputCallbackFn) : false; + + // init typing bubble var bubbleTyping = document.createElement("div"); @@ -25,9 +59,10 @@ function Bubbles(container, self, options) { bubbleWrap.appendChild(bubbleTyping); // accept JSON & create bubbles - this.talk = function(convo) { + this.talk = function(convo, here) { this.convo = convo; - this.reply(); + this.reply(this.convo[here]); + here ? standingAnswer = here : false; } this.reply = function(turn) { turn = typeof turn !== "undefined" ? turn : this.convo.ice; @@ -52,7 +87,7 @@ function Bubbles(container, self, options) { // navigate "answers" this.answer = function(key){ var func = function(key){ typeof window[key] === "function" ? window[key]() : false; } - this.convo[key] !== undefined ? this.reply(this.convo[key]) : func(key); + this.convo[key] !== undefined ? (this.reply(this.convo[key]), standingAnswer = key) : func(key); }; // api for typing bubble @@ -77,7 +112,10 @@ function Bubbles(container, self, options) { start(); } + + // create a bubble + var bubbleQueue = false; var addBubble = function(say, posted, reply){ reply = typeof reply !== "undefined" ? reply : ""; // create bubble element @@ -91,7 +129,10 @@ function Bubbles(container, self, options) { // answer picker styles if(reply !== ""){ var bubbleButtons = bubbleContent.querySelectorAll(".bubble-button"); - bubbleButtons.forEach(function(el){ el.style.width = el.offsetWidth - sidePadding * 2 + widerBy + "px"; }); + bubbleButtons.forEach(function(el){ + if(!el.parentNode.parentNode.classList.contains("reply-freeform")) + el.style.width = el.offsetWidth - sidePadding * 2 + widerBy + "px"; + }); bubble.addEventListener("click", function(){ bubbleButtons.forEach(function(el){ el.style.width = 0 + "px"; @@ -110,7 +151,7 @@ function Bubbles(container, self, options) { setTimeout(function() { bubbleTyping.classList.remove("imagine"); }, animationTime ); } setTimeout(function() { bubbleTyping.classList.add("imagine"); }, wait - animationTime * 2 ); - setTimeout(function() { + bubbleQueue = setTimeout(function() { bubble.classList.remove("imagine"); var bubbleWidthCalc = bubbleContent.offsetWidth + widerBy + "px"; bubble.style.width = reply == "" ? bubbleWidthCalc : ""; @@ -134,4 +175,6 @@ function Bubbles(container, self, options) { }, wait + animationTime * 2); } -} \ No newline at end of file + + +} // close function \ No newline at end of file diff --git a/component/start-here/hello.html b/component/start-here/hello.html index 55865c2..a96ccfa 100644 --- a/component/start-here/hello.html +++ b/component/start-here/hello.html @@ -12,6 +12,7 @@ + @@ -322,7 +323,43 @@