399 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var Parser = {}
 | |
| 
 | |
| Parser.init = function() {
 | |
|   var staticPath = '//static.4chan.org/image/';
 | |
|   
 | |
|   var tail = window.devicePixelRatio >= 2 ? '@2x.gif' : '.gif';
 | |
|   
 | |
|   this.icons = {
 | |
|     admin: staticPath + 'adminicon' + tail,
 | |
|     mod: staticPath + 'modicon' + tail,
 | |
|     dev: staticPath + 'developericon' + tail,
 | |
|     del: staticPath + 'filedeleted-res' + tail
 | |
|   };
 | |
| };
 | |
| 
 | |
| function buildHTMLFromJSON(data) {
 | |
|   var
 | |
|     container = document.createElement('div'),
 | |
|     isOP = false,
 | |
|     
 | |
|     userId,
 | |
|     fileDims = '',
 | |
|     imgSrc = '',
 | |
|     fileBuildStart = '',
 | |
|     fileBuildEnd = '',
 | |
|     fileInfo = '',
 | |
|     fileHtml = '',
 | |
|     fileThumb,
 | |
|     fileSize = '',
 | |
|     fileClass = '',
 | |
|     shortFile = '',
 | |
|     longFile = '',
 | |
|     tripcode = '',
 | |
|     capcodeStart = '',
 | |
|     capcodeClass = '',
 | |
|     capcode = '',
 | |
|     flag,
 | |
|     highlight = '',
 | |
|     emailStart = '',
 | |
|     emailEnd = '',
 | |
|     name,
 | |
|     subject,
 | |
|     noLink,
 | |
|     quoteLink,
 | |
|     noFilename,
 | |
|     maxSize = 150,
 | |
|     ratio, imgWidth, imgHeight,
 | |
|     
 | |
|     imgDir = '//images.4chan.org/' + data.board + '/src';
 | |
|   
 | |
|   noLink = 'res/' + data.resto + '#p' + data.no;
 | |
|   quoteLink = 'res/' + data.resto + '#q' + data.no;
 | |
|   
 | |
|   if (!data.capcode && data.id) {
 | |
|     userId = ' <span class="posteruid id_'
 | |
|       + data.id + '">(ID: <span class="hand" title="Highlight posts by this ID">'
 | |
|       + data.id + '</span>)</span> ';
 | |
|   }
 | |
|   else {
 | |
|     userId = '';
 | |
|   }
 | |
|   
 | |
|   switch (data.capcode) {
 | |
|     case 'admin_highlight':
 | |
|       highlight = ' highlightPost';
 | |
|     case 'admin':
 | |
|       capcodeStart = ' <strong class="capcode hand id_admin"'
 | |
|         + 'title="Highlight posts by the Administrator">## Admin</strong>';
 | |
|       capcodeClass = ' capcodeAdmin';
 | |
|       
 | |
|       capcode = ' <img src="' + Parser.icons.admin + '" '
 | |
|         + 'alt="This user is the 4chan Administrator." '
 | |
|         + 'title="This user is the 4chan Administrator." class="identityIcon">';
 | |
|       break;
 | |
|     case 'mod':
 | |
|       capcodeStart = ' <strong class="capcode hand id_mod" '
 | |
|         + 'title="Highlight posts by Moderators">## Mod</strong>';
 | |
|       capcodeClass = ' capcodeMod';
 | |
|       
 | |
|       capcode = ' <img src="' + Parser.icons.mod + '" '
 | |
|         + 'alt="This user is a 4chan Moderator." '
 | |
|         + 'title="This user is a 4chan Moderator." class="identityIcon">';
 | |
|       break;
 | |
|     case 'developer':
 | |
|       capcodeStart = ' <strong class="capcode hand id_developer" '
 | |
|         + 'title="Highlight posts by Developers">## Developer</strong>';
 | |
|       capcodeClass = ' capcodeDeveloper';
 | |
|       
 | |
|       capcode = ' <img src="' + Parser.icons.dev + '" '
 | |
|         + 'alt="This user is a 4chan Developer." '
 | |
|         + 'title="This user is a 4chan Developer." class="identityIcon">';
 | |
|       break;
 | |
|   }
 | |
|   
 | |
|   if (data.email) {
 | |
|     emailStart = '<a href="mailto:' + data.email.replace(/ /g, '%20') + '" class="useremail">';
 | |
|     emailEnd = '</a>';
 | |
|   }
 | |
|   
 | |
|   if (data.country) {
 | |
|     flag = ' <img src="//static.4chan.org/image/country/'
 | |
|       + (data.board == 'pol' ? 'troll/' : '')
 | |
|       + data.country.toLowerCase() + '.gif" alt="'
 | |
|       + data.country + '" title="' + data.country_name + '" class="countryFlag">';
 | |
|   }
 | |
|   else {
 | |
|     flag = '';
 | |
|   }
 | |
| 
 | |
|   if (data.ext) {
 | |
|     shortFile = longFile = data.filename + data.ext;
 | |
|     if (data.filename.length > 30) {
 | |
|       shortFile = data.filename.slice(0, 25) + '(...)' + data.ext;
 | |
|     }
 | |
| 
 | |
|     if (!data.tn_w && !data.tn_h && data.ext == '.gif') {
 | |
|       data.tn_w = data.w;
 | |
|       data.tn_h = data.h;
 | |
|     }
 | |
|     if (data.fsize >= 1048576) {
 | |
|       fileSize = ((0 | (data.fsize / 1048576 * 100 + 0.5)) / 100) + ' M';
 | |
|     }
 | |
|     else if (data.fsize > 1024) {
 | |
|       fileSize = (0 | (data.fsize / 1024 + 0.5)) + ' K';
 | |
|     }
 | |
|     else {
 | |
|       fileSize = data.fsize + ' ';
 | |
|     }
 | |
|     
 | |
|     fileThumb = '//images.4chan.org/bans/thumb/' + data.board + '/' + data.thumb + 's.jpg';
 | |
|     
 | |
|     imgWidth = data.tn_w;
 | |
|     imgHeight = data.tn_h;
 | |
|     
 | |
|     if (imgWidth > maxSize) {
 | |
|       ratio = maxSize / imgWidth;
 | |
|       imgWidth = maxSize;
 | |
|       imgHeight = imgHeight * ratio;
 | |
|     }
 | |
|     if (imgHeight > maxSize) {
 | |
|       ratio = maxSize / imgHeight;
 | |
|       imgWidth = imgWidth * ratio;
 | |
|       imgHeight = maxSize;
 | |
|     }
 | |
|     
 | |
|     imgSrc = '<a class="fileThumb' + fileClass + '" href="' + imgDir + '/'
 | |
|       + data.tim + data.ext + '" target="_blank"><img src="' + fileThumb
 | |
|       + '" alt="' + fileSize + 'B" data-md5="' + data.md5
 | |
|       + '" style="height: ' + imgHeight + 'px; width: '
 | |
|       + imgWidth + 'px;"></a>';
 | |
|     
 | |
|     fileDims = data.ext == '.pdf' ? 'PDF' : data.w + 'x' + data.h;
 | |
|     fileInfo = '<span class="fileText" id="fT' + data.no
 | |
|       + '">File: <a href="' + imgDir + '/' + data.tim + data.ext
 | |
|       + '" target="_blank">' + data.tim + data.ext + '</a>-(' + fileSize
 | |
|       + 'B, ' + fileDims
 | |
|       + (noFilename ? '' : (', <span title="' + longFile + '">'
 | |
|       + shortFile + '</span>')) + ')</span>';
 | |
|     
 | |
|     fileBuildStart = fileInfo ? '<div class="fileInfo">' : '';
 | |
|     fileBuildEnd = fileInfo ? '</div>' : '';
 | |
|     
 | |
|     fileHtml = '<div id="f' + data.no + '" class="file">'
 | |
|       + fileBuildStart + fileInfo + fileBuildEnd + imgSrc + '</div>';
 | |
|   }
 | |
|   else if (data.filedeleted) {
 | |
|     fileHtml = '<div id="f' + data.no + '" class="file"><span class="fileThumb"><img src="'
 | |
|       + Parser.icons.del + '" class="fileDeletedRes" alt="File deleted."></span></div>';
 | |
|   }
 | |
|   
 | |
|   if (data.trip) {
 | |
|     tripcode = ' <span class="postertrip">' + data.trip + '</span>';
 | |
|   }
 | |
|   
 | |
|   name = data.name || '';
 | |
|   
 | |
|   subject = data.sub || '';
 | |
|   
 | |
|   container.id = 'p' + data.no;
 | |
|   container.className = 'post reply' + highlight + (data.ws_board ? ' ws' : ' nws');
 | |
|   container.innerHTML =
 | |
|     '<div class="postInfo desktop" id="pi' + data.no + '">' +
 | |
|       '<input type="checkbox" name="' + data.no + '" value="delete"> ' +
 | |
|       '<span class="subject">' + subject + '</span> ' +
 | |
|       '<span class="nameBlock' + capcodeClass + '">' + emailStart +
 | |
|         '<span class="name">' + name + '</span>' +
 | |
|         tripcode + capcodeStart + emailEnd + capcode + userId + flag +
 | |
|       ' </span> ' +
 | |
|       '<span class="dateTime" data-utc="' + data.time + '">' + data.now + '</span> ' +
 | |
|       '<span class="postNum desktop">' +
 | |
|         '<a href="' + noLink + '" title="Highlight this post">No.</a><a href="' +
 | |
|         quoteLink + '" title="Quote this post">' + data.no + '</a>' +
 | |
|       '</span>' +
 | |
|     '</div>' + fileHtml +
 | |
|     '<blockquote class="postMessage" id="m' + data.no + '">'
 | |
|     + (data.com || '') + '</blockquote>';
 | |
|   
 | |
|   return container;
 | |
| }
 | |
