phpmyadmin relation links

When browsing data, adds a link to foreign key values to open the related row. When looking at the table structure, highlights index fields and adds a link to the related table for foreign keys

  1. // ==UserScript==
  2. // @name phpmyadmin relation links
  3. // @author ameboide
  4. // @namespace http://userscripts.org/scripts/show/118889
  5. // @description When browsing data, adds a link to foreign key values to open the related row. When looking at the table structure, highlights index fields and adds a link to the related table for foreign keys
  6. // @version 1.01
  7. // @include */phpmyadmin/*
  8. // ==/UserScript==
  9. function $(q, elem){
  10. if(!elem) elem = document;
  11. return elem.querySelector(q);
  12. }
  13.  
  14. function $$(q, elem){
  15. if(!elem) elem = document;
  16. return elem.querySelectorAll(q);
  17. }
  18.  
  19. var urls = ['tbl_change', 'tbl_select'];
  20. for(var i=0; i<urls.length; i++){
  21. var omnipresente = urls[i];
  22. var urlBase = $('[href*="'+omnipresente+'.php?"]');
  23. if(urlBase) break;
  24. }
  25. if(urlBase){
  26. urlBase = urlBase.href;
  27.  
  28. //retorna el ancestro mas cercano de ese tipo
  29. function ancestro(nodo, tag){
  30. while(nodo && nodo.nodeName != tag.toUpperCase()) nodo = nodo.parentNode;
  31. return nodo;
  32. }
  33.  
  34. //usa los datos de las FK para linkear (primero con lo cacheado, despues actualiza el cache)
  35. function ejecutar(rellenar){
  36. //si ya habia visitado esta tabla, tengo las claves foraneas guardadas
  37. var codigo_cache = document.location.host + ' : ' +
  38. urlBase.match(/(\?|&)db=(\w+)/)[2] + ' . ' +
  39. urlBase.match(/(\?|&)table=(\w+)/)[2];
  40.  
  41. var cache = GM_getValue(codigo_cache, null);
  42. try{ if(cache) rellenar(JSON.parse(cache)); }
  43. catch(e){}
  44.  
  45. //leer la pag de las claves foraneas (si estaba cacheado, leo igual para actualizar)
  46. var xhr = new XMLHttpRequest();
  47. xhr.onreadystatechange = function(){
  48. if (xhr.readyState == 4 && xhr.status == 200){
  49. try{
  50. var div = document.createElement('div');
  51. div.innerHTML = xhr.responseText;
  52.  
  53. var claves = {};
  54.  
  55. var opts = $$('select[name^="destination"] option[selected]', div);
  56. for(var i=0; i<opts.length; i++){
  57. var opt = opts[i];
  58. var tr = ancestro(opt, 'tr');
  59.  
  60. var fk = opt.value.replace(/`/g, '').split('.');
  61. var ondel = $('select[name^="on_delete"] option[selected]', tr);
  62. var onup = $('select[name^="on_update"] option[selected]', tr);
  63.  
  64. claves[tr.firstElementChild.textContent.trim()] = {
  65. db: fk[0],
  66. tabla: fk[1],
  67. campo: fk[2],
  68. ondel: ondel ? ondel.value : '',
  69. onup: onup ? onup.value : ''
  70. };
  71. }
  72.  
  73. var claves_str = JSON.stringify(claves);
  74. //si no es lo mismo q tenia cacheado, vuelvo a rellenar con la info nueva
  75. if(claves_str != cache){
  76. //workaround para error raro
  77. setTimeout(function() {
  78. GM_setValue(codigo_cache, claves_str);
  79. }, 0);
  80. rellenar(claves);
  81. }
  82. }
  83. catch(e){}
  84. }
  85. }
  86. xhr.open('GET', urlBase.replace(omnipresente, 'tbl_relation'), true);
  87. xhr.send(null);
  88. }
  89.  
  90. var listaCampos = $$('#tablestructure tbody th');
  91. if(listaCampos.length){ //estoy en la estructura de la tabla
  92. //tds_campos['nombre_del_campo'] = td
  93. var tds_campos = {};
  94. for(var i=0; i<listaCampos.length; i++){
  95. var campo = listaCampos[i];
  96. var txt = campo.textContent.trim();
  97. tds_campos[txt] = campo;
  98.  
  99. //id sin indice -> rojo claro / codigo sin indice -> rojo oscuro
  100. if(txt.match(/^id_|_id$/i) || txt.match(/^Id[A-Z]|[A-Z]Id$/)) campo.style.color = '#f00';
  101. else if(txt.match(/^codigo_|_codigo$|^codigo$/i) || txt.match(/^Codigo[A-Z]|[A-Z]Codigo$|Cod[A-Z]|[A-Z]Cod/)) campo.style.color = '#800';
  102. }
  103.  
  104. //idx -> azul oscuro
  105. var idxs = $$('#table_indexes tbody tr:not(.tblFooters) td:last-of-type');
  106. if(!idxs.length){
  107. var edit = $('[href^="tbl_indexes.php"]');
  108. if(edit) idxs = $$('td:nth-of-type(6)', ancestro(edit, 'tr').parentNode);
  109. }
  110. for(i=0; i<idxs.length; i++){
  111. var campo = tds_campos[idxs[i].textContent.trim()];
  112. if(campo) campo.style.color = '#008';
  113. }
  114.  
  115. var matches = $('a.tabactive').href.match(/\/(\w+\.php).*token=(\w+)/);
  116. var url = matches[1];
  117. var token = matches[2];
  118.  
  119. //FK -> link azul claro
  120. ejecutar(function(claves){
  121. for(var campo in claves){
  122. if(!tds_campos[campo]) continue;
  123. var fk = claves[campo];
  124.  
  125. var a = document.createElement('a');
  126. a.href = url+'?db='+fk.db+'&token='+token+'&table='+fk.tabla;
  127. a.title = fk.tabla+' . '+fk.campo+
  128. (fk.ondel?' [DEL: '+fk.ondel+']':'')+
  129. (fk.onup?' [UP: '+fk.onup+'] ':'');
  130. a.id = 'link_fk_' + campo;
  131. a.innerHTML = ' &gt; ['+fk.tabla+
  132. (fk.ondel?' D:'+fk.ondel[0]:'')+
  133. (fk.onup?' U:'+fk.onup[0]:'')+']';
  134. a.style.cssFloat = 'left';
  135. a.style.fontSize = 'xx-small';
  136.  
  137. var link_viejo = document.getElementById(a.id);
  138. if(link_viejo) tds_campos[campo].removeChild(link_viejo);
  139.  
  140. tds_campos[campo].appendChild(a);
  141. tds_campos[campo].style.color = '#00f';
  142. }
  143. });
  144. }
  145. else if($('#table_results')){ //estoy viendo los datos
  146. //indices['nombre_campo'] = indice_del_td_con_el_valor
  147. var indices = {};
  148. var ths = $$('th', $('#table_results th:not([colspan])').parentNode);
  149. for(var i=0, idx=0; i<ths.length; i++){
  150. var th = ths[i];
  151. var colspan = th.getAttribute('colspan');
  152. if(colspan){
  153. idx += parseInt(colspan);
  154. continue;
  155. }
  156.  
  157. var a = $('a', th);
  158. var campo = a ? a : th.childNodes[0];
  159. indices[campo.textContent.trim()] = ++idx;
  160. }
  161.  
  162. //FK -> link a un select * from fk.tabla where fk.campo = valor
  163. ejecutar(function(claves){
  164. for(var campo in claves){
  165. var idx = indices[campo];
  166. if(!idx) continue;
  167. var fk = claves[campo];
  168.  
  169. var url = urlBase.replace(omnipresente, 'sql')
  170. .replace(/(db=)\w+/, '$1'+fk.db)
  171. .replace(/(table=)\w+/, '$1'+fk.tabla) +
  172. '&show_query=1&sql_query=' +
  173. encodeURI("SELECT * FROM "+fk.tabla+" WHERE "+fk.campo+" = '-valor-'");
  174.  
  175. //reemplazar los valores por links q entregan la fila asociada
  176. var tds = $$('#table_results td:nth-of-type('+idx+')');
  177. for(var j=0; j<tds.length; j++){
  178. var td = tds[j];
  179. if(td.innerHTML.trim() == '<i>NULL</i>') continue;
  180.  
  181. td.innerHTML = '<a href="'+url.replace('-valor-', td.textContent)+
  182. '" title="'+fk.tabla+' . '+fk.campo+'">'+td.textContent+'</a>';
  183. }
  184. }
  185. });
  186. }
  187. }