1class TypingPlaceholder { 2 constructor(element) { 3 // Handle both selector string and element object 4 this.input = typeof element === 'string' ? document.querySelector(element) : element; 5 if (!this.input) return; 6 7 this.phrases = this.input.getAttribute('data-typing')?.split('|') || []; 8 this.typingSpeed = parseInt(this.input.getAttribute('data-typing-speed')) || 50; 9 this.backspaceSpeed = parseInt(this.input.getAttribute('data-typing-backspace-speed')) || 30; 10 this.pauseDuration = parseInt(this.input.getAttribute('data-typing-pause')) || 2000; 11 12 this.currentPhraseIndex = 0; 13 this.currentCharIndex = 0; 14 this.isTyping = true; 15 this.isPaused = false; 16 17 this.originalPlaceholder = this.input.getAttribute('placeholder'); 18 this.init(); 19 } 20 21 init() { 22 // Start typing animation 23 this.type(); 24 25 // Handle focus/blur events 26 this.input.addEventListener('focus', () => { 27 this.input.setAttribute('placeholder', this.originalPlaceholder); 28 }); 29 30 this.input.addEventListener('blur', () => { 31 if (!this.input.value) { 32 this.animate(); 33 } 34 }); 35 36 // Start animation if input is empty 37 if (!this.input.value) { 38 this.animate(); 39 } 40 } 41 42 animate() { 43 this.currentPhraseIndex = 0; 44 this.currentCharIndex = 0; 45 this.isTyping = true; 46 this.isPaused = false; 47 this.type(); 48 } 49 50 type() { 51 if (this.isPaused) return; 52 53 const currentPhrase = this.phrases[this.currentPhraseIndex]; 54 55 if (this.isTyping) { 56 // Typing characters 57 if (this.currentCharIndex < currentPhrase.length) { 58 this.input.setAttribute('placeholder', currentPhrase.substring(0, this.currentCharIndex + 1)); 59 this.currentCharIndex++; 60 setTimeout(() => this.type(), this.typingSpeed); 61 } else { 62 // Finished typing, pause before backspace 63 this.isTyping = false; 64 this.isPaused = true; 65 setTimeout(() => { 66 this.isPaused = false; 67 this.type(); 68 }, this.pauseDuration); 69 } 70 } else { 71 // Backspacing characters 72 if (this.currentCharIndex > 0) { 73 this.input.setAttribute('placeholder', currentPhrase.substring(0, this.currentCharIndex - 1)); 74 this.currentCharIndex--; 75 setTimeout(() => this.type(), this.backspaceSpeed); 76 } else { 77 // Move to next phrase 78 this.currentPhraseIndex = (this.currentPhraseIndex + 1) % this.phrases.length; 79 this.isTyping = true; 80 setTimeout(() => this.type(), 500); // Brief pause before next phrase 81 } 82 } 83 } 84} 85 86// Initialize typing placeholders 87document.addEventListener('DOMContentLoaded', () => { 88 const typingInputs = document.querySelectorAll('[data-typing]'); 89 typingInputs.forEach(input => { 90 new TypingPlaceholder(input); 91 }); 92});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.