GAB User Autocomplete

User Autocomplete requirement 2 of 2: show a pop-up of users that match the @mention found at the end of the text entry

  1. // ==UserScript==
  2. // @name GAB User Autocomplete
  3. // @namespace https://gab.ai/Jeremy20_9
  4. // @version 0.1
  5. // @description User Autocomplete requirement 2 of 2: show a pop-up of users that match the @mention found at the end of the text entry
  6. // @author Jeremiah 20:9
  7. // @match https://gab.ai/home
  8. // @grant none
  9. // @require https://code.jquery.com/jquery-1.8.2.js
  10. // ==/UserScript==
  11. var followers = localStorage.getItem("gab-user-followers");
  12. var following = localStorage.getItem("gab-user-following");
  13. var availableTags = [];
  14.  
  15. if(followers)
  16. {
  17. availableTags = availableTags.concat(JSON.parse(followers));
  18. }
  19. if(following)
  20. {
  21. availableTags = availableTags.concat(JSON.parse(following));
  22. }
  23. var subset = [];
  24. var itvcheck = -1;
  25. var choiceidx = 0;
  26. function checkfortxt()
  27. {
  28. if($( ".composer--open > .composer__content > textarea" ).length > 0)
  29. {
  30. clearInterval(itvcheck);
  31. var ops = document.createElement("div");
  32. $(ops).css("position", "absolute");
  33. $(ops).css("left", "50px");
  34. $(ops).css("bottom", "0px");
  35. $(ops).css("width", "300px");
  36. $(ops).css("height", "100px");
  37. $(ops).css("background-color", "white");
  38. $(ops).css("box-shadow", "0px 0px 2px rgba(0,0,0,.5)");
  39. $(ops).css("display", "none");
  40. $(".composer__content").append(ops);
  41. $( ".composer__content > textarea" ).on("keydown", function(evt){
  42. var txt = $(".composer__content > textarea").val();
  43. var regex = new RegExp("^[a-zA-Z0-9_-]+$");
  44. var str = String.fromCharCode(!evt.charCode ? evt.which : evt.charCode);
  45. if (!regex.test(str) && evt.which != 38 && evt.which != 40 && evt.which != 13 && evt.which != 8 && evt.which != 46) {
  46. $(ops).css("display", "none");
  47. return;
  48. }
  49. else if(evt.which != 38 && evt.which != 40 && evt.which != 13 && evt.which != 8 && evt.which != 46)
  50. txt += evt.key;
  51. var rex = /@[A-Za-z]+[A-Za-z0-9_-]*$/g;
  52. var userinfo = rex.exec(txt);
  53.  
  54. if(!userinfo)
  55. {
  56. $(ops).css("display", "none");
  57. return;
  58. }
  59. var user = userinfo[0].substr(1); // strip the "@"
  60. subset = [];
  61. for(var a = 0; a < availableTags.length && subset.length < 3; a++)
  62. {
  63. if(user.toLowerCase() == availableTags[a].atname.toLowerCase().substr(0,user.length) || user.toLowerCase() == availableTags[a].name.toLowerCase().substr(0,user.length))
  64. {
  65. var found = false;
  66. for(var s in subset)
  67. {
  68. if(availableTags[a].atname == subset[s].atname)
  69. {
  70. found = true;
  71. break;
  72. }
  73. }
  74. if(!found)
  75. subset.push(availableTags[a]);
  76. }
  77. }
  78. if(subset.length === 0)
  79. {
  80. $(ops).css("display", "none");
  81. return;
  82. }
  83. else
  84. {
  85. $(ops).css("height", (subset.length * 30) + "px");
  86. }
  87. if(evt.which == 38) // up
  88. {
  89. evt.preventDefault();
  90. choiceidx--;
  91. if(choiceidx < 0)
  92. choiceidx = subset.length - 1;
  93. }
  94. else if(evt.which == 40) //down
  95. {
  96. evt.preventDefault();
  97. choiceidx++;
  98. if(choiceidx >= subset.length)
  99. choiceidx = 0;
  100. }
  101. else if(evt.which == 13)
  102. {
  103. evt.preventDefault();
  104. $(".composer__content > textarea").val(txt.substr(0, txt.length-user.length) + subset[choiceidx].atname + " ");
  105. $(ops).css("display", "none");
  106. return;
  107. }
  108. var render = "";
  109. for(var c = 0; c < subset.length; c++)
  110. {
  111. render += "<div style='padding:3px; position:absolute;width:300px;height:30px;top:" + (c * 30) + "px;";
  112. if(c == choiceidx)
  113. render += "background-color:blue;color:white;";
  114. else
  115. render += "color:black;";
  116. render += "'>";
  117. render += "<img src='"+subset[c].pic+"' style='height:24px; width:24px; border-radius:12px; margin-right:4px' align='left' />";
  118. render += "" + subset[c].name + "";
  119. render += "<span style='margin-left:4px;font-style:italic;opacity:0.7;'>@" + subset[c].atname + "</span>";
  120. render += "</div>";
  121. }
  122. $(ops).html(render);
  123. $(ops).css("display", "block");
  124. });
  125. }
  126. }
  127. $("document").ready(function(){
  128. itvcheck = setInterval(checkfortxt, 500);
  129. });