typeit
Advanced tools
Comparing version 1.1.1 to 2.0.0
/** | ||
* jQuery TypeIt | ||
* @author Alex MacArthur (http://macarthur.me) | ||
* @version 1.1.1 | ||
* @version 2.0.0 | ||
* @copyright 2015 Alex MacArthur | ||
@@ -23,21 +23,29 @@ * @description Types out a given string or strings. | ||
$.fn.typeIt.typeItClass = function(theElement, options, callback){ | ||
// plugin default settings | ||
/* VARIABLES THAT WON'T CHANGE BETWEEN RUNS */ | ||
// default settings | ||
this.defaults = { | ||
whatToType:'This is the default string. Please replace this string with your own.', | ||
typeSpeed: 200, | ||
lifeLike: false, | ||
showCursor: true, | ||
breakLines: true, | ||
breakWait: 500, | ||
delayStart: 250 | ||
whatToType:'You probably want to use your own string.', | ||
typeSpeed: 100, | ||
lifeLike: true, | ||
showCursor: true, | ||
breakLines: true, | ||
breakDelay: 750, | ||
startDelay: 250, | ||
loop: false, | ||
loopDelay: 750 | ||
}; | ||
// data-typeit-* settings | ||
this.dataAttDefaults = { | ||
whatToType : theElement.data('typeitWhattotype'), | ||
typeSpeed: theElement.data('typeitSpeed'), | ||
whatToType: theElement.data('typeitWhattotype'), | ||
typeSpeed: theElement.data('typeitTypespeed'), | ||
lifeLike: theElement.data('typeitLifelike'), | ||
showCursor: theElement.data('typeitShowcursor'), | ||
breakLines: theElement.data('typeitBreaklines'), | ||
breakWait: theElement.data('typeitBreakWait'), | ||
delayStart : theElement.data('typeitDelayStart') | ||
breakDelay: theElement.data('typeitBreakdelay'), | ||
startDelay: theElement.data('typeitStartdelay'), | ||
loop: theElement.data('typeitLoop'), | ||
loopDelay: theElement.data('typeitLoopdelay') | ||
}; | ||
@@ -47,2 +55,4 @@ | ||
this.settings = {}; | ||
// merge settings into this.settings object | ||
$.extend(this.settings, this.defaults, options, this.dataAttDefaults); | ||
// the element that holds the text | ||
@@ -52,8 +62,11 @@ this.theElement = theElement; | ||
this.callback = callback; | ||
// the number of types a character has been typed for each pass over a string | ||
this.typeCount = 0; | ||
// the character number of a string that's currently being deleted | ||
this.deleteCount = 0; | ||
// the string number that's currently being typed or deleted | ||
this.stringCount = 0; | ||
// let 'r rip | ||
this.init(options); | ||
}; | ||
// create a new prototype | ||
_proto = $.fn.typeIt.typeItClass.prototype; | ||
_proto.init = function(options){ | ||
// the place we're at in the big merged string | ||
@@ -65,23 +78,42 @@ this.stringPlaceCount = 0; | ||
this.stringArray = []; | ||
// the index of the string we're handling | ||
this.stringArrayIndex = 0; | ||
// the index of the character we're currently printing | ||
this.stringArrayCharacterIndex = 0; | ||
// hold where we need to replace characters because of HTML tags | ||
this.contentStartEnd = []; | ||
// the index for the string within an HTML tag | ||
this.contentStartEndIndex = 0; | ||
// the span of characters for the string inside an HTML tag | ||
this.contentStartEndSpan = 0; | ||
// holds whether we're currently printing inside HTML tags | ||
this.printingInTag = false; | ||
// the specific character we're currently appending | ||
this.characterToAppend = null; | ||
// the current ti-text-container we're dealing | ||
this.thisTiTextContainer = null; | ||
// the current string we're handling | ||
this.thisString = null; | ||
// the particular HTML tag we're handling | ||
this.thisTag = null; | ||
// array holding the length of each string | ||
this.stringLengths = []; | ||
// the string we're currently deleting | ||
this.stringToDelete = null; | ||
// the timeout responsible for typing/adding characters | ||
this.typeTimeout = null; | ||
// the timeout responsible for deleting characters | ||
this.deleteTimeout = null; | ||
// the timeout responsible for typing/adding characters | ||
this.typeTimeout = null; | ||
// the progressively shorter string as it's being deleted | ||
this.shortenedText = null; | ||
// let 'r rip | ||
this.init(options); | ||
}; | ||
// the span of the range a type speed is allowed to be randomized | ||
this.typeSpeedRangeSpan = null; | ||
// the minimum of a randomized type speed | ||
this.typeSpeedMin = null; | ||
// the maximum of a randomized type speed | ||
this.typeSpeedMax = null; | ||
// create a new prototype | ||
_proto = $.fn.typeIt.typeItClass.prototype; | ||
_proto.init = function(options){ | ||
// make sure the callback function is all good | ||
if(this.validateCallbackFunction() === false){ return false; } | ||
// merge settings into this.settings object | ||
$.extend(this.settings, this.defaults, options, this.dataAttDefaults); | ||
// string override | ||
this.testForElementStringOverride(); | ||
// process the whatToType data to get it so we can use it | ||
@@ -94,7 +126,20 @@ this.processWhatToType(); | ||
this.typeLoop(); | ||
}.bind(this), this.settings.delayStart); | ||
}.bind(this), this.settings.startDelay); | ||
}; | ||
_proto.testForElementStringOverride = function() { | ||
// if there's a string already typed in the element, replace whatToType with it | ||
if(this.theElement.text().length > 0 && !this.theElement.has('.ti-container')) { | ||
this.settings.whatToType = this.theElement.html(); | ||
} | ||
}; | ||
_proto.setupDOMComponents = function() { | ||
// clear out the element in case we're looping | ||
this.theElement.html(''); | ||
// get the string lengths and save to array, set up ti-containers for each string | ||
@@ -123,13 +168,71 @@ for(j=0; j < this.stringArray.length; j++){ | ||
_proto.processWhatToType = function() { | ||
this.stringArray = this.settings.whatToType; | ||
// check if the value is an array or just a string | ||
if(Object.prototype.toString.call(this.stringArray) !== '[object Array]'){ | ||
// since it's not already an array, turn it into one, since later functionality depends on it being one | ||
this.stringArray = '["' + this.stringArray + '"]'; | ||
this.stringArray = JSON.parse(this.stringArray); | ||
// check if the value is an array or just a string | ||
if(Object.prototype.toString.call(this.settings.whatToType) !== '[object Array]'){ | ||
// since it's not already an array, turn it into one, since later functionality depends on it being one | ||
this.stringArray = '["' + this.settings.whatToType + '"]'; | ||
this.stringArray = JSON.parse(this.stringArray); | ||
// if it is an array, clone it | ||
} else { | ||
// clone what to typed, so we don't modify the original strings in case we loop | ||
this.stringArrayTemp = $.extend( {}, this.settings.whatToType ); | ||
// convert cloned object to array | ||
this.stringArrayTemp = $.map(this.stringArrayTemp, function(value, index) { | ||
return [value]; | ||
}); | ||
// get the right values and put into stringArray so it's formatted correctly for processing | ||
for(var h = 0; h < this.stringArrayTemp.length; h++) { | ||
this.stringArray.push(this.stringArrayTemp[h]); | ||
} | ||
// turn string array into a big string | ||
this.mergedStrings = this.stringArray.join(''); | ||
}; | ||
} | ||
// turn each string into sub arrays | ||
for(var i = 0; i < this.stringArray.length; i++) { | ||
this.contentStartEnd = []; | ||
this.contentStartEndIndex = 0; | ||
this.contentStartEndSpan = 0; | ||
// turn each string into sub array | ||
this.stringArray[i] = this.stringArray[i].split(''); | ||
// find the location of HTML tag | ||
for(var j = 0, subArray = this.stringArray[i]; j < subArray.length; j++) { | ||
if(subArray[j] === '<') { | ||
this.contentStartEnd[this.contentStartEndIndex] = []; | ||
this.contentStartEnd[this.contentStartEndIndex][0] = j; | ||
} | ||
if(subArray[j] === '>') { | ||
this.contentStartEnd[this.contentStartEndIndex][1] = j; | ||
this.contentStartEndIndex++; | ||
} | ||
} | ||
// merge individual tag characters into single array index | ||
for(var positionIndex = 0; positionIndex < this.contentStartEnd.length; positionIndex++) { | ||
// move those tag pieces into a single array item | ||
for (var l = this.contentStartEnd[positionIndex][0]; l < this.contentStartEnd[positionIndex][1]; l++) { | ||
this.stringArray[i][this.contentStartEnd[positionIndex][0]] = this.stringArray[i][this.contentStartEnd[positionIndex][0]] + this.stringArray[i][l+1]; | ||
} | ||
} | ||
// cut array items based on the start/end positions we know, but move back the start point each time by the number of items we previously removed | ||
for( var m = 0; m < this.contentStartEnd.length; m++ ) { | ||
var startPos = this.contentStartEnd[m][0]+1; | ||
this.stringArray[i].splice(startPos, this.contentStartEnd[m][1] - this.contentStartEnd[m][0]); | ||
var span = this.contentStartEnd[m][1] - this.contentStartEnd[m][0]; | ||
// go through and update the start and positions by the span length we just cut | ||
for(var n = 0; n < this.contentStartEnd.length; n++) { | ||
this.contentStartEnd[n][0] = this.contentStartEnd[n][0] - span; | ||
this.contentStartEnd[n][1] = this.contentStartEnd[n][1] - span; | ||
} | ||
} | ||
} | ||
}; | ||
_proto.validateCallbackFunction = function() { | ||
@@ -144,50 +247,92 @@ | ||
_proto.typeLoop = function(){ | ||
// set the length of the current phrase being typed | ||
this.phraseLength = this.stringLengths[this.stringCount]; | ||
// make it human-like if specified in the settings | ||
_proto.randomizeTypeSpeed = function() { | ||
// make it human-like if specified in the settings | ||
if(this.settings.lifeLike === true){ | ||
this.delayTime = this.settings.typeSpeed*Math.random(); | ||
// set to 50% of the actual type speed, so the randomization goes no further than that ratio | ||
this.typeSpeedRangeSpan = this.settings.typeSpeed/2; | ||
this.typeSpeedMin = this.settings.typeSpeed-this.typeSpeedRangeSpan; | ||
this.typeSpeedMax = this.settings.typeSpeed+this.typeSpeedRangeSpan; | ||
this.delayTime = Math.abs(Math.random() * (this.typeSpeedMax - this.typeSpeedMin) + this.typeSpeedMin); | ||
} else { | ||
this.delayTime = this.settings.typeSpeed; | ||
} | ||
}; | ||
_proto.typeLoop = function(){ | ||
// get this particular string we're printing | ||
this.thisString = this.stringArray[this.stringArrayIndex]; | ||
// set the length of the current phrase being typed | ||
this.phraseLength = this.thisString.length; | ||
// start the typing timeout | ||
this.typeTimeout = setTimeout(function () { | ||
// append the string of letters to the respective .ti-text-container | ||
var characterToAppend = this.mergedStrings[this.typeCount+this.stringPlaceCount]; | ||
this.randomizeTypeSpeed(); | ||
// if breakLines is set to true, add the 'active-container' class to the next .ti-text-container in the list. | ||
if(this.settings.breakLines === true) { | ||
this.theElement.find('.ti-text-container:eq('+ this.stringCount +')').addClass('active-container').append(characterToAppend); | ||
} else { | ||
this.theElement.find('.ti-text-container').addClass('active-container').append(characterToAppend); | ||
// the the specific character we're printing | ||
this.characterToAppend = this.stringArray[this.stringArrayIndex][this.stringArrayCharacterIndex]; | ||
// if it's an HTML tag, do stuff | ||
if(this.characterToAppend.indexOf('<') !== -1 && this.characterToAppend.indexOf('</') === -1){ | ||
this.contentStartEndIndex = 0; | ||
// get the start & end positions of the actual string within the HTML tags | ||
this.contentStartEnd[0] = this.stringArrayCharacterIndex + 1; | ||
for(var t = this.stringArrayCharacterIndex; t < this.thisString.length; t++){ | ||
if(this.thisString[t].indexOf('</') !== -1) { | ||
// set the ending of the string segment in an HTML tag | ||
this.contentStartEnd[1] = t - 1; | ||
// as soon as we hit a match for a closing character | ||
break; | ||
} | ||
} | ||
this.contentStartEndSpan = this.contentStartEnd[1] - this.contentStartEnd[0]; | ||
// create a DOM node from the string we get | ||
this.thisTag = $($.parseHTML(this.characterToAppend)); | ||
// set the current character to append to the tag we just created, so that we can create it in the DOM | ||
this.characterToAppend = this.thisTag; | ||
// append the tag | ||
this.appendTheCharacter(); | ||
// set this to true so we know we're currently printing inside an HTML tag | ||
this.printingInTag = true; | ||
} | ||
this.typeCount++; | ||
// if there are still characters to be typed, call the same function again | ||
if (this.typeCount < this.phraseLength) { | ||
this.typeLoop(this.stringLengths[this.stringCount]); | ||
// if there are no more characters to print and there is more than one string to be typed, delete the string just printed | ||
this.appendTheCharacter(); | ||
this.stringArrayCharacterIndex++; | ||
// there are still characters to be typed, so repeat function | ||
if (this.stringArrayCharacterIndex < this.phraseLength) { | ||
this.typeLoop(); | ||
// there are no more characters to print and there is more than one string to be typed, so delete the string just printed | ||
} else if(this.stringArray.length > 1) { | ||
// reset this.stringArrayCharacterIndex since we're done using it for this string | ||
this.stringArrayCharacterIndex = 0; | ||
// update the this.stringPlaceCount so that we're appending starting at the correct spot in the merged string | ||
this.stringPlaceCount = this.stringPlaceCount + this.phraseLength; | ||
// reset this.typeCount in case this function needs to be reused | ||
this.typeCount = 0; | ||
// if the stringCount is the same as the number of strings we started with, we're done, so call the callback function | ||
if(this.stringCount+1 === this.stringArray.length) { | ||
this.callback(); | ||
// if the this.stringArrayIndex is the same as the number of strings we started with, we're done, so call the callback function | ||
if(this.stringArrayIndex + 1 === this.stringArray.length) { | ||
// multiple strings ending | ||
this.endOfStringsFork(); | ||
// if we're not on the last string, then move on to to delete, unless the user wants to break lines | ||
} else if((this.stringCount+1 < this.stringArray.length) && this.settings.breakLines === false){ | ||
} else if((this.stringArrayIndex + 1 < this.stringArray.length) && this.settings.breakLines === false){ | ||
setTimeout(function(){ | ||
this.deleteLoop(); | ||
}.bind(this), this.settings.breakWait); | ||
}.bind(this), this.settings.breakDelay); | ||
// if breakLines is true and we still have strings left to type, break it and continue | ||
} else if (this.stringCount+1 < this.stringArray.length && this.settings.breakLines === true){ | ||
this.stringCount++; | ||
// if breakLines is true and we still have strings left to type, break it and continue with the next string | ||
} else if (this.stringArrayIndex + 1 < this.stringArray.length && this.settings.breakLines === true){ | ||
// before starting the next string, make sure the index has been bumped up | ||
this.stringArrayIndex++; | ||
@@ -200,3 +345,3 @@ setTimeout(function(){ | ||
// give 'active-container' class to next container, so the cursor can start blinking | ||
this.theElement.find('.ti-text-container:eq('+ this.stringCount +')').addClass('active-container'); | ||
this.theElement.find('.ti-text-container:eq('+ this.stringArrayIndex +')').addClass('active-container'); | ||
@@ -206,5 +351,5 @@ // after another slight delay, continue typing the next string | ||
this.typeLoop(); | ||
}.bind(this), this.settings.breakWait); | ||
}.bind(this), this.settings.breakDelay); | ||
}.bind(this), this.settings.breakWait); | ||
}.bind(this), this.settings.breakDelay); | ||
@@ -215,4 +360,6 @@ } | ||
} else { | ||
this.callback(); | ||
// single string ending | ||
this.endOfStringsFork(); | ||
} | ||
}.bind(this), this.delayTime); | ||
@@ -222,32 +369,135 @@ | ||
_proto.deleteLoop = function() { | ||
_proto.endOfStringsFork = function() { | ||
if(this.settings.loop === true){ | ||
// delete the remaining string | ||
setTimeout(function(){ | ||
this.deleteLoop(); | ||
}.bind(this), this.settings.loopDelay); | ||
} else { | ||
this.callback(); | ||
} | ||
}; | ||
_proto.appendTheCharacter = function() { | ||
// if breakLines is set to true, add the 'active-container' class to the next .ti-text-container in the list. | ||
if(this.settings.breakLines === true) { | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container:eq('+ this.stringArrayIndex +')'); | ||
this.thisTiTextContainer.addClass('active-container'); | ||
} else { | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container'); | ||
this.thisTiTextContainer.addClass('active-container'); | ||
} | ||
// append the character to the HTML tag if we're printing in a tag, or else just append the character | ||
this.appendToHTMLTag(function(){ | ||
this.thisTiTextContainer.append(this.characterToAppend); | ||
}.bind(this)); | ||
}; | ||
_proto.appendToHTMLTag = function(notInTagFunction) { | ||
if(this.printingInTag === true) { | ||
// resave the character to append | ||
this.characterToAppend = this.thisString[this.contentStartEnd[0] + this.contentStartEndIndex]; | ||
// append to the latest tag (the one we just printed) in the element | ||
$(this.thisTag, this.theElement).last().append(this.characterToAppend); | ||
// if we're at the end of the string segment, turn off printingInTag | ||
this.printingInTag = (this.contentStartEnd[1] === this.contentStartEnd[0] + this.contentStartEndIndex - 1) ? false : true; | ||
this.contentStartEndIndex++; | ||
} else { | ||
notInTagFunction(); | ||
} | ||
}; | ||
_proto.deleteLoop = function(undefined) { | ||
// set the current ti-text-container | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container'); | ||
this.deleteTimeout = setTimeout(function () { | ||
// get the string from the element and cut it by one character at the end | ||
shortenedText = this.theElement.find('.ti-text-container').text().substring(0, this.theElement.find('.ti-text-container').text().length - 1); | ||
// randomize the delete speed, if applicable | ||
this.randomizeTypeSpeed(); | ||
// then, put that shortened text into the element so it looks like it's being deleted | ||
this.theElement.find('.ti-text-container').text(shortenedText); | ||
// get the string | ||
this.stringToDelete = this.thisTiTextContainer.last().html(); | ||
this.deleteCount++; | ||
// if there are still characters in the string, run the function again | ||
if (this.deleteCount < this.phraseLength) { | ||
this.deleteLoop(); | ||
// convert to array | ||
this.arrayToDelete = this.stringToDelete.split(""); | ||
// loop over array | ||
for (var n = this.arrayToDelete.length-1; n > -1; n--) { | ||
// TAG HANDLING | ||
if(this.arrayToDelete[n] === '>') { | ||
// find the beginning tag piece | ||
for(var o = n-1; o > -1; o--) { | ||
// find the opening piece | ||
// o = position of opening piece | ||
if(this.arrayToDelete[o] === '<') { | ||
// if the next piece before it isn't an HTML tag, just delete the text in between | ||
if(this.arrayToDelete[o-1] !== '>') { | ||
// remove character right before HTML tag begins and escape the loop | ||
this.arrayToDelete.splice(o-1, 1); | ||
break; | ||
} | ||
} | ||
} | ||
break; | ||
} | ||
// REGULAR CHARACTER HANDLING | ||
else { | ||
// remove the character and escape the loop | ||
this.arrayToDelete.splice(n, 1); | ||
break; | ||
} | ||
} | ||
// repopulate the element with the shortened string so it looks like it's being deleted | ||
this.thisTiTextContainer.last().html(this.arrayToDelete.join('')); | ||
// if nothing left, clear out the emtpy HTML tags | ||
if(this.thisTiTextContainer.last().text().length === 0){ | ||
this.thisTiTextContainer.last().html(''); | ||
} | ||
// if characters are still in the string, run the function again | ||
if (this.thisTiTextContainer.last().text().length > 0) { | ||
this.deleteLoop(); | ||
// if there are still strings in the array, go back to typing. | ||
} else if(this.stringArray[this.stringCount+1] !== undefined){ | ||
this.deleteCount = 0; | ||
this.stringCount++; | ||
this.typeLoop(); | ||
} | ||
} else if(this.stringArray[this.stringArrayIndex+1] !== undefined){ | ||
this.stringArrayIndex++; | ||
this.typeLoop(); | ||
// that was the last string in the array, so now just check if loop is enabled | ||
} else if (this.settings.loop === true){ | ||
// if there are multiple strings that have been typed, remove the current one and repeat deleteLoop | ||
if(this.thisTiTextContainer.length > 1) { | ||
// remove the current container so we don't fill it with junk | ||
this.thisTiTextContainer.last().remove(); | ||
// make sure the NEW last container has 'active-container' status | ||
// need to use find() again instead of stored selection because that stored selection is now outdated since we just removed a container | ||
this.theElement.find('.ti-text-container').last().addClass('active-container'); | ||
this.deleteLoop(); | ||
} else { | ||
// otherwise, re-run the whole thing again | ||
this.init(); | ||
} | ||
} | ||
// make backspacing much quicker by dividing delayTime (arbitrarily) by three | ||
}.bind(this), this.delayTime/3); | ||
}; | ||
}.bind(this), this.delayTime/3); | ||
}; | ||
// stop the plugin from typing or deleting stuff whenever it's called | ||
_proto.stopTyping = function() { | ||
// stop the plugin from typing or deleting stuff whenever it's called | ||
_proto.stop = function() { | ||
clearTimeout(this.typeTimeout); | ||
clearTimeout(this.deleteTimeout); | ||
}; | ||
}; | ||
}(jQuery)); |
@@ -1,1 +0,492 @@ | ||
!function(t,e){t.fn.typeIt=function(e,i){return this.each(function(){t(this).data("typeit",new t.fn.typeIt.typeItClass(t(this),e,i))})},t.fn.typeIt.typeItClass=function(t,e,i){this.defaults={whatToType:"This is the default string. Please replace this string with your own.",typeSpeed:200,lifeLike:!1,showCursor:!0,breakLines:!0,breakWait:500,delayStart:250},this.dataAttDefaults={whatToType:t.data("typeitWhattotype"),typeSpeed:t.data("typeitSpeed"),lifeLike:t.data("typeitLifelike"),showCursor:t.data("typeitShowcursor"),breakLines:t.data("typeitBreaklines"),breakWait:t.data("typeitBreakWait"),delayStart:t.data("typeitDelayStart")},this.settings={},this.theElement=t,this.callback=i,this.typeCount=0,this.deleteCount=0,this.stringCount=0,this.stringPlaceCount=0,this.phraseLength=0,this.stringArray=[],this.stringLengths=[],this.deleteTimeout=null,this.typeTimeout=null,this.shortenedText=null,this.init(e)},_proto=t.fn.typeIt.typeItClass.prototype,_proto.init=function(e){return this.validateCallbackFunction()===!1?!1:(t.extend(this.settings,this.defaults,e,this.dataAttDefaults),this.processWhatToType(),this.setupDOMComponents(),void setTimeout(function(){this.typeLoop()}.bind(this),this.settings.delayStart))},_proto.setupDOMComponents=function(){for(j=0;j<this.stringArray.length;j++)this.stringLengths[j]=this.stringArray[j].length,this.theElement.append('<span class="ti-container"><span class="ti-text-container ti-cursor"></span></span>');this.theElement.find(".ti-container:first-child").find(".ti-text-container").addClass("active-container"),this.settings.breakLines===!1&&(this.theElement.find(".ti-container").remove(),this.theElement.append('<span class="ti-container"><span class="ti-text-container ti-cursor"></span></span>')),this.settings.showCursor===!1&&this.theElement.find(".ti-text-container").removeClass("ti-cursor")},_proto.processWhatToType=function(){this.stringArray=this.settings.whatToType,"[object Array]"!==Object.prototype.toString.call(this.stringArray)&&(this.stringArray='["'+this.stringArray+'"]',this.stringArray=JSON.parse(this.stringArray)),this.mergedStrings=this.stringArray.join("")},_proto.validateCallbackFunction=function(){"undefined"==typeof this.callback&&(this.callback=function(){return!0})},_proto.typeLoop=function(){this.phraseLength=this.stringLengths[this.stringCount],this.settings.lifeLike===!0?this.delayTime=this.settings.typeSpeed*Math.random():this.delayTime=this.settings.typeSpeed,this.typeTimeout=setTimeout(function(){var t=this.mergedStrings[this.typeCount+this.stringPlaceCount];this.settings.breakLines===!0?this.theElement.find(".ti-text-container:eq("+this.stringCount+")").addClass("active-container").append(t):this.theElement.find(".ti-text-container").addClass("active-container").append(t),this.typeCount++,this.typeCount<this.phraseLength?this.typeLoop(this.stringLengths[this.stringCount]):this.stringArray.length>1?(this.stringPlaceCount=this.stringPlaceCount+this.phraseLength,this.typeCount=0,this.stringCount+1===this.stringArray.length?this.callback():this.stringCount+1<this.stringArray.length&&this.settings.breakLines===!1?setTimeout(function(){this.deleteLoop()}.bind(this),this.settings.breakWait):this.stringCount+1<this.stringArray.length&&this.settings.breakLines===!0&&(this.stringCount++,setTimeout(function(){this.theElement.find(".ti-text-container").removeClass("active-container"),this.theElement.find(".ti-text-container:eq("+this.stringCount+")").addClass("active-container"),setTimeout(function(){this.typeLoop()}.bind(this),this.settings.breakWait)}.bind(this),this.settings.breakWait))):this.callback()}.bind(this),this.delayTime)},_proto.deleteLoop=function(){this.deleteTimeout=setTimeout(function(){shortenedText=this.theElement.find(".ti-text-container").text().substring(0,this.theElement.find(".ti-text-container").text().length-1),this.theElement.find(".ti-text-container").text(shortenedText),this.deleteCount++,this.deleteCount<this.phraseLength?this.deleteLoop():this.stringArray[this.stringCount+1]!==e&&(this.deleteCount=0,this.stringCount++,this.typeLoop())}.bind(this),this.delayTime/3)},_proto.stopTyping=function(){clearTimeout(this.typeTimeout),clearTimeout(this.deleteTimeout)}}(jQuery); | ||
/** | ||
* jQuery TypeIt | ||
* @author Alex MacArthur (http://macarthur.me) | ||
* @version 2.0.0 | ||
* @copyright 2015 Alex MacArthur | ||
* @description Types out a given string or strings. | ||
*/ | ||
(function($, undefined){ | ||
var proto; | ||
// the actual jQuery function | ||
$.fn.typeIt = function(options, callback){ | ||
// now call a callback function | ||
return this.each(function(){ | ||
$(this).data("typeit", new $.fn.typeIt.typeItClass($(this), options, callback)); | ||
}); | ||
}; | ||
// create the class | ||
$.fn.typeIt.typeItClass = function(theElement, options, callback){ | ||
/* VARIABLES THAT WON'T CHANGE BETWEEN RUNS */ | ||
// default settings | ||
this.defaults = { | ||
whatToType:'You probably want to use your own string.', | ||
typeSpeed: 100, | ||
lifeLike: true, | ||
showCursor: true, | ||
breakLines: true, | ||
breakDelay: 750, | ||
startDelay: 250, | ||
loop: false, | ||
loopDelay: 750 | ||
}; | ||
// data-typeit-* settings | ||
this.dataAttDefaults = { | ||
whatToType: theElement.data('typeitWhattotype'), | ||
typeSpeed: theElement.data('typeitTypespeed'), | ||
lifeLike: theElement.data('typeitLifelike'), | ||
showCursor: theElement.data('typeitShowcursor'), | ||
breakLines: theElement.data('typeitBreaklines'), | ||
breakDelay: theElement.data('typeitBreakdelay'), | ||
startDelay: theElement.data('typeitStartdelay'), | ||
loop: theElement.data('typeitLoop'), | ||
loopDelay: theElement.data('typeitLoopdelay') | ||
}; | ||
// the settings for the plugin instance | ||
this.settings = {}; | ||
// merge settings into this.settings object | ||
$.extend(this.settings, this.defaults, options, this.dataAttDefaults); | ||
// the element that holds the text | ||
this.theElement = theElement; | ||
// callback function that executes after strings have been printed | ||
this.callback = callback; | ||
// let 'r rip | ||
this.init(options); | ||
}; | ||
// create a new prototype | ||
_proto = $.fn.typeIt.typeItClass.prototype; | ||
_proto.init = function(options){ | ||
// the place we're at in the big merged string | ||
this.stringPlaceCount = 0; | ||
// the length of the current string being handled | ||
this.phraseLength = 0; | ||
// array that holds whatToType string(s) | ||
this.stringArray = []; | ||
// the index of the string we're handling | ||
this.stringArrayIndex = 0; | ||
// the index of the character we're currently printing | ||
this.stringArrayCharacterIndex = 0; | ||
// hold where we need to replace characters because of HTML tags | ||
this.contentStartEnd = []; | ||
// the index for the string within an HTML tag | ||
this.contentStartEndIndex = 0; | ||
// the span of characters for the string inside an HTML tag | ||
this.contentStartEndSpan = 0; | ||
// holds whether we're currently printing inside HTML tags | ||
this.printingInTag = false; | ||
// the specific character we're currently appending | ||
this.characterToAppend = null; | ||
// the current ti-text-container we're dealing | ||
this.thisTiTextContainer = null; | ||
// the current string we're handling | ||
this.thisString = null; | ||
// the particular HTML tag we're handling | ||
this.thisTag = null; | ||
// array holding the length of each string | ||
this.stringLengths = []; | ||
// the string we're currently deleting | ||
this.stringToDelete = null; | ||
// the timeout responsible for typing/adding characters | ||
this.typeTimeout = null; | ||
// the timeout responsible for deleting characters | ||
this.deleteTimeout = null; | ||
// the span of the range a type speed is allowed to be randomized | ||
this.typeSpeedRangeSpan = null; | ||
// the minimum of a randomized type speed | ||
this.typeSpeedMin = null; | ||
// the maximum of a randomized type speed | ||
this.typeSpeedMax = null; | ||
// make sure the callback function is all good | ||
if(this.validateCallbackFunction() === false){ return false; } | ||
// string override | ||
this.testForElementStringOverride(); | ||
// process the whatToType data to get it so we can use it | ||
this.processWhatToType(); | ||
// add all the elements & classes we'll be needing | ||
this.setupDOMComponents(); | ||
// start to type the string(s) after the specified delay | ||
setTimeout(function() { | ||
this.typeLoop(); | ||
}.bind(this), this.settings.startDelay); | ||
}; | ||
_proto.testForElementStringOverride = function() { | ||
// if there's a string already typed in the element, replace whatToType with it | ||
if(this.theElement.text().length > 0 && !this.theElement.has('.ti-container')) { | ||
this.settings.whatToType = this.theElement.html(); | ||
} | ||
}; | ||
_proto.setupDOMComponents = function() { | ||
// clear out the element in case we're looping | ||
this.theElement.html(''); | ||
// get the string lengths and save to array, set up ti-containers for each string | ||
for(j=0; j < this.stringArray.length; j++){ | ||
this.stringLengths[j] = this.stringArray[j].length; | ||
// set up the number of ti-containers we'll need to hold the strings | ||
this.theElement.append('<span class="ti-container"><span class="ti-text-container ti-cursor"></span></span>'); | ||
} | ||
// add .active-container to the first .ti-text-container so the cursor starts blinking before a string is printed | ||
this.theElement.find('.ti-container:first-child').find('.ti-text-container').addClass('active-container'); | ||
// if breakLines is false, then we for sure only need ONE ti-container even if there multiple strings, so make sure of that | ||
if(this.settings.breakLines === false) { | ||
this.theElement.find('.ti-container').remove(); | ||
this.theElement.append('<span class="ti-container"><span class="ti-text-container ti-cursor"></span></span>'); | ||
} | ||
// if showCursor is false, then remove the ti-cursor class | ||
if(this.settings.showCursor === false) { | ||
this.theElement.find('.ti-text-container').removeClass('ti-cursor'); | ||
} | ||
}; | ||
_proto.processWhatToType = function() { | ||
// check if the value is an array or just a string | ||
if(Object.prototype.toString.call(this.settings.whatToType) !== '[object Array]'){ | ||
// since it's not already an array, turn it into one, since later functionality depends on it being one | ||
this.stringArray = '["' + this.settings.whatToType + '"]'; | ||
this.stringArray = JSON.parse(this.stringArray); | ||
// if it is an array, clone it | ||
} else { | ||
// clone what to typed, so we don't modify the original strings in case we loop | ||
this.stringArrayTemp = $.extend( {}, this.settings.whatToType ); | ||
// convert cloned object to array | ||
this.stringArrayTemp = $.map(this.stringArrayTemp, function(value, index) { | ||
return [value]; | ||
}); | ||
// get the right values and put into stringArray so it's formatted correctly for processing | ||
for(var h = 0; h < this.stringArrayTemp.length; h++) { | ||
this.stringArray.push(this.stringArrayTemp[h]); | ||
} | ||
} | ||
// turn each string into sub arrays | ||
for(var i = 0; i < this.stringArray.length; i++) { | ||
this.contentStartEnd = []; | ||
this.contentStartEndIndex = 0; | ||
this.contentStartEndSpan = 0; | ||
// turn each string into sub array | ||
this.stringArray[i] = this.stringArray[i].split(''); | ||
// find the location of HTML tag | ||
for(var j = 0, subArray = this.stringArray[i]; j < subArray.length; j++) { | ||
if(subArray[j] === '<') { | ||
this.contentStartEnd[this.contentStartEndIndex] = []; | ||
this.contentStartEnd[this.contentStartEndIndex][0] = j; | ||
} | ||
if(subArray[j] === '>') { | ||
this.contentStartEnd[this.contentStartEndIndex][1] = j; | ||
this.contentStartEndIndex++; | ||
} | ||
} | ||
// merge individual tag characters into single array index | ||
for(var positionIndex = 0; positionIndex < this.contentStartEnd.length; positionIndex++) { | ||
// move those tag pieces into a single array item | ||
for (var l = this.contentStartEnd[positionIndex][0]; l < this.contentStartEnd[positionIndex][1]; l++) { | ||
this.stringArray[i][this.contentStartEnd[positionIndex][0]] = this.stringArray[i][this.contentStartEnd[positionIndex][0]] + this.stringArray[i][l+1]; | ||
} | ||
} | ||
// cut array items based on the start/end positions we know, but move back the start point each time by the number of items we previously removed | ||
for( var m = 0; m < this.contentStartEnd.length; m++ ) { | ||
var startPos = this.contentStartEnd[m][0]+1; | ||
this.stringArray[i].splice(startPos, this.contentStartEnd[m][1] - this.contentStartEnd[m][0]); | ||
var span = this.contentStartEnd[m][1] - this.contentStartEnd[m][0]; | ||
// go through and update the start and positions by the span length we just cut | ||
for(var n = 0; n < this.contentStartEnd.length; n++) { | ||
this.contentStartEnd[n][0] = this.contentStartEnd[n][0] - span; | ||
this.contentStartEnd[n][1] = this.contentStartEnd[n][1] - span; | ||
} | ||
} | ||
} | ||
}; | ||
_proto.validateCallbackFunction = function() { | ||
// if undefined, assign blank callback | ||
if(typeof this.callback === 'undefined') { | ||
this.callback = function(){return true;}; | ||
} | ||
}; | ||
_proto.randomizeTypeSpeed = function() { | ||
// make it human-like if specified in the settings | ||
if(this.settings.lifeLike === true){ | ||
// set to 50% of the actual type speed, so the randomization goes no further than that ratio | ||
this.typeSpeedRangeSpan = this.settings.typeSpeed/2; | ||
this.typeSpeedMin = this.settings.typeSpeed-this.typeSpeedRangeSpan; | ||
this.typeSpeedMax = this.settings.typeSpeed+this.typeSpeedRangeSpan; | ||
this.delayTime = Math.abs(Math.random() * (this.typeSpeedMax - this.typeSpeedMin) + this.typeSpeedMin); | ||
} else { | ||
this.delayTime = this.settings.typeSpeed; | ||
} | ||
}; | ||
_proto.typeLoop = function(){ | ||
// get this particular string we're printing | ||
this.thisString = this.stringArray[this.stringArrayIndex]; | ||
// set the length of the current phrase being typed | ||
this.phraseLength = this.thisString.length; | ||
// start the typing timeout | ||
this.typeTimeout = setTimeout(function () { | ||
this.randomizeTypeSpeed(); | ||
// the the specific character we're printing | ||
this.characterToAppend = this.stringArray[this.stringArrayIndex][this.stringArrayCharacterIndex]; | ||
// if it's an HTML tag, do stuff | ||
if(this.characterToAppend.indexOf('<') !== -1 && this.characterToAppend.indexOf('</') === -1){ | ||
this.contentStartEndIndex = 0; | ||
// get the start & end positions of the actual string within the HTML tags | ||
this.contentStartEnd[0] = this.stringArrayCharacterIndex + 1; | ||
for(var t = this.stringArrayCharacterIndex; t < this.thisString.length; t++){ | ||
if(this.thisString[t].indexOf('</') !== -1) { | ||
// set the ending of the string segment in an HTML tag | ||
this.contentStartEnd[1] = t - 1; | ||
// as soon as we hit a match for a closing character | ||
break; | ||
} | ||
} | ||
this.contentStartEndSpan = this.contentStartEnd[1] - this.contentStartEnd[0]; | ||
// create a DOM node from the string we get | ||
this.thisTag = $($.parseHTML(this.characterToAppend)); | ||
// set the current character to append to the tag we just created, so that we can create it in the DOM | ||
this.characterToAppend = this.thisTag; | ||
// append the tag | ||
this.appendTheCharacter(); | ||
// set this to true so we know we're currently printing inside an HTML tag | ||
this.printingInTag = true; | ||
} | ||
this.appendTheCharacter(); | ||
this.stringArrayCharacterIndex++; | ||
// there are still characters to be typed, so repeat function | ||
if (this.stringArrayCharacterIndex < this.phraseLength) { | ||
this.typeLoop(); | ||
// there are no more characters to print and there is more than one string to be typed, so delete the string just printed | ||
} else if(this.stringArray.length > 1) { | ||
// reset this.stringArrayCharacterIndex since we're done using it for this string | ||
this.stringArrayCharacterIndex = 0; | ||
// update the this.stringPlaceCount so that we're appending starting at the correct spot in the merged string | ||
this.stringPlaceCount = this.stringPlaceCount + this.phraseLength; | ||
// if the this.stringArrayIndex is the same as the number of strings we started with, we're done, so call the callback function | ||
if(this.stringArrayIndex + 1 === this.stringArray.length) { | ||
// multiple strings ending | ||
this.endOfStringsFork(); | ||
// if we're not on the last string, then move on to to delete, unless the user wants to break lines | ||
} else if((this.stringArrayIndex + 1 < this.stringArray.length) && this.settings.breakLines === false){ | ||
setTimeout(function(){ | ||
this.deleteLoop(); | ||
}.bind(this), this.settings.breakDelay); | ||
// if breakLines is true and we still have strings left to type, break it and continue with the next string | ||
} else if (this.stringArrayIndex + 1 < this.stringArray.length && this.settings.breakLines === true){ | ||
// before starting the next string, make sure the index has been bumped up | ||
this.stringArrayIndex++; | ||
setTimeout(function(){ | ||
// remove any 'active-container' classes fromt the elements | ||
this.theElement.find('.ti-text-container').removeClass('active-container'); | ||
// give 'active-container' class to next container, so the cursor can start blinking | ||
this.theElement.find('.ti-text-container:eq('+ this.stringArrayIndex +')').addClass('active-container'); | ||
// after another slight delay, continue typing the next string | ||
setTimeout(function(){ | ||
this.typeLoop(); | ||
}.bind(this), this.settings.breakDelay); | ||
}.bind(this), this.settings.breakDelay); | ||
} | ||
// since there are no more strings to be typed, we're done and can call the callback function | ||
} else { | ||
// single string ending | ||
this.endOfStringsFork(); | ||
} | ||
}.bind(this), this.delayTime); | ||
}; | ||
_proto.endOfStringsFork = function() { | ||
if(this.settings.loop === true){ | ||
// delete the remaining string | ||
setTimeout(function(){ | ||
this.deleteLoop(); | ||
}.bind(this), this.settings.loopDelay); | ||
} else { | ||
this.callback(); | ||
} | ||
}; | ||
_proto.appendTheCharacter = function() { | ||
// if breakLines is set to true, add the 'active-container' class to the next .ti-text-container in the list. | ||
if(this.settings.breakLines === true) { | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container:eq('+ this.stringArrayIndex +')'); | ||
this.thisTiTextContainer.addClass('active-container'); | ||
} else { | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container'); | ||
this.thisTiTextContainer.addClass('active-container'); | ||
} | ||
// append the character to the HTML tag if we're printing in a tag, or else just append the character | ||
this.appendToHTMLTag(function(){ | ||
this.thisTiTextContainer.append(this.characterToAppend); | ||
}.bind(this)); | ||
}; | ||
_proto.appendToHTMLTag = function(notInTagFunction) { | ||
if(this.printingInTag === true) { | ||
// resave the character to append | ||
this.characterToAppend = this.thisString[this.contentStartEnd[0] + this.contentStartEndIndex]; | ||
// append to the latest tag (the one we just printed) in the element | ||
$(this.thisTag, this.theElement).last().append(this.characterToAppend); | ||
// if we're at the end of the string segment, turn off printingInTag | ||
this.printingInTag = (this.contentStartEnd[1] === this.contentStartEnd[0] + this.contentStartEndIndex - 1) ? false : true; | ||
this.contentStartEndIndex++; | ||
} else { | ||
notInTagFunction(); | ||
} | ||
}; | ||
_proto.deleteLoop = function(undefined) { | ||
// set the current ti-text-container | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container'); | ||
this.deleteTimeout = setTimeout(function () { | ||
// randomize the delete speed, if applicable | ||
this.randomizeTypeSpeed(); | ||
// get the string | ||
this.stringToDelete = this.thisTiTextContainer.last().html(); | ||
// convert to array | ||
this.arrayToDelete = this.stringToDelete.split(""); | ||
// loop over array | ||
for (var n = this.arrayToDelete.length-1; n > -1; n--) { | ||
// TAG HANDLING | ||
if(this.arrayToDelete[n] === '>') { | ||
// find the beginning tag piece | ||
for(var o = n-1; o > -1; o--) { | ||
// find the opening piece | ||
// o = position of opening piece | ||
if(this.arrayToDelete[o] === '<') { | ||
// if the next piece before it isn't an HTML tag, just delete the text in between | ||
if(this.arrayToDelete[o-1] !== '>') { | ||
// remove character right before HTML tag begins and escape the loop | ||
this.arrayToDelete.splice(o-1, 1); | ||
break; | ||
} | ||
} | ||
} | ||
break; | ||
} | ||
// REGULAR CHARACTER HANDLING | ||
else { | ||
// remove the character and escape the loop | ||
this.arrayToDelete.splice(n, 1); | ||
break; | ||
} | ||
} | ||
// repopulate the element with the shortened string so it looks like it's being deleted | ||
this.thisTiTextContainer.last().html(this.arrayToDelete.join('')); | ||
// if nothing left, clear out the emtpy HTML tags | ||
if(this.thisTiTextContainer.last().text().length === 0){ | ||
this.thisTiTextContainer.last().html(''); | ||
} | ||
// if characters are still in the string, run the function again | ||
if (this.thisTiTextContainer.last().text().length > 0) { | ||
this.deleteLoop(); | ||
// if there are still strings in the array, go back to typing. | ||
} else if(this.stringArray[this.stringArrayIndex+1] !== undefined){ | ||
this.stringArrayIndex++; | ||
this.typeLoop(); | ||
// that was the last string in the array, so now just check if loop is enabled | ||
} else if (this.settings.loop === true){ | ||
// if there are multiple strings that have been typed, remove the current one and repeat deleteLoop | ||
if(this.thisTiTextContainer.length > 1) { | ||
// remove the current container so we don't fill it with junk | ||
this.thisTiTextContainer.last().remove(); | ||
// make sure the NEW last container has 'active-container' status | ||
// need to use find() again instead of stored selection because that stored selection is now outdated since we just removed a container | ||
this.theElement.find('.ti-text-container').last().addClass('active-container'); | ||
this.deleteLoop(); | ||
} else { | ||
// otherwise, re-run the whole thing again | ||
this.init(); | ||
} | ||
} | ||
// make backspacing much quicker by dividing delayTime (arbitrarily) by three | ||
}.bind(this), this.delayTime/3); | ||
}; | ||
// stop the plugin from typing or deleting stuff whenever it's called | ||
_proto.stop = function() { | ||
clearTimeout(this.typeTimeout); | ||
clearTimeout(this.deleteTimeout); | ||
}; | ||
}(jQuery)); |
@@ -19,3 +19,3 @@ // load our plugins | ||
gulp.src('src/typeit.js') | ||
.pipe(uglify()) | ||
//.pipe(uglify()) | ||
.pipe(rename('typeit.min.js')) | ||
@@ -26,3 +26,3 @@ .pipe(gulp.dest('dist')); | ||
gulp.src('src/scripts.js') | ||
.pipe(uglify()) | ||
//.pipe(uglify()) | ||
.pipe(rename('scripts.min.js')) | ||
@@ -29,0 +29,0 @@ .pipe(gulp.dest('src')); |
{ | ||
"name": "typeit", | ||
"version": "1.1.1", | ||
"version": "2.0.0", | ||
"license": "GPL-2.0", | ||
@@ -5,0 +5,0 @@ "author": "Alex MacArthur <alex@macarthur.me>", |
103
README.md
# TypeIt: A jQuery Animated Typing Plugin | ||
## Description | ||
A jQuery plugin that outputs text like it's being typed. It allows you to type single strings, multiple strings that stack, and multiple strings that delete & replace each other. It's lightweight, scalable, responsive, and super easy to implement. | ||
A jQuery plugin that outputs text like it's being typed. It allows you to type single strings, multiple strings that stack, multiple strings that delete & replace each other, and even text wrapped in HTML tags (including custom classes, ID's, etc.). You can also loop strings or sets of strings continuously. | ||
## Some of the Perks | ||
* Responsive | ||
* Multiple easy ways to set up/initialize | ||
* Handles HTML tags (including your custom classes, ID's, etc.) with ease. **Note: only supports HTML tags that aren't nested in other tags in the string.** | ||
## Demo | ||
Checkout several demos and a sandbox where you can try it out at <a href="http://alexmacarthur.github.io/typeit">alexmacarthur.github.io/typeit</a>. | ||
Checkout several demos and a sandbox where you can try it out at <a href="http://macarthur.me/typeit">macarthur.me/typeit</a>. | ||
## Setup | ||
## Getting Started | ||
@@ -15,5 +20,5 @@ ### Download the Plugin | ||
### Initializing on Your Site | ||
### Prepare to Initialize on Your Site | ||
1. Create an empty HTML element to select. | ||
1. Create an empty HTML element to select. (If you want to have a fallback for users without JavaScript, you can put a string right into the element you create. More on that later.) | ||
@@ -31,3 +36,3 @@ ```<span class="type-it"></span>``` | ||
You're ready to initialize it! | ||
You're ready to start typing! | ||
@@ -40,6 +45,31 @@ ## Usage | ||
#### About Using Settings Object | ||
* When using a single string, just wrap it in quotation marks. | ||
* When using multiple strings, place them in an array. Ex: `whatToType: ['String #1','String #2']` | ||
Example: | ||
`` | ||
<span class="type-it"></span> | ||
`` | ||
``` | ||
$('.type-it').typeIt({ | ||
whatToType: 'Enter your string here!', | ||
typeSpeed: 300, | ||
lifeLike: false, | ||
showCursor: true | ||
}); | ||
``` | ||
#### About Using Data Attributes | ||
* Make sure the names are all lowercase. | ||
* When using multiple strings, wrap your array of strings inside quotation marks. Ex: `data-typeit-whattotype='["string #1", "string #2"]'` | ||
Example: | ||
``` | ||
<span class="type-it" | ||
data-typeit-whattotype="A new string to type." | ||
data-typeit-speed="100" | ||
data-typeit-typespeed="100" | ||
data-typeit-lifelike="true" | ||
@@ -55,28 +85,19 @@ data-typeit-showcursor="true"> | ||
or... | ||
You can also define what to type a third way -- by simply filling the element with a string of text. This is convenient because if a user doesn't have JavaScript enabled, they'll still be able to read the text. **Note: by default, the plugin will use the string that's in the element. If strings are defined either in the function call or data attributes, they will be overridden.** | ||
`` | ||
<span class="type-it"></span> | ||
`` | ||
``` | ||
$('.type-it').typeIt({ | ||
whatToType:'Enter your string here!', | ||
typeSpeed: 300, | ||
lifeLike: false, | ||
showCursor: true | ||
}); | ||
``` | ||
<span class="type-it">This is the string that will be typed.</span> | ||
``` | ||
### Typing Multiple Strings | ||
Aside from simply typing a single string, you can configure TypeIt to type multiple strings. By default, they stack on top of each other. To use this feature, just enter an array of several strings. | ||
Aside from simply typing a single string, you can configure TypeIt to type multiple strings. **Note: while you can define a single string by just putting it in quotation marks, multiple strings must be defined inside an array, like shown below.** By default, they stack on top of each other. To use this feature, just enter an array of several strings. | ||
``` | ||
$('.type-it').typeIt({ | ||
whatToType:['Enter your string here!', 'Another string!'] | ||
whatToType: ['Enter your string here!', 'Another string!'] | ||
}); | ||
``` | ||
Or, you can have type strings that delete & replace each other. Do this, set the 'breakLines' setting to `false`. | ||
Or, you can have type strings that delete & replace each other. To do this, set the 'breakLines' setting to `false`. | ||
@@ -89,6 +110,22 @@ ``` | ||
``` | ||
### Handling HTML Tags | ||
TypeIt will handle HTML tags in your strings, as long as they're only one level deep: | ||
``` | ||
// GOOD! :) | ||
$('.typeit-box').typeIt({ | ||
whatToType: '<h1 class="your-class">This is a string!</h1>', | ||
} | ||
``` | ||
``` | ||
// BAD! :( | ||
$('.typeit-box').typeIt({ | ||
whatToType: '<h1 class="your-class"><span>This is a string!</span></h1>', | ||
} | ||
``` | ||
### Using a Callback Function | ||
TypeIt allows you to use a custom callback function when you've completed typing. To use one, simply add it as the second argument when it's initialized. | ||
TypeIt allows you to use a custom callback function when you've completed typing. To use one, simply add it as the second argument when it's initialized. **Note: if you've enabled `loop`, this is useless.** | ||
@@ -101,3 +138,2 @@ ``` | ||
}); | ||
</script> | ||
``` | ||
@@ -111,13 +147,15 @@ | ||
| ------------- | ------------- | ------------- | | ||
| whatToType | The string to be typed. | 'This is the default string. Please replace this string with your own.' | | ||
| typeSpeed | The typing speed. | 200 | | ||
| whatToType | The string to be typed. | 'This is the default string. Replace it with your own.' | | ||
| typeSpeed | The typing speed. | 100 | | ||
| lifeLike | Will make the typing pace irregular, as if a real person is doing it. | true | | ||
| showCursor | Show a blinking cursor at the end of the string. | true | | ||
| breakLines | Choose whether you want multiple strings to be printed on top of each other (breakLines = true), or if you want each string to be deleted and replaced by the next one (breakLines = false). | true | | ||
| breakWait | The amount of time between typing multiple strings. | 500 | | ||
| delayStart | The amount of time before the plugin begins typing after initalizing. | 250 | | ||
| breakDelay | The amount of time between typing multiple strings. | 750 | | ||
| startDelay | The amount of time before the plugin begins typing after initalizing. | 250 | | ||
| loop | Have your string or strings continuously loop after completing. | false | | ||
| loopDelay | The amount of time between looping over a string or set of strings again. | 750 | | ||
## Ideas for Improvement? | ||
If you choose to develop it locally, Gulp is configured to check & minify JavaScript and compile & compress SASS. In the root of the repo, use these commands to run these default tasks and watch for file changes (make sure Node.js, npm, and Gulp are installed on your computer): | ||
Let me know! Otherwise, if you choose to develop it locally, Gulp is configured to check & minify JavaScript and compile & compress SASS. In the root of the repo, use these commands to run these default tasks and watch for file changes (make sure Node.js, npm, and Gulp are installed on your computer): | ||
@@ -128,1 +166,8 @@ ``` | ||
``` | ||
## Donate | ||
If I've made your life eaiser in some way by creating this thing and want to kick a small "thank you" my way, I'd very much appreciate it! | ||
PayPal: <a href="http://paypal.me/alexmacarthur">paypal.me/alexmacarthur</a> | ||
Venmo: <a href="https://venmo.com/amacarthur">venmo.com/amacarthur</a> |
@@ -1,56 +0,59 @@ | ||
$('.typeit-box').typeIt({ | ||
whatToType: ['A jQuery plugin that types stuff for you.'], | ||
typeSpeed: 100 | ||
$('#typeit-box').typeIt({ | ||
whatToType: ['A jQuery plugin that <span class="emphasized">types</span> stuff for you.', '<span class="emphasized emphasized-duh">(Duh.)</span>'], | ||
typeSpeed: 100, | ||
breakLines: true, | ||
breakDelay: 1000 | ||
}); | ||
$('.example1').typeIt({ | ||
whatToType: "You've just initialized this bad boy.", | ||
typeSpeed: 100 | ||
}); | ||
var $example1 = $('#example1'); | ||
var $example2 = $('#example2'); | ||
var $example3 = $('#example3'); | ||
var $example4 = $('#example4'); | ||
var $example5 = $('#example5'); | ||
var $example6 = $('#example6'); | ||
$('section').on('click','.btn-example1',function() { | ||
$('.example1').data().typeit.stopTyping(); | ||
$('.example1').html(''); | ||
$('.example1').typeIt({ | ||
whatToType: "You've just initialized this bad boy.", | ||
function example4() { | ||
$example4.typeIt({ | ||
whatToType: ["This is a string!", "And here's another one."], | ||
typeSpeed: 100 | ||
}); | ||
}); | ||
} | ||
$('.example2').typeIt(); | ||
example4(); | ||
$('section').on('click','.btn-example2',function() { | ||
$('.example2').data().typeit.stopTyping(); | ||
$('.example2').html(''); | ||
$('.example2').typeIt(); | ||
$('section').on('click','#btn-example4',function() { | ||
$example4.data('typeit').stop(); | ||
$example4.html(''); | ||
example4(); | ||
}); | ||
$('.example3').typeIt({ | ||
whatToType: ["This is a string!", "And here's another one."], | ||
typeSpeed: 100 | ||
function example5() { | ||
$example5.typeIt({ | ||
whatToType: ["This is a great string.","But here is a better one."], | ||
typeSpeed: 100, | ||
breakLines: false | ||
}); | ||
} | ||
example5(); | ||
$('section').on('click','#btn-example5',function() { | ||
$example5.data('typeit').stop(); | ||
$example5.html(''); | ||
example5(); | ||
}); | ||
$('section').on('click','.btn-example3',function() { | ||
$('.example3').data().typeit.stopTyping(); | ||
$('.example3').html(''); | ||
$('.example3').typeIt({ | ||
whatToType: ["This is a string!", "And here's another one."], | ||
function example6() { | ||
$example6.typeIt({ | ||
whatToType: ["Here's text <span class='just-a-class'>wrapped in HTML</span>."], | ||
typeSpeed: 100 | ||
}); | ||
}); | ||
} | ||
$('.example4').typeIt({ | ||
whatToType: ["This is a great string.", "But here is a better one."], | ||
typeSpeed: 100, | ||
breakLines: false | ||
}); | ||
example6(); | ||
$('section').on('click','.btn-example4',function() { | ||
$('.example4').data().typeit.stopTyping(); | ||
$('.example4').html(''); | ||
$('.example4').typeIt({ | ||
whatToType: ["This is a great string.", "But here is a better one."], | ||
typeSpeed: 100, | ||
breakLines: false | ||
}); | ||
$('section').on('click','#btn-example6', function() { | ||
$example6.data('typeit').stop(); | ||
$example6.html(''); | ||
example6(); | ||
}); | ||
@@ -61,4 +64,4 @@ | ||
$('#iTypeSpeed').val('250'); | ||
$('#iBreakWait').val('500'); | ||
$('#iDelayStart').val('250'); | ||
$('#ibreakDelay').val('500'); | ||
$('#istartDelay').val('250'); | ||
@@ -71,3 +74,3 @@ $('#TIInput').on('click','#TISubmit', function(e){ | ||
if($.hasData($(this))) { | ||
$(this).data().typeit.stopTyping(); | ||
$(this).data('typeit').stop(); | ||
} | ||
@@ -111,8 +114,8 @@ $('#TIOutput').html(''); | ||
} | ||
var breakWait = $('#iBreakWait').val(); | ||
var breakDelay = $('#ibreakDelay').val(); | ||
var breakStart = $('#iBreakStart').val(); | ||
var delayStart = $('#iDelayStart').val(); | ||
var startDelay = $('#istartDelay').val(); | ||
// hide the temp text | ||
$('.temp-text').animate({ | ||
$('#tempText').animate({ | ||
opacity: 0 | ||
@@ -122,3 +125,3 @@ }); | ||
// expand the container | ||
$('.ti-output-box').animate({ | ||
$('#TIOutputBox').animate({ | ||
height: newHeight | ||
@@ -128,3 +131,3 @@ }, function() { | ||
$('html, body').animate({ | ||
scrollTop: $(".ti-output-box").offset().top - 200 | ||
scrollTop: $("#TIOutputBox").offset().top - 200 | ||
}, 800); | ||
@@ -139,5 +142,4 @@ | ||
breakLines: breakLines, | ||
breakWait: breakWait, | ||
breakStart: breakStart, | ||
delayStart: delayStart | ||
breakDelay: breakDelay, | ||
startDelay: startDelay | ||
}); | ||
@@ -144,0 +146,0 @@ }, 800); |
@@ -1,1 +0,161 @@ | ||
$(".typeit-box").typeIt({whatToType:["A jQuery plugin that types stuff for you."],typeSpeed:100}),$(".example1").typeIt({whatToType:"You've just initialized this bad boy.",typeSpeed:100}),$("section").on("click",".btn-example1",function(){$(".example1").data().typeit.stopTyping(),$(".example1").html(""),$(".example1").typeIt({whatToType:"You've just initialized this bad boy.",typeSpeed:100})}),$(".example2").typeIt(),$("section").on("click",".btn-example2",function(){$(".example2").data().typeit.stopTyping(),$(".example2").html(""),$(".example2").typeIt()}),$(".example3").typeIt({whatToType:["This is a string!","And here's another one."],typeSpeed:100}),$("section").on("click",".btn-example3",function(){$(".example3").data().typeit.stopTyping(),$(".example3").html(""),$(".example3").typeIt({whatToType:["This is a string!","And here's another one."],typeSpeed:100})}),$(".example4").typeIt({whatToType:["This is a great string.","But here is a better one."],typeSpeed:100,breakLines:!1}),$("section").on("click",".btn-example4",function(){$(".example4").data().typeit.stopTyping(),$(".example4").html(""),$(".example4").typeIt({whatToType:["This is a great string.","But here is a better one."],typeSpeed:100,breakLines:!1})}),function(){$("#iTypeSpeed").val("250"),$("#iBreakWait").val("500"),$("#iDelayStart").val("250"),$("#TIInput").on("click","#TISubmit",function(e){e.preventDefault(),$.hasData($(this))&&$(this).data().typeit.stopTyping(),$("#TIOutput").html("");var t,a=[];if(""===$("#stringTI").val())a="You didn't enter a string!";else{t=$("#stringTI").val().split("\n");for(var i=0;i<t.length;i++)void 0!==t[i]&&null!==t[i]&&""!==t[i]&&a.push(t[i])}var p=$("#stringTI").val()?38*a.length+40:75,n=$("#iTypeSpeed").val(),o=$("#iLifeLike").val();o="true"===o?!0:!1;var l=$("#iShowCursor").val();l="true"===l?!0:!1;var s=$("#iBreakLines").val();s="true"===s?!0:!1;var r=$("#iBreakWait").val(),h=$("#iBreakStart").val(),y=$("#iDelayStart").val();$(".temp-text").animate({opacity:0}),$(".ti-output-box").animate({height:p},function(){$("html, body").animate({scrollTop:$(".ti-output-box").offset().top-200},800),setTimeout(function(){$("#TIOutput").typeIt({whatToType:a,typeSpeed:n,lifeLike:o,showCursor:l,breakLines:s,breakWait:r,breakStart:h,delayStart:y})},800)})})}(),$(function(){$("a[href*=#]:not([href=#])").click(function(){if(location.pathname.replace(/^\//,"")==this.pathname.replace(/^\//,"")&&location.hostname==this.hostname){var e=$(this.hash);if(e=e.length?e:$("[name="+this.hash.slice(1)+"]"),e.length)return $("html,body").animate({scrollTop:e.offset().top},1e3),!1}})}); | ||
$('#typeit-box').typeIt({ | ||
whatToType: ['A jQuery plugin that <span class="emphasized">types</span> stuff for you.', '<span class="emphasized emphasized-duh">(Duh.)</span>'], | ||
typeSpeed: 100, | ||
breakLines: true, | ||
breakDelay: 1000 | ||
}); | ||
var $example1 = $('#example1'); | ||
var $example2 = $('#example2'); | ||
var $example3 = $('#example3'); | ||
var $example4 = $('#example4'); | ||
var $example5 = $('#example5'); | ||
var $example6 = $('#example6'); | ||
function example4() { | ||
$example4.typeIt({ | ||
whatToType: ["This is a string!", "And here's another one."], | ||
typeSpeed: 100 | ||
}); | ||
} | ||
example4(); | ||
$('section').on('click','#btn-example4',function() { | ||
$example4.data('typeit').stop(); | ||
$example4.html(''); | ||
example4(); | ||
}); | ||
function example5() { | ||
$example5.typeIt({ | ||
whatToType: ["This is a great string.","But here is a better one."], | ||
typeSpeed: 100, | ||
breakLines: false | ||
}); | ||
} | ||
example5(); | ||
$('section').on('click','#btn-example5',function() { | ||
$example5.data('typeit').stop(); | ||
$example5.html(''); | ||
example5(); | ||
}); | ||
function example6() { | ||
$example6.typeIt({ | ||
whatToType: ["Here's text <span class='just-a-class'>wrapped in HTML</span>."], | ||
typeSpeed: 100 | ||
}); | ||
} | ||
example6(); | ||
$('section').on('click','#btn-example6', function() { | ||
$example6.data('typeit').stop(); | ||
$example6.html(''); | ||
example6(); | ||
}); | ||
(function() { | ||
$('#iTypeSpeed').val('250'); | ||
$('#ibreakDelay').val('500'); | ||
$('#istartDelay').val('250'); | ||
$('#TIInput').on('click','#TISubmit', function(e){ | ||
e.preventDefault(); | ||
// if there's another process going on, stop it and wipe the output box | ||
if($.hasData($(this))) { | ||
$(this).data('typeit').stop(); | ||
} | ||
$('#TIOutput').html(''); | ||
// get variables figured out | ||
var whatToType; | ||
var cleanedWhatToType = []; | ||
if($('#stringTI').val() === '') { | ||
cleanedWhatToType = 'You didn\'t enter a string!'; | ||
} else { | ||
whatToType = $('#stringTI').val().split('\n'); | ||
// remove empty array item | ||
for (var i = 0; i < whatToType.length; i++) { | ||
if (whatToType[i] !== undefined && whatToType[i] !== null && whatToType[i] !== "") { | ||
cleanedWhatToType.push(whatToType[i]); | ||
} | ||
} | ||
} | ||
var newHeight = ($('#stringTI').val()) ? (cleanedWhatToType.length * 38) + 40 : 75; | ||
var typeSpeed = $('#iTypeSpeed').val(); | ||
var lifeLike = $('#iLifeLike').val(); | ||
if(lifeLike === 'true'){ | ||
lifeLike = true; | ||
} else { | ||
lifeLike = false; | ||
} | ||
var showCursor = $('#iShowCursor').val(); | ||
if(showCursor === 'true'){ | ||
showCursor = true; | ||
} else { | ||
showCursor = false; | ||
} | ||
var breakLines = $('#iBreakLines').val(); | ||
if(breakLines === 'true'){ | ||
breakLines = true; | ||
} else { | ||
breakLines = false; | ||
} | ||
var breakDelay = $('#ibreakDelay').val(); | ||
var breakStart = $('#iBreakStart').val(); | ||
var startDelay = $('#istartDelay').val(); | ||
// hide the temp text | ||
$('#tempText').animate({ | ||
opacity: 0 | ||
}); | ||
// expand the container | ||
$('#TIOutputBox').animate({ | ||
height: newHeight | ||
}, function() { | ||
$('html, body').animate({ | ||
scrollTop: $("#TIOutputBox").offset().top - 200 | ||
}, 800); | ||
setTimeout(function() { | ||
$('#TIOutput').typeIt({ | ||
whatToType: cleanedWhatToType, | ||
typeSpeed: typeSpeed, | ||
lifeLike: lifeLike, | ||
showCursor: showCursor, | ||
breakLines: breakLines, | ||
breakDelay: breakDelay, | ||
startDelay: startDelay | ||
}); | ||
}, 800); | ||
}); | ||
}); | ||
})(); | ||
$(function() { | ||
$('a[href*=#]:not([href=#])').click(function() { | ||
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) { | ||
var target = $(this.hash); | ||
target = target.length ? target : $('[name=' + this.hash.slice(1) +']'); | ||
if (target.length) { | ||
$('html,body').animate({ | ||
scrollTop: target.offset().top | ||
}, 1000); | ||
return false; | ||
} | ||
} | ||
}); | ||
}); |
/** | ||
* jQuery TypeIt | ||
* @author Alex MacArthur (http://macarthur.me) | ||
* @version 1.1.1 | ||
* @version 2.0.0 | ||
* @copyright 2015 Alex MacArthur | ||
@@ -23,21 +23,29 @@ * @description Types out a given string or strings. | ||
$.fn.typeIt.typeItClass = function(theElement, options, callback){ | ||
// plugin default settings | ||
/* VARIABLES THAT WON'T CHANGE BETWEEN RUNS */ | ||
// default settings | ||
this.defaults = { | ||
whatToType:'This is the default string. Please replace this string with your own.', | ||
typeSpeed: 200, | ||
lifeLike: false, | ||
showCursor: true, | ||
breakLines: true, | ||
breakWait: 500, | ||
delayStart: 250 | ||
whatToType:'You probably want to use your own string.', | ||
typeSpeed: 100, | ||
lifeLike: true, | ||
showCursor: true, | ||
breakLines: true, | ||
breakDelay: 750, | ||
startDelay: 250, | ||
loop: false, | ||
loopDelay: 750 | ||
}; | ||
// data-typeit-* settings | ||
this.dataAttDefaults = { | ||
whatToType : theElement.data('typeitWhattotype'), | ||
typeSpeed: theElement.data('typeitSpeed'), | ||
whatToType: theElement.data('typeitWhattotype'), | ||
typeSpeed: theElement.data('typeitTypespeed'), | ||
lifeLike: theElement.data('typeitLifelike'), | ||
showCursor: theElement.data('typeitShowcursor'), | ||
breakLines: theElement.data('typeitBreaklines'), | ||
breakWait: theElement.data('typeitBreakWait'), | ||
delayStart : theElement.data('typeitDelayStart') | ||
breakDelay: theElement.data('typeitBreakdelay'), | ||
startDelay: theElement.data('typeitStartdelay'), | ||
loop: theElement.data('typeitLoop'), | ||
loopDelay: theElement.data('typeitLoopdelay') | ||
}; | ||
@@ -47,2 +55,4 @@ | ||
this.settings = {}; | ||
// merge settings into this.settings object | ||
$.extend(this.settings, this.defaults, options, this.dataAttDefaults); | ||
// the element that holds the text | ||
@@ -52,8 +62,11 @@ this.theElement = theElement; | ||
this.callback = callback; | ||
// the number of types a character has been typed for each pass over a string | ||
this.typeCount = 0; | ||
// the character number of a string that's currently being deleted | ||
this.deleteCount = 0; | ||
// the string number that's currently being typed or deleted | ||
this.stringCount = 0; | ||
// let 'r rip | ||
this.init(options); | ||
}; | ||
// create a new prototype | ||
_proto = $.fn.typeIt.typeItClass.prototype; | ||
_proto.init = function(options){ | ||
// the place we're at in the big merged string | ||
@@ -65,23 +78,42 @@ this.stringPlaceCount = 0; | ||
this.stringArray = []; | ||
// the index of the string we're handling | ||
this.stringArrayIndex = 0; | ||
// the index of the character we're currently printing | ||
this.stringArrayCharacterIndex = 0; | ||
// hold where we need to replace characters because of HTML tags | ||
this.contentStartEnd = []; | ||
// the index for the string within an HTML tag | ||
this.contentStartEndIndex = 0; | ||
// the span of characters for the string inside an HTML tag | ||
this.contentStartEndSpan = 0; | ||
// holds whether we're currently printing inside HTML tags | ||
this.printingInTag = false; | ||
// the specific character we're currently appending | ||
this.characterToAppend = null; | ||
// the current ti-text-container we're dealing | ||
this.thisTiTextContainer = null; | ||
// the current string we're handling | ||
this.thisString = null; | ||
// the particular HTML tag we're handling | ||
this.thisTag = null; | ||
// array holding the length of each string | ||
this.stringLengths = []; | ||
// the string we're currently deleting | ||
this.stringToDelete = null; | ||
// the timeout responsible for typing/adding characters | ||
this.typeTimeout = null; | ||
// the timeout responsible for deleting characters | ||
this.deleteTimeout = null; | ||
// the timeout responsible for typing/adding characters | ||
this.typeTimeout = null; | ||
// the progressively shorter string as it's being deleted | ||
this.shortenedText = null; | ||
// let 'r rip | ||
this.init(options); | ||
}; | ||
// the span of the range a type speed is allowed to be randomized | ||
this.typeSpeedRangeSpan = null; | ||
// the minimum of a randomized type speed | ||
this.typeSpeedMin = null; | ||
// the maximum of a randomized type speed | ||
this.typeSpeedMax = null; | ||
// create a new prototype | ||
_proto = $.fn.typeIt.typeItClass.prototype; | ||
_proto.init = function(options){ | ||
// make sure the callback function is all good | ||
if(this.validateCallbackFunction() === false){ return false; } | ||
// merge settings into this.settings object | ||
$.extend(this.settings, this.defaults, options, this.dataAttDefaults); | ||
// string override | ||
this.testForElementStringOverride(); | ||
// process the whatToType data to get it so we can use it | ||
@@ -94,7 +126,20 @@ this.processWhatToType(); | ||
this.typeLoop(); | ||
}.bind(this), this.settings.delayStart); | ||
}.bind(this), this.settings.startDelay); | ||
}; | ||
_proto.testForElementStringOverride = function() { | ||
// if there's a string already typed in the element, replace whatToType with it | ||
if(this.theElement.text().length > 0 && !this.theElement.has('.ti-container')) { | ||
this.settings.whatToType = this.theElement.html(); | ||
} | ||
}; | ||
_proto.setupDOMComponents = function() { | ||
// clear out the element in case we're looping | ||
this.theElement.html(''); | ||
// get the string lengths and save to array, set up ti-containers for each string | ||
@@ -123,13 +168,71 @@ for(j=0; j < this.stringArray.length; j++){ | ||
_proto.processWhatToType = function() { | ||
this.stringArray = this.settings.whatToType; | ||
// check if the value is an array or just a string | ||
if(Object.prototype.toString.call(this.stringArray) !== '[object Array]'){ | ||
// since it's not already an array, turn it into one, since later functionality depends on it being one | ||
this.stringArray = '["' + this.stringArray + '"]'; | ||
this.stringArray = JSON.parse(this.stringArray); | ||
// check if the value is an array or just a string | ||
if(Object.prototype.toString.call(this.settings.whatToType) !== '[object Array]'){ | ||
// since it's not already an array, turn it into one, since later functionality depends on it being one | ||
this.stringArray = '["' + this.settings.whatToType + '"]'; | ||
this.stringArray = JSON.parse(this.stringArray); | ||
// if it is an array, clone it | ||
} else { | ||
// clone what to typed, so we don't modify the original strings in case we loop | ||
this.stringArrayTemp = $.extend( {}, this.settings.whatToType ); | ||
// convert cloned object to array | ||
this.stringArrayTemp = $.map(this.stringArrayTemp, function(value, index) { | ||
return [value]; | ||
}); | ||
// get the right values and put into stringArray so it's formatted correctly for processing | ||
for(var h = 0; h < this.stringArrayTemp.length; h++) { | ||
this.stringArray.push(this.stringArrayTemp[h]); | ||
} | ||
// turn string array into a big string | ||
this.mergedStrings = this.stringArray.join(''); | ||
}; | ||
} | ||
// turn each string into sub arrays | ||
for(var i = 0; i < this.stringArray.length; i++) { | ||
this.contentStartEnd = []; | ||
this.contentStartEndIndex = 0; | ||
this.contentStartEndSpan = 0; | ||
// turn each string into sub array | ||
this.stringArray[i] = this.stringArray[i].split(''); | ||
// find the location of HTML tag | ||
for(var j = 0, subArray = this.stringArray[i]; j < subArray.length; j++) { | ||
if(subArray[j] === '<') { | ||
this.contentStartEnd[this.contentStartEndIndex] = []; | ||
this.contentStartEnd[this.contentStartEndIndex][0] = j; | ||
} | ||
if(subArray[j] === '>') { | ||
this.contentStartEnd[this.contentStartEndIndex][1] = j; | ||
this.contentStartEndIndex++; | ||
} | ||
} | ||
// merge individual tag characters into single array index | ||
for(var positionIndex = 0; positionIndex < this.contentStartEnd.length; positionIndex++) { | ||
// move those tag pieces into a single array item | ||
for (var l = this.contentStartEnd[positionIndex][0]; l < this.contentStartEnd[positionIndex][1]; l++) { | ||
this.stringArray[i][this.contentStartEnd[positionIndex][0]] = this.stringArray[i][this.contentStartEnd[positionIndex][0]] + this.stringArray[i][l+1]; | ||
} | ||
} | ||
// cut array items based on the start/end positions we know, but move back the start point each time by the number of items we previously removed | ||
for( var m = 0; m < this.contentStartEnd.length; m++ ) { | ||
var startPos = this.contentStartEnd[m][0]+1; | ||
this.stringArray[i].splice(startPos, this.contentStartEnd[m][1] - this.contentStartEnd[m][0]); | ||
var span = this.contentStartEnd[m][1] - this.contentStartEnd[m][0]; | ||
// go through and update the start and positions by the span length we just cut | ||
for(var n = 0; n < this.contentStartEnd.length; n++) { | ||
this.contentStartEnd[n][0] = this.contentStartEnd[n][0] - span; | ||
this.contentStartEnd[n][1] = this.contentStartEnd[n][1] - span; | ||
} | ||
} | ||
} | ||
}; | ||
_proto.validateCallbackFunction = function() { | ||
@@ -144,50 +247,92 @@ | ||
_proto.typeLoop = function(){ | ||
// set the length of the current phrase being typed | ||
this.phraseLength = this.stringLengths[this.stringCount]; | ||
// make it human-like if specified in the settings | ||
_proto.randomizeTypeSpeed = function() { | ||
// make it human-like if specified in the settings | ||
if(this.settings.lifeLike === true){ | ||
this.delayTime = this.settings.typeSpeed*Math.random(); | ||
// set to 50% of the actual type speed, so the randomization goes no further than that ratio | ||
this.typeSpeedRangeSpan = this.settings.typeSpeed/2; | ||
this.typeSpeedMin = this.settings.typeSpeed-this.typeSpeedRangeSpan; | ||
this.typeSpeedMax = this.settings.typeSpeed+this.typeSpeedRangeSpan; | ||
this.delayTime = Math.abs(Math.random() * (this.typeSpeedMax - this.typeSpeedMin) + this.typeSpeedMin); | ||
} else { | ||
this.delayTime = this.settings.typeSpeed; | ||
} | ||
}; | ||
_proto.typeLoop = function(){ | ||
// get this particular string we're printing | ||
this.thisString = this.stringArray[this.stringArrayIndex]; | ||
// set the length of the current phrase being typed | ||
this.phraseLength = this.thisString.length; | ||
// start the typing timeout | ||
this.typeTimeout = setTimeout(function () { | ||
// append the string of letters to the respective .ti-text-container | ||
var characterToAppend = this.mergedStrings[this.typeCount+this.stringPlaceCount]; | ||
this.randomizeTypeSpeed(); | ||
// if breakLines is set to true, add the 'active-container' class to the next .ti-text-container in the list. | ||
if(this.settings.breakLines === true) { | ||
this.theElement.find('.ti-text-container:eq('+ this.stringCount +')').addClass('active-container').append(characterToAppend); | ||
} else { | ||
this.theElement.find('.ti-text-container').addClass('active-container').append(characterToAppend); | ||
// the the specific character we're printing | ||
this.characterToAppend = this.stringArray[this.stringArrayIndex][this.stringArrayCharacterIndex]; | ||
// if it's an HTML tag, do stuff | ||
if(this.characterToAppend.indexOf('<') !== -1 && this.characterToAppend.indexOf('</') === -1){ | ||
this.contentStartEndIndex = 0; | ||
// get the start & end positions of the actual string within the HTML tags | ||
this.contentStartEnd[0] = this.stringArrayCharacterIndex + 1; | ||
for(var t = this.stringArrayCharacterIndex; t < this.thisString.length; t++){ | ||
if(this.thisString[t].indexOf('</') !== -1) { | ||
// set the ending of the string segment in an HTML tag | ||
this.contentStartEnd[1] = t - 1; | ||
// as soon as we hit a match for a closing character | ||
break; | ||
} | ||
} | ||
this.contentStartEndSpan = this.contentStartEnd[1] - this.contentStartEnd[0]; | ||
// create a DOM node from the string we get | ||
this.thisTag = $($.parseHTML(this.characterToAppend)); | ||
// set the current character to append to the tag we just created, so that we can create it in the DOM | ||
this.characterToAppend = this.thisTag; | ||
// append the tag | ||
this.appendTheCharacter(); | ||
// set this to true so we know we're currently printing inside an HTML tag | ||
this.printingInTag = true; | ||
} | ||
this.typeCount++; | ||
// if there are still characters to be typed, call the same function again | ||
if (this.typeCount < this.phraseLength) { | ||
this.typeLoop(this.stringLengths[this.stringCount]); | ||
// if there are no more characters to print and there is more than one string to be typed, delete the string just printed | ||
this.appendTheCharacter(); | ||
this.stringArrayCharacterIndex++; | ||
// there are still characters to be typed, so repeat function | ||
if (this.stringArrayCharacterIndex < this.phraseLength) { | ||
this.typeLoop(); | ||
// there are no more characters to print and there is more than one string to be typed, so delete the string just printed | ||
} else if(this.stringArray.length > 1) { | ||
// reset this.stringArrayCharacterIndex since we're done using it for this string | ||
this.stringArrayCharacterIndex = 0; | ||
// update the this.stringPlaceCount so that we're appending starting at the correct spot in the merged string | ||
this.stringPlaceCount = this.stringPlaceCount + this.phraseLength; | ||
// reset this.typeCount in case this function needs to be reused | ||
this.typeCount = 0; | ||
// if the stringCount is the same as the number of strings we started with, we're done, so call the callback function | ||
if(this.stringCount+1 === this.stringArray.length) { | ||
this.callback(); | ||
// if the this.stringArrayIndex is the same as the number of strings we started with, we're done, so call the callback function | ||
if(this.stringArrayIndex + 1 === this.stringArray.length) { | ||
// multiple strings ending | ||
this.endOfStringsFork(); | ||
// if we're not on the last string, then move on to to delete, unless the user wants to break lines | ||
} else if((this.stringCount+1 < this.stringArray.length) && this.settings.breakLines === false){ | ||
} else if((this.stringArrayIndex + 1 < this.stringArray.length) && this.settings.breakLines === false){ | ||
setTimeout(function(){ | ||
this.deleteLoop(); | ||
}.bind(this), this.settings.breakWait); | ||
}.bind(this), this.settings.breakDelay); | ||
// if breakLines is true and we still have strings left to type, break it and continue | ||
} else if (this.stringCount+1 < this.stringArray.length && this.settings.breakLines === true){ | ||
this.stringCount++; | ||
// if breakLines is true and we still have strings left to type, break it and continue with the next string | ||
} else if (this.stringArrayIndex + 1 < this.stringArray.length && this.settings.breakLines === true){ | ||
// before starting the next string, make sure the index has been bumped up | ||
this.stringArrayIndex++; | ||
@@ -200,3 +345,3 @@ setTimeout(function(){ | ||
// give 'active-container' class to next container, so the cursor can start blinking | ||
this.theElement.find('.ti-text-container:eq('+ this.stringCount +')').addClass('active-container'); | ||
this.theElement.find('.ti-text-container:eq('+ this.stringArrayIndex +')').addClass('active-container'); | ||
@@ -206,5 +351,5 @@ // after another slight delay, continue typing the next string | ||
this.typeLoop(); | ||
}.bind(this), this.settings.breakWait); | ||
}.bind(this), this.settings.breakDelay); | ||
}.bind(this), this.settings.breakWait); | ||
}.bind(this), this.settings.breakDelay); | ||
@@ -215,4 +360,6 @@ } | ||
} else { | ||
this.callback(); | ||
// single string ending | ||
this.endOfStringsFork(); | ||
} | ||
}.bind(this), this.delayTime); | ||
@@ -222,32 +369,135 @@ | ||
_proto.deleteLoop = function() { | ||
_proto.endOfStringsFork = function() { | ||
if(this.settings.loop === true){ | ||
// delete the remaining string | ||
setTimeout(function(){ | ||
this.deleteLoop(); | ||
}.bind(this), this.settings.loopDelay); | ||
} else { | ||
this.callback(); | ||
} | ||
}; | ||
_proto.appendTheCharacter = function() { | ||
// if breakLines is set to true, add the 'active-container' class to the next .ti-text-container in the list. | ||
if(this.settings.breakLines === true) { | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container:eq('+ this.stringArrayIndex +')'); | ||
this.thisTiTextContainer.addClass('active-container'); | ||
} else { | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container'); | ||
this.thisTiTextContainer.addClass('active-container'); | ||
} | ||
// append the character to the HTML tag if we're printing in a tag, or else just append the character | ||
this.appendToHTMLTag(function(){ | ||
this.thisTiTextContainer.append(this.characterToAppend); | ||
}.bind(this)); | ||
}; | ||
_proto.appendToHTMLTag = function(notInTagFunction) { | ||
if(this.printingInTag === true) { | ||
// resave the character to append | ||
this.characterToAppend = this.thisString[this.contentStartEnd[0] + this.contentStartEndIndex]; | ||
// append to the latest tag (the one we just printed) in the element | ||
$(this.thisTag, this.theElement).last().append(this.characterToAppend); | ||
// if we're at the end of the string segment, turn off printingInTag | ||
this.printingInTag = (this.contentStartEnd[1] === this.contentStartEnd[0] + this.contentStartEndIndex - 1) ? false : true; | ||
this.contentStartEndIndex++; | ||
} else { | ||
notInTagFunction(); | ||
} | ||
}; | ||
_proto.deleteLoop = function(undefined) { | ||
// set the current ti-text-container | ||
this.thisTiTextContainer = this.theElement.find('.ti-text-container'); | ||
this.deleteTimeout = setTimeout(function () { | ||
// get the string from the element and cut it by one character at the end | ||
shortenedText = this.theElement.find('.ti-text-container').text().substring(0, this.theElement.find('.ti-text-container').text().length - 1); | ||
// randomize the delete speed, if applicable | ||
this.randomizeTypeSpeed(); | ||
// then, put that shortened text into the element so it looks like it's being deleted | ||
this.theElement.find('.ti-text-container').text(shortenedText); | ||
// get the string | ||
this.stringToDelete = this.thisTiTextContainer.last().html(); | ||
this.deleteCount++; | ||
// if there are still characters in the string, run the function again | ||
if (this.deleteCount < this.phraseLength) { | ||
this.deleteLoop(); | ||
// convert to array | ||
this.arrayToDelete = this.stringToDelete.split(""); | ||
// loop over array | ||
for (var n = this.arrayToDelete.length-1; n > -1; n--) { | ||
// TAG HANDLING | ||
if(this.arrayToDelete[n] === '>') { | ||
// find the beginning tag piece | ||
for(var o = n-1; o > -1; o--) { | ||
// find the opening piece | ||
// o = position of opening piece | ||
if(this.arrayToDelete[o] === '<') { | ||
// if the next piece before it isn't an HTML tag, just delete the text in between | ||
if(this.arrayToDelete[o-1] !== '>') { | ||
// remove character right before HTML tag begins and escape the loop | ||
this.arrayToDelete.splice(o-1, 1); | ||
break; | ||
} | ||
} | ||
} | ||
break; | ||
} | ||
// REGULAR CHARACTER HANDLING | ||
else { | ||
// remove the character and escape the loop | ||
this.arrayToDelete.splice(n, 1); | ||
break; | ||
} | ||
} | ||
// repopulate the element with the shortened string so it looks like it's being deleted | ||
this.thisTiTextContainer.last().html(this.arrayToDelete.join('')); | ||
// if nothing left, clear out the emtpy HTML tags | ||
if(this.thisTiTextContainer.last().text().length === 0){ | ||
this.thisTiTextContainer.last().html(''); | ||
} | ||
// if characters are still in the string, run the function again | ||
if (this.thisTiTextContainer.last().text().length > 0) { | ||
this.deleteLoop(); | ||
// if there are still strings in the array, go back to typing. | ||
} else if(this.stringArray[this.stringCount+1] !== undefined){ | ||
this.deleteCount = 0; | ||
this.stringCount++; | ||
this.typeLoop(); | ||
} | ||
} else if(this.stringArray[this.stringArrayIndex+1] !== undefined){ | ||
this.stringArrayIndex++; | ||
this.typeLoop(); | ||
// that was the last string in the array, so now just check if loop is enabled | ||
} else if (this.settings.loop === true){ | ||
// if there are multiple strings that have been typed, remove the current one and repeat deleteLoop | ||
if(this.thisTiTextContainer.length > 1) { | ||
// remove the current container so we don't fill it with junk | ||
this.thisTiTextContainer.last().remove(); | ||
// make sure the NEW last container has 'active-container' status | ||
// need to use find() again instead of stored selection because that stored selection is now outdated since we just removed a container | ||
this.theElement.find('.ti-text-container').last().addClass('active-container'); | ||
this.deleteLoop(); | ||
} else { | ||
// otherwise, re-run the whole thing again | ||
this.init(); | ||
} | ||
} | ||
// make backspacing much quicker by dividing delayTime (arbitrarily) by three | ||
}.bind(this), this.delayTime/3); | ||
}; | ||
}.bind(this), this.delayTime/3); | ||
}; | ||
// stop the plugin from typing or deleting stuff whenever it's called | ||
_proto.stopTyping = function() { | ||
// stop the plugin from typing or deleting stuff whenever it's called | ||
_proto.stop = function() { | ||
clearTimeout(this.typeTimeout); | ||
clearTimeout(this.deleteTimeout); | ||
}; | ||
}; | ||
}(jQuery)); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
225790
29
1909
166
1