a11yInsta

Script criado pra tornar o Instagram mais acessível

  1. // ==UserScript==
  2. // @name a11yInsta
  3. // @namespace https://github.com/geanCarneiro/WebAcessivel
  4. // @version 0.4
  5. // @description Script criado pra tornar o Instagram mais acessível
  6. // @author Gean G. Carneiro
  7. // @match https://www.instagram.com/
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=instagram.com
  9. // @grant GM_xmlhttpRequest
  10. // @connect github.com
  11. // @connect githubusercontent.com
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. window.onload = function () {
  18.  
  19. let observer = new MutationObserver(function(mutations) {
  20. mutations.forEach(mutation => {
  21. if(mutation.type == 'childList') {
  22. mutation.addedNodes.forEach(node => {
  23. updatePost(node)
  24. })
  25. }
  26. })
  27. })
  28.  
  29. waitForElm('main div[style] > div > div:nth-of-type(2) > div').then(elem => {
  30. let postsArea = elem.querySelector('article[class]')
  31. postsArea = postsArea.parentNode;
  32.  
  33. observer.observe(postsArea, {childList: true})
  34. })
  35.  
  36. /*
  37. window .addEventListener(
  38. "keydown",
  39. ( @type {KeyboardEvent} evt) => {
  40. @type {Node}
  41. let post = evt.target
  42.  
  43. let focusTarget;
  44.  
  45. // controles das publicações
  46. if(post.tagName == 'ARTICLE'){
  47. if(evt.altKey && evt.key.toLowerCase() == "l"){
  48. evt.preventDefault()
  49. evt.stopPropagation()
  50. let botaoCurtir = post.querySelector('svg[aria-label="Curtir"]');
  51. let curtir = botaoCurtir != null
  52. if(!curtir)
  53. botaoCurtir = post.querySelector('svg[aria-label="Descurtir"]')
  54.  
  55. botaoCurtir = botaoCurtir != null ? botaoCurtir.parentNode : null
  56. botaoCurtir = botaoCurtir != null ? botaoCurtir.parentNode : null
  57. botaoCurtir = botaoCurtir != null ? botaoCurtir.parentNode : null
  58. botaoCurtir != null ? botaoCurtir.click() : null
  59. if(botaoCurtir != null)
  60. curtir ? notifyScreenReader('curtiu') : notifyScreenReader('descurtiu')
  61.  
  62. }
  63. }
  64. // controle gerais
  65. if(evt.altKey && evt.key.toLowerCase() == "f"){
  66. evt.preventDefault()
  67. evt.stopPropagation()
  68. let feedTitle = document.querySelector('#feedTitle');
  69. feedTitle != null ? feedTitle.focus() : null
  70. }
  71. }, false
  72. ) */
  73.  
  74. // garantir a primeira execução dos metodos
  75. insertTitles()
  76. updateAllPost()
  77. fixDoubleSemantic()
  78. }
  79. function fixDoubleSemantic(){
  80. let instagramLink = document.querySelector('a[class][href="/"]');
  81. instagramLink.ariaLabel = 'Instagram'
  82. let instagramImg = instagramLink.querySelector('[role="img"]')
  83. instagramImg.ariaHidden = 'true'
  84.  
  85. let menu = document.querySelector('span[aria-describedby]').parentNode.parentNode.parentNode;
  86. menu.querySelectorAll('svg').forEach(graph => {
  87. graph.ariaHidden = 'true'
  88. })
  89.  
  90. }
  91.  
  92. function insertTitles(){
  93. // insert Post Title
  94. waitForElm('main div[style] > div > div:nth-of-type(2) > div').then(elem => {
  95. let postsArea = elem.querySelector('article[class]')
  96. postsArea = postsArea.parentNode.parentNode;
  97.  
  98. createTitleIn(2, 'Feed', postsArea, 'feedTitle')
  99. })
  100.  
  101. // insert Stories Title
  102. waitForElm('main [role="menu"] [role="presentation"]').then(storiesArea => {
  103. storiesArea = storiesArea.parentNode;
  104.  
  105. createTitleIn(2, 'Stories', storiesArea)
  106. })
  107.  
  108.  
  109. // set Instagram as tittle
  110. createTitleIn(1, 'Instagram', document.body)
  111. }
  112.  
  113. function notifyScreenReader(msg){
  114. let ariaLive = getAriaLiveElement();
  115. ariaLive.textContent = msg;
  116. setTimeout(() => {
  117. ariaLive.textContent = '';
  118. }, 1000)
  119. }
  120.  
  121. function getAriaLiveElement(){
  122. let ariaLive = document.querySelector('#aria-live-elem')
  123. if (!ariaLive) {
  124. ariaLive = document.createElement('span');
  125. ariaLive.id = 'aria-live-elem'
  126. ariaLive.setAttribute('aria-live', 'assertive')
  127. document.body.appendChild(ariaLive)
  128. }
  129. return ariaLive;
  130. }
  131.  
  132. function updateAllPost() {
  133. let posts = document.querySelector('main div[style] > div > div:nth-of-type(2) > div').querySelectorAll('article[class]')
  134.  
  135. posts.forEach(post => {
  136. updatePost(post)
  137. });
  138. }
  139.  
  140. function updatePost(post){
  141. let postOwner = post.querySelector('div > div:nth-of-type(1) span[dir] a span[dir]');
  142. postOwner = postOwner.textContent;
  143.  
  144. createTitleIn(3, 'publicação de ' + postOwner, post)
  145. post.tabIndex = "0"
  146.  
  147.  
  148. if(!post.querySelector('section').parentNode.querySelector('article')){
  149. let pivot = post.querySelector('section');
  150. let textElem = pivot.nextSibling;
  151.  
  152. let sectionElem = document.createElement('article');
  153. sectionElem.tabIndex = '-1'
  154.  
  155. pivot.after(sectionElem)
  156. sectionElem.appendChild(textElem)
  157. }
  158.  
  159. let botoesLink = post.querySelectorAll('[role="button"]');
  160. botoesLink.forEach(botaoLink => {
  161. let img = botaoLink.querySelector('[role="img"]');
  162. if(img) {
  163. img.ariaHidden = 'true'
  164. botaoLink.ariaLabel = img.ariaLabel
  165. }
  166. })
  167.  
  168.  
  169. let botaoCompartilhar = post.querySelector('button');
  170. if(botaoCompartilhar){
  171. let img = botaoCompartilhar.querySelector('[role="img"]');
  172. if(img) {
  173. img.ariaHidden = 'true'
  174. botaoCompartilhar.ariaLabel = img.ariaLabel
  175. }
  176. }
  177. }
  178.  
  179. function createTitleIn(titleLevel, text, elemParent, id = null){
  180. if(!elemParent.querySelector('h' + titleLevel)){
  181. let title = document.createElement('h' + titleLevel)
  182. title.style.width = '0'
  183. title.style.height = '0'
  184. title.style.overflow = 'hidden'
  185. if (id != null) {
  186. title.id = id
  187. title.tabIndex = '0'
  188. }
  189. title.textContent = text
  190. elemParent.prepend(title)
  191. }
  192. }
  193.  
  194. function waitForElm(selector) {
  195. return new Promise(resolve => {
  196. if (document.querySelector(selector)) {
  197. return resolve(document.querySelector(selector));
  198. }
  199. const observer = new MutationObserver(mutations => {
  200. if (document.querySelector(selector)) {
  201. observer.disconnect();
  202. resolve(document.querySelector(selector));
  203. }
  204. });
  205. observer.observe(document.body, {
  206. childList: true,
  207. subtree: true
  208. });
  209. });
  210. }
  211. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址