Show My Passwords

Show/Hide the contents of password fields by clicking on the eye icon or with hotkey

目前为 2021-02-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Show My Passwords
  3. // @namespace ShowMyPasswords
  4. // @version 1.3
  5. // @description Show/Hide the contents of password fields by clicking on the eye icon or with hotkey
  6. // @author Elwyn (wakeupneo33@gmail.com)
  7. // @license MIT License
  8. // @homepage https://github.com/WakeupNeo33/ShowMyPasswords-userscript
  9. // @supportURL https://greasyfork.org/scripts/32049-show-my-passwords/feedback
  10. // @iconURL https://github.com/WakeupNeo33/ShowMyPasswords-userscript/raw/main/icon.png
  11. // @name:es Ver Mis Contraseñas
  12. // @description:es Muestra/Ocultar el contenido de los campos de contraseña haciendo clic en el icono o con conbinacion de teclas
  13. // @include http://*
  14. // @include https://*
  15. // @grant GM_setValue
  16. // @grant GM_getValue
  17. // @grant unsafeWindow
  18. // @run-at document-end
  19. // @encoding utf-8
  20. // ==/UserScript==
  21.  
  22. // Note: We use Pure Javascript to prevent potential conflicts on some websites
  23. // *******************************************************************************
  24. (function() {
  25. 'use strict';
  26.  
  27. // USER SETTINGS
  28. //-----------------------------------------------------------------------------
  29.  
  30. // ¿Use HotKeys to Show/Hide passwords on password fields?
  31. var useHotKeys = true;
  32.  
  33. // HotKey to Show/Hide passwords on password fields
  34. var passwordHotkey = {
  35. useCtrlKey : true,
  36. useAltKey : true,
  37. charKey : 'S',
  38. };
  39.  
  40. // HotKey to Show/Hide Eye Icon on passwords fields
  41. var iconHotkey = {
  42. useCtrlKey : true,
  43. useAltKey : true,
  44. charKey : 'P',
  45. };
  46.  
  47. // Show Eye Icons on Scirpt Init
  48. var showEyeIcon = true;
  49.  
  50. //-----------------------------------------------------------------------------
  51. // END OF USER SETTINGS
  52.  
  53. try{
  54. showEyeIcon = GM_getValue('showEyeIcon', showEyeIcon);
  55. }catch(e){}
  56.  
  57. var isVisible = false;
  58. var passwordKeyCode = (passwordHotkey.charKey.toLowerCase()).charCodeAt(0) - 32;
  59. var iconKeyCode = (iconHotkey.charKey.toLowerCase()).charCodeAt(0) - 32;
  60.  
  61. // Function Helpers
  62. function getStyle(el, styleProp)
  63. {
  64. var val;
  65. if (el.currentStyle)
  66. val = el.currentStyle[styleProp];
  67. else if (window.getComputedStyle)
  68. val = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
  69. return val;
  70. }
  71.  
  72. var toggleVisibility = function() {
  73. var fields = document.querySelectorAll( 'input[aria-eye="true"]' );
  74. for (var i = 0; i < fields.length; i++)
  75. {
  76. if( fields[i].type == 'password' )
  77. {
  78. fields[i].setAttribute( 'type', 'text' );
  79. fields[i].className += ' show-pass-warning';
  80. } else {
  81. fields[i].setAttribute( 'type', 'password' );
  82. fields[i].className = fields[i].className.replace(/\s*show-pass-warning/,'');
  83. }
  84. }
  85. isVisible = !isVisible;
  86. };
  87.  
  88. var showPassword = function() {
  89. if ( isVisible ) return;
  90. var fields = document.querySelectorAll( 'input[aria-eye="true"]' );
  91. for (var i = 0; i < fields.length; i++)
  92. {
  93. fields[i].setAttribute( 'type', 'text' );
  94. fields[i].className += ' show-pass-warning';
  95. }
  96. isVisible = true;
  97. };
  98.  
  99. var hidePassword = function() {
  100. if ( !isVisible ) return;
  101. var fields = document.querySelectorAll( 'input[aria-eye="true"]' );
  102. for (var i = 0; i < fields.length; i++)
  103. {
  104. fields[i].setAttribute( 'type', 'password' );
  105. fields[i].className = fields[i].className.replace(/\s*show-pass-warning/,'');
  106. }
  107. isVisible = false;
  108. };
  109.  
  110. // Main Function
  111. var addEyeIcon = function(){
  112.  
  113. var password_fields = document.querySelectorAll('input[type="password"]');
  114.  
  115. if ( password_fields.length )
  116. {
  117. for (var i = 0; i < password_fields.length; i++)
  118. {
  119. var current_field = password_fields[i];
  120.  
  121. // Check the initialization flag to prevent multiple initializations of the same field
  122. if ( current_field.getAttribute('aria-eye') == 'true' ) continue;
  123.  
  124. // get the field style properties
  125. var field_height = parseInt( getStyle( current_field, 'height' ) );
  126. if ( field_height < 20 ) { field_height = 20; }
  127. var field_margin_top = parseInt( getStyle( current_field, 'margin-top' ) );
  128. var field_padding_left = parseInt( getStyle( current_field, 'padding-left' ) );
  129. var field_padding_right = parseInt( getStyle( current_field, 'padding-right' ) );
  130.  
  131. // we use a container for the icon element for right position on the screen
  132. var icon_container = document.createElement( 'div' );
  133. var container_size = parseInt(getStyle( current_field, 'width'));
  134. icon_container.setAttribute('style','position:absolute; width:' + container_size + 'px;');
  135.  
  136. var icon_button = document.createElement( 'span' );
  137. icon_button.className = 'eye-pass-icon';
  138. icon_button.setAttribute('aria-eye','true');
  139. icon_button.setAttribute('style','height:' + field_height + 'px!important; margin-top:' + field_margin_top + 'px !important; margin-right:' + ( field_padding_right ) + 'px !important;');
  140. icon_button.setAttribute('title','( ' + (iconHotkey.useCtrlKey ? 'Ctrl + ': '') + (iconHotkey.useCtrlKey ? 'Alt + ': '') + (iconHotkey.charKey.charAt(0)).toUpperCase() + ' ) Show/Hide Eye Icon');
  141.  
  142. if ( showEyeIcon === false )
  143. {
  144. icon_button.setAttribute( 'aria-eye', 'false' );
  145. icon_button.className += ' hide-eye-icon';
  146. }
  147.  
  148. // add a click event in every eye icon and YES, we show and hide the fields with any icon
  149. icon_button.addEventListener( 'click', function(){
  150. toggleVisibility();
  151. }, false);
  152.  
  153. // We generate a flag in the field to prevent multiple initiations
  154. current_field.setAttribute('aria-eye','true');
  155.  
  156. //We add the icon before the field for a correct positioning in the screen
  157. icon_container.appendChild( icon_button );
  158. current_field.parentNode.insertBefore( icon_container, current_field );
  159.  
  160. icon_button.setAttribute('title', icon_button.getAttribute('title') + '\n( ' + (passwordHotkey.useCtrlKey ? 'Ctrl + ': '') + (passwordHotkey.useCtrlKey ? 'Alt + ': '') + (passwordHotkey.charKey.charAt(0)).toUpperCase() + ' ) Show/Hide Password');
  161. }
  162. }
  163. };
  164.  
  165. var toggleIcon = function()
  166. {
  167. var icons = document.querySelectorAll( '.eye-pass-icon' );
  168. for (var i = 0; i < icons.length; i++)
  169. {
  170. if( icons[i].getAttribute('aria-eye') == 'true' )
  171. {
  172. icons[i].setAttribute( 'aria-eye', 'false' );
  173. icons[i].className = 'eye-pass-icon hide-eye-icon';
  174. try{
  175. GM_setValue('showEyeIcon', false);
  176. }catch(e){}
  177. } else {
  178. icons[i].setAttribute( 'aria-eye', 'true' );
  179. icons[i].className = 'eye-pass-icon';
  180. try{
  181. GM_setValue('showEyeIcon', true);
  182. }catch(e){}
  183. }
  184. }
  185. };
  186.  
  187. // CSS Styles
  188. var css = [
  189. '.eye-pass-icon {',
  190. 'position:absolute;',
  191. 'display:block;',
  192. 'top: 0;',
  193. 'right: 0;',
  194. 'margin:0 2px;',
  195. 'border:0;',
  196. 'padding: 1px 2px;',
  197. 'width: 24px;',
  198. 'height: 20px;',
  199. 'line-height: 20px;',
  200. 'text-align:center;',
  201. 'background-image:url(data:image/png;base64,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);',
  202. 'background-position: center center;',
  203. 'background-repeat: no-repeat;',
  204. 'background-size: 18px 18px;',
  205. 'cursor: pointer;',
  206. 'z-index: 100;',
  207. 'opacity: 0.7;',
  208. '}',
  209. '.eye-pass-icon:hover {',
  210. 'background-size: 20px 20px;',
  211. 'opacity: 1;',
  212. '}',
  213. '.hide-eye-icon {',
  214. 'display:none;',
  215. '}',
  216. '.show-pass-warning {',
  217. 'border: 1px solid rgba(236, 81, 81, 0.7) !important;',
  218. 'box-shadow: 0 0 5px rgba(236, 81, 81, 1) !important;',
  219. '}'
  220. ];
  221. var style_obj = document.createElement('style');
  222. style_obj.innerText = css.join('');
  223. document.documentElement.appendChild(style_obj);
  224.  
  225. // First Run
  226. setTimeout(addEyeIcon, 1000);
  227.  
  228. // insertion-query v1.0.3 (2016-01-20)
  229. // license:MIT
  230. // Zbyszek Tenerowicz <naugtur@gmail.com> (http://naugtur.pl/)
  231. var insertionQ=function(){"use strict";function a(a,b){var d,e="insQ_"+g++,f=function(a){(a.animationName===e||a[i]===e)&&(c(a.target)||b(a.target))};d=document.createElement("style"),d.innerHTML="@"+j+"keyframes "+e+" { from { outline: 1px solid transparent } to { outline: 0px solid transparent } }\n"+a+" { animation-duration: 0.001s; animation-name: "+e+"; "+j+"animation-duration: 0.001s; "+j+"animation-name: "+e+"; } ",document.head.appendChild(d);var h=setTimeout(function(){document.addEventListener("animationstart",f,!1),document.addEventListener("MSAnimationStart",f,!1),document.addEventListener("webkitAnimationStart",f,!1)},n.timeout);return{destroy:function(){clearTimeout(h),d&&(document.head.removeChild(d),d=null),document.removeEventListener("animationstart",f),document.removeEventListener("MSAnimationStart",f),document.removeEventListener("webkitAnimationStart",f)}}}function b(a){a.QinsQ=!0}function c(a){return n.strictlyNew&&a.QinsQ===!0}function d(a){return c(a.parentNode)?a:d(a.parentNode)}function e(a){for(b(a),a=a.firstChild;a;a=a.nextSibling)void 0!==a&&1===a.nodeType&&e(a)}function f(f,g){var h=[],i=function(){var a;return function(){clearTimeout(a),a=setTimeout(function(){h.forEach(e),g(h),h=[]},10)}}();return a(f,function(a){if(!c(a)){b(a);var e=d(a);h.indexOf(e)<0&&h.push(e),i()}})}var g=100,h=!1,i="animationName",j="",k="Webkit Moz O ms Khtml".split(" "),l="",m=document.createElement("div"),n={strictlyNew:!0,timeout:20};if(m.style.animationName&&(h=!0),h===!1)for(var o=0;o<k.length;o++)if(void 0!==m.style[k[o]+"AnimationName"]){l=k[o],i=l+"AnimationName",j="-"+l.toLowerCase()+"-",h=!0;break}var p=function(b){return h&&b.match(/[^{}]/)?(n.strictlyNew&&e(document.body),{every:function(c){return a(b,c)},summary:function(a){return f(b,a)}}):!1};return p.config=function(a){for(var b in a)a.hasOwnProperty(b)&&(n[b]=a[b])},p}();"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=insertionQ);
  232.  
  233. // Alternative Run to contemplate possible future DOM insertion of password fields through events
  234. insertionQ('input[type="password"]').every(addEyeIcon);
  235.  
  236. // Key Event to Show/Hide Eye Icon and Password
  237. document.addEventListener( 'keydown', function(e){
  238. // Ensure event is not null
  239. e = e || window.event;
  240. var key = e.which || e.keyCode || 0;
  241. if ( useHotKeys ) {
  242. if ( e.ctrlKey == passwordHotkey.useCtrlKey && e.altKey == passwordHotkey.useAltKey ) {
  243. if ( key == passwordKeyCode ) {
  244. toggleVisibility();
  245. } else if ( passwordHotkey.charKey == '' && isVisible == false ) {
  246. showPassword();
  247. }
  248. }
  249. }
  250. if ( e.ctrlKey == iconHotkey.useCtrlKey && e.altKey == iconHotkey.useAltKey ) {
  251. if ( key == iconKeyCode ) {
  252. toggleIcon();
  253. }
  254. }
  255. }, false);
  256.  
  257. document.addEventListener( 'keyup', function(e){
  258. // Ensure event is not null
  259. e = e || window.event;
  260. if ( passwordHotkey.charKey == '' && isVisible == true ) {
  261. hidePassword();
  262. }
  263. }, false);
  264.  
  265.  
  266. })();