typerbot
Version:
Flexible library for programmatic typing.
1 lines • 9.17 kB
JavaScript
class Typerbot{constructor(t,e){this._fieldElement=t||e.fieldElement||function(){throw new Error("No element provided")}(),this._settings=e?Object.assign(Typerbot.defaultSettings(),e):Typerbot.defaultSettings(),this._characterEntries=this._splitUpTextNodes(this._fieldElement)||[],this._cursorPosition=this._characterEntries.length,this._cursorElement=document.createElement("span"),this._cursorBlink=null,this._cursorBlinkTimeout=null,this._cursorElement.appendChild(document.createTextNode("|")),this._cursorElement.classList.add(this._settings.cursorClass),this._fieldElement.appendChild(this._cursorElement),this._settings.cursor?(this._calculateCursorMargins(),this._startCursorBlink()):this._cursorElement.style.visibility="hidden"}getCursorPosition(){return this._cursorPosition}getCharacterEntries(){return this._characterEntries}_parseHTMLString(t){var e=document.createElement("template");return e.innerHTML=t,e.content}_getNextTextOrHTMLNode(t){if(!t.nextSibling)return null;for(var e=t.nextSibling;!(e instanceof HTMLElement||e instanceof Text);)e=e.nextSibling;return e}_splitUpTextNodes(t){var e=[];return Array.from(t.childNodes).forEach((s=>{if(s instanceof Text){s.nodeValue=s.nodeValue.replaceAll(/(\s)+/g," ")," "==s.nodeValue[s.nodeValue.length-1]&&(s.nodeValue=s.nodeValue.substring(0,s.nodeValue.length-1))," "==s.nodeValue[0]&&(s.nodeValue=s.nodeValue.substring(1,s.nodeValue.length));var r=this._getNextTextOrHTMLNode(s);s.parentNode.removeChild(s),Array.from(s.nodeValue).forEach((s=>{var i=document.createTextNode(s);e.push(i),r?t.appendChild(i):t.insertBefore(i,r)}))}else s instanceof HTMLElement&&e.concat(this._splitUpTextNodes(s))})),e}_beginBlinkStartTimeout(){this._settings.cursor&&(this._cursorBlinkTimeout||(this._cursorBlinkTimeout=setTimeout((()=>{this._cursorBlinkTimeout=null,this._startCursorBlink()}),100)))}_clearBlinkStartTimeout(){clearTimeout(this._cursorBlinkTimeout),this._cursorBlinkTimeout=null}_startCursorBlink(){if(this._settings.cursor){var t=!0;this._cursorBlink||(this._cursorElement.style.visibility="visible",this._cursorBlink=setInterval((()=>{this._cursorElement.style.visibility=t?"hidden":"visible",t=!t}),this._settings.cursorBlinkInterval))}}_stopCursorBlink(){clearInterval(this._cursorBlink),this._cursorBlink=null}_calculateCursorMargins(){var t=this._cursorElement.getBoundingClientRect().width;this._cursorElement.style.margin=`0 ${-.6*t}px 0 ${-.4*t}px`}updateSettings(t){Object.assign(this._settings,t)}updateSettings(t){Object.assign(this._settings,t)}resetSettings(){this._settings=this.defaultSettings()}getSettings(){return this._settings}static defaultSettings(){return{keystrokeInterval:200,keystrokeDelay:0,cursorBlinkInterval:800,delayDuration:0,pauseDuration:1e3,cursorClass:"Typerbot-cursor",animation:!0,refreshCursorOnWindowResize:!1,html:!0,cursor:!0,cursorString:"|",afterLineComplete:()=>{},beforeLineComplete:()=>{},beforeKeyInput:()=>{},afterKeyInput:()=>{},afterComplete:()=>{}}}async pause(t){return new Promise((e=>{setTimeout((()=>{e()}),(()=>{if("number"==typeof t)return Math.abs(Math.floor(t));if("number"==typeof this._settings.pauseDuration)return Math.abs(Math.floor(this._settings.pauseDuration));throw new Error("Typerbot.pause only accepts number inputs")})())}))}async type(t,e){if("string"!=typeof t)throw new Error("Typerbot.type only accepts string values at positon 1");var s,r=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),e);r.html?s=this._parseHTMLString(t):(s=document.createElement("template")).appendChild(t),this._beginBlinkStartTimeout(),await this.pause(r.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();var i=[];Array.from(s.childNodes).forEach((t=>{i.push(t)}));for(var n=0;n<i.length;n++)await this._typeNodeContents(i[n],r)}async _typeNodeContents(t,e){if(t instanceof Text)for(var s=0;s<t.nodeValue.length;s++){this._clearBlinkStartTimeout(),this._beginBlinkStartTimeout();var r=document.createTextNode(t.nodeValue[s]);this._cursorElement.parentNode.insertBefore(r,this._cursorElement),this._characterEntries.splice(this._cursorPosition++,null,r),await this.pause("function"==typeof e.keystrokeInterval?e.keystrokeInterval():e.keystrokeInterval)}else{var i=[];Array.from(t.childNodes).forEach((e=>{i.push(t.removeChild(e))})),this._cursorElement.parentNode.insertBefore(t,this._cursorElement),t.appendChild(this._cursorElement.parentNode.removeChild(this._cursorElement));for(var n=0;n<i.length;n++)await this._typeNodeContents(i[n],e);t.nextSibling?t.nextSibling.parentNode.insertBefore(this._cursorElement.parentNode.removeChild(this._cursorElement),t.nextSibling):t.parentNode.appendChild(this._cursorElement.parentNode.removeChild(this._cursorElement))}}async move(t,e){if("number"!=typeof t)throw new Error("Typerbot.move only accepts number values at position 1");var s=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),e);this._beginBlinkStartTimeout(),await this.pause(s.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();for(var r=0;r<Math.abs(Math.floor(t))&&this._cursorPosition>=0&&this._cursorPosition<=this._characterEntries.length;r++){if(t>0&&this._cursorPosition+1>this._characterEntries.length||t<0&&this._cursorPosition-1<0)return;if(this._clearBlinkStartTimeout(),this._beginBlinkStartTimeout(),this._cursorPosition+=t>0?1:-1,this._cursorElement.parentNode.removeChild(this._cursorElement),this._characterEntries[this._cursorPosition])this._characterEntries[this._cursorPosition]?.parentNode.insertBefore(this._cursorElement,this._characterEntries[this._cursorPosition]);else this._fieldElement.appendChild(this._cursorElement);await this.pause("function"==typeof s.keystrokeInterval?s.keystrokeInterval():s.keystrokeInterval)}this._beginBlinkStartTimeout()}async moveToEnd(t){var e=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),t);for(this._beginBlinkStartTimeout(),await this.pause(e.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();this._cursorPosition<this._characterEntries.length;)await this.move(1,{keystrokeDelay:0,keystrokeInterval:"function"==typeof e.keystrokeInterval?e.keystrokeInterval():e.keystrokeInterval})}async moveToStart(t){var e=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),t);for(this._beginBlinkStartTimeout(),await this.pause(e.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();this._cursorPosition>0;)await this.move(-1,{keystrokeDelay:0,keystrokeInterval:"function"==typeof e.keystrokeInterval?e.keystrokeInterval():e.keystrokeInterval})}async deleteAll(t){var e=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),t);for(this._beginBlinkStartTimeout(),await this.pause(e.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();this._cursorPosition>0;)this._clearBlinkStartTimeout(),this._beginBlinkStartTimeout(),await this.delete(1,{keystrokeDelay:0,keystrokeInterval:"function"==typeof e.keystrokeInterval?e.keystrokeInterval():e.keystrokeInterval});this._beginBlinkStartTimeout()}async delete(t,e){if("number"!=typeof t)throw new Error("Typerbot.type only accepts number arguments as first parameter");var s=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),e);this._beginBlinkStartTimeout(),await this.pause(s.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();for(var r=0;r<Math.floor(t)&&this._cursorPosition>0;r++)this._clearBlinkStartTimeout(),this._beginBlinkStartTimeout(),this._characterEntries[this._cursorPosition-1].parentNode.removeChild(this._characterEntries[this._cursorPosition-1]),this._characterEntries.splice(this._cursorPosition-1,1),this._cursorPosition--,await this.pause("function"==typeof s.keystrokeInterval?s.keystrokeInterval():s.keystrokeInterval);this._beginBlinkStartTimeout()}async deleteUntilDelimiter(t,e){if(this.isFrozen())throw new Error("Typerbot is frozen and cannot handle new inputs");if("string"!=typeof t)throw new Error("Typerbot.deleteUntilDelimiter only accepts string values at position 1");var s=Object.assign(Object.assign(Typerbot.defaultSettings(),this._settings),e);for(this._beginBlinkStartTimeout(),await this.pause(s.keystrokeDelay||this._settings.keystrokeDelay),this._stopCursorBlink();this._cursorPosition>0&&this._characterEntries[this._cursorPosition-1].nodeValue!=t;)await this.delete(1,{keystrokeDelay:0,keystrokeInterval:"function"==typeof s.keystrokeInterval?s.keystrokeInterval(this):s.keystrokeInterval});this._beginBlinkStartTimeout()}freeze(){this._frozen=!0,this._clearBlinkStartTimeout(),this._stopCursorBlink(),this._cursorElement.parentNode.removeChild(this._cursorElement)}unfreeze(){this._frozen=!1,this._characterEntries[this._cursorPosition]?this._cursorElement.parentNode.insertBefore(this._cursorElement,this._characterEntries[this._cursorPosition]):this._fieldElement.appendChild(this._cursorElement),this._startCursorBlink()}isFrozen(){return!!this._frozen}clear(){var t=this._cursorElement;t.parentNode.removeChild(t),this._fieldElement.innerHTML="",this._fieldElement.appendChild(t),this._characterEntries=[],this._cursorPosition=0}}export default Typerbot;