From c2dfc1bb34e8153bc7372ce6056c6883616ece9b Mon Sep 17 00:00:00 2001 From: Joseph Date: Wed, 28 Feb 2018 23:33:35 +0000 Subject: Add error messages (#30) * Add error messages Signed-off-by: JoeBanks13 * Remove un-used keyword arg from 404 * Assert for status code instead of full content * PEP8 * test lint * please coverage * oh * Exclude websockets.py from coverage * Move code output into terminal * Switch typewriter href protocol * Add tests for websockets.py * Abort previous commit, coveralls did not let coverage go down * Add more pauses and request => response * move css and js out, add typewriter JS to our own repo & add method for appending text in bulk. * Enable REPL on 4XX and change error descriptions * commas * /error path --- static/css/window.css | 262 +++++++++++++++++++++ static/js/500.js | 36 +++ static/js/typewriter.js | 612 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 910 insertions(+) create mode 100644 static/css/window.css create mode 100644 static/js/500.js create mode 100644 static/js/typewriter.js (limited to 'static') diff --git a/static/css/window.css b/static/css/window.css new file mode 100644 index 00000000..3f3b7f56 --- /dev/null +++ b/static/css/window.css @@ -0,0 +1,262 @@ + .window { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: 0 4px 12px rgba(0, 0, 0, .5); + -webkit-box-shadow: 0 4px 12px rgba(0, 0, 0, .5); + box-shadow: 0 4px 12px rgba(0, 0, 0, .5); + width: 800px; + margin: auto; + margin-top: 20px; + border: 1px solid #C1C2C2; + height: 500px; + padding-bottom: 20px; + } + + .inside { + background: black; + padding-right: 20px; + height: 100%; + } + + .inside .blok { + width: 100%; + background: black; + } + + .top { + padding: 7px 0; + position: relative; + background: #f1f1f1; + background: -moz-linear-gradient(top, #E9E9E9 3%, #d8d8d8 100%); + background: -webkit-gradient(left top, left bottom, color-stop(3%, #E9E9E9), color-stop(100%, #d8d8d8)); + background: -webkit-linear-gradient(top, #E9E9E9 3%, #d8d8d8 100%); + background: -o-linear-gradient(top, #E9E9E9 3%, #d8d8d8 100%); + background: -ms-linear-gradient(top, #E9E9E9 3%, #d8d8d8 100%); + background: linear-gradient(to bottom, #E9E9E9 3%, #d8d8d8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f1f1f1', endColorstr='#d8d8d8', GradientType=0); + + -webkit-box-shadow: inset 0px 1px 1px 0px rgba(255, 255, 255, 0.76); + -moz-box-shadow: inset 0px 1px 1px 0px rgba(255, 255, 255, 0.76); + box-shadow: inset 0px 1px 1px 0px rgba(255, 255, 255, 0.76); + + overflow: hidden; + border-bottom: 2px solid #BDBCC1; + } + + .top > div { + float: left; + } + + .panel { + padding-left: 9px; + padding-top: 2px; + } + + .panel > span { + display: inline-block; + float: left; + width: 12px; + height: 12px; + margin-right: 7px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + + } + + .panel span.first { + background: #FF5F4F; + } + + .panel span.second { + background: #F9C206; + } + + .panel span.third { + background: #19CC32; + } + + .nav { + overflow: hidden; + } + + .nav > span { + display: inline-block; + float: left; + background: #FBFBFB; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + height: 23px; + padding: 0 8px; + cursor: pointer; + color: #B4B4B4; + border-bottom: 1px solid #CECECE; + } + + .nav > span:hover { + background: #f2f2f2; + color: #666; + } + + .nav > span i.fa { + font-size: 23px; + } + + .nav span.active { + color: #707070; + } + + .nav span.prev { + margin-right: 1px; + margin-left: 7px; + } + + .nav span.next { + margin-right: 7px; + } + + .nav span.set i { + font-size: 14px; + position: relative; + top: 3px; + } + + .nav span.address { + width: 400px; + margin-left: 75px; + display: inline-block; + background: #fff; + line-height: 23px; + padding: 0; + text-align: center; + position: relative; + } + + .nav span.address > input { + font-size: 12px; + color: #505050; + border: none; + background: none; + text-align: center; + position: relative; + width: 300px; + } + + .nav span.address > input:focus { + outline: none; + } + + .nav span.address > input.class { + text-align: left; + } + + .nav span.address > i.fa { + position: absolute; + right: 5px; + top: 7px; + font-size: 11px; + color: #010101; + } + + .nav.right { + float: right !important; + margin-right: 35px; + } + + .nav span.share { + margin-right: 7px; + } + + .nav span.share > i.fa { + font-size: 11px; + position: relative; + top: 2px; + } + + .nav span.tabs { + position: relative; + width: 26px; + padding: 0; + } + + .nav span.tabs span { + height: 7px; + width: 7px; + border: 1px solid #B4B4B4; + display: inline-block; + position: absolute; + background: #FBFBFB; + } + + .nav span.tabs span.front { + top: 8px; + left: 6px; + z-index: 6; + } + + .nav span.tabs span.behind { + top: 6px; + left: 8px; + z-index: 5; + } + + .nav span.tabs:hover span { + border: 1px solid #666; + } + + span.new { + cursor: pointer; + position: absolute; + right: 0; + bottom: 0; + background: #CACACA; + width: 23px; + height: 23px; + text-align: center; + line-height: 23px; + border-top: 1px solid #C1C2C2; + border-left: 1px solid #C1C2C2; + } + + span.new:hover { + -webkit-box-shadow: inset 0px 1px 1px 0px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0px 1px 1px 0px rgba(0, 0, 0, 0.1); + box-shadow: inset 0px 1px 1px 0px rgba(0, 0, 0, 0.1); + } + + span.new .plus { + position: absolute; + background: #b0b0b0; + display: inline-block; + } + + span.new .plus.x { + height: 1px; + width: 14px; + top: 12px; + right: 0; + left: 0; + margin: auto; + } + + span.new .plus.y { + height: 14px; + width: 1px; + bottom: 0; + top: 0; + margin: auto; + + } + + #terminal { + height: 100%; + width: 100%; + } + + pre { + border: 0; + border-radius: 3px; + } \ No newline at end of file diff --git a/static/js/500.js b/static/js/500.js new file mode 100644 index 00000000..2b1c461e --- /dev/null +++ b/static/js/500.js @@ -0,0 +1,36 @@ + var app = document.getElementById('error'); + + var typewriter = new Typewriter(app, { + loop: false, + deleteSpeed: 40, + typingSpeed: "natural", + devMode: false + }); + + + + typewriter.appendText('Python 3.6.4 (default, Jan 5 2018, 02:35:40)\n') + .appendText('[GCC 7.2.1 20171224] on linux\n') + .appendText('Type "help", "copyright", "credits" or "license" for more information.\n') + .appendText('>>> ') + .pauseFor(1000) + .typeString("impor requests") + .deleteChars(9) + .typeString("t requests\n") + .appendText(">>> ") + .pauseFor(750) + .changeSettings({typingSpeed: "natural"}) + .typeString("response = requests."+window._RequestMethod+"('https://pythim") + .deleteChars(2) + .typeString("ondiscord.con/") + .deleteChars(2) + .typeString("m"+window._Path+"')\n") + .pauseFor(1000) + .appendText("<Response ["+window._Code+"]>\n>>> ") + .typeString("# hmmmm") + .pauseFor(1000) + .deleteChars(7) + .pauseFor(1000) + .typeString("response.text\n") + .appendText("'"+window._ErrorMsg+"'\n>>> ") + .start(); diff --git a/static/js/typewriter.js b/static/js/typewriter.js new file mode 100644 index 00000000..e9f82adc --- /dev/null +++ b/static/js/typewriter.js @@ -0,0 +1,612 @@ +/* + * Title: Typewriter JS + * Description: A native javascript plugin that can be used to create an elegent automatic typewriter animation effect on websites. + * Author: Tameem Safi + * Website: https://safi.me.uk + * Version: 1.0.0 + */ + +(function() { + + "use strict"; + + // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel + // MIT license + (function() { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] + || window[vendors[x]+'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function() { callback(currTime + timeToCall); }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; + }()); + + window.Typewriter = function Typewriter(element, options) { + this._settings = { + cursorAnimationPaused: false, + opacityIncreasing: false, + currentOpacity: 1, + delayedQue: [], + delayItemsCount: 0, + eventQue: [], + calledEvents: [], + eventRunning: false, + timeout: false, + delayExecution: false, + fps: (60/1000), + typingFrameCount: 0, + stringToTypeHTMLArray: [], + currentTypedCharacters: [], + typing: false, + usedIDs: [], + charAmountToDelete: false, + userOptions: {}, + eventLoopRerun: 0 + }; + + if(!element) { + return console.error('Please choose an DOM element so that type writer can display itself.'); + } + + // if(!options.strings && !(options.strings instanceof Array || typeof options.strings === 'string')) { + // return console.error('Please enter an array of strings for the typewriter animation to work.'); + // } + + if(typeof options !== 'object') { + return console.error('Typewriter only accepts the options as an object.'); + } + + this._settings.userOptions = options; + + this.default_options = { + strings: false, + cursorClassName: 'typewriter-cursor', + cursor: '|', + animateCursor: true, + blinkSpeed: 50, + typingSpeed: 'natural', + deleteSpeed: 'natural', + charSpanClassName: 'typewriter-char', + wrapperClassName: 'typewriter-wrapper', + loop: false, + autoStart: false, + devMode: false + }; + + this.options = this._setupOptions(options); + + this.el = element; + + this._setupTypwriterWrapper(); + + this._startCursorAnimation(); + + if(this.options.autoStart === true && this.options.strings) { + this.typeOutAllStrings(); + } + + }; + + var TypewriterPrototype = window.Typewriter.prototype; + + TypewriterPrototype.stop = function() { + this._addToEventQue(this._stopEventLoop) + return this; + }; + + TypewriterPrototype.start = function() { + this._startEventLoop(); + return this; + }; + + TypewriterPrototype.rerun = function() { + this._addToEventQue(this._rerunCalledEvents); + return this; + }; + + TypewriterPrototype.typeString = function(string) { + if(!string || typeof string != 'string') { + return console.error('Please enter a string as the paramater.'); + } + + var string_chars = this._getCharacters(string); + + this._addToEventQue([this._typeCharacters, [string_chars]]); + return this; + }; + + TypewriterPrototype.deleteAll = function() { + this._addToEventQue([this._deleteChars, ['all']]); + return this; + }; + + TypewriterPrototype.deleteChars = function(amount) { + this._addToEventQue([this._deleteChars, [amount]]); + return this; + }; + + TypewriterPrototype.pauseFor = function(ms) { + this._addToEventQue([this._pauseFor, [ms]]); + return this; + }; + + TypewriterPrototype.typeOutAllStrings = function() { + var characters_array = this._getStringsAsCharsArray(); + + if(characters_array.length === 1) { + this._typeCharacters(characters_array[0]); + } else { + for(var i = 0, length = characters_array.length; i < length; i++) { + this._addToEventQue([this._typeCharacters, [characters_array[i]]]); + this.pauseFor(this._randomInteger(1500, 2500)); + this.deleteAll(); + this.pauseFor(this._randomInteger(1500, 2500)); + } + } + + return this; + + }; + + TypewriterPrototype.changeSettings = function(new_settings) { + if(!new_settings && typeof new_settings !== 'object') { + return console.error('Typewriter will only accept an object as the settings.'); + } + + this._addToEventQue([this._changeSettings, [JSON.stringify(new_settings)]]); + + return this; + + }; + + TypewriterPrototype.changeBlinkSpeed = function(new_speed) { + if(!new_speed && typeof new_speed !== 'number') { + return console.error('Please enter a number for the new blink speed.'); + } + + this.changeSettings({ + blinkSpeed: new_speed + }); + + return this; + }; + + TypewriterPrototype.changeTypingSpeed = function(new_speed) { + if(!new_speed && typeof new_speed !== 'number') { + return console.error('Please enter a number for the new typing speed.'); + } + + var new_settings = { + typingSpeed: new_speed + }; + + this.changeSettings({ + typingSpeed: new_speed + }); + + return this; + }; + + TypewriterPrototype.changeDeleteSpeed = function(new_speed) { + if(!new_speed && typeof new_speed !== 'number') { + return console.error('Please enter a number for the new delete speed.'); + } + + this.changeSettings({ + changeDeleteSpeed: new_speed + }); + + return this; + }; + + TypewriterPrototype._rerunCalledEvents = function() { + if(this._settings.currentTypedCharacters.length > 0) { + this.deleteAll(); + this._resetEventLoop('rerunCalledEvents'); + } else { + this._settings.eventQue = this._settings.calledEvents; + this._settings.calledEvents = []; + this.options = this._setupOptions(this._settings.userOptions); + this._settings.usedIDs = []; + this.charAmountToDelete = false; + this._startEventLoop(); + } + }; + + TypewriterPrototype._deleteChars = function(amount) { + + + if(amount) { + this._settings.charAmountToDelete = amount; + } + this._deletingCharIdsAnimation = window.requestAnimationFrame(this._deletingCharAnimationFrame.bind(this)); + return this; + }; + + TypewriterPrototype._pauseFor = function(ms) { + var self = this; + self._settings.eventRunning = true; + setTimeout(function() { + self._resetEventLoop('pauseFor'); + }, ms); + }; + + TypewriterPrototype._changeSettings = function(new_settings) { + this.options = this._setupOptions(JSON.parse(new_settings[0])); + this._resetEventLoop('changeSettings'); + + if(this.options.devMode) { + console.log('New settings', this.options); + } + + }; + + TypewriterPrototype._deletingCharAnimationFrame = function() { + var self = this; + var delete_speed = this.options.deleteSpeed; + var typewriter_wrapper_class_name = self.options.wrapperClassName; + var current_typed_char_ids = self._settings.currentTypedCharacters; + var char_amount_to_delete = self._settings.charAmountToDelete; + + if(!self._settings.charAmountToDelete || self._settings.charAmountToDelete === 0 || current_typed_char_ids === 0) { + self._resetEventLoop('deletingCharAnimationFrame'); + return true; + } + + if(delete_speed == 'natural') { + delete_speed = self._randomInteger(50, 150); + } + + if(char_amount_to_delete == 'all') { + char_amount_to_delete = current_typed_char_ids.length; + self._settings.charAmountToDelete = char_amount_to_delete; + } + + setTimeout(function() { + if(self._settings.charAmountToDelete) { + var last_typed_char_index = current_typed_char_ids.length - 1; + var get_last_typed_char = current_typed_char_ids[last_typed_char_index]; + + self._settings.currentTypedCharacters.splice(last_typed_char_index, 1); + + var char_to_delete_el = document.getElementById(get_last_typed_char); + + if(char_to_delete_el) { + var typewriter_wrapper_el = self.el.querySelector('.' + typewriter_wrapper_class_name); + typewriter_wrapper_el.removeChild(char_to_delete_el); + self._settings.charAmountToDelete = char_amount_to_delete - 1; + + if(self.options.devMode) { + console.log('Deleted char with ID', get_last_typed_char); + } + } + + } + + self._deletingCharIdsAnimation = window.requestAnimationFrame(self._deletingCharAnimationFrame.bind(self)); + + }, delete_speed); + }; + + TypewriterPrototype._setupOptions = function(new_options) { + var merged_options = {}; + + for (var attrname in this.default_options) { + merged_options[attrname] = this.default_options[attrname]; + } + + if(this._settings.userOptions) { + for (var attrname in this._settings.userOptions) { + merged_options[attrname] = this._settings.userOptions[attrname]; + } + } + + for (var attrname in new_options) { + merged_options[attrname] = new_options[attrname]; + } + + return merged_options; + } + + TypewriterPrototype._addToEventQue = function(event) { + this._settings.eventQue.push(event); + if(this._settings.eventQue.length > 0 && !this._settings.eventRunning && this.options.autoStart) { + this._startEventLoop(); + } + }; + + TypewriterPrototype._startEventLoop = function() { + if(this.options.devMode) { + console.log('Event loop started.'); + } + + if(!this._settings.eventRunning) { + + if(this._settings.eventQue.length > 0) { + this.eventLoopRerun = 0; + var first_event = this._settings.eventQue[0]; + if(typeof first_event == 'function') { + this._settings.eventRunning = true; + this._settings.calledEvents.push(first_event); + this._settings.eventQue.splice(0, 1); + first_event.call(this); + if(this.options.devMode) { + console.log('Event started.'); + } + } else if(first_event instanceof Array) { + if(typeof first_event[0] == 'function' && first_event[1] instanceof Array) { + this._settings.eventRunning = true; + this._settings.calledEvents.push(first_event); + this._settings.eventQue.splice(0, 1); + first_event[0].call(this, first_event[1]); + if(this.options.devMode) { + console.log('Event started.'); + } + } + } + } + this._eventQueAnimation = window.requestAnimationFrame(this._startEventLoop.bind(this)); + } + + if(!this._settings.eventRunning && this._settings.eventQue.length <= 0) { + var self = this; + self._stopEventLoop(); + setTimeout(function() { + if(self.options.loop) { + self.eventLoopRerun++; + if(self.options.devMode) { + console.log('Before Loop State', self._settings); + } + if(self.eventLoopRerun > 4) { + console.error('Maximum amount of loop retries reached.'); + self._stopEventLoop(); + } else { + if(self.options.devMode) { + console.log('Looping events.'); + } + self._rerunCalledEvents(); + } + } + }, 1000); + return; + } + + }; + + TypewriterPrototype._resetEventLoop = function(name) { + var event_name = name || 'Event'; + this._settings.eventRunning = false; + this._startEventLoop(); + if(this.options.devMode) { + console.log(event_name, 'Finished'); + } + }; + + TypewriterPrototype._stopEventLoop = function() { + window.cancelAnimationFrame(this._eventQueAnimation); + if(this.options.devMode) { + console.log('Event loop stopped.'); + } + }; + + TypewriterPrototype._setupTypwriterWrapper = function() { + var typewriter_wrapper_class_name = this.options.wrapperClassName; + var typewriter_wrapper = document.createElement('span'); + typewriter_wrapper.className = typewriter_wrapper_class_name; + this.el.innerHTML = ''; + this.el.appendChild(typewriter_wrapper); + }; + + TypewriterPrototype._typeCharacters = function(characters_array) { + this._settings.stringToTypeHTMLArray = this._convertCharsToHTML(characters_array); + this._typingAnimation = window.requestAnimationFrame(this._typingAnimationFrame.bind(this, characters_array.length)); + return this; + }; + + TypewriterPrototype._typingAnimationFrame = function(total_items) { + var self = this; + var typing_speed = this.options.typingSpeed; + var typewriter_wrapper_class_name = self.options.wrapperClassName; + + if(self._settings.stringToTypeHTMLArray.length == 0) { + window.cancelAnimationFrame(self._typingAnimation); + this._resetEventLoop('typingAnimationFrame'); + return true; + } + + if(typing_speed == 'natural') { + typing_speed = this._randomInteger(50, 150); + } + + setTimeout(function() { + var el_inner_html = self.el.innerHTML; + var item_to_type = self._settings.stringToTypeHTMLArray[0]; + self.el.querySelector('.' + typewriter_wrapper_class_name).appendChild(item_to_type.el); + self._settings.currentTypedCharacters.push(item_to_type.id); + self._settings.stringToTypeHTMLArray.splice(0, 1); + self._typingAnimation = window.requestAnimationFrame(self._typingAnimationFrame.bind(self, total_items)); + if(self.options.devMode) { + console.log('Typed', item_to_type); + } + }, typing_speed); + }; + + TypewriterPrototype._convertCharsToHTML = function(chars) { + var chars_html_wrap_array = []; + var char_class_name = this.options.charSpanClassName; + var chars_array = chars[0]; + + for(var i = 0, length = chars_array.length; i < length; i++) { + var char_element = document.createElement('span'); + var char_id = this._generateUniqueID(); + char_element.id = char_id; + char_element.className = char_class_name + ' typewriter-item-' + i; + char_element.innerHTML = chars_array[i]; + chars_html_wrap_array.push({ + id: char_id, + el: char_element + }); + } + + return chars_html_wrap_array; + }; + + TypewriterPrototype._getCharacters = function(string) { + if(typeof string !== 'string') { + return false; + } + return string.split(""); + }; + + TypewriterPrototype._getStringsAsCharsArray = function() { + var strings_array_check = this.options.strings instanceof Array; + var strings_string_check = typeof this.options.strings === 'string'; + if(!strings_array_check) { + if(!strings_string_check) { + return console.error('Typewriter only accepts strings or an array of strings as the input.'); + } + return [this.options.strings.split("")]; + } + + var strings_chars_array = []; + + for (var i = 0, length = this.options.strings.length; i < length; i++) { + var string_chars = this._getCharacters(this.options.strings[i]); + if(!string_chars) { + console.error('Please enter only strings.'); + break; + } + strings_chars_array.push(string_chars); + } + + return strings_chars_array; + }; + + TypewriterPrototype._cursorAnimationFrame = function() { + if(!this._settings.cursorAnimationPaused) { + var blink_speed = this.options.blinkSpeed; + var opacity_amount = (1/1000) * blink_speed; + + var cursor_el = this.el.querySelector('.typewriter-cursor'); + + if(this._settings.opacityIncreasing == true) { + if(this._settings.currentOpacity >= 1) { + this._settings.opacityIncreasing = false; + this._settings.currentOpacity = 1; + } + + this._settings.currentOpacity += opacity_amount; + } + + if(this._settings.opacityIncreasing == false) { + if(this._settings.currentOpacity <= 0) { + this._settings.opacityIncreasing = true; + this._settings.currentOpacity = 0; + } + + this._settings.currentOpacity -= opacity_amount; + } + + cursor_el.style.opacity = this._settings.currentOpacity; + this._cursorAnimation = window.requestAnimationFrame(this._cursorAnimationFrame.bind(this)); + } + }; + + TypewriterPrototype.appendText = function(text){ + this._addToEventQue([this._appendText, [text]]) + return this + } + + TypewriterPrototype._appendText = function(text){ + var char_class_name = this.options.charSpanClassName; + var char_element = document.createElement('span'); + var char_id = this._generateUniqueID(); + char_element.id = char_id; + char_element.className = char_class_name + ' dom-appended' + char_element.innerHTML = text + var items = [] + items.push({ + id: char_id, + el: char_element + }); + + this._settings.stringToTypeHTMLArray = items + + window.requestAnimationFrame(this._typingAnimationFrame.bind(this, 1)); + + } + + TypewriterPrototype._startCursorAnimation = function() { + var cursor = this.options.cursor; + var cursor_class_name = this.options.cursorClassName; + + var cursor_element = document.createElement('span'); + cursor_element.className = cursor_class_name; + cursor_element.innerHTML = cursor; + + this.el.appendChild(cursor_element); + if(this.options.animateCursor) { + this._cursorAnimation = window.requestAnimationFrame(this._cursorAnimationFrame.bind(this)); + } + }; + + TypewriterPrototype._pauseCursorAnimation = function() { + if(!this._settings.cursorAnimationPaused) { + window.cancelAnimationFrame(this._cursorAnimation); + this._settings.cursorAnimationPaused = true; + } + }; + + TypewriterPrototype._restartCursorAnimation = function() { + if(!this._settings.cursorAnimationPaused) { + return console.error('Cursor animation is already running.') + } + + this._settings.cursorAnimationPaused = false; + this._cursorAnimation = window.requestAnimationFrame(this._cursorAnimationFrame.bind(this)); + }; + + /* Utils */ + TypewriterPrototype._randomInteger = function(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + }; + + TypewriterPrototype._randomID = function() { + var text = ""; + var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + for( var i=0; i < this._randomInteger(5, 15); i++ ) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + }; + + TypewriterPrototype._generateUniqueID = function() { + var temp_id = this._randomID(); + if(this._settings.usedIDs.indexOf(temp_id) == -1) { + this._settings.usedIDs.push(temp_id); + return temp_id; + } + return this._generateUniqueID.call(this); + }; + + +})(); \ No newline at end of file -- cgit v1.2.3