Skip to content

Instantly share code, notes, and snippets.

@teocci
Created September 12, 2023 12:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teocci/f3e1eb9e52919a5dc229a486ad11ab25 to your computer and use it in GitHub Desktop.
Save teocci/f3e1eb9e52919a5dc229a486ad11ab25 to your computer and use it in GitHub Desktop.
(function (global) {
"use strict";
var Typed = function (element, options) {
this.el = document.querySelector(element);
this.options = Object.assign({}, Typed.DEFAULTS, options);
this.isInput = this.el.tagName.toLowerCase() === "input";
this.attr = this.options.attr;
this.showCursor = !this.isInput && this.options.showCursor;
this.elContent = this.attr ? this.el.getAttribute(this.attr) : this.el.textContent;
this.contentType = this.options.contentType;
this.typeSpeed = this.options.typeSpeed;
this.startDelay = this.options.startDelay;
this.backSpeed = this.options.backSpeed;
this.backDelay = this.options.backDelay;
this.strings = this.options.strings;
this.strPos = 0;
this.arrayPos = 0;
this.stopNum = 0;
this.loop = this.options.loop;
this.loopCount = this.options.loopCount;
this.curLoop = 0;
this.stop = false;
this.cursorChar = this.options.cursorChar;
this.shuffle = this.options.shuffle;
this.sequence = [];
this.build();
};
Typed.prototype = {
constructor: Typed,
init: function () {
var self = this;
self.timeout = setTimeout(function () {
self.sequence = [...Array(self.strings.length).keys()];
if (self.shuffle) {
self.sequence = self.shuffleArray(self.sequence);
}
self.typewrite(self.strings[self.sequence[self.arrayPos]], self.strPos);
}, self.startDelay);
},
build: function () {
if (this.showCursor === true) {
this.cursor = document.createElement("span");
this.cursor.className = "typed-cursor";
this.el.insertAdjacentElement("afterend", this.cursor);
}
this.init();
},
typewrite: function (curString, curStrPos) {
if (this.stop !== true) {
var humanize = Math.round(Math.random() * (100 - 30)) + this.typeSpeed;
var self = this;
self.timeout = setTimeout(function () {
var charPause = 0;
var nextString = curString.substr(curStrPos);
if (nextString.charAt(0) === "^") {
var skip = 1;
/^(\^\d+)/.test(nextString) && (nextString = /\d+/.exec(nextString)[0], skip += nextString.length, charPause = parseInt(nextString));
curString = curString.substring(0, curStrPos) + curString.substring(curStrPos + skip);
}
if (curString.charAt(0) === "<" && ["<", "&"].includes(nextString.charAt(0))) {
var charIndex = 1;
var tempString = "";
while (nextString.charAt(charIndex) !== ">" && nextString.charAt(charIndex) !== ";") {
tempString += nextString.charAt(charIndex);
charIndex++;
}
charIndex++;
curStrPos += charIndex;
curString += tempString + ">";
}
if (self.contentType === "html") {
var curChar = curString.substr(curStrPos).charAt(0);
if (curChar === "<" || curChar === "&") {
var endTag = curChar === "<" ? ">" : ";";
var tempString = "";
while (nextString.charAt(0) !== endTag) {
tempString += nextString.charAt(0);
nextString = nextString.substring(1);
}
nextString = nextString.substring(1);
curStrPos += tempString.length + 1;
curString += tempString + endTag;
}
}
self.timeout = setTimeout(function () {
if (curStrPos === curString.length) {
self.options.onStringTyped(self.arrayPos);
if (self.arrayPos === self.strings.length - 1) {
self.options.callback();
self.curLoop++;
if (self.loop === false || (self.curLoop === self.loopCount)) {
return;
}
}
self.timeout = setTimeout(function () {
self.backspace(curString, curStrPos);
}, self.backDelay);
} else {
if (curStrPos === 0) {
self.options.preStringTyped(self.arrayPos);
}
var nextString = curString.substr(0, curStrPos + 1);
if (self.attr) {
self.el.setAttribute(self.attr, nextString);
} else {
if (self.isInput) {
self.el.value = nextString;
} else if (self.contentType === "html") {
self.el.innerHTML = nextString;
} else {
self.el.textContent = nextString;
}
}
curStrPos++;
self.typewrite(curString, curStrPos);
}
}, charPause);
}, humanize);
}
},
backspace: function (curString, curStrPos) {
if (this.stop !== true) {
var humanize = Math.round(Math.random() * (100 - 30)) + this.backSpeed;
var self = this;
self.timeout = setTimeout(function () {
if (self.contentType === "html") {
var curChar = curString.substr(curStrPos).charAt(0);
if (curChar === ">" || curChar === ";") {
var endTag = curChar === ">" ? "<" : "&";
var tempString = "";
while (curString.charAt(curStrPos) !== endTag) {
tempString = curString.charAt(curStrPos) + tempString;
curStrPos--;
}
curStrPos--;
tempString += endTag;
curString = curString.substring(0, curStrPos + 1) + tempString;
}
}
var nextString = curString.substr(0, curStrPos);
if (self.attr) {
self.el.setAttribute(self.attr, nextString);
} else {
if (self.isInput) {
self.el.value = nextString;
} else if (self.contentType === "html") {
self.el.innerHTML = nextString;
} else {
self.el.textContent = nextString;
}
}
if (curStrPos > self.stopNum) {
curStrPos--;
self.backspace(curString, curStrPos);
} else if (curStrPos <= self.stopNum) {
self.arrayPos++;
if (self.arrayPos === self.strings.length) {
self.arrayPos = 0;
if (self.shuffle) {
self.sequence = self.shuffleArray(self.sequence);
}
self.init();
} else {
self.typewrite(self.strings[self.sequence[self.arrayPos]], curStrPos);
}
}
}, humanize);
}
},
shuffleArray: function (array) {
var currentIndex = array.length,
temporaryValue, randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
},
reset: function () {
clearInterval(this.timeout);
var id = this.el.getAttribute("id");
this.el.insertAdjacentHTML("afterend", '<span id="' + id + '"></span>');
this.el.remove();
if (typeof this.cursor !== "undefined") {
this.cursor.remove();
}
this.options.resetCallback();
}
};
Typed.DEFAULTS = {
strings: ["These are the default values...", "You know what you should do?", "Use your own!", "Have a great day!"],
typeSpeed: 0,
startDelay: 0,
backSpeed: 0,
shuffle: false,
backDelay: 500,
loop: false,
loopCount: false,
showCursor: true,
cursorChar: "|",
attr: null,
contentType: "html",
callback: function () {},
preStringTyped: function () {},
onStringTyped: function () {},
resetCallback: function () {}
};
global.Typed = Typed;
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment