Merge branch 'api' into v3
This commit is contained in:
commit
ff1411d6ed
327
4chan_x.user.js
327
4chan_x.user.js
@ -8,11 +8,16 @@
|
|||||||
// @match *://boards.4chan.org/*
|
// @match *://boards.4chan.org/*
|
||||||
// @match *://images.4chan.org/*
|
// @match *://images.4chan.org/*
|
||||||
// @match *://sys.4chan.org/*
|
// @match *://sys.4chan.org/*
|
||||||
|
// @match *://api.4chan.org/*
|
||||||
// @match *://*.foolz.us/api/*
|
// @match *://*.foolz.us/api/*
|
||||||
|
// @grant GM_getValue
|
||||||
|
// @grant GM_setValue
|
||||||
|
// @grant GM_deleteValue
|
||||||
|
// @grant GM_openInTab
|
||||||
// @run-at document-start
|
// @run-at document-start
|
||||||
// @updateURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
// @updateURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
||||||
// @downloadURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
// @downloadURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
||||||
// @icon http://mayhemydg.github.com/4chan-x/favicon.gif
|
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
@ -81,6 +86,7 @@
|
|||||||
Config = {
|
Config = {
|
||||||
main: {
|
main: {
|
||||||
Enhancing: {
|
Enhancing: {
|
||||||
|
'Disable 4chan\'s extension': [true, 'Avoid conflicts between 4chan X and 4chan\'s inline extension.'],
|
||||||
'404 Redirect': [true, 'Redirect dead threads and images.'],
|
'404 Redirect': [true, 'Redirect dead threads and images.'],
|
||||||
'Keybinds': [true, 'Bind actions to keyboard shortcuts.'],
|
'Keybinds': [true, 'Bind actions to keyboard shortcuts.'],
|
||||||
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.'],
|
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.'],
|
||||||
@ -937,6 +943,9 @@
|
|||||||
return (_ref2 = $.id('boardNavDesktopFoot')) != null ? _ref2.hidden = true : void 0;
|
return (_ref2 = $.id('boardNavDesktopFoot')) != null ? _ref2.hidden = true : void 0;
|
||||||
},
|
},
|
||||||
initFeatures: function() {
|
initFeatures: function() {
|
||||||
|
if (Conf['Disable 4chan\'s extension']) {
|
||||||
|
localStorage.setItem('4chan-settings', '{"disableAll":true}');
|
||||||
|
}
|
||||||
if (Conf['Resurrect Quotes']) {
|
if (Conf['Resurrect Quotes']) {
|
||||||
try {
|
try {
|
||||||
Quotify.init();
|
Quotify.init();
|
||||||
@ -1086,7 +1095,7 @@
|
|||||||
return $.on(d, 'DOMNodeInserted', Main.addStyle);
|
return $.on(d, 'DOMNodeInserted', Main.addStyle);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
css: "/* general */\n.dialog.reply {\n display: block;\n border: 1px solid rgba(0, 0, 0, .25);\n padding: 0;\n}\n.move {\n cursor: move;\n}\nlabel {\n cursor: pointer;\n}\na[href=\"javascript:;\"] {\n text-decoration: none;\n}\n.warning {\n color: red;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\n display: block !important;\n}\n.post {\n overflow: visible !important;\n}\n\n/* header */\nbody.fourchan_x {\n margin-top: 2.5em;\n}\n#boardNavDesktop.reply {\n border-width: 0 0 1px;\n padding: 4px;\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n transition: opacity .1s ease-in-out;\n -o-transition: opacity .1s ease-in-out;\n -moz-transition: opacity .1s ease-in-out;\n -webkit-transition: opacity .1s ease-in-out;\n z-index: 1;\n}\n#boardNavDesktop.reply:not(:hover) {\n opacity: .4;\n transition: opacity 1.5s .5s ease-in-out;\n -o-transition: opacity 1.5s .5s ease-in-out;\n -moz-transition: opacity 1.5s .5s ease-in-out;\n -webkit-transition: opacity 1.5s .5s ease-in-out;\n}\n#boardNavDesktop.reply a {\n margin: -1px;\n}\n#settings {\n float: right;\n}\n\n/* quote */\n.inlined {\n opacity: .5;\n}\n#qp input, .forwarded {\n display: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\n text-decoration: none;\n border-bottom: 1px dashed;\n}\n.inline {\n border: 1px solid rgba(128, 128, 128, .5);\n display: table;\n margin: 2px 0;\n}\n.inline .post {\n border: 0 !important;\n display: table !important;\n margin: 0 !important;\n padding: 1px 2px !important;\n}\n#qp {\n position: fixed;\n padding: 2px 2px 5px;\n}\n#qp .post {\n border: none;\n margin: 0;\n padding: 0;\n}\n#qp img {\n max-height: 300px;\n max-width: 500px;\n}\n.qphl {\n outline: 2px solid rgba(216, 94, 49, .7);\n}\n\n/* file */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull {\n display: none;\n}\n#ihover {\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n max-height: 100%;\n max-width: 75%;\n position: fixed;\n padding-bottom: 16px;\n}"
|
css: "/* general */\n.dialog.reply {\n display: block;\n border: 1px solid rgba(0, 0, 0, .25);\n padding: 0;\n}\n.move {\n cursor: move;\n}\nlabel {\n cursor: pointer;\n}\na[href=\"javascript:;\"] {\n text-decoration: none;\n}\n.warning {\n color: red;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\n display: block !important;\n}\n.post {\n overflow: visible !important;\n}\n\n/* header */\nbody.fourchan_x {\n margin-top: 2.5em;\n}\n#boardNavDesktop.reply {\n border-width: 0 0 1px;\n padding: 4px;\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n transition: opacity .1s ease-in-out;\n -o-transition: opacity .1s ease-in-out;\n -moz-transition: opacity .1s ease-in-out;\n -webkit-transition: opacity .1s ease-in-out;\n z-index: 1;\n}\n#boardNavDesktop.reply:not(:hover) {\n opacity: .4;\n transition: opacity 1.5s .5s ease-in-out;\n -o-transition: opacity 1.5s .5s ease-in-out;\n -moz-transition: opacity 1.5s .5s ease-in-out;\n -webkit-transition: opacity 1.5s .5s ease-in-out;\n}\n#boardNavDesktop.reply a {\n margin: -1px;\n}\n#settings {\n float: right;\n}\n\n/* quote */\n.quotelink.deadlink {\n text-decoration: underline !important;\n}\n.inlined {\n opacity: .5;\n}\n#qp input, .forwarded {\n display: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\n text-decoration: none;\n border-bottom: 1px dashed;\n}\n.inline {\n border: 1px solid rgba(128, 128, 128, .5);\n display: table;\n margin: 2px 0;\n}\n.inline .post {\n border: 0 !important;\n display: table !important;\n margin: 0 !important;\n padding: 1px 2px !important;\n}\n#qp {\n position: fixed;\n padding: 2px 2px 5px;\n}\n#qp .post {\n border: none;\n margin: 0;\n padding: 0;\n}\n#qp img {\n max-height: 300px;\n max-width: 500px;\n}\n.qphl {\n outline: 2px solid rgba(216, 94, 49, .7);\n}\n\n/* file */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull {\n display: none;\n}\n#ihover {\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n max-height: 100%;\n max-width: 75%;\n position: fixed;\n padding-bottom: 16px;\n}"
|
||||||
};
|
};
|
||||||
|
|
||||||
Redirect = {
|
Redirect = {
|
||||||
@ -1230,6 +1239,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Build = {
|
Build = {
|
||||||
|
spoilerRange: {},
|
||||||
shortFilename: function(filename, isReply) {
|
shortFilename: function(filename, isReply) {
|
||||||
var threshold;
|
var threshold;
|
||||||
threshold = isReply ? 30 : 40;
|
threshold = isReply ? 30 : 40;
|
||||||
@ -1239,120 +1249,139 @@
|
|||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
post: function(o) {
|
postFromObject: function(data, board) {
|
||||||
var board, bq, capcode, comment, container, date, dateUTC, email, file, fl, flag, flagTitle, html, isOP, name, pi, post, postID, subject, threadID, tripcode, uniqueID;
|
var o;
|
||||||
postID = o.postID, threadID = o.threadID, board = o.board, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flag = o.flag, flagTitle = o.flagTitle, date = o.date, dateUTC = o.dateUTC, comment = o.comment, file = o.file;
|
o = {
|
||||||
|
postID: data.no,
|
||||||
|
threadID: data.resto || data.no,
|
||||||
|
board: board,
|
||||||
|
name: data.name,
|
||||||
|
capcode: data.capcode,
|
||||||
|
tripcode: data.trip,
|
||||||
|
uniqueID: data.id,
|
||||||
|
email: data.email ? encodeURIComponent(data.email) : '',
|
||||||
|
subject: data.sub,
|
||||||
|
flagCode: data.country,
|
||||||
|
flagName: data.country_name,
|
||||||
|
date: data.now,
|
||||||
|
dateUTC: data.time,
|
||||||
|
comment: data.com,
|
||||||
|
isSticky: !!data.sticky,
|
||||||
|
isClosed: !!data.closed
|
||||||
|
};
|
||||||
|
if (data.ext || data.filedeleted) {
|
||||||
|
o.file = {
|
||||||
|
name: data.filename + data.ext,
|
||||||
|
timestamp: "" + data.tim + data.ext,
|
||||||
|
url: "//images.4chan.org/" + board + "/src/" + data.tim + data.ext,
|
||||||
|
height: data.h,
|
||||||
|
width: data.w,
|
||||||
|
MD5: data.md5,
|
||||||
|
size: data.fsize,
|
||||||
|
turl: "//thumbs.4chan.org/" + board + "/thumb/" + data.tim + "s.jpg",
|
||||||
|
theight: data.tn_h,
|
||||||
|
twidth: data.tn_w,
|
||||||
|
isSpoiler: !!data.spoiler,
|
||||||
|
isDeleted: !!data.filedeleted
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Build.post(o);
|
||||||
|
},
|
||||||
|
post: function(o, isArchived) {
|
||||||
|
/*
|
||||||
|
This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
|
||||||
|
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
var a, board, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
|
||||||
|
postID = o.postID, threadID = o.threadID, board = o.board, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
|
||||||
isOP = postID === threadID;
|
isOP = postID === threadID;
|
||||||
html = [];
|
staticPath = '//static.4chan.org';
|
||||||
html.push("<input type=checkbox name=" + postID + " value=delete> ");
|
|
||||||
html.push("<span class=subject>" + subject + "</span> ");
|
|
||||||
html.push("<span class='nameBlock");
|
|
||||||
html.push((function() {
|
|
||||||
switch (capcode) {
|
|
||||||
case 'M':
|
|
||||||
return ' capcodeMod';
|
|
||||||
case 'A':
|
|
||||||
return ' capcodeAdmin';
|
|
||||||
case 'D':
|
|
||||||
return ' capcodeDeveloper';
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
})());
|
|
||||||
html.push("'>");
|
|
||||||
if (email) {
|
if (email) {
|
||||||
html.push("<a href=mailto:" + email + " class=useremail>");
|
emailStart = '<a href="mailto:' + email + '" class="useremail">';
|
||||||
}
|
emailEnd = '</a>';
|
||||||
html.push("<span class=name>" + name + "</span>");
|
} else {
|
||||||
if (tripcode) {
|
emailStart = '';
|
||||||
html.push(" <span class=postertrip>" + tripcode + "</span>");
|
emailEnd = '';
|
||||||
}
|
|
||||||
if (uniqueID) {
|
|
||||||
html.push(" <span class='posteruid id_" + uniqueID + "'>(ID: <span class=hand title='Highlight posts by this ID'>" + uniqueID + "</span>)</span>");
|
|
||||||
}
|
}
|
||||||
|
subject = subject ? "<span class=subject>" + subject + "</span>" : '';
|
||||||
|
userID = !capcode && uniqueID ? (" <span class='posteruid id_" + uniqueID + "'>(ID: ") + ("<span class=hand title='Highlight posts by this ID'>" + uniqueID + "</span>)</span> ") : '';
|
||||||
switch (capcode) {
|
switch (capcode) {
|
||||||
case 'M':
|
case 'admin':
|
||||||
html.push(' <strong class="capcode hand id_mod" title="Highlight posts by Moderators">## Mod</strong>');
|
case 'admin_highlight':
|
||||||
html.push(' <img src=//static.4chan.org/image/modicon.gif alt="This user is a 4chan Moderator." title="This user is a 4chan Moderator." class=identityIcon>');
|
capcodeClass = " capcodeAdmin";
|
||||||
|
capcodeStart = " <strong class='capcode hand id_admin'" + "title='Highlight posts by the Administrator'>## Admin</strong>";
|
||||||
|
capcode = (" <img src='" + staticPath + "/image/adminicon.gif' ") + "alt='This user is the 4chan Administrator.' " + "title='This user is the 4chan Administrator.' class=identityIcon>";
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'mod':
|
||||||
html.push(' <strong class="capcode hand id_admin" title="Highlight posts by the Administrator">## Admin</strong>');
|
capcodeClass = " capcodeMod";
|
||||||
html.push(' <img src=//static.4chan.org/image/adminicon.gif alt="This user is the 4chan Administrator." title="This user is the 4chan Administrator." class=identityIcon>');
|
capcodeStart = " <strong class='capcode hand id_mod' " + "title='Highlight posts by Moderators'>## Moderator</strong>";
|
||||||
|
capcode = (" <img src='" + staticPath + "/image/modicon.gif' ") + "alt='This user is a 4chan Moderator.' " + "title='This user is a 4chan Moderator.' class=identityIcon>";
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'developer':
|
||||||
html.push(' <strong class="capcode hand id_mod" title="Highlight posts by Moderators">## Mod</strong>');
|
capcodeClass = " capcodeDeveloper";
|
||||||
html.push(' <img src=//static.4chan.org/image/developericon.gif alt="This user is a 4chan Developer." title="This user is a 4chan Developer." class=identityIcon>');
|
capcodeStart = " <strong class='capcode hand id_developer' " + "title='Highlight posts by Developers'>## Developer</strong>";
|
||||||
|
capcode = (" <img src='" + staticPath + "/image/developericon.gif' ") + "alt='This user is a 4chan Developer.' " + "title='This user is a 4chan Developer.' class=identityIcon>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
capcodeClass = '';
|
||||||
|
capcodeStart = '';
|
||||||
|
capcode = '';
|
||||||
}
|
}
|
||||||
if (email) {
|
flag = flagCode ? (" <img src='" + staticPath + "/image/country/" + (board === 'pol' ? 'troll/' : '')) + flagCode.toLowerCase() + (".gif' alt=" + flagCode + " title='" + flagName + "' class=countryFlag>") : '';
|
||||||
html.push('</a>');
|
if (file != null ? file.isDeleted : void 0) {
|
||||||
}
|
fileHTML = isOP ? ("<div class=file id=f" + postID + "><div class=fileInfo></div><span class=fileThumb>") + ("<img src='" + staticPath + "/image/filedeleted.gif' alt='File deleted.'>") + "</span></div>" : ("<div id=f" + postID + " class=file><span class=fileThumb>") + ("<img src='" + staticPath + "/image/filedeleted-res.gif' alt='File deleted.'>") + "</span></div>";
|
||||||
if (flag) {
|
} else if (file) {
|
||||||
html.push(" <img src=//static.4chan.org/image/country/" + (flag.toLowerCase()) + ".gif alt=" + flag + " title='" + flagTitle + "' class=countryFlag>");
|
ext = file.name.slice(-3);
|
||||||
}
|
if (!file.twidth && !file.theight && ext === 'gif') {
|
||||||
html.push('</span> ');
|
file.twidth = file.width;
|
||||||
html.push("<span class=dateTime data-utc=" + dateUTC + ">" + date + "</span> ");
|
file.theight = file.height;
|
||||||
html.push('<span class="postNum desktop">');
|
}
|
||||||
html.push("<a href=/" + board + "/res/" + threadID + "#p" + postID + " title='Highlight this post'>No.</a>");
|
fileSize = $.bytesToString(file.size);
|
||||||
html.push("<a href=\"" + (g.REPLY ? "javascript:quote('" + postID + "');" : "/" + board + "/res/" + threadID + "#q" + postID) + "\" title='Quote this post'>" + postID + "</a>");
|
fileThumb = file.turl;
|
||||||
html.push('</span>');
|
|
||||||
pi = $.el('div', {
|
|
||||||
id: "pi" + postID,
|
|
||||||
className: 'postInfo desktop',
|
|
||||||
innerHTML: html.join('')
|
|
||||||
});
|
|
||||||
bq = $.el('blockquote', {
|
|
||||||
id: "m" + postID,
|
|
||||||
className: 'postMessage',
|
|
||||||
innerHTML: comment
|
|
||||||
});
|
|
||||||
if (file.name) {
|
|
||||||
html = [];
|
|
||||||
html.push('<div class=fileInfo>');
|
|
||||||
html.push("<span id=fT" + postID + " class=fileText" + (file.isSpoiler ? " title='file.name'" : '') + ">File: ");
|
|
||||||
html.push("<a href=" + file.url + " target=_blank>" + file.origin + "</a>");
|
|
||||||
html.push('-(');
|
|
||||||
if (file.isSpoiler) {
|
if (file.isSpoiler) {
|
||||||
html.push('Spoiler Image, ');
|
fileSize = "Spoiler Image, " + fileSize;
|
||||||
|
if (!isArchived) {
|
||||||
|
fileThumb = '//static.4chan.org/image/spoiler';
|
||||||
|
if (spoilerRange = Build.spoilerRange[board]) {
|
||||||
|
fileThumb += ("-" + board) + Math.floor(1 + spoilerRange * Math.random());
|
||||||
|
}
|
||||||
|
fileThumb += '.png';
|
||||||
|
file.twidth = file.theight = 100;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
html.push("" + ($.bytesToString(file.size)) + ", ");
|
imgSrc = ("<a class='fileThumb" + (file.isSpoiler ? ' imgspoiler' : '') + "' href='" + file.url + "' target=_blank>") + ("<img src='" + fileThumb + "' alt='" + fileSize + "' data-md5=" + file.MD5 + " style='width:" + file.twidth + "px;height:" + file.theight + "px'></a>");
|
||||||
html.push(/\.pdf$/i.test(file.name) ? "PDF" : "" + file.width + "x" + file.height);
|
a = $.el('a', {
|
||||||
if (!file.isSpoiler) {
|
innerHTML: file.name
|
||||||
html.push(", <span title='" + file.name + "'>" + (Build.shortFilename(file.name)) + "</span>");
|
|
||||||
}
|
|
||||||
html.push(")</span></div>");
|
|
||||||
html.push("<a class='fileThumb" + (file.isSpoiler ? ' imgspoiler' : '') + "' href=" + file.url + " target=_blank>");
|
|
||||||
html.push("<img src=" + file.turl + " alt='" + (file.isSpoiler ? 'Spoiler Image, ' : '') + ($.bytesToString(file.size)) + "' data-md5='" + file.MD5 + "' style='height:" + file.theight + "px;width:" + file.twidth + "px'>");
|
|
||||||
html.push('</a>');
|
|
||||||
fl = $.el('div', {
|
|
||||||
id: "f" + postID,
|
|
||||||
className: 'file',
|
|
||||||
innerHTML: html.join('')
|
|
||||||
});
|
});
|
||||||
|
filename = a.textContent.replace(/%22/g, '"');
|
||||||
|
a.textContent = Build.shortFilename(filename);
|
||||||
|
shortFilename = a.innerHTML;
|
||||||
|
a.textContent = filename;
|
||||||
|
filename = a.innerHTML.replace(/'/g, ''');
|
||||||
|
fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
|
||||||
|
fileInfo = ("<span class=fileText id=fT" + postID + (file.isSpoiler ? " title='" + filename + "'" : '') + ">File: <a href='" + file.url + "' target=_blank>" + file.timestamp + "</a>") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", <span title='" + filename + "'>" + shortFilename + "</span>")) + ")</span>";
|
||||||
|
fileHTML = "<div id=f" + postID + " class=file><div class=fileInfo>" + fileInfo + "</div>" + imgSrc + "</div>";
|
||||||
|
} else {
|
||||||
|
fileHTML = '';
|
||||||
}
|
}
|
||||||
post = $.el('div', {
|
tripcode = tripcode ? " <span class=postertrip>" + tripcode + "</span>" : '';
|
||||||
id: "p" + postID,
|
sticky = isSticky ? ' <img src=//static.4chan.org/image/sticky.gif alt=Sticky title=Sticky style="height:16px;width:16px">' : '';
|
||||||
className: "post " + (isOP ? 'op' : 'reply')
|
closed = isClosed ? ' <img src=//static.4chan.org/image/closed.gif alt=Closed title=Closed style="height:16px;width:16px">' : '';
|
||||||
});
|
|
||||||
if (fl && isOP) {
|
|
||||||
$.add(post, fl);
|
|
||||||
}
|
|
||||||
$.add(post, pi);
|
|
||||||
if (fl && !isOP) {
|
|
||||||
$.add(post, fl);
|
|
||||||
}
|
|
||||||
$.add(post, bq);
|
|
||||||
container = $.el('div', {
|
container = $.el('div', {
|
||||||
id: "pc" + postID,
|
id: "pc" + postID,
|
||||||
className: "postContainer " + (isOP ? 'op' : 'reply') + "Container"
|
className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
|
||||||
|
innerHTML: (isOP ? '' : "<div class=sideArrows id=sa" + postID + ">>></div>") + ("<div id=p" + postID + " class='post " + (isOP ? 'op' : 'reply') + (capcode === 'admin_highlight' ? ' highlightPost' : '') + "'>") + ("<div class='postInfoM mobile' id=pim" + postID + ">") + ("<span class='nameBlock" + capcodeClass + "'>") + ("<span class=name>" + (name || '') + "</span>") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("<br>" + subject) + ("</span><span class='dateTime postNum' data-utc=" + dateUTC + ">" + date) + '<br><em>' + ("<a href=" + ("/" + board + "/res/" + threadID + "#p" + postID) + ">No.</a>") + ("<a href='" + (g.REPLY && g.THREAD_ID === threadID ? "javascript:quote(" + postID + ")" : "/" + board + "/res/" + threadID + "#q" + postID) + "'>" + postID + "</a>") + '</em></span>' + '</div>' + (isOP ? fileHTML : '') + ("<div class='postInfo desktop' id=pi" + postID + ">") + ("<input type=checkbox name=" + postID + " value=delete> ") + ("" + subject + " ") + ("<span class='nameBlock" + capcodeClass + "'>") + emailStart + ("<span class=name>" + (name || '') + "</span>") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' </span> ' + ("<span class=dateTime data-utc=" + dateUTC + ">" + date + "</span> ") + "<span class='postNum desktop'>" + ("<a href=" + ("/" + board + "/res/" + threadID + "#p" + postID) + " title='Highlight this post'>No.</a>") + ("<a href='" + (g.REPLY && g.THREAD_ID === threadID ? "javascript:quote(" + postID + ")" : "/" + board + "/res/" + threadID + "#q" + postID) + "' title='Quote this post'>" + postID + "</a>") + '</span>' + '</div>' + (isOP ? '' : fileHTML) + ("<blockquote class=postMessage id=m" + postID + ">" + (comment || '') + "</blockquote> ") + '</div>'
|
||||||
});
|
});
|
||||||
if (!isOP) {
|
_ref = $$('.quotelink', container);
|
||||||
$.add(container, $.el('div', {
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
id: "sa" + postID,
|
quote = _ref[_i];
|
||||||
className: 'sideArrows',
|
href = quote.getAttribute('href');
|
||||||
textContent: '>>'
|
if (href[0] === '/') {
|
||||||
}));
|
continue;
|
||||||
|
}
|
||||||
|
quote.href = "/" + board + "/res/" + href;
|
||||||
}
|
}
|
||||||
$.add(container, post);
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1397,7 +1426,7 @@
|
|||||||
}
|
}
|
||||||
root.textContent = "Loading post No." + postID + "...";
|
root.textContent = "Loading post No." + postID + "...";
|
||||||
if (threadID) {
|
if (threadID) {
|
||||||
return $.cache("/" + board + "/res/" + threadID, function() {
|
return $.cache("//api.4chan.org/" + board + "/res/" + threadID + ".json", function() {
|
||||||
return Get.fetchedPost(this, board, threadID, postID, root, context);
|
return Get.fetchedPost(this, board, threadID, postID, root, context);
|
||||||
});
|
});
|
||||||
} else if (url = Redirect.post(board, postID)) {
|
} else if (url = Redirect.post(board, postID)) {
|
||||||
@ -1420,7 +1449,7 @@
|
|||||||
return $.add(root, nodes.root);
|
return $.add(root, nodes.root);
|
||||||
},
|
},
|
||||||
fetchedPost: function(req, board, threadID, postID, root, context) {
|
fetchedPost: function(req, board, threadID, postID, root, context) {
|
||||||
var doc, href, link, pc, post, quote, status, thread, url, _i, _len, _ref;
|
var post, posts, spoilerRange, status, thread, url, _i, _len;
|
||||||
if (post = g.posts["" + board + "." + postID]) {
|
if (post = g.posts["" + board + "." + postID]) {
|
||||||
Get.insert(post, root, context);
|
Get.insert(post, root, context);
|
||||||
return;
|
return;
|
||||||
@ -1429,48 +1458,44 @@
|
|||||||
if (status !== 200) {
|
if (status !== 200) {
|
||||||
if (url = Redirect.post(board, postID)) {
|
if (url = Redirect.post(board, postID)) {
|
||||||
$.cache(url, function() {
|
$.cache(url, function() {
|
||||||
return Get.archivedPost(this, board, postID, root);
|
return Get.archivedPost(this, board, postID, root, context);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$.addClass(root, 'warning');
|
$.addClass(root, 'warning');
|
||||||
root.textContent = status === 404 ? "Thread No." + threadID + " has not been found." : "Error " + req.status + ": " + req.statusText + ".";
|
root.textContent = status === 404 ? "Thread No." + threadID + " 404'd." : "Error " + req.status + ": " + req.statusText + ".";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
doc = d.implementation.createHTMLDocument('');
|
posts = JSON.parse(req.response).posts;
|
||||||
doc.documentElement.innerHTML = req.response;
|
if (spoilerRange = posts[0].custom_spoiler) {
|
||||||
if (!(pc = doc.getElementById("pc" + postID))) {
|
Build.spoilerRange[board] = spoilerRange;
|
||||||
if (url = Redirect.post(board, postID)) {
|
|
||||||
$.cache(url, function() {
|
|
||||||
return Get.archivedPost(this, board, postID, root);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$.addClass(root, 'warning');
|
|
||||||
root.textContent = "Post No." + postID + " has not been found.";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
pc = d.importNode(pc, true);
|
postID = +postID;
|
||||||
_ref = $$('.quotelink', pc);
|
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
||||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
post = posts[_i];
|
||||||
quote = _ref[_i];
|
if (post.no === postID) {
|
||||||
href = quote.getAttribute('href');
|
break;
|
||||||
if (href[0] === '/') {
|
}
|
||||||
continue;
|
if (post.no > postID) {
|
||||||
|
if (url = Redirect.post(board, postID)) {
|
||||||
|
$.cache(url, function() {
|
||||||
|
return Get.parseArchivedPost(this, board, postID, root, context);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$.addClass(root, 'warning');
|
||||||
|
root.textContent = "Post No." + postID + " was not found.";
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
quote.href = "/" + board + "/res/" + href;
|
|
||||||
}
|
}
|
||||||
link = $('a[title="Highlight this post"]', pc);
|
|
||||||
link.href = "/" + board + "/res/" + threadID + "#p" + postID;
|
|
||||||
link.nextSibling.href = "/" + board + "/res/" + threadID + "#q" + postID;
|
|
||||||
board = g.boards[board] || new Board(board);
|
board = g.boards[board] || new Board(board);
|
||||||
thread = g.threads["" + board + "." + threadID] || new Thread(threadID, board);
|
thread = g.threads["" + board + "." + threadID] || new Thread(threadID, board);
|
||||||
post = new Post(pc, thread, board);
|
post = new Post(Build.postFromObject(post, board), thread, board);
|
||||||
Main.callbackNodes(Post, [post]);
|
Main.callbackNodes(Post, [post]);
|
||||||
return Get.insert(post, root, context);
|
return Get.insert(post, root, context);
|
||||||
},
|
},
|
||||||
archivedPost: function(req, board, postID, root, context) {
|
archivedPost: function(req, board, postID, root, context) {
|
||||||
var bq, comment, data, post, postContainer, thread, threadID;
|
var bq, comment, data, o, post, thread, threadID;
|
||||||
if (post = g.posts["" + board + "." + postID]) {
|
if (post = g.posts["" + board + "." + postID]) {
|
||||||
Get.insert(post, root, context);
|
Get.insert(post, root, context);
|
||||||
return;
|
return;
|
||||||
@ -1512,37 +1537,49 @@
|
|||||||
});
|
});
|
||||||
comment = bq.innerHTML.replace(/(^|>)(>[^<$]+)(<|$)/g, '$1<span class=quote>$2</span>$3');
|
comment = bq.innerHTML.replace(/(^|>)(>[^<$]+)(<|$)/g, '$1<span class=quote>$2</span>$3');
|
||||||
threadID = data.thread_num;
|
threadID = data.thread_num;
|
||||||
postContainer = Build.post({
|
o = {
|
||||||
postID: postID,
|
postID: postID,
|
||||||
threadID: threadID,
|
threadID: threadID,
|
||||||
board: board,
|
board: board,
|
||||||
name: data.name,
|
name: data.name_processed,
|
||||||
capcode: data.capcode,
|
capcode: (function() {
|
||||||
|
switch (data.capcode) {
|
||||||
|
case 'M':
|
||||||
|
return 'mod';
|
||||||
|
case 'A':
|
||||||
|
return 'admin';
|
||||||
|
case 'D':
|
||||||
|
return 'developer';
|
||||||
|
}
|
||||||
|
})(),
|
||||||
tripcode: data.trip,
|
tripcode: data.trip,
|
||||||
uniqueID: data.poster_hash,
|
uniqueID: data.poster_hash,
|
||||||
email: data.email,
|
email: encodeURIComponent(data.email),
|
||||||
subject: data.title,
|
subject: data.title_processed,
|
||||||
flag: data.poster_country,
|
flagCode: data.poster_country,
|
||||||
|
flagName: data.poster_country_name_processed,
|
||||||
date: data.fourchan_date,
|
date: data.fourchan_date,
|
||||||
dateUTC: data.timestamp,
|
dateUTC: data.timestamp,
|
||||||
comment: comment,
|
comment: comment
|
||||||
file: {
|
};
|
||||||
name: data.media_filename,
|
if (data.media_filename) {
|
||||||
origin: data.media_orig,
|
o.file = {
|
||||||
|
name: data.media_filename_processed,
|
||||||
|
timestamp: data.media_orig,
|
||||||
url: data.media_link || data.remote_media_link,
|
url: data.media_link || data.remote_media_link,
|
||||||
height: data.media_h,
|
height: data.media_h,
|
||||||
width: data.media_w,
|
width: data.media_w,
|
||||||
isSpoiler: data.spoiler === '1',
|
|
||||||
MD5: data.media_hash,
|
MD5: data.media_hash,
|
||||||
size: data.media_size,
|
size: data.media_size,
|
||||||
turl: data.thumb_link || ("//thumbs.4chan.org/" + board + "/thumb/" + data.preview_orig),
|
turl: data.thumb_link || ("//thumbs.4chan.org/" + board + "/thumb/" + data.preview_orig),
|
||||||
theight: data.preview_h,
|
theight: data.preview_h,
|
||||||
twidth: data.preview_w
|
twidth: data.preview_w,
|
||||||
}
|
isSpoiler: data.spoiler === '1'
|
||||||
});
|
};
|
||||||
|
}
|
||||||
board = g.boards[board] || new Board(board);
|
board = g.boards[board] || new Board(board);
|
||||||
thread = g.threads["" + board + "." + threadID] || new Thread(threadID, board);
|
thread = g.threads["" + board + "." + threadID] || new Thread(threadID, board);
|
||||||
post = new Post(postContainer, thread, board, {
|
post = new Post(Build.post(o, true), thread, board, {
|
||||||
isArchived: true
|
isArchived: true
|
||||||
});
|
});
|
||||||
Main.callbackNodes(Post, [post]);
|
Main.callbackNodes(Post, [post]);
|
||||||
|
|||||||
7
Cakefile
7
Cakefile
@ -19,11 +19,16 @@ HEADER = """
|
|||||||
// @match *://boards.4chan.org/*
|
// @match *://boards.4chan.org/*
|
||||||
// @match *://images.4chan.org/*
|
// @match *://images.4chan.org/*
|
||||||
// @match *://sys.4chan.org/*
|
// @match *://sys.4chan.org/*
|
||||||
|
// @match *://api.4chan.org/*
|
||||||
// @match *://*.foolz.us/api/*
|
// @match *://*.foolz.us/api/*
|
||||||
|
// @grant GM_getValue
|
||||||
|
// @grant GM_setValue
|
||||||
|
// @grant GM_deleteValue
|
||||||
|
// @grant GM_openInTab
|
||||||
// @run-at document-start
|
// @run-at document-start
|
||||||
// @updateURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
// @updateURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
||||||
// @downloadURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
// @downloadURL https://github.com/MayhemYDG/4chan-x/raw/stable/4chan_x.user.js
|
||||||
// @icon http://mayhemydg.github.com/4chan-x/favicon.gif
|
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
|||||||
16
changelog
16
changelog
@ -4,6 +4,22 @@ alpha
|
|||||||
Fix Quote Backlinks not affecting inlined quotes.
|
Fix Quote Backlinks not affecting inlined quotes.
|
||||||
Fix Quote Highlighting not affecting inlined quotes.
|
Fix Quote Highlighting not affecting inlined quotes.
|
||||||
|
|
||||||
|
master
|
||||||
|
- Mayhem
|
||||||
|
Use 4chan's API to fetch posts for:
|
||||||
|
- Thread Updater.
|
||||||
|
- Quote Inlining.
|
||||||
|
- Quote Previewing.
|
||||||
|
- Thread Expansion.
|
||||||
|
- Comment Expansion.
|
||||||
|
This will make fetching faster, and reduce bandwidth usage.
|
||||||
|
Add an option to disable 4chan's inline extension. Enabled by default.
|
||||||
|
Fix compatibility with Scriptish's auto-udpater.
|
||||||
|
|
||||||
|
2.34.10
|
||||||
|
- Mayhem
|
||||||
|
Fix 4chan X. Blame moot.
|
||||||
|
|
||||||
2.34.9
|
2.34.9
|
||||||
- Mayhem
|
- Mayhem
|
||||||
Add /g/, /k/, /w/, /an/, /cgl/, /ck/, /lit/, /toy/ and /x/ archived image redirection.
|
Add /g/, /k/, /w/, /an/, /cgl/, /ck/, /lit/, /toy/ and /x/ archived image redirection.
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
postMessage({version:'2.34.9'},'*')
|
postMessage({version:'2.34.10'},'*')
|
||||||
420
script.coffee
420
script.coffee
@ -1,6 +1,7 @@
|
|||||||
Config =
|
Config =
|
||||||
main:
|
main:
|
||||||
Enhancing:
|
Enhancing:
|
||||||
|
'Disable 4chan\'s extension': [true, 'Avoid conflicts between 4chan X and 4chan\'s inline extension.']
|
||||||
'404 Redirect': [true, 'Redirect dead threads and images.']
|
'404 Redirect': [true, 'Redirect dead threads and images.']
|
||||||
'Keybinds': [true, 'Bind actions to keyboard shortcuts.']
|
'Keybinds': [true, 'Bind actions to keyboard shortcuts.']
|
||||||
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.']
|
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.']
|
||||||
@ -741,6 +742,9 @@ Main =
|
|||||||
$.id('boardNavDesktopFoot')?.hidden = true
|
$.id('boardNavDesktopFoot')?.hidden = true
|
||||||
|
|
||||||
initFeatures: ->
|
initFeatures: ->
|
||||||
|
if Conf['Disable 4chan\'s extension']
|
||||||
|
localStorage.setItem '4chan-settings', '{"disableAll":true}'
|
||||||
|
|
||||||
if Conf['Resurrect Quotes']
|
if Conf['Resurrect Quotes']
|
||||||
try
|
try
|
||||||
Quotify.init()
|
Quotify.init()
|
||||||
@ -935,6 +939,9 @@ body.fourchan_x {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* quote */
|
/* quote */
|
||||||
|
.quotelink.deadlink {
|
||||||
|
text-decoration: underline !important;
|
||||||
|
}
|
||||||
.inlined {
|
.inlined {
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
}
|
}
|
||||||
@ -1060,6 +1067,7 @@ Redirect =
|
|||||||
url or ''
|
url or ''
|
||||||
|
|
||||||
Build =
|
Build =
|
||||||
|
spoilerRange: {}
|
||||||
shortFilename: (filename, isReply) ->
|
shortFilename: (filename, isReply) ->
|
||||||
# FILENAME SHORTENING SCIENCE:
|
# FILENAME SHORTENING SCIENCE:
|
||||||
# OPs have a +10 characters threshold.
|
# OPs have a +10 characters threshold.
|
||||||
@ -1069,117 +1077,249 @@ Build =
|
|||||||
"#{filename[...threshold - 5]}(...).#{filename[-3..]}"
|
"#{filename[...threshold - 5]}(...).#{filename[-3..]}"
|
||||||
else
|
else
|
||||||
filename
|
filename
|
||||||
post: (o) ->
|
postFromObject: (data, board) ->
|
||||||
|
o =
|
||||||
|
# id
|
||||||
|
postID: data.no
|
||||||
|
threadID: data.resto or data.no
|
||||||
|
board: board
|
||||||
|
# info
|
||||||
|
name: data.name
|
||||||
|
capcode: data.capcode
|
||||||
|
tripcode: data.trip
|
||||||
|
uniqueID: data.id
|
||||||
|
email: if data.email then encodeURIComponent data.email else ''
|
||||||
|
subject: data.sub
|
||||||
|
flagCode: data.country
|
||||||
|
flagName: data.country_name
|
||||||
|
date: data.now
|
||||||
|
dateUTC: data.time
|
||||||
|
comment: data.com
|
||||||
|
# thread status
|
||||||
|
isSticky: !!data.sticky
|
||||||
|
isClosed: !!data.closed
|
||||||
|
# file
|
||||||
|
if data.ext or data.filedeleted
|
||||||
|
o.file =
|
||||||
|
name: data.filename + data.ext
|
||||||
|
timestamp: "#{data.tim}#{data.ext}"
|
||||||
|
url: "//images.4chan.org/#{board}/src/#{data.tim}#{data.ext}"
|
||||||
|
height: data.h
|
||||||
|
width: data.w
|
||||||
|
MD5: data.md5
|
||||||
|
size: data.fsize
|
||||||
|
turl: "//thumbs.4chan.org/#{board}/thumb/#{data.tim}s.jpg"
|
||||||
|
theight: data.tn_h
|
||||||
|
twidth: data.tn_w
|
||||||
|
isSpoiler: !!data.spoiler
|
||||||
|
isDeleted: !!data.filedeleted
|
||||||
|
Build.post o
|
||||||
|
post: (o, isArchived) ->
|
||||||
|
###
|
||||||
|
This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
|
||||||
|
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
|
||||||
|
###
|
||||||
{
|
{
|
||||||
postID, threadID, board
|
postID, threadID, board
|
||||||
name, capcode, tripcode, uniqueID, email, subject, flag, flagTitle, date, dateUTC, comment
|
name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC
|
||||||
|
isSticky, isClosed
|
||||||
|
comment
|
||||||
file
|
file
|
||||||
} = o
|
} = o
|
||||||
isOP = postID is threadID
|
isOP = postID is threadID
|
||||||
|
|
||||||
# post info
|
staticPath = '//static.4chan.org'
|
||||||
html = []
|
|
||||||
# input
|
if email
|
||||||
html.push "<input type=checkbox name=#{postID} value=delete> "
|
emailStart = '<a href="mailto:' + email + '" class="useremail">'
|
||||||
# subject
|
emailEnd = '</a>'
|
||||||
html.push "<span class=subject>#{subject}</span> "
|
else
|
||||||
# name block
|
emailStart = ''
|
||||||
html.push "<span class='nameBlock"
|
emailEnd = ''
|
||||||
html.push switch capcode
|
|
||||||
when 'M' then ' capcodeMod'
|
subject =
|
||||||
when 'A' then ' capcodeAdmin'
|
if subject
|
||||||
when 'D' then ' capcodeDeveloper'
|
"<span class=subject>#{subject}</span>"
|
||||||
else ''
|
|
||||||
html.push "'>"
|
|
||||||
# mail start
|
|
||||||
html.push "<a href=mailto:#{email} class=useremail>" if email
|
|
||||||
# name
|
|
||||||
html.push "<span class=name>#{name}</span>"
|
|
||||||
# tripcode
|
|
||||||
html.push " <span class=postertrip>#{tripcode}</span>" if tripcode
|
|
||||||
# user id
|
|
||||||
html.push " <span class='posteruid id_#{uniqueID}'>(ID: <span class=hand title='Highlight posts by this ID'>#{uniqueID}</span>)</span>" if uniqueID
|
|
||||||
# capcode
|
|
||||||
switch capcode
|
|
||||||
when 'M'
|
|
||||||
html.push ' <strong class="capcode hand id_mod" title="Highlight posts by Moderators">## Mod</strong>'
|
|
||||||
html.push ' <img src=//static.4chan.org/image/modicon.gif alt="This user is a 4chan Moderator." title="This user is a 4chan Moderator." class=identityIcon>'
|
|
||||||
when 'A'
|
|
||||||
html.push ' <strong class="capcode hand id_admin" title="Highlight posts by the Administrator">## Admin</strong>'
|
|
||||||
html.push ' <img src=//static.4chan.org/image/adminicon.gif alt="This user is the 4chan Administrator." title="This user is the 4chan Administrator." class=identityIcon>'
|
|
||||||
when 'D'
|
|
||||||
html.push ' <strong class="capcode hand id_mod" title="Highlight posts by Moderators">## Mod</strong>'
|
|
||||||
html.push ' <img src=//static.4chan.org/image/developericon.gif alt="This user is a 4chan Developer." title="This user is a 4chan Developer." class=identityIcon>'
|
|
||||||
# mail end
|
|
||||||
html.push '</a>' if email
|
|
||||||
# flag
|
|
||||||
# XXX what about troll flags in /pol/?
|
|
||||||
html.push " <img src=//static.4chan.org/image/country/#{flag.toLowerCase()}.gif alt=#{flag} title='#{flagTitle}' class=countryFlag>" if flag
|
|
||||||
# end name block
|
|
||||||
html.push '</span> '
|
|
||||||
# date
|
|
||||||
html.push "<span class=dateTime data-utc=#{dateUTC}>#{date}</span> "
|
|
||||||
# post num
|
|
||||||
html.push '<span class="postNum desktop">'
|
|
||||||
html.push "<a href=/#{board}/res/#{threadID}#p#{postID} title='Highlight this post'>No.</a>"
|
|
||||||
html.push "<a href=\"#{
|
|
||||||
if g.REPLY
|
|
||||||
"javascript:quote('#{postID}');"
|
|
||||||
else
|
else
|
||||||
"/#{board}/res/#{threadID}#q#{postID}"
|
''
|
||||||
}\" title='Quote this post'>#{postID}</a>"
|
|
||||||
# XXX closed/sticky?
|
|
||||||
html.push '</span>'
|
|
||||||
pi = $.el 'div',
|
|
||||||
id: "pi#{postID}"
|
|
||||||
className: 'postInfo desktop'
|
|
||||||
innerHTML: html.join ''
|
|
||||||
|
|
||||||
bq = $.el 'blockquote',
|
userID =
|
||||||
id: "m#{postID}"
|
if !capcode and uniqueID
|
||||||
className: 'postMessage'
|
" <span class='posteruid id_#{uniqueID}'>(ID: " +
|
||||||
innerHTML: comment
|
"<span class=hand title='Highlight posts by this ID'>#{uniqueID}</span>)</span> "
|
||||||
|
else
|
||||||
|
''
|
||||||
|
|
||||||
# file
|
switch capcode
|
||||||
if file.name # XXX need to fix support of Flash
|
when 'admin', 'admin_highlight'
|
||||||
html = []
|
capcodeClass = " capcodeAdmin"
|
||||||
html.push '<div class=fileInfo>'
|
capcodeStart = " <strong class='capcode hand id_admin'" +
|
||||||
html.push "<span id=fT#{postID} class=fileText#{if file.isSpoiler then " title='file.name'" else ''}>File: "
|
"title='Highlight posts by the Administrator'>## Admin</strong>"
|
||||||
html.push "<a href=#{file.url} target=_blank>#{file.origin}</a>"
|
capcode = " <img src='#{staticPath}/image/adminicon.gif' " +
|
||||||
html.push '-('
|
"alt='This user is the 4chan Administrator.' " +
|
||||||
html.push 'Spoiler Image, ' if file.isSpoiler
|
"title='This user is the 4chan Administrator.' class=identityIcon>"
|
||||||
html.push "#{$.bytesToString file.size}, "
|
when 'mod'
|
||||||
html.push if /\.pdf$/i.test file.name
|
capcodeClass = " capcodeMod"
|
||||||
"PDF"
|
capcodeStart = " <strong class='capcode hand id_mod' " +
|
||||||
|
"title='Highlight posts by Moderators'>## Moderator</strong>"
|
||||||
|
capcode = " <img src='#{staticPath}/image/modicon.gif' " +
|
||||||
|
"alt='This user is a 4chan Moderator.' " +
|
||||||
|
"title='This user is a 4chan Moderator.' class=identityIcon>"
|
||||||
|
when 'developer'
|
||||||
|
capcodeClass = " capcodeDeveloper"
|
||||||
|
capcodeStart = " <strong class='capcode hand id_developer' " +
|
||||||
|
"title='Highlight posts by Developers'>## Developer</strong>"
|
||||||
|
capcode = " <img src='#{staticPath}/image/developericon.gif' " +
|
||||||
|
"alt='This user is a 4chan Developer.' " +
|
||||||
|
"title='This user is a 4chan Developer.' class=identityIcon>"
|
||||||
|
else
|
||||||
|
capcodeClass = ''
|
||||||
|
capcodeStart = ''
|
||||||
|
capcode = ''
|
||||||
|
|
||||||
|
flag =
|
||||||
|
if flagCode
|
||||||
|
" <img src='#{staticPath}/image/country/#{if board is 'pol' then 'troll/' else ''}" +
|
||||||
|
flagCode.toLowerCase() + ".gif' alt=#{flagCode} title='#{flagName}' class=countryFlag>"
|
||||||
|
else
|
||||||
|
''
|
||||||
|
|
||||||
|
if file?.isDeleted
|
||||||
|
fileHTML =
|
||||||
|
if isOP
|
||||||
|
"<div class=file id=f#{postID}><div class=fileInfo></div><span class=fileThumb>" +
|
||||||
|
"<img src='#{staticPath}/image/filedeleted.gif' alt='File deleted.'>" +
|
||||||
|
"</span></div>"
|
||||||
else
|
else
|
||||||
"#{file.width}x#{file.height}"
|
"<div id=f#{postID} class=file><span class=fileThumb>" +
|
||||||
html.push ", <span title='#{file.name}'>#{Build.shortFilename file.name}</span>" unless file.isSpoiler
|
"<img src='#{staticPath}/image/filedeleted-res.gif' alt='File deleted.'>" +
|
||||||
html.push ")</span></div>"
|
"</span></div>"
|
||||||
html.push "<a class='fileThumb#{if file.isSpoiler then ' imgspoiler' else ''}' href=#{file.url} target=_blank>"
|
else if file
|
||||||
html.push "<img src=#{file.turl} alt='#{if file.isSpoiler then 'Spoiler Image, ' else ''}#{$.bytesToString file.size}' data-md5='#{file.MD5}' style='height:#{file.theight}px;width:#{file.twidth}px'>"
|
ext = file.name[-3..]
|
||||||
html.push '</a>'
|
if !file.twidth and !file.theight and ext is 'gif' # wtf ?
|
||||||
fl = $.el 'div',
|
file.twidth = file.width
|
||||||
id: "f#{postID}"
|
file.theight = file.height
|
||||||
className: 'file'
|
|
||||||
innerHTML: html.join ''
|
|
||||||
|
|
||||||
post = $.el 'div',
|
fileSize = $.bytesToString file.size
|
||||||
id: "p#{postID}"
|
|
||||||
className: "post #{if isOP then 'op' else 'reply'}"
|
fileThumb = file.turl
|
||||||
$.add post, fl if fl and isOP
|
if file.isSpoiler
|
||||||
$.add post, pi
|
fileSize = "Spoiler Image, #{fileSize}"
|
||||||
$.add post, fl if fl and !isOP
|
unless isArchived
|
||||||
$.add post, bq
|
fileThumb = '//static.4chan.org/image/spoiler'
|
||||||
|
if spoilerRange = Build.spoilerRange[board]
|
||||||
|
# Randomize the spoiler image.
|
||||||
|
fileThumb += "-#{board}" + Math.floor 1 + spoilerRange * Math.random()
|
||||||
|
fileThumb += '.png'
|
||||||
|
file.twidth = file.theight = 100
|
||||||
|
|
||||||
|
imgSrc = "<a class='fileThumb#{if file.isSpoiler then ' imgspoiler' else ''}' href='#{file.url}' target=_blank>" +
|
||||||
|
"<img src='#{fileThumb}' alt='#{fileSize}' data-md5=#{file.MD5} style='width:#{file.twidth}px;height:#{file.theight}px'></a>"
|
||||||
|
|
||||||
|
# Ha Ha filenames.
|
||||||
|
# html -> text, translate WebKit's %22s into "s
|
||||||
|
a = $.el 'a', innerHTML: file.name
|
||||||
|
filename = a.textContent.replace /%22/g, '"'
|
||||||
|
|
||||||
|
# shorten filename, get html
|
||||||
|
a.textContent = Build.shortFilename filename
|
||||||
|
shortFilename = a.innerHTML
|
||||||
|
|
||||||
|
# get html
|
||||||
|
a.textContent = filename
|
||||||
|
filename = a.innerHTML.replace /'/g, '''
|
||||||
|
|
||||||
|
fileDims = if ext is 'pdf' then 'PDF' else "#{file.width}x#{file.height}"
|
||||||
|
fileInfo = "<span class=fileText id=fT#{postID}#{if file.isSpoiler then " title='#{filename}'" else ''}>File: <a href='#{file.url}' target=_blank>#{file.timestamp}</a>" +
|
||||||
|
"-(#{fileSize}, #{fileDims}#{
|
||||||
|
if file.isSpoiler
|
||||||
|
''
|
||||||
|
else
|
||||||
|
", <span title='#{filename}'>#{shortFilename}</span>"
|
||||||
|
}" + ")</span>"
|
||||||
|
|
||||||
|
fileHTML = "<div id=f#{postID} class=file><div class=fileInfo>#{fileInfo}</div>#{imgSrc}</div>"
|
||||||
|
else
|
||||||
|
fileHTML = ''
|
||||||
|
|
||||||
|
tripcode =
|
||||||
|
if tripcode
|
||||||
|
" <span class=postertrip>#{tripcode}</span>"
|
||||||
|
else
|
||||||
|
''
|
||||||
|
|
||||||
|
sticky =
|
||||||
|
if isSticky
|
||||||
|
' <img src=//static.4chan.org/image/sticky.gif alt=Sticky title=Sticky style="height:16px;width:16px">'
|
||||||
|
else
|
||||||
|
''
|
||||||
|
closed =
|
||||||
|
if isClosed
|
||||||
|
' <img src=//static.4chan.org/image/closed.gif alt=Closed title=Closed style="height:16px;width:16px">'
|
||||||
|
else
|
||||||
|
''
|
||||||
|
|
||||||
container = $.el 'div',
|
container = $.el 'div',
|
||||||
id: "pc#{postID}"
|
id: "pc#{postID}"
|
||||||
className: "postContainer #{if isOP then 'op' else 'reply'}Container"
|
className: "postContainer #{if isOP then 'op' else 'reply'}Container"
|
||||||
unless isOP
|
innerHTML: \
|
||||||
$.add container, $.el 'div',
|
(if isOP then '' else "<div class=sideArrows id=sa#{postID}>>></div>") +
|
||||||
id: "sa#{postID}"
|
"<div id=p#{postID} class='post #{if isOP then 'op' else 'reply'}#{
|
||||||
className: 'sideArrows'
|
if capcode is 'admin_highlight'
|
||||||
textContent: '>>'
|
' highlightPost'
|
||||||
$.add container, post
|
else
|
||||||
|
''
|
||||||
|
}'>" +
|
||||||
|
|
||||||
|
"<div class='postInfoM mobile' id=pim#{postID}>" +
|
||||||
|
"<span class='nameBlock#{capcodeClass}'>" +
|
||||||
|
"<span class=name>#{name or ''}</span>" + tripcode +
|
||||||
|
capcodeStart + capcode + userID + flag + sticky + closed +
|
||||||
|
"<br>#{subject}" +
|
||||||
|
"</span><span class='dateTime postNum' data-utc=#{dateUTC}>#{date}" +
|
||||||
|
'<br><em>' +
|
||||||
|
"<a href=#{"/#{board}/res/#{threadID}#p#{postID}"}>No.</a>" +
|
||||||
|
"<a href='#{
|
||||||
|
if g.REPLY and g.THREAD_ID is threadID
|
||||||
|
"javascript:quote(#{postID})"
|
||||||
|
else
|
||||||
|
"/#{board}/res/#{threadID}#q#{postID}"
|
||||||
|
}'>#{postID}</a>" +
|
||||||
|
'</em></span>' +
|
||||||
|
'</div>' +
|
||||||
|
|
||||||
|
(if isOP then fileHTML else '') +
|
||||||
|
|
||||||
|
"<div class='postInfo desktop' id=pi#{postID}>" +
|
||||||
|
"<input type=checkbox name=#{postID} value=delete> " +
|
||||||
|
"#{subject} " +
|
||||||
|
"<span class='nameBlock#{capcodeClass}'>" +
|
||||||
|
emailStart +
|
||||||
|
"<span class=name>#{name or ''}</span>" + tripcode +
|
||||||
|
capcodeStart + emailEnd + capcode + userID + flag + sticky + closed +
|
||||||
|
' </span> ' +
|
||||||
|
"<span class=dateTime data-utc=#{dateUTC}>#{date}</span> " +
|
||||||
|
"<span class='postNum desktop'>" +
|
||||||
|
"<a href=#{"/#{board}/res/#{threadID}#p#{postID}"} title='Highlight this post'>No.</a>" +
|
||||||
|
"<a href='#{
|
||||||
|
if g.REPLY and g.THREAD_ID is threadID
|
||||||
|
"javascript:quote(#{postID})"
|
||||||
|
else
|
||||||
|
"/#{board}/res/#{threadID}#q#{postID}"
|
||||||
|
}' title='Quote this post'>#{postID}</a>" +
|
||||||
|
'</span>' +
|
||||||
|
'</div>' +
|
||||||
|
|
||||||
|
(if isOP then '' else fileHTML) +
|
||||||
|
|
||||||
|
"<blockquote class=postMessage id=m#{postID}>#{comment or ''}</blockquote> " +
|
||||||
|
|
||||||
|
'</div>'
|
||||||
|
|
||||||
|
for quote in $$ '.quotelink', container
|
||||||
|
href = quote.getAttribute 'href'
|
||||||
|
continue if href[0] is '/' # Cross-board quote, or board link
|
||||||
|
quote.href = "/#{board}/res/#{href}" # Fix pathnames
|
||||||
|
|
||||||
container
|
container
|
||||||
|
|
||||||
@ -1213,7 +1353,7 @@ Get =
|
|||||||
|
|
||||||
root.textContent = "Loading post No.#{postID}..."
|
root.textContent = "Loading post No.#{postID}..."
|
||||||
if threadID
|
if threadID
|
||||||
$.cache "/#{board}/res/#{threadID}", ->
|
$.cache "//api.4chan.org/#{board}/res/#{threadID}.json", ->
|
||||||
Get.fetchedPost @, board, threadID, postID, root, context
|
Get.fetchedPost @, board, threadID, postID, root, context
|
||||||
else if url = Redirect.post board, postID
|
else if url = Redirect.post board, postID
|
||||||
$.cache url, ->
|
$.cache url, ->
|
||||||
@ -1242,43 +1382,37 @@ Get =
|
|||||||
# The thread can die by the time we check a quote.
|
# The thread can die by the time we check a quote.
|
||||||
if url = Redirect.post board, postID
|
if url = Redirect.post board, postID
|
||||||
$.cache url, ->
|
$.cache url, ->
|
||||||
Get.archivedPost @, board, postID, root
|
Get.archivedPost @, board, postID, root, context
|
||||||
else
|
else
|
||||||
$.addClass root, 'warning'
|
$.addClass root, 'warning'
|
||||||
root.textContent =
|
root.textContent =
|
||||||
if status is 404
|
if status is 404
|
||||||
"Thread No.#{threadID} has not been found."
|
"Thread No.#{threadID} 404'd."
|
||||||
else
|
else
|
||||||
"Error #{req.status}: #{req.statusText}."
|
"Error #{req.status}: #{req.statusText}."
|
||||||
return
|
return
|
||||||
|
|
||||||
doc = d.implementation.createHTMLDocument ''
|
posts = JSON.parse(req.response).posts
|
||||||
doc.documentElement.innerHTML = req.response
|
if spoilerRange = posts[0].custom_spoiler
|
||||||
|
Build.spoilerRange[board] = spoilerRange
|
||||||
unless pc = doc.getElementById "pc#{postID}"
|
postID = +postID
|
||||||
# The post can be deleted by the time we check a quote.
|
for post in posts
|
||||||
if url = Redirect.post board, postID
|
break if post.no is postID # we found it!
|
||||||
$.cache url, ->
|
if post.no > postID
|
||||||
Get.archivedPost @, board, postID, root
|
# The post can be deleted by the time we check a quote.
|
||||||
else
|
if url = Redirect.post board, postID
|
||||||
$.addClass root, 'warning'
|
$.cache url, ->
|
||||||
root.textContent = "Post No.#{postID} has not been found."
|
Get.parseArchivedPost @, board, postID, root, context
|
||||||
return
|
else
|
||||||
pc = d.importNode pc, true
|
$.addClass root, 'warning'
|
||||||
|
root.textContent = "Post No.#{postID} was not found."
|
||||||
for quote in $$ '.quotelink', pc
|
return
|
||||||
href = quote.getAttribute 'href'
|
|
||||||
continue if href[0] is '/' # Cross-board quote, or board link
|
|
||||||
quote.href = "/#{board}/res/#{href}" # Fix pathnames
|
|
||||||
link = $ 'a[title="Highlight this post"]', pc
|
|
||||||
link.href = "/#{board}/res/#{threadID}#p#{postID}"
|
|
||||||
link.nextSibling.href = "/#{board}/res/#{threadID}#q#{postID}"
|
|
||||||
|
|
||||||
board = g.boards[board] or
|
board = g.boards[board] or
|
||||||
new Board board
|
new Board board
|
||||||
thread = g.threads["#{board}.#{threadID}"] or
|
thread = g.threads["#{board}.#{threadID}"] or
|
||||||
new Thread threadID, board
|
new Thread threadID, board
|
||||||
post = new Post pc, thread, board
|
post = new Post Build.postFromObject(post, board), thread, board
|
||||||
Main.callbackNodes Post, [post]
|
Main.callbackNodes Post, [post]
|
||||||
Get.insert post, root, context
|
Get.insert post, root, context
|
||||||
archivedPost: (req, board, postID, root, context) ->
|
archivedPost: (req, board, postID, root, context) ->
|
||||||
@ -1332,42 +1466,46 @@ Get =
|
|||||||
comment = bq.innerHTML.replace /(^|>)(>[^<$]+)(<|$)/g, '$1<span class=quote>$2</span>$3'
|
comment = bq.innerHTML.replace /(^|>)(>[^<$]+)(<|$)/g, '$1<span class=quote>$2</span>$3'
|
||||||
|
|
||||||
threadID = data.thread_num
|
threadID = data.thread_num
|
||||||
postContainer = Build.post
|
o =
|
||||||
# id
|
# id
|
||||||
postID: postID
|
postID: postID
|
||||||
threadID: threadID
|
threadID: threadID
|
||||||
board: board
|
board: board
|
||||||
# info
|
# info
|
||||||
name: data.name
|
name: data.name_processed
|
||||||
capcode: data.capcode
|
capcode: switch data.capcode
|
||||||
tripcode: data.trip
|
when 'M' then 'mod'
|
||||||
uniqueID: data.poster_hash
|
when 'A' then 'admin'
|
||||||
email: data.email
|
when 'D' then 'developer'
|
||||||
subject: data.title
|
tripcode: data.trip
|
||||||
flag: data.poster_country
|
uniqueID: data.poster_hash
|
||||||
# XXX flagTitle: data.???
|
email: encodeURIComponent data.email
|
||||||
date: data.fourchan_date
|
subject: data.title_processed
|
||||||
dateUTC: data.timestamp
|
flagCode: data.poster_country
|
||||||
comment: comment
|
flagName: data.poster_country_name_processed
|
||||||
|
date: data.fourchan_date
|
||||||
|
dateUTC: data.timestamp
|
||||||
|
comment: comment
|
||||||
# file
|
# file
|
||||||
file:
|
if data.media_filename
|
||||||
name: data.media_filename
|
o.file =
|
||||||
origin: data.media_orig
|
name: data.media_filename_processed
|
||||||
|
timestamp: data.media_orig
|
||||||
url: data.media_link or data.remote_media_link
|
url: data.media_link or data.remote_media_link
|
||||||
height: data.media_h
|
height: data.media_h
|
||||||
width: data.media_w
|
width: data.media_w
|
||||||
isSpoiler: data.spoiler is '1'
|
|
||||||
MD5: data.media_hash
|
MD5: data.media_hash
|
||||||
size: data.media_size
|
size: data.media_size
|
||||||
turl: data.thumb_link or "//thumbs.4chan.org/#{board}/thumb/#{data.preview_orig}"
|
turl: data.thumb_link or "//thumbs.4chan.org/#{board}/thumb/#{data.preview_orig}"
|
||||||
theight: data.preview_h
|
theight: data.preview_h
|
||||||
twidth: data.preview_w
|
twidth: data.preview_w
|
||||||
|
isSpoiler: data.spoiler is '1'
|
||||||
|
|
||||||
board = g.boards[board] or
|
board = g.boards[board] or
|
||||||
new Board board
|
new Board board
|
||||||
thread = g.threads["#{board}.#{threadID}"] or
|
thread = g.threads["#{board}.#{threadID}"] or
|
||||||
new Thread threadID, board
|
new Thread threadID, board
|
||||||
post = new Post postContainer, thread, board,
|
post = new Post Build.post(o, true), thread, board,
|
||||||
isArchived: true
|
isArchived: true
|
||||||
Main.callbackNodes Post, [post]
|
Main.callbackNodes Post, [post]
|
||||||
Get.insert post, root, context
|
Get.insert post, root, context
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user