typed.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // The MIT License (MIT)
  2. // Typed.js | Copyright (c) 2014 Matt Boldt | www.mattboldt.com
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. // The above copyright notice and this permission notice shall be included in
  10. // all copies or substantial portions of the Software.
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. // THE SOFTWARE.
  18. ! function($) {
  19. "use strict";
  20. var Typed = function(el, options) {
  21. // chosen element to manipulate text
  22. this.el = $(el);
  23. // options
  24. this.options = $.extend({}, $.fn.typed.defaults, options);
  25. // attribute to type into
  26. this.isInput = this.el.is('input');
  27. this.attr = this.options.attr;
  28. // show cursor
  29. this.showCursor = this.isInput ? false : this.options.showCursor;
  30. // text content of element
  31. this.elContent = this.attr ? this.el.attr(this.attr) : this.el.text()
  32. // html or plain text
  33. this.contentType = this.options.contentType;
  34. // typing speed
  35. this.typeSpeed = this.options.typeSpeed;
  36. // add a delay before typing starts
  37. this.startDelay = this.options.startDelay;
  38. // backspacing speed
  39. this.backSpeed = this.options.backSpeed;
  40. // amount of time to wait before backspacing
  41. this.backDelay = this.options.backDelay;
  42. // input strings of text
  43. this.strings = this.options.strings;
  44. // character number position of current string
  45. this.strPos = 0;
  46. // current array position
  47. this.arrayPos = 0;
  48. // number to stop backspacing on.
  49. // default 0, can change depending on how many chars
  50. // you want to remove at the time
  51. this.stopNum = 0;
  52. // Looping logic
  53. this.loop = this.options.loop;
  54. this.loopCount = this.options.loopCount;
  55. this.curLoop = 0;
  56. // for stopping
  57. this.stop = false;
  58. // custom cursor
  59. this.cursorChar = this.options.cursorChar;
  60. // All systems go!
  61. this.build();
  62. };
  63. Typed.prototype = {
  64. constructor: Typed
  65. ,
  66. init: function() {
  67. // begin the loop w/ first current string (global self.string)
  68. // current string will be passed as an argument each time after this
  69. var self = this;
  70. self.timeout = setTimeout(function() {
  71. // Start typing
  72. self.typewrite(self.strings[self.arrayPos], self.strPos);
  73. }, self.startDelay);
  74. }
  75. ,
  76. build: function() {
  77. // Insert cursor
  78. if (this.showCursor === true) {
  79. this.cursor = $("<span class=\"typed-cursor\">" + this.cursorChar + "</span>");
  80. this.el.after(this.cursor);
  81. }
  82. this.init();
  83. }
  84. // pass current string state to each function, types 1 char per call
  85. ,
  86. typewrite: function(curString, curStrPos) {
  87. // exit when stopped
  88. if (this.stop === true) {
  89. return;
  90. }
  91. // varying values for setTimeout during typing
  92. // can't be global since number changes each time loop is executed
  93. var humanize = Math.round(Math.random() * (100 - 30)) + this.typeSpeed;
  94. var self = this;
  95. // ------------- optional ------------- //
  96. // backpaces a certain string faster
  97. // ------------------------------------ //
  98. // if (self.arrayPos == 1){
  99. // self.backDelay = 50;
  100. // }
  101. // else{ self.backDelay = 500; }
  102. // contain typing function in a timeout humanize'd delay
  103. self.timeout = setTimeout(function() {
  104. // check for an escape character before a pause value
  105. // format: \^\d+ .. eg: ^1000 .. should be able to print the ^ too using ^^
  106. // single ^ are removed from string
  107. var charPause = 0;
  108. var substr = curString.substr(curStrPos);
  109. if (substr.charAt(0) === '^') {
  110. var skip = 1; // skip atleast 1
  111. if (/^\^\d+/.test(substr)) {
  112. substr = /\d+/.exec(substr)[0];
  113. skip += substr.length;
  114. charPause = parseInt(substr);
  115. }
  116. // strip out the escape character and pause value so they're not printed
  117. curString = curString.substring(0, curStrPos) + curString.substring(curStrPos + skip);
  118. }
  119. if (self.contentType === 'html') {
  120. // skip over html tags while typing
  121. var curChar = curString.substr(curStrPos).charAt(0)
  122. if (curChar === '<' || curChar === '&') {
  123. var tag = '';
  124. var endTag = '';
  125. if (curChar === '<') {
  126. endTag = '>'
  127. } else {
  128. endTag = ';'
  129. }
  130. while (curString.substr(curStrPos).charAt(0) !== endTag) {
  131. tag += curString.substr(curStrPos).charAt(0);
  132. curStrPos++;
  133. }
  134. curStrPos++;
  135. tag += endTag;
  136. }
  137. }
  138. // timeout for any pause after a character
  139. self.timeout = setTimeout(function() {
  140. if (curStrPos === curString.length) {
  141. // fires callback function
  142. self.options.onStringTyped(self.arrayPos);
  143. // is this the final string
  144. if (self.arrayPos === self.strings.length - 1) {
  145. // animation that occurs on the last typed string
  146. self.options.callback();
  147. self.curLoop++;
  148. // quit if we wont loop back
  149. if (self.loop === false || self.curLoop === self.loopCount)
  150. return;
  151. }
  152. self.timeout = setTimeout(function() {
  153. self.backspace(curString, curStrPos);
  154. }, self.backDelay);
  155. } else {
  156. /* call before functions if applicable */
  157. if (curStrPos === 0)
  158. self.options.preStringTyped(self.arrayPos);
  159. // start typing each new char into existing string
  160. // curString: arg, self.el.html: original text inside element
  161. var nextString = curString.substr(0, curStrPos + 1);
  162. if (self.attr) {
  163. self.el.attr(self.attr, nextString);
  164. } else {
  165. if (self.isInput) {
  166. self.el.val(nextString);
  167. } else if (self.contentType === 'html') {
  168. self.el.html(nextString);
  169. } else {
  170. self.el.text(nextString);
  171. }
  172. }
  173. // add characters one by one
  174. curStrPos++;
  175. // loop the function
  176. self.typewrite(curString, curStrPos);
  177. }
  178. // end of character pause
  179. }, charPause);
  180. // humanized value for typing
  181. }, humanize);
  182. }
  183. ,
  184. backspace: function(curString, curStrPos) {
  185. // exit when stopped
  186. if (this.stop === true) {
  187. return;
  188. }
  189. // varying values for setTimeout during typing
  190. // can't be global since number changes each time loop is executed
  191. var humanize = Math.round(Math.random() * (100 - 30)) + this.backSpeed;
  192. var self = this;
  193. self.timeout = setTimeout(function() {
  194. // ----- this part is optional ----- //
  195. // check string array position
  196. // on the first string, only delete one word
  197. // the stopNum actually represents the amount of chars to
  198. // keep in the current string. In my case it's 14.
  199. // if (self.arrayPos == 1){
  200. // self.stopNum = 14;
  201. // }
  202. //every other time, delete the whole typed string
  203. // else{
  204. // self.stopNum = 0;
  205. // }
  206. if (self.contentType === 'html') {
  207. // skip over html tags while backspacing
  208. if (curString.substr(curStrPos).charAt(0) === '>') {
  209. var tag = '';
  210. while (curString.substr(curStrPos).charAt(0) !== '<') {
  211. tag -= curString.substr(curStrPos).charAt(0);
  212. curStrPos--;
  213. }
  214. curStrPos--;
  215. tag += '<';
  216. }
  217. }
  218. // ----- continue important stuff ----- //
  219. // replace text with base text + typed characters
  220. var nextString = curString.substr(0, curStrPos);
  221. if (self.attr) {
  222. self.el.attr(self.attr, nextString);
  223. } else {
  224. if (self.isInput) {
  225. self.el.val(nextString);
  226. } else if (self.contentType === 'html') {
  227. self.el.html(nextString);
  228. } else {
  229. self.el.text(nextString);
  230. }
  231. }
  232. // if the number (id of character in current string) is
  233. // less than the stop number, keep going
  234. if (curStrPos > self.stopNum) {
  235. // subtract characters one by one
  236. curStrPos--;
  237. // loop the function
  238. self.backspace(curString, curStrPos);
  239. }
  240. // if the stop number has been reached, increase
  241. // array position to next string
  242. else if (curStrPos <= self.stopNum) {
  243. self.arrayPos++;
  244. if (self.arrayPos === self.strings.length) {
  245. self.arrayPos = 0;
  246. self.init();
  247. } else
  248. self.typewrite(self.strings[self.arrayPos], curStrPos);
  249. }
  250. // humanized value for typing
  251. }, humanize);
  252. }
  253. // Start & Stop currently not working
  254. // , stop: function() {
  255. // var self = this;
  256. // self.stop = true;
  257. // clearInterval(self.timeout);
  258. // }
  259. // , start: function() {
  260. // var self = this;
  261. // if(self.stop === false)
  262. // return;
  263. // this.stop = false;
  264. // this.init();
  265. // }
  266. // Reset and rebuild the element
  267. ,
  268. reset: function() {
  269. var self = this;
  270. clearInterval(self.timeout);
  271. var id = this.el.attr('id');
  272. this.el.after('<span id="' + id + '"/>')
  273. this.el.remove();
  274. if (typeof this.cursor !== 'undefined') {
  275. this.cursor.remove();
  276. }
  277. // Send the callback
  278. self.options.resetCallback();
  279. }
  280. };
  281. $.fn.typed = function(option) {
  282. return this.each(function() {
  283. var $this = $(this),
  284. data = $this.data('typed'),
  285. options = typeof option == 'object' && option;
  286. if (!data) $this.data('typed', (data = new Typed(this, options)));
  287. if (typeof option == 'string') data[option]();
  288. });
  289. };
  290. $.fn.typed.defaults = {
  291. strings: ["These are the default values...", "You know what you should do?", "Use your own!", "Have a great day!"],
  292. // typing speed
  293. typeSpeed: 0,
  294. // time before typing starts
  295. startDelay: 0,
  296. // backspacing speed
  297. backSpeed: 0,
  298. // time before backspacing
  299. backDelay: 500,
  300. // loop
  301. loop: false,
  302. // false = infinite
  303. loopCount: false,
  304. // show cursor
  305. showCursor: true,
  306. // character for cursor
  307. cursorChar: "|",
  308. // attribute to type (null == text)
  309. attr: null,
  310. // either html or text
  311. contentType: 'html',
  312. // call when done callback function
  313. callback: function() {},
  314. // starting callback function before each string
  315. preStringTyped: function() {},
  316. //callback for every typed string
  317. onStringTyped: function() {},
  318. // callback for reset
  319. resetCallback: function() {}
  320. };
  321. }(window.jQuery);