| 
 | |
| function showPreview(e) {
 | |
|     var rect, postHeight, doc, docWidth, style, pos, top, scrollTop, link, post, match, bid;
 | |
|     
 | |
|     if (e.target.nodeName == 'A' && (match = e.target.className.match(/^bannedPost_([0-9]+)/))) {
 | |
|       link = e.target;
 | |
|       bid = match[1];
 | |
|     }
 | |
|     else {
 | |
|       return;
 | |
|     }
 | |
|     
 | |
|     post = buildHTMLFromJSON(window['banjson_' + bid]);
 | |
|     
 | |
|     post.id = 'quote-preview';
 | |
|     
 | |
|     rect = link.getBoundingClientRect();
 | |
|     doc = document.documentElement;
 | |
|     docWidth = doc.offsetWidth;
 | |
|     style = post.style;
 | |
|     
 | |
|     document.body.appendChild(post);
 | |
|     
 | |
|     if ((docWidth - rect.right) < (0 | (docWidth * 0.3))) {
 | |
|       pos = docWidth - rect.left;
 | |
|       style.right = pos + 5 + 'px';
 | |
|     }
 | |
|     else {
 | |
|       pos = rect.left + rect.width;
 | |
|       style.left = pos + 5 + 'px';
 | |
|     }
 | |
|     
 | |
|     top = rect.top + link.offsetHeight + window.pageYOffset
 | |
|       - post.offsetHeight / 2 - rect.height / 2;
 | |
|     
 | |
|     postHeight = post.getBoundingClientRect().height;
 | |
|     
 | |
|     if (doc.scrollTop != document.body.scrollTop) {
 | |
|       scrollTop = doc.scrollTop + document.body.scrollTop;
 | |
|     } else {
 | |
|       scrollTop = document.body.scrollTop;
 | |
|     }
 | |
|     
 | |
|     if (top < scrollTop) {
 | |
|       style.top = scrollTop + 'px';
 | |
|     }
 | |
|     else if (top + postHeight > scrollTop + doc.clientHeight) {
 | |
|       style.top = scrollTop + doc.clientHeight - postHeight + 'px';
 | |
|     }
 | |
|     else {
 | |
|       style.top = top + 'px';
 | |
|     }
 | |
| }
 | |
