Facebook Notifications Highlighter

Highlights your interesting notifications.

当前为 2017-03-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Facebook Notifications Highlighter
  3. // @namespace http://www.JamesKoss.com/
  4. // @version 2.0.0
  5. // @description Highlights your interesting notifications.
  6. // @author James Koss
  7. // @match https://www.facebook.com/*
  8. // @supportURL https://greasyfork.org/en/scripts/27189-facebook-your-notifications-highlighter/feedback
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13. var first = true;
  14. var hidden = false;
  15. var updater = null;
  16. var fbNotificationsFlyout = null;
  17. var ulElement = null;
  18. var firstNotification = null;
  19. var lastNotification = null;
  20. // Wait for page to load.
  21. window.addEventListener('load', function() {
  22. startScript();
  23. }, false);
  24. function startScript() {
  25. fbNotificationsFlyout = document.getElementById('fbNotificationsFlyout');
  26. // Listen to a click on the notifications button on FB.
  27. var fbNotificationsJewel = document.getElementById("fbNotificationsJewel");
  28. fbNotificationsJewel.addEventListener("click", onclickJewel);
  29. // Auto updater.
  30. updater = setInterval(updateView, 500);
  31. }
  32. // Clicking the notifications button on FB.
  33. function onclickJewel(e) {
  34. if (e.which === 1) {
  35. updateNotifications();
  36. }
  37. }
  38. // Check if notifications need updating while displayed.
  39. function updateView() {
  40. // Notifications must be visible and ready.
  41. if (fbNotificationsFlyout.offsetParent === null) return;
  42. if (ulElement === null) return;
  43. // Request more notifications.
  44. if (hidden === true) {
  45. // Scrollbar hidden.
  46. var sb = fbNotificationsFlyout.querySelector('div.uiScrollableAreaGripper.hidden_elem');
  47. // Or scrolled to bottom.
  48. var wrap = fbNotificationsFlyout.querySelector('div.uiScrollableAreaWrap');
  49. var bottom = wrap.offsetHeight + wrap.scrollTop >= wrap.scrollHeight - 10;
  50. // And loading jewel must exist, otherwise finished all loadings.
  51. var jewel = fbNotificationsFlyout.querySelector('div.uiScrollableAreaContent span.jewelLoading');
  52. if (jewel && (sb !== null || bottom === true)) {
  53. // Fake a scroll event for loader.
  54. var e = new Event('scroll');
  55. fbNotificationsFlyout.querySelector('div.uiScrollableArea').dispatchEvent(e);
  56. }
  57. }
  58. var curFirstNotification = ulElement.firstChild;
  59. var curLastNotification = ulElement.lastChild;
  60. // Update view, if new notifications, or loaded old ones.
  61. if (curLastNotification !== lastNotification ||
  62. curFirstNotification !== firstNotification) {
  63. updateNotifications();
  64. updateVisibility();
  65. }
  66. firstNotification = curFirstNotification;
  67. lastNotification = curLastNotification;
  68. }
  69. // After clicking the notification, remove highlight color and eventListener.
  70. function removeHighlight(e) {
  71. e.currentTarget.removeEventListener("click", removeHighlight, false);
  72. e.currentTarget.style.backgroundColor = "";
  73. if (e.currentTarget.paramA !== null) {
  74. e.currentTarget.paramA.style.backgroundColor = "";
  75. }
  76. // Remove highlight class.
  77. e.currentTarget.classList.remove("highlightedNotification");
  78. updateVisibility();
  79. }
  80. // Update notifications visibility.
  81. function updateVisibility() {
  82. var notificationsOld = ulElement.querySelectorAll('li:not(.highlightedNotification), li.highlightedReact');
  83. for (var i=0; i < notificationsOld.length; i++) {
  84. var displayMode = null;
  85. if (hidden === true) displayMode = 'none';
  86.  
  87. notificationsOld[i].style.display = displayMode;
  88. }
  89. }
  90. // Update relevant notifications with highlight.
  91. function updateNotifications() {
  92. if (ulElement === null) ulElement = fbNotificationsFlyout.querySelector('ul');
  93. // Delay until notifications elements are available.
  94. if (ulElement === null) {
  95. setTimeout(function(){ updateNotifications(); }, 500);
  96. return;
  97. }
  98. // On first viewing.
  99. if (first === true) {
  100. first = false;
  101. // Hide/Show option.
  102. var headerActions = fbNotificationsFlyout.querySelector('div.uiHeaderActions');
  103. var toggleOption = document.createElement("a");
  104. toggleOption.style = "font-weight: bold;";
  105. toggleOption.title = "Hide unimportant notifications.";
  106. toggleOption.innerHTML = 'Hide Unimportant';
  107. toggleOption.onclick = function(e) {
  108. e.stopPropagation();
  109. e.preventDefault();
  110. if (hidden === true) {
  111. hidden = false;
  112. toggleOption.title = "Hide unimportant notifications.";
  113. toggleOption.innerHTML = 'Hide Unimportant';
  114. } else {
  115. hidden = true;
  116. toggleOption.title = "Show unimportant notifications.";
  117. toggleOption.innerHTML = 'Show Unimportant';
  118. }
  119. updateVisibility();
  120. };
  121. var spacer = document.createElement("span");
  122. spacer.setAttribute("role", "presentation");
  123. spacer.setAttribute("aria-hidden", "true");
  124. spacer.innerHTML = ' · ';
  125. headerActions.insertBefore(toggleOption, headerActions.firstChild);
  126. headerActions.insertBefore(spacer, toggleOption.nextSibling);
  127. }
  128. // Only check new notifications.
  129. var notificationsNew = ulElement.querySelectorAll('li.jewelItemNew');
  130.  
  131. for (var i = 0; i < notificationsNew.length; i++) {
  132. var current = notificationsNew[i];
  133. var notificationParent = current.querySelector('div[class="_4l_v"]');
  134. var notificationYour = notificationParent.querySelectorAll('span');
  135. // match 1 for interest highlight, 2 for "Like" highlight.
  136. var match = false;
  137. for (var j=0; j < notificationYour.length; j++) {
  138. var cur = notificationYour[j];
  139. var t = cur.textContent;
  140. // Relevant text inside notification element.
  141. if (t.indexOf("replied to your") !== -1 ||
  142. t.indexOf("commented on your") !== -1 ||
  143. t.indexOf("shared your") !== -1 ||
  144. t.indexOf("mentioned you") !== -1 ||
  145. t.indexOf("tagged you") !== -1 ||
  146. t.indexOf("you're tagged in") !== -1 ||
  147. t.indexOf("made you") !== -1 ||
  148. t.indexOf("also replied") !== -1 ||
  149. (t.indexOf("replied to") !== -1 && t.indexOf("on your") !== -1)) {
  150. match = 1;
  151. break;
  152. } else if (t.indexOf("likes your") !== -1 ||
  153. t.indexOf("like your") !== -1 ||
  154. t.indexOf("liked your") !== -1 ||
  155. t.indexOf("reacted to") !== -1) {
  156. match = 2;
  157. break;
  158. } else if (t.indexOf("approved your") !== -1 ||
  159. t.indexOf("changed the name of the") !== -1 ||
  160. t.indexOf("changed the type of the") !== -1) {
  161. match = 3;
  162. break;
  163. } else if (t.indexOf("needs review") !== -1 ||
  164. t.indexOf("your Timeline") !== -1 ||
  165. t.indexOf("flagged as possible spam") !== -1) {
  166. match = 4;
  167. break;
  168. }
  169. }
  170. // No match.
  171. if (match === false) {
  172. continue;
  173. }
  174. // Remember highlight.
  175. current.classList.add("highlightedNotification");
  176. // Select color by matching value.
  177. var color;
  178. switch(match) {
  179. case 1:
  180. color = "#c3d4ef"; // darker blue
  181. break;
  182. case 2:
  183. color = "#faedf8"; // light pink
  184. current.classList.add("highlightedReact");
  185. break;
  186. case 3:
  187. color = "#d7f4d7"; // light green
  188. break;
  189. case 4:
  190. color = "#dec3ef"; // darker purple
  191. break;
  192. }
  193. // Update the li & a elements backgrounds.
  194. var a = current.querySelector('a[class="_33e _1_0e"]');
  195. if (a !== null) {
  196. a.style.backgroundColor = color;
  197. }
  198. current.style.backgroundColor = color;
  199. current.paramA = a; // Pass to object, for highlight removal after clicked.
  200. current.addEventListener("click", removeHighlight, false);
  201. }
  202. }
  203. })();