Answer to...

Shows the comment for which this comment is an answer

  1. // Answer to...
  2. // by Yuriy Babak aka Inversion (http://inversion.habrahabr.ru/), mailto: yura.des@gmail.com
  3.  
  4. // ==UserScript==
  5. // @name Answer to...
  6. // @version 1.3.5
  7. // @namespace Habrahabr
  8. // @description Shows the comment for which this comment is an answer
  9. // @include http://habrahabr.ru/*
  10. // ==/UserScript==
  11.  
  12. /*
  13.  
  14. v1.3.5 (10.03.13)
  15. - fixed: broken commentd body finder
  16.  
  17. v1.3.4 (09.12.12)
  18. - оптимизирован враппер
  19.  
  20. v1.3.3 (12.04.12)
  21. v1.3.2 (01.04.12)
  22. - исправлена совместимость с Opera
  23. v1.3.1 (08.02.12)
  24. - исправлено некорректное отображение в связи с изменением верстки на сайте
  25. - добавлена более выразительная тень
  26. - комментарий в попапе теперь показывается как можно более полно, использую доступное пространство
  27. - новый режим подсветки: если комментарий не вышел за пределы экрана, то он подсвечивается прямо на странице
  28. v1.2.2 (26.11.11)
  29. - поддержка старой верстки
  30. v1.2.1 (07.11.11)
  31. - теперь работает и когда не авторизирован
  32. v1.2 (06.11.11)
  33. - просто возобновление работы после изменений на сайте
  34. - улучшена адаптация ширины комментариев
  35. v1.1 (07.11.09)
  36. - Теперь работает и для комментариев, которые динамически появляются при клике на кнопке, что справа
  37. - Исправлено перекрывание окошка панелькой, что внизу топика
  38.  
  39. v1.0 (27.10.09)
  40. - public release
  41. */
  42.  
  43.  
  44.  
  45. /*
  46. класс стрелочки вверх — up-to-parent
  47. href — #comment_1706843
  48.  
  49. ID ответа — comment_1706843
  50. класс заголовка — div info
  51. класс тела — div message
  52. */
  53.  
  54. "use strict";
  55.  
  56. !function(win) {
  57.  
  58. if (window != window.top) return
  59. var doc = win.document
  60.  
  61. win.addEventListener("load", function() {
  62. if (doc.getElementById('comments')) {
  63. var msgStyle = "\
  64. background-color:white;\
  65. padding:3px 2px 0 5px;\
  66. position:absolute;\
  67. z-index:1;\
  68. overflow-y:auto;\
  69. -webkit-box-shadow: 0px 3px 12px 3px rgba(0, 0, 0, 0.3);\
  70. -moz-box-shadow: 0px 3px 12px 3px rgba(0, 0, 0, 0.3);\
  71. box-shadow: 0px 3px 12px 3px rgba(0, 0, 0, 0.3);"
  72. // поддержка старой верстки
  73. if (doc.getElementById('main-page')) {
  74. win.msgContainer_cont = doc.createElement("ul")
  75. win.msgContainer_cont.className = "hentry"
  76. win.msgContainer_cont.innerHTML = '<li class="comment_holder vote_holder" style="'+msgStyle+'"></li>'
  77. win.msgContainer_cont.style.cssText = "position:fixed;top:0px;left:0px;width:64.8%;display:none;z-index:99;margin:0 !important;padding:0 !important;overflow:visible;text-align:left;"
  78. doc.body.appendChild(win.msgContainer_cont)
  79. win.msgContainer = win.msgContainer_cont.firstChild
  80. win.comments = doc.getElementById("comments")
  81. // прописываем ховер стрелочкам всех комментов
  82. var arrsUp = win.comments.getElementsByTagName('li')
  83. for (var i=0, l=arrsUp.length; i<l; i++) {
  84. var el = arrsUp[i]
  85. if (el.className == 'up-to-parent') {
  86. el.firstChild.addEventListener("mouseover", function(){
  87. showTargetComment(this.getAttribute('href'), this)
  88. }, false)
  89. el.firstChild.addEventListener("mouseout", hideTargetComment, false)
  90. }
  91. }
  92. }
  93. else {
  94. // готовим контейнер для просмотра
  95. win.msgContainer_cont = doc.createElement("div")
  96. win.msgContainer_cont.className = "comments_list comments_list_answerTo"
  97. win.msgContainer_cont.innerHTML = '<div class="comment_item" style="'+msgStyle+'"></div>'
  98. win.msgContainer_cont.style.cssText = "position:fixed;top:0px;left:0px;display:none;z-index:99;margin:0 !important;padding:0 !important;overflow:visible;text-align:left;"
  99. doc.body.appendChild(win.msgContainer_cont)
  100. win.msgContainer = win.msgContainer_cont.firstChild
  101. // прописываем ховер стрелочкам всех комментов
  102. var arr = doc.links
  103. for (i=0,l=doc.links.length; i<l; i++) {
  104. var link = doc.links[i]
  105. if (link.className == 'to_parent') {
  106. activateArrow(link)
  107. }
  108. }
  109. // таймер для активации новых комментариев
  110. setInterval(function() {
  111. var $ = win.jQuery
  112. if ($) {
  113. var newComments = $('.comment .is_new .to_parent')
  114. for (var i=0, li=newComments.length; i<li; i++) {
  115. var link = newComments[i]
  116. if (link.getAttribute('oninit') != 'activaded') {
  117. activateArrow(link)
  118. link.setAttribute('oninit', 'activaded')
  119. }
  120. }
  121. }
  122. }, 2000)
  123. }
  124. // на клик — прячем коммент
  125. win.addEventListener("mousedown", hideTargetComment, false)
  126. }
  127. }, false);
  128.  
  129. function activateArrow(arrEl) {
  130. arrEl.addEventListener("mouseover", function(){
  131. showTargetComment(this.getAttribute('href'), arrEl)
  132. }, false)
  133. arrEl.addEventListener("mouseout", hideTargetComment, false)
  134. }
  135.  
  136. function showTargetComment(href, arrEl) {
  137. // ищем объект по id
  138. var id = href.replace(/^.*?#/, '')
  139. var target = doc.getElementById(id)
  140. // чистим контейнер
  141. while (win.msgContainer.childNodes.length) {win.msgContainer.removeChild(win.msgContainer.childNodes[0])}
  142. // поддержка старой верстки
  143. if (doc.getElementById('main-page')) {
  144. // заполняем контейнер новым комментом
  145. for (var i=0, l=target.childNodes.length; i<l; i++) {
  146. var tmp = target.childNodes[i]
  147. if (/msg-meta|entry-content/.test(tmp.className)) {
  148. win.msgContainer.appendChild(tmp.cloneNode(true))
  149. }
  150. // выходим из цикла
  151. if (tmp.className == "entry-content") break
  152. }
  153. }
  154. else {
  155. // заполняем контейнер новым комментом
  156. var comment_body = null
  157. for (var i=0, l=target.childNodes.length; i<l; i++) {
  158. var tmp = target.childNodes[i]
  159. if (/comment_body/.test(tmp.className)) {
  160. comment_body = tmp
  161. break
  162. }
  163. }
  164. if (comment_body) {
  165. for (var i=0, l=comment_body.childNodes.length; i<l; i++) {
  166. var tmp = comment_body.childNodes[i]
  167. if (/info|message/.test(tmp.className)) {
  168. win.msgContainer.appendChild(tmp.cloneNode(true))
  169. }
  170. // выходим из цикла
  171. if (tmp.className == "message") break
  172. }
  173. }
  174. }
  175. // подгоняем ширину под блок комментариев
  176. var pageComments_cont = doc.getElementById('comments')
  177. win.msgContainer_cont.style.width = pageComments_cont.offsetWidth+absLeft(pageComments_cont)-8 + 'px'
  178. var targetTop = absTop(target)
  179. var windowScrollPos = doc.documentElement.scrollTop || doc.body.scrollTop
  180. // inline highlight
  181. win.msgContainer.style.top = targetTop>windowScrollPos ? targetTop-windowScrollPos-3 +'px' : 0
  182. // height auto adjustment
  183. if (targetTop<windowScrollPos) {
  184. var currentCommentTop = absTop(arrEl.parentNode.parentNode)
  185. var targetCommentHeight = target.offsetHeight
  186. var delta = (windowScrollPos + targetCommentHeight) - (currentCommentTop-10)
  187. win.msgContainer.style.maxHeight = delta>0 ? targetCommentHeight-delta +'px' : ''
  188. }
  189. else {
  190. win.msgContainer.style.maxHeight = ''
  191. }
  192.  
  193. // показываем
  194. win.msgContainer.parentNode.style.display = "block"
  195. // отступы
  196. win.msgContainer.style.marginLeft = absLeft(target)-5+'px'
  197. win.msgContainer.style.width = win.msgContainer.parentNode.offsetWidth-parseInt(win.msgContainer.style.marginLeft)+'px'
  198. }
  199.  
  200. function hideTargetComment() {
  201. win.msgContainer.parentNode.style.display = "none"
  202. }
  203.  
  204. function absLeft(o) {
  205. var l = 0
  206. do {
  207. if (o.offsetLeft) l += o.offsetLeft-o.scrollLeft;
  208. } while (o = o.offsetParent)
  209. return l
  210. }
  211. function absTop(o) {
  212. var l = 0
  213. do {
  214. if (o.offsetTop) l += o.offsetTop-o.scrollTop;
  215. } while (o = o.offsetParent)
  216. return l
  217. }
  218.  
  219. }(typeof unsafeWindow == 'undefined' ? window : unsafeWindow)