GitHub Sortable Filelist

appends sorting function to github directories

当前为 2014-11-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Sortable Filelist
  3. // @namespace trespassersW
  4. // @description appends sorting function to github directories
  5. // @include https://github.com/*
  6. // @version 14.11.11.1
  7. // .1 optimization; span.title
  8. // @created 2014-11-10
  9. // @updated 2014-11-11
  10. // @author trespassersW
  11. // @licence MIT
  12. // @run-at document-end
  13. // @grant GM_none
  14. // ==/UserScript==
  15.  
  16. if(document.querySelector('.file-wrap')){
  17.  
  18. (function(){ "use strict";
  19. var llii=0; function _l(m){ if(1) console.log(++llii +': '+m) }
  20.  
  21. function stickStyle(css){
  22. var s=document.createElement("style"); s.type="text/css";
  23. s.appendChild(document.createTextNode(css));
  24. return (document.head||document.documentElement).appendChild(s);
  25. }
  26. function insBefore(n,e){
  27. return e.parentNode.insertBefore(n,e);
  28. }
  29. function insAfter(n,e){
  30. if(e.nextElementSibling)
  31. return e.parentNode.insertBefore(n,e.nextElementSibling);
  32. return e.parentNode.appendChild(n);
  33. }
  34. function outerNode(target, node) {
  35. if (target.nodeName==node) return target;
  36. if (target.parentNode)
  37. while (target = target.parentNode) try{
  38. if (target.nodeName==node)
  39. return target;
  40. }catch(e){};
  41. return null;
  42. }
  43.  
  44. function css(){
  45. stickStyle('\
  46. .fsort-butt, .tables.file {position: relative; }\
  47. .fsort-butt:before{\
  48. position: absolute; left:1.5em; top: -1em; \
  49. cursor: pointer;\
  50. content: "";\
  51. z-index:99999;\
  52. width: 0; height: 0;\
  53. opacity:.2;\
  54. }\
  55. .fsort-asc:before,\
  56. .fsort-desc.fsort-sel:hover:before\
  57. {\
  58. border-left: 6px solid transparent;\
  59. border-right: 6px solid transparent;\
  60. border-bottom: 14px solid #444;\
  61. border-top: 0;\
  62. }\
  63. .fsort-desc:before,\
  64. .fsort-asc.fsort-sel:hover:before{\
  65. border-left: 6px solid transparent;\
  66. border-right: 6px solid transparent;\
  67. border-bottom: 0;\
  68. border-top: 14px solid #444;\
  69. }\
  70. .fsort-butt.fsort-desc.fsort-sel:hover:before,\
  71. .fsort-butt.fsort-asc.fsort-sel:before{\
  72. border-bottom: 14px solid #4183C4;\
  73. border-top: 0;\
  74. }\
  75. .fsort-butt.fsort-desc.fsort-sel:before,\
  76. .fsort-butt.fsort-asc.fsort-sel:hover:before{\
  77. border-bottom: 0;\
  78. border-top: 14px solid #4183C4;\
  79. }\
  80. \
  81. .fsort-butt.fsort-sel:before{ opacity: .6 }\
  82. .fsort-butt:hover:before{ opacity: 1 !important;}\
  83. /* patches */\
  84. table.files td.age {text-align: left !important;}\
  85. table.files td.message {overflow-y: visible !important;}\
  86. ');//#80A6CD
  87. }
  88. var ii=0;
  89. var d0=[0,0,1];
  90. var C=[{c:1, d: 0, s: 0},{c:2, d: 0, s: 0},{c:3, d: 1, s: 0}];
  91. var ASC;
  92. var oa=[],ca=[];
  93. var D=document, TB;
  94. var catcher;
  95. function setC(n){
  96. for(var i=0,il=C.length; i<il; i++ ){
  97. if(i!=n) C[i].s= 0, C[i].d=d0[i];
  98. else C[i].s=1;
  99. oa[i].className='fsort-butt fsort-'+(C[i].d?'desc':'asc')+(C[i].s?' fsort-sel':'') ;
  100. oa[i].title=C[i].d? '\u21ca' : '\u21c8';
  101. }
  102. }
  103.  
  104. function isDir(x){
  105. return (TB.rows[x].cells[0].querySelector("span.octicon-file-directory")) != null;
  106. }
  107.  
  108. var sDir,sCells;
  109.  
  110. var sort_p= [ // prepare data for sorting
  111. function(){
  112. sDir=[],sCells=[];
  113. for(var tl=TB.rows.length, a=0; a<tl; a++){
  114. sDir.push(isDir(a));
  115. sCells.push(TB.rows[a].cells[1].querySelector('span.css-truncate-target a').textContent);
  116. }
  117. }
  118. ,
  119. function(){
  120. sDir=[],sCells=[];
  121. for(var tl=TB.rows.length, a=0; a<tl; a++){
  122. sDir.push(isDir(a));
  123. sCells.push(TB.rows[a].cells[2].querySelector('span.css-truncate').textContent);
  124. }
  125. }
  126. ,
  127. function(){
  128. sDir=[],sCells=[];
  129. for(var tl=TB.rows.length, a=0; a<tl; a++){
  130. sDir.push(isDir(a));
  131. sCells.push(TB.rows[a].cells[3].querySelector('span.css-truncate>time').getAttribute('datetime'));
  132. }
  133. }
  134. ]
  135.  
  136. function sort_fn(a,b){
  137. var x=sDir[a], y=sDir[b];
  138. if(x!=y) return ((x<y)<<1)-1;
  139. x= sCells[a], y= sCells[b];
  140. return x==y? 0: (((x>y)^ASC)<<1)-1;
  141. }
  142. var CNn={content: 0, message: 1, age: 2}
  143.  
  144. function oClr(){
  145. var o= catcher.querySelectorAll('.fsort-butt')
  146. for(var ol=o.length,i=0;i<ol;i++)
  147. o[i].parentNode.removeChild(o[i]);
  148. }
  149. //
  150. function doSort(t){
  151. TB=outerNode(t,'TBODY');
  152. var tb=[],ix=[], i, tl;
  153. if(!TB) throw "*GHSFL* TBODY not found";
  154. var n=CNn[t.parentNode.className];
  155. if(typeof n=="undefined") throw "*GHSFL* undefined col";
  156. _l('n:'+n);
  157. tl=TB.rows.length;
  158. ASC=C[n];
  159. ASC=C[n].d^=C[n].s;
  160. for( i=0; i<tl; i++)
  161. ix.push(i);
  162. oClr();
  163. sort_p[n]();
  164. ix.sort(sort_fn);
  165. for( i=0; i<tl; i++)
  166. tb.push(TB.rows[ix[i]].innerHTML);
  167. for( i=0; i<tl; i++)
  168. TB.rows[i].innerHTML=tb[i];
  169. setC(n);
  170. gitDir1(0);
  171. }
  172.  
  173. function onClik(e){doSort(e.target)}
  174.  
  175. function gitDir1(x){
  176. if(x && document.querySelector('.fsort-butt')) {
  177. _l('gitDir'+x+' - already'); return;
  178. }
  179. _l('gitDir'+x)
  180. var c,o;
  181. ca=[];
  182. c= D.querySelector('.file-wrap table.files td.content >span');
  183. if(!c) throw '*GHSFL* no content';
  184. ca.push(c);
  185. c=D.querySelector('.file-wrap table.files td.message >span');
  186. if(!c) throw '*GHSFL* no messages';
  187. ca.push(c);
  188. c=D.querySelector('.file-wrap table.files td.age >span');
  189. if(!c) throw '*GHSFL* no ages';
  190. ca.push(c);
  191. if(x){ oClr(); oa=[];
  192. o=D.createElement('span');
  193. o.textContent='';
  194. oa.push(o);
  195. o=o.cloneNode(true);
  196. oa.push(o);
  197. o=o.cloneNode(true);
  198. oa.push(o);
  199. setC(-1);
  200. }
  201. insBefore(oa[0],ca[0]);
  202. insBefore(oa[1],ca[1]);
  203. insBefore(oa[2],ca[2]);
  204. }
  205.  
  206. function gitDir(){
  207. gitDir1(1);
  208. }
  209.  
  210. catcher= D.querySelector('#js-repo-pjax-container');
  211. if(!catcher) throw "*GHSFL* err0r";
  212.  
  213. catcher.addEventListener('mousedown',function(e){
  214. if(e.target.nodeName && e.target.nodeName=='SPAN' &&
  215. e.target.className.indexOf('fsort-butt')>-1)
  216. { onClik(e); }
  217. }
  218. ,false);
  219. _l('startup()');
  220. css();
  221. gitDir();
  222. window.GH_SFL=C;
  223. var target = catcher; //document.body; //D.querSelector('.file-wrap');
  224. var MO = window.MutationObserver;
  225. if(!MO) MO= window.WebKitMutationObserver;
  226. if(!MO) return;
  227. var observer = new MO(function(mutations) {
  228. mutations.forEach(function(m) {
  229. if( m.type= "attributes" &&
  230. m.target.nodeName == 'DIV' &&
  231. m.target.className == "file-wrap" )
  232. gitDir(0);
  233. });
  234. });
  235. observer.observe(D.body, { attributes: true, subtree: true } );
  236. /* attributes: true , childList: true, subtree: true,
  237. characterData: true, attributeOldValue:true, characterDataOldValue:true
  238. */
  239.  
  240. })()};
  241.  
  242. /*
  243. to do: persistent settings; sorting by file extensions; toggling date/time display mode
  244. ... do we really need it?
  245. */