banned_dev.js
1 var Parser = {} 2 3 Parser.init = function() { 4 var staticPath = '//static.4chan.org/image/'; 5 6 var tail = window.devicePixelRatio >= 2 ? '@2x.gif' : '.gif'; 7 8 this.icons = { 9 admin: staticPath + 'adminicon' + tail, 10 mod: staticPath + 'modicon' + tail, 11 dev: staticPath + 'developericon' + tail, 12 del: staticPath + 'filedeleted-res' + tail 13 }; 14 }; 15 16 function buildHTMLFromJSON(data) { 17 var 18 container = document.createElement('div'), 19 isOP = false, 20 21 userId, 22 fileDims = '', 23 imgSrc = '', 24 fileBuildStart = '', 25 fileBuildEnd = '', 26 fileInfo = '', 27 fileHtml = '', 28 fileThumb, 29 fileSize = '', 30 fileClass = '', 31 shortFile = '', 32 longFile = '', 33 tripcode = '', 34 capcodeStart = '', 35 capcodeClass = '', 36 capcode = '', 37 flag, 38 highlight = '', 39 emailStart = '', 40 emailEnd = '', 41 name, 42 subject, 43 noLink, 44 quoteLink, 45 noFilename, 46 maxSize = 150, 47 ratio, imgWidth, imgHeight, 48 49 imgDir = '//images.4chan.org/' + data.board + '/src'; 50 51 noLink = 'res/' + data.resto + '#p' + data.no; 52 quoteLink = 'res/' + data.resto + '#q' + data.no; 53 54 if (!data.capcode && data.id) { 55 userId = ' <span class="posteruid id_' 56 + data.id + '">(ID: <span class="hand" title="Highlight posts by this ID">' 57 + data.id + '</span>)</span> '; 58 } 59 else { 60 userId = ''; 61 } 62 63 switch (data.capcode) { 64 case 'admin_highlight': 65 highlight = ' highlightPost'; 66 case 'admin': 67 capcodeStart = ' <strong class="capcode hand id_admin"' 68 + 'title="Highlight posts by the Administrator">## Admin</strong>'; 69 capcodeClass = ' capcodeAdmin'; 70 71 capcode = ' <img src="' + Parser.icons.admin + '" ' 72 + 'alt="This user is the 4chan Administrator." ' 73 + 'title="This user is the 4chan Administrator." class="identityIcon">'; 74 break; 75 case 'mod': 76 capcodeStart = ' <strong class="capcode hand id_mod" ' 77 + 'title="Highlight posts by Moderators">## Mod</strong>'; 78 capcodeClass = ' capcodeMod'; 79 80 capcode = ' <img src="' + Parser.icons.mod + '" ' 81 + 'alt="This user is a 4chan Moderator." ' 82 + 'title="This user is a 4chan Moderator." class="identityIcon">'; 83 break; 84 case 'developer': 85 capcodeStart = ' <strong class="capcode hand id_developer" ' 86 + 'title="Highlight posts by Developers">## Developer</strong>'; 87 capcodeClass = ' capcodeDeveloper'; 88 89 capcode = ' <img src="' + Parser.icons.dev + '" ' 90 + 'alt="This user is a 4chan Developer." ' 91 + 'title="This user is a 4chan Developer." class="identityIcon">'; 92 break; 93 } 94 95 if (data.email) { 96 emailStart = '<a href="mailto:' + data.email.replace(/ /g, '%20') + '" class="useremail">'; 97 emailEnd = '</a>'; 98 } 99 100 if (data.country) { 101 flag = ' <img src="//static.4chan.org/image/country/' 102 + (data.board == 'pol' ? 'troll/' : '') 103 + data.country.toLowerCase() + '.gif" alt="' 104 + data.country + '" title="' + data.country_name + '" class="countryFlag">'; 105 } 106 else { 107 flag = ''; 108 } 109 110 if (data.ext) { 111 shortFile = longFile = data.filename + data.ext; 112 if (data.filename.length > 30) { 113 shortFile = data.filename.slice(0, 25) + '(...)' + data.ext; 114 } 115 116 if (!data.tn_w && !data.tn_h && data.ext == '.gif') { 117 data.tn_w = data.w; 118 data.tn_h = data.h; 119 } 120 if (data.fsize >= 1048576) { 121 fileSize = ((0 | (data.fsize / 1048576 * 100 + 0.5)) / 100) + ' M'; 122 } 123 else if (data.fsize > 1024) { 124 fileSize = (0 | (data.fsize / 1024 + 0.5)) + ' K'; 125 } 126 else { 127 fileSize = data.fsize + ' '; 128 } 129 130 fileThumb = '//images.4chan.org/bans/thumb/' + data.board + '/' + data.thumb + 's.jpg'; 131 132 imgWidth = data.tn_w; 133 imgHeight = data.tn_h; 134 135 if (imgWidth > maxSize) { 136 ratio = maxSize / imgWidth; 137 imgWidth = maxSize; 138 imgHeight = imgHeight * ratio; 139 } 140 if (imgHeight > maxSize) { 141 ratio = maxSize / imgHeight; 142 imgWidth = imgWidth * ratio; 143 imgHeight = maxSize; 144 } 145 146 imgSrc = '<a class="fileThumb' + fileClass + '" href="' + imgDir + '/' 147 + data.tim + data.ext + '" target="_blank"><img src="' + fileThumb 148 + '" alt="' + fileSize + 'B" data-md5="' + data.md5 149 + '" style="height: ' + imgHeight + 'px; width: ' 150 + imgWidth + 'px;"></a>'; 151 152 fileDims = data.ext == '.pdf' ? 'PDF' : data.w + 'x' + data.h; 153 fileInfo = '<span class="fileText" id="fT' + data.no 154 + '">File: <a href="' + imgDir + '/' + data.tim + data.ext 155 + '" target="_blank">' + data.tim + data.ext + '</a>-(' + fileSize 156 + 'B, ' + fileDims 157 + (noFilename ? '' : (', <span title="' + longFile + '">' 158 + shortFile + '</span>')) + ')</span>'; 159 160 fileBuildStart = fileInfo ? '<div class="fileInfo">' : ''; 161 fileBuildEnd = fileInfo ? '</div>' : ''; 162 163 fileHtml = '<div id="f' + data.no + '" class="file">' 164 + fileBuildStart + fileInfo + fileBuildEnd + imgSrc + '</div>'; 165 } 166 else if (data.filedeleted) { 167 fileHtml = '<div id="f' + data.no + '" class="file"><span class="fileThumb"><img src="' 168 + Parser.icons.del + '" class="fileDeletedRes" alt="File deleted."></span></div>'; 169 } 170 171 if (data.trip) { 172 tripcode = ' <span class="postertrip">' + data.trip + '</span>'; 173 } 174 175 name = data.name || ''; 176 177 subject = data.sub || ''; 178 179 container.id = 'p' + data.no; 180 container.className = 'post reply' + highlight + (data.ws_board ? ' ws' : ' nws'); 181 container.innerHTML = 182 '<div class="postInfo desktop" id="pi' + data.no + '">' + 183 '<input type="checkbox" name="' + data.no + '" value="delete"> ' + 184 '<span class="subject">' + subject + '</span> ' + 185 '<span class="nameBlock' + capcodeClass + '">' + emailStart + 186 '<span class="name">' + name + '</span>' + 187 tripcode + capcodeStart + emailEnd + capcode + userId + flag + 188 ' </span> ' + 189 '<span class="dateTime" data-utc="' + data.time + '">' + data.now + '</span> ' + 190 '<span class="postNum desktop">' + 191 '<a href="' + noLink + '" title="Highlight this post">No.</a><a href="' + 192 quoteLink + '" title="Quote this post">' + data.no + '</a>' + 193 '</span>' + 194 '</div>' + fileHtml + 195 '<blockquote class="postMessage" id="m' + data.no + '">' 196 + (data.com || '') + '</blockquote>'; 197 198 return container; 199 } 200 201 function showPreview(e) { 202 var rect, postHeight, doc, docWidth, style, pos, top, scrollTop, link, post, match, bid; 203 204 if (e.target.nodeName == 'A' && (match = e.target.className.match(/^bannedPost_([0-9]+)/))) { 205 link = e.target; 206 bid = match[1]; 207 } 208 else { 209 return; 210 } 211 212 post = buildHTMLFromJSON(window['banjson_' + bid]); 213 214 post.id = 'quote-preview'; 215 216 rect = link.getBoundingClientRect(); 217 doc = document.documentElement; 218 docWidth = doc.offsetWidth; 219 style = post.style; 220 221 document.body.appendChild(post); 222 223 if ((docWidth - rect.right) < (0 | (docWidth * 0.3))) { 224 pos = docWidth - rect.left; 225 style.right = pos + 5 + 'px'; 226 } 227 else { 228 pos = rect.left + rect.width; 229 style.left = pos + 5 + 'px'; 230 } 231 232 top = rect.top + link.offsetHeight + window.pageYOffset 233 - post.offsetHeight / 2 - rect.height / 2; 234 235 postHeight = post.getBoundingClientRect().height; 236 237 if (doc.scrollTop != document.body.scrollTop) { 238 scrollTop = doc.scrollTop + document.body.scrollTop; 239 } else { 240 scrollTop = document.body.scrollTop; 241 } 242 243 if (top < scrollTop) { 244 style.top = scrollTop + 'px'; 245 } 246 else if (top + postHeight > scrollTop + doc.clientHeight) { 247 style.top = scrollTop + doc.clientHeight - postHeight + 'px'; 248 } 249 else { 250 style.top = top + 'px'; 251 } 252 } 253 254 function removePreview() { 255 if (cnt = document.getElementById('quote-preview')) { 256 document.body.removeChild(cnt); 257 } 258 } 259 260 function run() { 261 Parser.init(); 262 addCSS(); 263 document.addEventListener('mouseover', showPreview, false); 264 document.addEventListener('mouseout', removePreview, false); 265 } 266 267 function addCSS() { 268 var style; 269 270 style = document.createElement('style'); 271 style.setAttribute('type', 'text/css'); 272 style.textContent = '\ 273 #quote-preview {\ 274 display: block;\ 275 position: absolute;\ 276 padding: 3px 6px 6px 3px;\ 277 margin: 0;\ 278 text-align: left;\ 279 border-width: 1px 2px 2px 1px;\ 280 border-style: solid;\ 281 }\ 282 #quote-preview.nws {\ 283 color: #800000;\ 284 border-color: #D9BFB7;\ 285 }\ 286 #quote-preview.ws {\ 287 color: #000;\ 288 border-color: #B7C5D9;\ 289 }\ 290 #quote-preview.ws a {\ 291 color: #34345C;\ 292 }\ 293 #quote-preview input {\ 294 margin: 3px 3px 3px 4px;\ 295 }\ 296 .ws.reply {\ 297 background-color: #D6DAF0;\ 298 }\ 299 .nws.reply {\ 300 background-color: #F0E0D6;\ 301 }\ 302 .subject {\ 303 font-weight: bold;\ 304 }\ 305 .ws .subject {\ 306 color: #0F0C5D;\ 307 }\ 308 .nws .subject {\ 309 color: #CC1105;\ 310 }\ 311 .quote {\ 312 color: #789922;\ 313 }\ 314 .quotelink,\ 315 .deadlink {\ 316 color: #789922 !important;\ 317 }\ 318 .ws .useremail .postertrip,\ 319 .ws .useremail .name {\ 320 color: #34345C !important;\ 321 }\ 322 .nws .useremail .postertrip,\ 323 .nws .useremail .name {\ 324 color: #0000EE !important;\ 325 }\ 326 .nameBlock {\ 327 display: inline-block;\ 328 }\ 329 .name {\ 330 color: #117743;\ 331 font-weight: bold;\ 332 }\ 333 .postertrip {\ 334 color: #117743;\ 335 font-weight: normal !important;\ 336 }\ 337 .postNum a {\ 338 text-decoration: none;\ 339 }\ 340 .ws .postNum a {\ 341 color: #000 !important;\ 342 }\ 343 .nws .postNum a {\ 344 color: #800000 !important;\ 345 }\ 346 .fileInfo {\ 347 margin-left: 20px;\ 348 }\ 349 .fileThumb {\ 350 float: left;\ 351 margin: 3px 20px 5px;\ 352 }\ 353 .fileThumb img {\ 354 border: none;\ 355 float: left;\ 356 }\ 357 s {\ 358 background-color: #000000 !important;\ 359 }\ 360 .capcode {\ 361 font-weight: bold !important;\ 362 }\ 363 .nameBlock.capcodeAdmin span.name, span.capcodeAdmin span.name a, span.capcodeAdmin span.postertrip, span.capcodeAdmin strong.capcode {\ 364 color: #FF0000 !important;\ 365 }\ 366 .nameBlock.capcodeMod span.name, span.capcodeMod span.name a, span.capcodeMod span.postertrip, span.capcodeMod strong.capcode {\ 367 color: #800080 !important;\ 368 }\ 369 .nameBlock.capcodeDeveloper span.name, span.capcodeDeveloper span.name a, span.capcodeDeveloper span.postertrip, span.capcodeDeveloper strong.capcode {\ 370 color: #0000F0 !important;\ 371 }\ 372 .identityIcon {\ 373 height: 16px;\ 374 margin-bottom: -3px;\ 375 width: 16px;\ 376 }\ 377 .postMessage {\ 378 margin: 13px 40px 13px 40px;\ 379 }\ 380 .countryFlag {\ 381 margin-bottom: -1px;\ 382 padding-top: 1px;\ 383 }\ 384 .fileDeletedRes {\ 385 height: 13px;\ 386 width: 127px;\ 387 }\ 388 span.fileThumb, span.fileThumb img {\ 389 float: none !important;\ 390 margin-bottom: 0 !important;\ 391 margin-top: 0 !important;\ 392 }\ 393 '; 394 395 (document.head || document.getElementsByTagName('head')[0]).appendChild(style); 396 } 397 398 document.addEventListener('DOMContentLoaded', run, false);