| 
 | |
| function removePreview() {
 | |
|   if (cnt = document.getElementById('quote-preview')) {
 | |
|     document.body.removeChild(cnt);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function run() { 
 | |
|   Parser.init();
 | |
|   addCSS();
 | |
|   document.addEventListener('mouseover', showPreview, false);
 | |
|   document.addEventListener('mouseout', removePreview, false);
 | |
| }
 | |
| 
 | |
| function addCSS() {
 | |
|   var style;
 | |
|   
 | |
|   style = document.createElement('style');
 | |
|   style.setAttribute('type', 'text/css');
 | |
|   style.textContent = '\
 | |
| #quote-preview {\
 | |
|   display: block;\
 | |
|   position: absolute;\
 | |
|   padding: 3px 6px 6px 3px;\
 | |
|   margin: 0;\
 | |
|   text-align: left;\
 | |
|   border-width: 1px 2px 2px 1px;\
 | |
|   border-style: solid;\
 | |
| }\
 | |
| #quote-preview.nws {\
 | |
|   color: #800000;\
 | |
|   border-color: #D9BFB7;\
 | |
| }\
 | |
| #quote-preview.ws {\
 | |
|   color: #000;\
 | |
|   border-color: #B7C5D9;\
 | |
| }\
 | |
| #quote-preview.ws a {\
 | |
