Autosave Form Inputs and Display Saved Entries

Autosaves and displays entries from a single input field. Entries can be recovered or deleted. Dropdown only shows when clicking on the input field

  1. // ==UserScript==
  2. // @name Autosave Form Inputs and Display Saved Entries
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-08-13
  5. // @description Autosaves and displays entries from a single input field. Entries can be recovered or deleted. Dropdown only shows when clicking on the input field
  6. // @author Lawrence d'Aniello
  7. // @match https://example.com/* // Customize to match your target website
  8. // @license MIT
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16.  
  17. let inputField;
  18. let searchButton;
  19. let savedInputEntries = JSON.parse(localStorage.getItem('savedInputEntries1')) || [];
  20.  
  21.  
  22. function initScript() {
  23. // Example selectors - change these to match the specific site
  24. const inputField = document.querySelector('input[type="text"]'); // Change CSS selector to match your input field
  25. const searchButton = document.querySelector('button'); // Change CSS selector to match your search button
  26.  
  27.  
  28. if (!inputField || !searchButton) {
  29. setTimeout(initScript, 1000);
  30. return;
  31. }
  32.  
  33.  
  34. inputField.setAttribute('autocomplete', 'off');
  35. setupEventListeners();
  36. }
  37.  
  38.  
  39. function setupEventListeners() {
  40. inputField.addEventListener('focus', displaySavedInputEntries);
  41. document.addEventListener('click', handleClick);
  42. inputField.addEventListener('input', hideSavedInputEntries);
  43. if (searchButton) {
  44. searchButton.addEventListener('click', forceInputSave);
  45. }
  46. window.addEventListener('beforeunload', forceInputSave);
  47. inputField.addEventListener('keydown', (event) => {
  48. if (event.key === 'Enter') {
  49. forceInputSave();
  50. }
  51. });
  52. }
  53.  
  54.  
  55. function forceInputSave() {
  56. const currentValue = inputField.value.trim();
  57. if (currentValue && !savedInputEntries.includes(currentValue)) {
  58. savedInputEntries.unshift(currentValue);
  59. if (savedInputEntries.length > 15) {
  60. savedInputEntries.pop();
  61. }
  62. localStorage.setItem('savedInputEntries1', JSON.stringify(savedInputEntries));
  63. }
  64. hideSavedInputEntries();
  65. }
  66.  
  67.  
  68. function displaySavedInputEntries() {
  69. hideSavedInputEntries();
  70.  
  71.  
  72. const dropdown = document.createElement('ul');
  73. dropdown.id = 'savedInputEntriesDropdown1';
  74. dropdown.style.cssText = `
  75. list-style-type: none;
  76. padding: 5px;
  77. border: 1px solid #ccc;
  78. position: absolute;
  79. background-color: #fff;
  80. z-index: 1000;
  81. max-height: 150px;
  82. overflow-y: auto;
  83. `;
  84.  
  85.  
  86. const inputRect = inputField.getBoundingClientRect();
  87. dropdown.style.left = `${inputRect.left}px`;
  88. dropdown.style.top = `${inputRect.bottom + window.scrollY}px`;
  89. dropdown.style.width = `${inputRect.width}px`;
  90.  
  91.  
  92. savedInputEntries.forEach(entry => {
  93. const listItem = document.createElement('li');
  94. listItem.style.cssText = `
  95. display: flex;
  96. justify-content: space-between;
  97. padding: 5px;
  98. cursor: pointer;
  99. position: relative;
  100. transition: background-color 0.3s, color 0.3s;
  101. `;
  102. listItem.textContent = entry;
  103.  
  104.  
  105. const deleteButton = document.createElement('button');
  106. deleteButton.textContent = '✖';
  107. deleteButton.style.cssText = `
  108. display: none;
  109. background: none;
  110. border: none;
  111. color: red;
  112. cursor: pointer;
  113. position: absolute;
  114. right: 10px;
  115. top: 50%;
  116. transform: translateY(-50%);
  117. `;
  118.  
  119.  
  120. listItem.appendChild(deleteButton);
  121.  
  122.  
  123. listItem.addEventListener('mouseover', () => {
  124. listItem.style.backgroundColor = '#f0f0f0';
  125. listItem.style.color = '#333';
  126. deleteButton.style.display = 'inline';
  127. });
  128.  
  129.  
  130. listItem.addEventListener('mouseout', () => {
  131. listItem.style.backgroundColor = '#fff';
  132. listItem.style.color = '#000';
  133. deleteButton.style.display = 'none';
  134. });
  135.  
  136.  
  137. deleteButton.addEventListener('click', (event) => {
  138. event.stopPropagation();
  139. deleteEntry(entry);
  140. });
  141.  
  142.  
  143. listItem.addEventListener('click', () => {
  144. inputField.value = entry;
  145. hideSavedInputEntries();
  146. inputField.focus();
  147. });
  148.  
  149.  
  150. dropdown.appendChild(listItem);
  151. });
  152.  
  153.  
  154. document.body.appendChild(dropdown);
  155. }
  156.  
  157.  
  158. function hideSavedInputEntries() {
  159. const existingDropdown = document.getElementById('savedInputEntriesDropdown1');
  160. if (existingDropdown) {
  161. existingDropdown.remove();
  162. }
  163. }
  164.  
  165.  
  166. function handleClick(event) {
  167. if (event.target !== inputField && !inputField.contains(event.target)) {
  168. hideSavedInputEntries();
  169. } else if (event.target === inputField) {
  170. displaySavedInputEntries();
  171. }
  172. }
  173.  
  174.  
  175. function deleteEntry(entryToDelete) {
  176. savedInputEntries = savedInputEntries.filter(entry => entry !== entryToDelete);
  177. localStorage.setItem('savedInputEntries1', JSON.stringify(savedInputEntries));
  178. displaySavedInputEntries();
  179. }
  180.  
  181.  
  182. initScript();
  183. })();