Add Post cloning. Close #315.
This commit is contained in:
parent
d96c7c92ae
commit
012d3ea332
159
4chan_x.user.js
159
4chan_x.user.js
@ -73,7 +73,9 @@
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $, $$, Board, Conf, Config, Main, Post, QuoteBacklink, Quotify, Thread, Time, UI, d, g;
|
||||
var $, $$, Board, Clone, Conf, Config, Main, Post, QuoteBacklink, Quotify, Thread, Time, UI, d, g,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Config = {
|
||||
main: {
|
||||
@ -657,45 +659,47 @@
|
||||
this.board = board;
|
||||
this.ID = +root.id.slice(2);
|
||||
post = $('.post', root);
|
||||
info = $('.postInfo', post);
|
||||
this.nodes = {
|
||||
root: root,
|
||||
post: post,
|
||||
info: $('.postInfo', post),
|
||||
info: info,
|
||||
comment: $('.postMessage', post),
|
||||
quotelinks: []
|
||||
quotelinks: [],
|
||||
backlinks: info.getElementsByClassName('backlink')
|
||||
};
|
||||
info = this.nodes.info;
|
||||
this.info = {};
|
||||
if (subject = $('.subject', info)) {
|
||||
this.nodes.subject = subject;
|
||||
this.subject = subject.textContent;
|
||||
this.info.subject = subject.textContent;
|
||||
}
|
||||
if (name = $('.name', info)) {
|
||||
this.nodes.name = name;
|
||||
this.name = name.textContent;
|
||||
this.info.name = name.textContent;
|
||||
}
|
||||
if (email = $('.useremail', info)) {
|
||||
this.nodes.email = email;
|
||||
this.email = decodeURIComponent(email.href.slice(7));
|
||||
this.info.email = decodeURIComponent(email.href.slice(7));
|
||||
}
|
||||
if (tripcode = $('.postertrip', info)) {
|
||||
this.nodes.tripcode = tripcode;
|
||||
this.tripcode = tripcode.textContent;
|
||||
this.info.tripcode = tripcode.textContent;
|
||||
}
|
||||
if (uniqueID = $('.posteruid', info)) {
|
||||
this.nodes.uniqueID = uniqueID;
|
||||
this.uniqueID = uniqueID.textContent;
|
||||
this.info.uniqueID = uniqueID.textContent;
|
||||
}
|
||||
if (capcode = $('.capcode', info)) {
|
||||
this.nodes.capcode = capcode;
|
||||
this.capcode = capcode.textContent;
|
||||
this.info.capcode = capcode.textContent;
|
||||
}
|
||||
if (flag = $('.countryFlag', info)) {
|
||||
this.nodes.flag = flag;
|
||||
this.flag = flag.title;
|
||||
this.info.flag = flag.title;
|
||||
}
|
||||
if (date = $('.dateTime', info)) {
|
||||
this.nodes.date = date;
|
||||
this.date = new Date(date.dataset.utc * 1000);
|
||||
this.info.date = new Date(date.dataset.utc * 1000);
|
||||
}
|
||||
bq = this.nodes.comment.cloneNode(true);
|
||||
_ref = $$('.abbr, .capcodeReplies, .exif, b', bq);
|
||||
@ -708,7 +712,7 @@
|
||||
for (i = _j = 0, _ref1 = nodes.snapshotLength; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
|
||||
text.push((data = nodes.snapshotItem(i).data) ? data : '\n');
|
||||
}
|
||||
this.comment = text.join('').replace(/^\n+|\n+$| +(?=\n|$)/g, '');
|
||||
this.info.comment = text.join('').replace(/^\n+|\n+$| +(?=\n|$)/g, '');
|
||||
quotes = {};
|
||||
_ref2 = $$('.quotelink', this.nodes.comment);
|
||||
for (_k = 0, _len1 = _ref2.length; _k < _len1; _k++) {
|
||||
@ -741,13 +745,105 @@
|
||||
}
|
||||
}
|
||||
this.isReply = $.hasClass(post, 'reply');
|
||||
this.clones = [];
|
||||
g.posts["" + board + "." + this] = thread.posts[this] = board.posts[this] = this;
|
||||
}
|
||||
|
||||
Post.prototype.addClone = function() {
|
||||
return new Clone(this);
|
||||
};
|
||||
|
||||
Post.prototype.rmClone = function(index) {
|
||||
var clone, i, _i, _ref;
|
||||
clone = this.clones.splice(index, 1);
|
||||
for (i = _i = index, _ref = this.clones.length; index <= _ref ? _i < _ref : _i > _ref; i = index <= _ref ? ++_i : --_i) {
|
||||
this.clones[i].nodes.root.setAttribute('data-clone', i);
|
||||
}
|
||||
return $.rm(clone.nodes.root);
|
||||
};
|
||||
|
||||
return Post;
|
||||
|
||||
})();
|
||||
|
||||
Clone = (function(_super) {
|
||||
|
||||
__extends(Clone, _super);
|
||||
|
||||
function Clone(origin) {
|
||||
var file, index, info, key, nodes, post, quotelink, root, val, _i, _j, _len, _len1, _ref, _ref1, _ref2;
|
||||
_ref = ['ID', 'board', 'thread', 'info', 'quotes', 'isReply'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
key = _ref[_i];
|
||||
this[key] = origin[key];
|
||||
}
|
||||
nodes = origin.nodes;
|
||||
root = nodes.root.cloneNode(true);
|
||||
post = $('.post', root);
|
||||
info = $('.postInfo', post);
|
||||
this.nodes = {
|
||||
root: root,
|
||||
post: post,
|
||||
info: info,
|
||||
comment: $('.postMessage', post),
|
||||
quotelinks: [],
|
||||
backlinks: info.getElementsByClassName('backlinks')
|
||||
};
|
||||
if (nodes.subject) {
|
||||
this.nodes.subject = $('.subject', info);
|
||||
}
|
||||
if (nodes.name) {
|
||||
this.nodes.name = $('.name', info);
|
||||
}
|
||||
if (nodes.email) {
|
||||
this.nodes.email = $('.useremail', info);
|
||||
}
|
||||
if (nodes.tripcode) {
|
||||
this.nodes.tripcode = $('.postertrip', info);
|
||||
}
|
||||
if (nodes.uniqueID) {
|
||||
this.nodes.uniqueID = $('.posteruid', info);
|
||||
}
|
||||
if (nodes.capcode) {
|
||||
this.nodes.capcode = $('.capcode', info);
|
||||
}
|
||||
if (nodes.flag) {
|
||||
this.nodes.flag = $('.countryFlag', info);
|
||||
}
|
||||
if (nodes.date) {
|
||||
this.nodes.date = $('.dateTime', info);
|
||||
}
|
||||
if (nodes.backlinkContainer) {
|
||||
this.nodes.backlinkContainer = $('.container', info);
|
||||
}
|
||||
_ref1 = $$('.quotelink', this.nodes.comment);
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
quotelink = _ref1[_j];
|
||||
if (quotelink.hash || $.hasClass(quotelink, 'deadlink')) {
|
||||
this.nodes.quotelinks.push(quotelink);
|
||||
}
|
||||
}
|
||||
if (origin.file) {
|
||||
this.file = {};
|
||||
_ref2 = origin.file;
|
||||
for (key in _ref2) {
|
||||
val = _ref2[key];
|
||||
this.file[key] = val;
|
||||
}
|
||||
file = $('.file', post);
|
||||
this.file.info = $('.fileInfo', file);
|
||||
this.file.text = $('.fileText', file);
|
||||
this.file.thumb = $('img[data-md5]', file);
|
||||
}
|
||||
this.isClone = true;
|
||||
index = origin.clones.push(this);
|
||||
root.setAttribute('data-clone', index);
|
||||
}
|
||||
|
||||
return Clone;
|
||||
|
||||
})(Post);
|
||||
|
||||
Main = {
|
||||
init: function() {
|
||||
var flatten, key, pathname, val;
|
||||
@ -913,6 +1009,9 @@
|
||||
},
|
||||
node: function() {
|
||||
var ID, a, board, data, i, index, m, node, nodes, quote, quoteID, quotes, snapshot, text, _i, _j, _len, _ref;
|
||||
if (this.isClone) {
|
||||
return;
|
||||
}
|
||||
snapshot = d.evaluate('.//text()[not(parent::a)]', this.nodes.comment, null, 6, null);
|
||||
for (i = _i = 0, _ref = snapshot.snapshotLength; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
node = snapshot.snapshotItem(i);
|
||||
@ -934,7 +1033,8 @@
|
||||
this.quotes.push(quoteID);
|
||||
}
|
||||
a = $.el('a', {
|
||||
textContent: quote
|
||||
textContent: quote,
|
||||
className: 'quotelink deadlink'
|
||||
});
|
||||
this.nodes.quotelinks.push(a);
|
||||
nodes.push(a);
|
||||
@ -964,8 +1064,8 @@
|
||||
});
|
||||
},
|
||||
firstNode: function() {
|
||||
var a, link, quote, _i, _len, _ref;
|
||||
if (!this.quotes.length) {
|
||||
var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
||||
if (this.isClone || !this.quotes.length) {
|
||||
return;
|
||||
}
|
||||
a = $.el('a', {
|
||||
@ -976,15 +1076,29 @@
|
||||
_ref = this.quotes;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
quote = _ref[_i];
|
||||
link = a.cloneNode(true);
|
||||
$.add(QuoteBacklink.getContainer(quote), [$.tn(' '), link]);
|
||||
containers = [QuoteBacklink.getContainer(quote)];
|
||||
if (post = g.posts[quote]) {
|
||||
_ref1 = post.clones;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
clone = _ref1[_j];
|
||||
containers.push(clone.nodes.backlinkContainer);
|
||||
}
|
||||
}
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
link = a.cloneNode(true);
|
||||
$.add(container, [$.tn(' '), link]);
|
||||
}
|
||||
}
|
||||
},
|
||||
secondNode: function() {
|
||||
if (!(Conf['OP Backlinks'] || this.isReply)) {
|
||||
var container;
|
||||
if (this.isClone || !(Conf['OP Backlinks'] || this.isReply)) {
|
||||
return;
|
||||
}
|
||||
return $.add(this.nodes.info, QuoteBacklink.getContainer("" + this.board + "." + this));
|
||||
container = QuoteBacklink.getContainer("" + this.board + "." + this);
|
||||
this.nodes.backlinkContainer = container;
|
||||
return $.add(this.nodes.info, container);
|
||||
},
|
||||
getContainer: function(id) {
|
||||
var _base;
|
||||
@ -1003,7 +1117,10 @@
|
||||
});
|
||||
},
|
||||
node: function() {
|
||||
return this.nodes.date.textContent = Time.funk(Time, this.date);
|
||||
if (this.isClone) {
|
||||
return;
|
||||
}
|
||||
return this.nodes.date.textContent = Time.funk(Time, this.info.date);
|
||||
},
|
||||
createFunc: function() {
|
||||
var code;
|
||||
|
||||
145
script.coffee
145
script.coffee
@ -324,7 +324,7 @@ $.extend $,
|
||||
$.add d.head, style
|
||||
style
|
||||
x: (path, root=d.body) ->
|
||||
# XPathResult.ANY_UNORDERED_NODE_TYPE is 8
|
||||
# XPathResult.ANY_UNORDERED_NODE_TYPE === 8
|
||||
d.evaluate(path, root, null, 8, null).singleNodeValue
|
||||
addClass: (el, className) ->
|
||||
el.classList.add className
|
||||
@ -504,39 +504,41 @@ class Post
|
||||
constructor: (root, @thread, @board) ->
|
||||
@ID = +root.id[2..]
|
||||
|
||||
post = $ '.post', root
|
||||
post = $ '.post', root
|
||||
info = $ '.postInfo', post
|
||||
@nodes =
|
||||
root: root
|
||||
post: post
|
||||
info: $ '.postInfo', post
|
||||
info: info
|
||||
comment: $ '.postMessage', post
|
||||
quotelinks: []
|
||||
backlinks: info.getElementsByClassName 'backlink'
|
||||
|
||||
info = @nodes.info
|
||||
@info = {}
|
||||
if subject = $ '.subject', info
|
||||
@nodes.subject = subject
|
||||
@subject = subject.textContent
|
||||
@info.subject = subject.textContent
|
||||
if name = $ '.name', info
|
||||
@nodes.name = name
|
||||
@name = name.textContent
|
||||
@info.name = name.textContent
|
||||
if email = $ '.useremail', info
|
||||
@nodes.email = email
|
||||
@email = decodeURIComponent email.href[7..]
|
||||
@info.email = decodeURIComponent email.href[7..]
|
||||
if tripcode = $ '.postertrip', info
|
||||
@nodes.tripcode = tripcode
|
||||
@tripcode = tripcode.textContent
|
||||
@info.tripcode = tripcode.textContent
|
||||
if uniqueID = $ '.posteruid', info
|
||||
@nodes.uniqueID = uniqueID
|
||||
@uniqueID = uniqueID.textContent
|
||||
@info.uniqueID = uniqueID.textContent
|
||||
if capcode = $ '.capcode', info
|
||||
@nodes.capcode = capcode
|
||||
@capcode = capcode.textContent
|
||||
@info.capcode = capcode.textContent
|
||||
if flag = $ '.countryFlag', info
|
||||
@nodes.flag = flag
|
||||
@flag = flag.title
|
||||
@info.flag = flag.title
|
||||
if date = $ '.dateTime', info
|
||||
@nodes.date = date
|
||||
@date = new Date date.dataset.utc * 1000
|
||||
@info.date = new Date date.dataset.utc * 1000
|
||||
|
||||
# Get the comment's text.
|
||||
# <br> -> \n
|
||||
@ -555,16 +557,16 @@ class Post
|
||||
nodes = d.evaluate './/br|.//text()', bq, null, 7, null
|
||||
for i in [0...nodes.snapshotLength]
|
||||
text.push if data = nodes.snapshotItem(i).data then data else '\n'
|
||||
@comment = text.join('').replace /^\n+|\n+$| +(?=\n|$)/g, ''
|
||||
@info.comment = text.join('').replace /^\n+|\n+$| +(?=\n|$)/g, ''
|
||||
|
||||
quotes = {}
|
||||
for quotelink in $$ '.quotelink', @nodes.comment
|
||||
# Don't add board links. (>>>/b/)
|
||||
# Don't add text-board quotelinks. (>>>/img/1234)
|
||||
# Don't count capcode replies as quote. (Admin/Mod/Dev Replies: ...)
|
||||
# Don't count capcode replies as quotes. (Admin/Mod/Dev Replies: ...)
|
||||
# Only add quotes that link to posts on an imageboard.
|
||||
if quotelink.hash
|
||||
@.nodes.quotelinks.push quotelink
|
||||
@nodes.quotelinks.push quotelink
|
||||
continue if quotelink.parentNode.parentNode.className is 'capcodeReplies'
|
||||
quotes["#{quotelink.pathname.split('/')[1]}.#{quotelink.hash[2..]}"] = true
|
||||
@quotes = Object.keys quotes
|
||||
@ -588,9 +590,74 @@ class Post
|
||||
@file.dimensions = @file.text.textContent.match(/\d+x\d+/)[0]
|
||||
|
||||
@isReply = $.hasClass post, 'reply'
|
||||
|
||||
@clones = []
|
||||
g.posts["#{board}.#{@}"] = thread.posts[@] = board.posts[@] = @
|
||||
|
||||
addClone: ->
|
||||
new Clone @
|
||||
rmClone: (index) ->
|
||||
clone = @clones.splice index, 1
|
||||
for i in [index...@clones.length]
|
||||
@clones[i].nodes.root.setAttribute 'data-clone', i
|
||||
$.rm clone.nodes.root
|
||||
|
||||
class Clone extends Post
|
||||
constructor: (origin) ->
|
||||
for key in ['ID', 'board', 'thread', 'info', 'quotes', 'isReply']
|
||||
# Copy or point to the origin's key value.
|
||||
@[key] = origin[key]
|
||||
|
||||
{nodes} = origin
|
||||
root = nodes.root.cloneNode true
|
||||
post = $ '.post', root
|
||||
info = $ '.postInfo', post
|
||||
@nodes =
|
||||
root: root
|
||||
post: post
|
||||
info: info
|
||||
comment: $ '.postMessage', post
|
||||
quotelinks: []
|
||||
backlinks: info.getElementsByClassName 'backlinks'
|
||||
|
||||
if nodes.subject
|
||||
@nodes.subject = $ '.subject', info
|
||||
if nodes.name
|
||||
@nodes.name = $ '.name', info
|
||||
if nodes.email
|
||||
@nodes.email = $ '.useremail', info
|
||||
if nodes.tripcode
|
||||
@nodes.tripcode = $ '.postertrip', info
|
||||
if nodes.uniqueID
|
||||
@nodes.uniqueID = $ '.posteruid', info
|
||||
if nodes.capcode
|
||||
@nodes.capcode = $ '.capcode', info
|
||||
if nodes.flag
|
||||
@nodes.flag = $ '.countryFlag', info
|
||||
if nodes.date
|
||||
@nodes.date = $ '.dateTime', info
|
||||
if nodes.backlinkContainer
|
||||
@nodes.backlinkContainer = $ '.container', info
|
||||
|
||||
for quotelink in $$ '.quotelink', @nodes.comment
|
||||
# See comments in Post's constructor.
|
||||
if quotelink.hash or $.hasClass quotelink, 'deadlink'
|
||||
@nodes.quotelinks.push quotelink
|
||||
|
||||
if origin.file
|
||||
# Copy values, point to relevant elements.
|
||||
# See comments in Post's constructor.
|
||||
@file = {}
|
||||
for key, val of origin.file
|
||||
@file[key] = val
|
||||
file = $ '.file', post
|
||||
@file.info = $ '.fileInfo', file
|
||||
@file.text = $ '.fileText', file
|
||||
@file.thumb = $ 'img[data-md5]', file
|
||||
|
||||
@isClone = true
|
||||
index = origin.clones.push @
|
||||
root.setAttribute 'data-clone', index
|
||||
|
||||
|
||||
Main =
|
||||
init: ->
|
||||
@ -779,9 +846,9 @@ Quotify =
|
||||
name: 'Resurrect Quotes'
|
||||
cb: @node
|
||||
node: ->
|
||||
# XXX return if post.isInlined and not post.isCrosspost
|
||||
return if @isClone
|
||||
|
||||
# XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 6
|
||||
# XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE === 6
|
||||
# Get all the text nodes that are not inside an anchor.
|
||||
snapshot = d.evaluate './/text()[not(parent::a)]', @nodes.comment, null, 6, null
|
||||
|
||||
@ -815,6 +882,8 @@ Quotify =
|
||||
# \u00A0 is nbsp
|
||||
# textContent: "#{quote}\u00A0(Dead)"
|
||||
textContent: quote
|
||||
# XXX
|
||||
className: 'quotelink deadlink'
|
||||
|
||||
# if board is g.BOARD and $.id "p#{ID}"
|
||||
# a.href = "#p#{ID}"
|
||||
@ -826,10 +895,6 @@ Quotify =
|
||||
# a.target = '_blank'
|
||||
# if Redirect.post board, ID
|
||||
# $.addClass a, 'quotelink'
|
||||
# # XXX https://github.com/greasemonkey/greasemonkey/issues/1571
|
||||
# # GM can't into dataset
|
||||
# # a.dataset.board = board
|
||||
# # a.dataset.id = ID
|
||||
# a.setAttribute 'data-board', board
|
||||
# a.setAttribute 'data-id', ID
|
||||
|
||||
@ -868,28 +933,34 @@ QuoteBacklink =
|
||||
name: 'Quote Backlinking Part 2'
|
||||
cb: @secondNode
|
||||
firstNode: ->
|
||||
# XXX return if post.isInlined
|
||||
return unless @quotes.length
|
||||
return if @isClone or !@quotes.length
|
||||
a = $.el 'a',
|
||||
href: "/#{@board}/res/#{@thread}#p#{@}"
|
||||
# XXX className: if post.el.hidden then 'filtered backlink' else 'backlink'
|
||||
className: 'backlink'
|
||||
textContent: QuoteBacklink.funk @ID
|
||||
for quote in @quotes
|
||||
link = a.cloneNode true
|
||||
# XXX
|
||||
# if Conf['Quote Preview']
|
||||
# $.on link, 'mouseover', QuotePreview.mouseover
|
||||
# if Conf['Quote Inline']
|
||||
# $.on link, 'click', QuoteInline.toggle
|
||||
# else
|
||||
# link.setAttribute 'onclick', "replyhl('#{post.ID}');"
|
||||
$.add QuoteBacklink.getContainer(quote), [$.tn(' '), link]
|
||||
containers = [QuoteBacklink.getContainer quote]
|
||||
if post = g.posts[quote]
|
||||
for clone in post.clones
|
||||
containers.push clone.nodes.backlinkContainer
|
||||
for container in containers
|
||||
link = a.cloneNode true
|
||||
# XXX
|
||||
# if Conf['Quote Preview']
|
||||
# $.on link, 'mouseover', QuotePreview.mouseover
|
||||
# if Conf['Quote Inline']
|
||||
# $.on link, 'click', QuoteInline.toggle
|
||||
# else
|
||||
# link.setAttribute 'onclick', "replyhl('#{post.ID}');"
|
||||
$.add container, [$.tn(' '), link]
|
||||
return
|
||||
secondNode: ->
|
||||
# Don't backlink the OP.
|
||||
return unless Conf['OP Backlinks'] or @isReply
|
||||
$.add @nodes.info, QuoteBacklink.getContainer "#{@board}.#{@}"
|
||||
return if @isClone or !(Conf['OP Backlinks'] or @isReply)
|
||||
container = QuoteBacklink.getContainer "#{@board}.#{@}"
|
||||
@nodes.backlinkContainer = container
|
||||
$.add @nodes.info, container
|
||||
getContainer: (id) ->
|
||||
@containers[id] or=
|
||||
$.el 'span', className: 'container'
|
||||
@ -901,8 +972,8 @@ Time =
|
||||
name: 'Time Formatting'
|
||||
cb: @node
|
||||
node: ->
|
||||
# XXX return if @isInlined and not @isCrosspost
|
||||
@nodes.date.textContent = Time.funk Time, @date
|
||||
return if @isClone
|
||||
@nodes.date.textContent = Time.funk Time, @info.date
|
||||
createFunc: ->
|
||||
code = Conf['time'].replace /%([A-Za-z])/g, (s, c) ->
|
||||
if c of Time.formatters
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user