Juick tweaks

Some feature testing

目前為 2016-09-06 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Juick tweaks
  3. // @namespace ForJuickCom
  4. // @description Some feature testing
  5. // @match *://juick.com/*
  6. // @author Killy
  7. // @version 1.4.1
  8. // @date 2016.09.02 - 2016.09.06
  9. // @run-at document-end
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_addStyle
  12. // ==/UserScript==
  13.  
  14.  
  15. function updateTagsOnAPostPage() {
  16. var tagsDiv = document.getElementsByClassName("msg-tags")[0];
  17. if(tagsDiv == null) { return; }
  18. var userId = document.getElementsByClassName("msg-avatar")[0].childNodes[0].childNodes[0].alt;
  19. tagsDiv.childNodes.forEach(function(item, i, arr) {
  20. var link = item.href;
  21. item.href = link.replace("tag/", userId + "/?tag=");
  22. });
  23. }
  24.  
  25. function updateTagsInFeed() {
  26. document.getElementById("content").getElementsByTagName('article').forEach(function(article, i, arr) {
  27. if(!article.hasAttribute('data-mid')) { return; }
  28. var userId = article.getElementsByClassName('msg-avatar')[0].getElementsByTagName('img')[0].alt;
  29. var tagsDiv = article.getElementsByClassName("msg-tags")[0];
  30. if(tagsDiv == null) { return; }
  31. tagsDiv.childNodes.forEach(function(item, j, arrj) {
  32. var link = item.href;
  33. item.href = link.replace("tag/", userId + "/?tag=");
  34. });
  35. });
  36. }
  37.  
  38. function addTagEditingLinkUnderPost() {
  39. var mtoolbar = document.getElementById("mtoolbar").childNodes[0];
  40. var canEdit = (mtoolbar.innerText.indexOf('Удалить') > -1) ? true : false;
  41. if(!canEdit) { return; }
  42. var linode = document.createElement("li");
  43. var anode = document.createElement("a");
  44. var mid = document.getElementById("content").getAttribute("data-mid");
  45. anode.href = "http://juick.com/post?body=%23" + mid + "+%2ATag";
  46. anode.innerHTML = "<div style='background-position: -16px 0'></div>Теги";
  47. linode.appendChild(anode);
  48. mtoolbar.appendChild(linode);
  49. }
  50.  
  51. function addYearLinks() {
  52. var userId = document.querySelector("div#ctitle a").innerText;
  53. var asideColumn = document.querySelector("aside#column");
  54. var hr1 = asideColumn.querySelector("p.tags + hr");
  55. var hr2 = document.createElement("hr");
  56. var linksContainer = document.createElement("p");
  57. var years = [
  58. {y: (new Date()).getFullYear(), b: ""},
  59. {y: 2015, b: "?before=2816362"},
  60. {y: 2014, b: "?before=2761245"},
  61. {y: 2013, b: "?before=2629477"},
  62. {y: 2012, b: "?before=2183986"},
  63. {y: 2011, b: "?before=1695443"}
  64. ];
  65. years.forEach(function(item, i, arr) {
  66. var anode = document.createElement("a");
  67. anode.href = "/" + userId + "/" + item.b;
  68. anode.innerText = item.y;
  69. linksContainer.appendChild(anode);
  70. linksContainer.appendChild(document.createTextNode (" "));
  71. });
  72. asideColumn.insertBefore(hr2, hr1);
  73. asideColumn.insertBefore(linksContainer, hr1);
  74. }
  75.  
  76. function loadTags(userId, doneCallback) {
  77. GM_xmlhttpRequest({
  78. method: "GET",
  79. url: "http://juick.com/" + userId + "/tags",
  80. onload: function(response) {
  81. var re = /<section id\=\"content\">[\s]*<p>([\s\S]+)<\/p>[\s]*<\/section>/i;
  82. var result = re.exec(response.responseText);
  83. if(result != null) {
  84. var tagsStr = result[1];
  85. var tagsContainer = document.createElement('p');
  86. tagsContainer.className += " tagsContainer";
  87. tagsContainer.innerHTML = tagsStr;
  88. doneCallback(tagsContainer);
  89. } else {
  90. console.log("no tags found");
  91. }
  92. }
  93. });
  94. }
  95.  
  96. function addEasyTagsUnderPostEditorSharp() {
  97. var userId = document.querySelector("nav#actions > ul > li:nth-child(2) > a").innerText.replace('@', '');
  98. loadTags(userId, function(tagsContainer){
  99. var messageform = document.getElementById("newmessage");
  100. var tagsfield = messageform.getElementsByTagName('div')[0].getElementsByClassName("tags")[0];
  101. messageform.getElementsByTagName('div')[0].appendChild(tagsContainer);
  102. sortAndColorizeTagsInContainer(tagsContainer, 50);
  103. tagsContainer.childNodes.forEach(function(item, i, arr) {
  104. var text = item.innerText;
  105. item.onclick = function() { tagsfield.value = (tagsfield.value + " " + text).trim() };
  106. item.href = "#";
  107. });
  108. });
  109. }
  110.  
  111. function parseRgbColor(colorStr){
  112. colorStr = colorStr.replace(/ /g,'');
  113. colorStr = colorStr.toLowerCase();
  114. var re = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;
  115. var bits = re.exec(colorStr);
  116. return [
  117. parseInt(bits[1]),
  118. parseInt(bits[2]),
  119. parseInt(bits[3])
  120. ];
  121. }
  122.  
  123. function sortAndColorizeTagsInContainer(tagsContainer, numberLimit) {
  124. tagsContainer.className += " tagsContainer";
  125. var linkColor = parseRgbColor(getComputedStyle(tagsContainer.getElementsByTagName('A')[0]).color);
  126. var backColor = parseRgbColor(getComputedStyle(document.documentElement).backgroundColor);
  127. var p0 = 0.7; // 70% of color range is used for color coding
  128. var maxC = 0.1;
  129. var sortedTags = [];
  130. tagsContainer.children.forEach(function(item, i, arr) {
  131. var anode = (item.tagName == 'A') ? item : item.getElementsByTagName('a')[0];
  132. var c = Math.log(parseInt(anode.title));
  133. maxC = (c > maxC) ? c : maxC;
  134. sortedTags.push({ c: c, a: anode, text: anode.innerText.toLowerCase()});
  135. });
  136. if((numberLimit != null) && (sortedTags.length > numberLimit)) {
  137. sortedTags = sortedTags.slice(0, numberLimit);
  138. }
  139. sortedTags.sort(function (a, b) {
  140. return a.text.localeCompare(b.text);
  141. });
  142. while (tagsContainer.firstChild) {
  143. tagsContainer.removeChild(tagsContainer.firstChild);
  144. }
  145. sortedTags.forEach(function(item, i, arr) {
  146. var c = item.c;
  147. var p = (c/maxC-1)*p0+1; // normalize to [p0..1]
  148. var r = Math.round(linkColor[0]*p + backColor[0]*(1-p));
  149. var g = Math.round(linkColor[1]*p + backColor[1]*(1-p));
  150. var b = Math.round(linkColor[2]*p + backColor[2]*(1-p));
  151. item.a.style.color = "rgb("+r+","+g+","+b+")";
  152. tagsContainer.appendChild(item.a);
  153. tagsContainer.appendChild(document.createTextNode (" "));
  154. });
  155. }
  156.  
  157. function sortTagsPage() {
  158. var tagsContainer = document.querySelector("section#content > p");
  159. sortAndColorizeTagsInContainer(tagsContainer, null);
  160. }
  161.  
  162. function loadUsers(unprocessedUsers, processedUsers, doneCallback) {
  163. if(unprocessedUsers.length == 0) {
  164. doneCallback();
  165. } else {
  166. var user = unprocessedUsers.splice(0,1)[0];
  167. GM_xmlhttpRequest({
  168. method: "GET",
  169. //url: "http://api.juick.com/messages?uname=" + user.id,
  170. url: "http://juick.com/" + user.id + "/",
  171. onload: function(response) {
  172. var re = /datetime\=\"([^\"]+)\"/;
  173. var result = re.exec(response.responseText);
  174. if(result != null) {
  175. var dateStr = result[1];
  176. var date = new Date(dateStr);
  177. user.date = date;
  178. user.a.appendChild(document.createTextNode (" (" + date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() + ")" ));
  179. } else {
  180. console.log("got null for " + user.id);
  181. }
  182. processedUsers.push(user);
  183. setTimeout(function(){ loadUsers(unprocessedUsers, processedUsers, doneCallback); }, 100);
  184. }
  185. });
  186. }
  187. };
  188.  
  189. function sortUsers() {
  190. var contentBlock = document.getElementById("content");
  191. var button = document.getElementById("usersSortingButton");
  192. button.parentNode.removeChild(button);
  193. var usersTable = document.querySelector("table.users");
  194. var unsortedUsers = [];
  195. var sortedUsers = [];
  196. usersTable.firstChild.children.forEach(function(tr, i, arr){
  197. tr.children.forEach(function(td, j, arrj){
  198. var anode = td.firstChild;
  199. var userId = anode.pathname.replace(/\//g, '');
  200. unsortedUsers.push({a: anode, id: userId, date: (new Date(1970, 1, 1))});
  201. });
  202. });
  203. loadUsers(unsortedUsers, sortedUsers, function(){
  204. sortedUsers.sort(function (b, a) {
  205. return ((a.date > b.date) - (a.date < b.date));
  206. });
  207. usersTable.parentNode.removeChild(usersTable);
  208. var ul = document.createElement("ul");
  209. ul.className = 'users';
  210. sortedUsers.forEach(function(user, i, arr){
  211. var li = document.createElement("li");
  212. li.appendChild(user.a);
  213. ul.appendChild(li);
  214. });
  215. contentBlock.appendChild(ul);
  216. });
  217. }
  218.  
  219. function addUsersSortingButton() {
  220. var contentBlock = document.getElementById("content");
  221. var usersTable = document.querySelector("table.users");
  222. var button = document.createElement("button");
  223. button.id = 'usersSortingButton';
  224. button.innerText="Sort by date";
  225. button.onclick = sortUsers;
  226. contentBlock.insertBefore(button, usersTable);
  227. }
  228.  
  229. function addStyle() {
  230. GM_addStyle(
  231. ".tagsContainer a { min-width: 25px; display: inline-block; text-align: center; }" // min-width for tags accessibility
  232. );
  233. }
  234.  
  235. var isPost = document.getElementById("content").hasAttribute("data-mid");
  236. var isFeed = (document.getElementById("content").getElementsByTagName('article').length > 1);
  237. var isPostEditorSharp = (document.getElementById('newmessage') === null) ? false : true;
  238. var isTagsPage = window.location.pathname.endsWith('/tags');
  239. var isUserColumn = (document.querySelector("aside#column > div#ctitle") === null) ? false : true;
  240. var isUsersTable = (document.querySelector("table.users") === null) ? false : true;
  241.  
  242. addStyle();
  243. if(isPost) {
  244. updateTagsOnAPostPage();
  245. addTagEditingLinkUnderPost();
  246. }
  247. if(isFeed) {
  248. updateTagsInFeed();
  249. }
  250. if(isUserColumn) {
  251. addYearLinks();
  252. }
  253. if(isPostEditorSharp) {
  254. addEasyTagsUnderPostEditorSharp();
  255. }
  256. if(isTagsPage) {
  257. sortTagsPage();
  258. }
  259. if(isUsersTable) {
  260. addUsersSortingButton();
  261. }