|   color: #34345C;\
 | |
| }\
 | |
| #quote-preview input {\
 | |
|   margin: 3px 3px 3px 4px;\
 | |
| }\
 | |
| .ws.reply {\
 | |
|   background-color: #D6DAF0;\
 | |
| }\
 | |
| .nws.reply {\
 | |
|   background-color: #F0E0D6;\
 | |
| }\
 | |
| .subject {\
 | |
|   font-weight: bold;\
 | |
| }\
 | |
| .ws .subject {\
 | |
|   color: #0F0C5D;\
 | |
| }\
 | |
| .nws .subject {\
 | |
|   color: #CC1105;\
 | |
| }\
 | |
| .quote {\
 | |
|   color: #789922;\
 | |
| }\
 | |
| .quotelink,\
 | |
| .deadlink {\
 | |
|   color: #789922 !important;\
 | |
| }\
 | |
| .ws .useremail .postertrip,\
 | |
| .ws .useremail .name {\
 | |
|   color: #34345C !important;\
 | |
| }\
 | |
| .nws .useremail .postertrip,\
 | |
| .nws .useremail .name {\
 | |
|   color: #0000EE !important;\
 | |
| }\
 | |
| .nameBlock {\
 | |
|   display: inline-block;\
 | |
| }\
 | |
| .name {\
 | |
|   color: #117743;\
 | |
|   font-weight: bold;\
 | |
| }\
 | |
| .postertrip {\
 | |
|   color: #117743;\
 | |
|   font-weight: normal !important;\
 | |
| }\
 | |
| .postNum a {\
 | |
|   text-decoration: none;\
 | |
| }\
 | |
| .ws .postNum a {\
 | |
|   color: #000 !important;\
 | |
| }\
 | |
| .nws .postNum a {\
 | |
|   color: #800000 !important;\
 | |
| }\
 | |
| .fileInfo {\
 | |
|   margin-left: 20px;\
 | |
| }\
 | |
| .fileThumb {\
 | |
|   float: left;\
 | |
|   margin: 3px 20px 5px;\
 | |
| }\
 | |
| .fileThumb img {\
 | |
|   border: none;\
 | |
|   float: left;\
 | |
| }\
 | |
| s {\
 | |
|   background-color: #000000 !important;\
 | |
| }\
 | |
| .capcode {\
 | |
|   font-weight: bold !important;\
 | |
| }\
 | |
| .nameBlock.capcodeAdmin span.name, span.capcodeAdmin span.name a, span.capcodeAdmin span.postertrip, span.capcodeAdmin strong.capcode {\
 | |
|   color: #FF0000 !important;\
 | |
| }\
 | |
| .nameBlock.capcodeMod span.name, span.capcodeMod span.name a, span.capcodeMod span.postertrip, span.capcodeMod strong.capcode {\
 | |
|   color: #800080 !important;\
 | |
| }\
 | |
| .nameBlock.capcodeDeveloper span.name, span.capcodeDeveloper span.name a, span.capcodeDeveloper span.postertrip, span.capcodeDeveloper strong.capcode {\
 | |
|   color: #0000F0 !important;\
 | |
| }\
 | |
| .identityIcon {\
 | |
|   height: 16px;\
 | |
|   margin-bottom: -3px;\
 | |
|   width: 16px;\
 | |
| }\
 | |
| .postMessage {\
 | |
|   margin: 13px 40px 13px 40px;\
 | |
| }\
 | |
| .countryFlag {\
 | |
|   margin-bottom: -1px;\
 | |
|   padding-top: 1px;\
 | |
| }\
 | |
| .fileDeletedRes {\
 | |
|   height: 13px;\
 | |
|   width: 127px;\
 | |
| }\
 | |
| span.fileThumb, span.fileThumb img {\
 | |
|   float: none !important;\
 | |
|   margin-bottom: 0 !important;\
 | |
|   margin-top: 0 !important;\
 | |
| }\
 | |
| ';
 | |
|   
 | |
|   (document.head || document.getElementsByTagName('head')[0]).appendChild(style);
 | |
| }
 | |
| 
 | |
| document.addEventListener('DOMContentLoaded', run, false);
 |