mirror of
https://github.com/wassname/talk.git
synced 2026-07-06 05:17:19 +08:00
222 lines
5.3 KiB
JavaScript
222 lines
5.3 KiB
JavaScript
import update from 'immutability-helper';
|
|
function determineCommentDepth(comment) {
|
|
let depth = 0;
|
|
let cur = comment;
|
|
while (cur.parent) {
|
|
cur = cur.parent;
|
|
depth++;
|
|
}
|
|
return depth;
|
|
}
|
|
|
|
function applyToCommentsOrigin(root, callback) {
|
|
if (root.comment) {
|
|
let comment = root.comment;
|
|
for (let depth = 0; depth <= determineCommentDepth(comment); depth++) {
|
|
let changes = {$apply: (node) => node ? callback(node) : node};
|
|
for (let i = 0; i < depth; i++) {
|
|
changes = {parent: changes};
|
|
}
|
|
comment = update(comment, changes);
|
|
}
|
|
|
|
return {
|
|
...root,
|
|
comment,
|
|
};
|
|
}
|
|
return update(root, {
|
|
asset: {$apply: (asset) => callback(asset)},
|
|
});
|
|
}
|
|
|
|
function findAndInsertComment(parent, comment) {
|
|
const [connectionField, countField, action] = parent.__typename === 'Asset'
|
|
? ['comments', 'commentCount', '$unshift']
|
|
: ['replies', 'replyCount', '$push'];
|
|
|
|
if (!comment.parent || parent.id === comment.parent.id) {
|
|
return update(parent, {
|
|
[connectionField]: {
|
|
nodes: {[action]: [comment]},
|
|
},
|
|
[countField]: {$apply: (c) => c + 1},
|
|
});
|
|
}
|
|
const connection = parent[connectionField];
|
|
if (!connection) {
|
|
return parent;
|
|
}
|
|
return update(parent, {
|
|
[connectionField]: {
|
|
nodes: {
|
|
$apply: (nodes) =>
|
|
nodes.map((node) => findAndInsertComment(node, comment))
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
export function insertCommentIntoEmbedQuery(root, comment) {
|
|
|
|
// Increase total comment count by one.
|
|
root = update(root, {
|
|
asset: {
|
|
totalCommentCount: {$apply: (c) => c + 1},
|
|
},
|
|
});
|
|
return applyToCommentsOrigin(root, (origin) => findAndInsertComment(origin, comment));
|
|
}
|
|
|
|
function findAndRemoveComment(parent, id) {
|
|
const [connectionField, countField] = parent.__typename === 'Asset'
|
|
? ['comments', 'commentCount']
|
|
: ['replies', 'replyCount'];
|
|
|
|
const connection = parent[connectionField];
|
|
if (!connection) {
|
|
return parent;
|
|
}
|
|
|
|
let next = connection.nodes.filter((node) => node.id !== id);
|
|
if (next.length === connection.nodes.length) {
|
|
next = next.map((node) => findAndRemoveComment(node, id));
|
|
}
|
|
let changes = {
|
|
[connectionField]: {
|
|
nodes: {$set: next},
|
|
},
|
|
};
|
|
|
|
if (parent[countField] && next.length !== connection.nodes.length) {
|
|
changes[countField] = {$set: parent[countField] - 1};
|
|
}
|
|
return update(parent, changes);
|
|
}
|
|
|
|
export function removeCommentFromEmbedQuery(root, id) {
|
|
|
|
// Decrease total comment by one.
|
|
root = update(root, {
|
|
asset: {
|
|
totalCommentCount: {$apply: (c) => c - 1},
|
|
},
|
|
});
|
|
return applyToCommentsOrigin(root, (origin) => findAndRemoveComment(origin, id));
|
|
}
|
|
|
|
export function getTopLevelParent(comment) {
|
|
if (comment.parent) {
|
|
return getTopLevelParent(comment.parent);
|
|
}
|
|
return comment;
|
|
}
|
|
|
|
function findComment(nodes, callback) {
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
const node = nodes[i];
|
|
if (callback(node)) {
|
|
return node;
|
|
}
|
|
if (node.replies) {
|
|
const find = findComment(node.replies.nodes, callback);
|
|
if (find){
|
|
return find;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export function findCommentInEmbedQuery(root, callbackOrId) {
|
|
let callback = callbackOrId;
|
|
if (typeof callbackOrId === 'string') {
|
|
callback = (node) => node.id === callbackOrId;
|
|
}
|
|
if (root.comment) {
|
|
return findComment([getTopLevelParent(root.comment)], callback);
|
|
}
|
|
if (!root.asset.comments) {
|
|
return false;
|
|
}
|
|
return findComment(root.asset.comments.nodes, callback);
|
|
}
|
|
|
|
const ascending = (a, b) => {
|
|
const dateA = new Date(a.created_at);
|
|
const dateB = new Date(b.created_at);
|
|
if (dateA < dateB) { return -1; }
|
|
if (dateA > dateB) { return 1; }
|
|
return 0;
|
|
};
|
|
|
|
function findAndInsertFetchedComments(parent, comments, parent_id) {
|
|
const isAsset = parent.__typename === 'Asset';
|
|
const connectionField = isAsset ? 'comments' : 'replies';
|
|
if (!parent_id && connectionField === 'comments' || parent.id === parent_id) {
|
|
return update(parent, {
|
|
[connectionField]: {
|
|
hasNextPage: {$set: comments.hasNextPage},
|
|
endCursor: {$set: comments.endCursor},
|
|
nodes: {$apply: (nodes) => {
|
|
if (isAsset) {
|
|
return nodes.concat(comments.nodes);
|
|
}
|
|
return nodes
|
|
.concat(comments.nodes.filter(
|
|
(comment) => !nodes.some((node) => node.id === comment.id)
|
|
))
|
|
.sort(ascending);
|
|
}},
|
|
},
|
|
});
|
|
}
|
|
|
|
const connection = parent[connectionField];
|
|
if (!connection) {
|
|
return parent;
|
|
}
|
|
return update(parent, {
|
|
[connectionField]: {
|
|
nodes: {
|
|
$apply: (nodes) =>
|
|
nodes.map((node) => findAndInsertFetchedComments(node, comments, parent_id))
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
export function insertFetchedCommentsIntoEmbedQuery(root, comments, parent_id) {
|
|
return applyToCommentsOrigin(root, (origin) => findAndInsertFetchedComments(origin, comments, parent_id));
|
|
}
|
|
|
|
/**
|
|
* Nest a string in itself repeatly until `level` has been reached.
|
|
*
|
|
* Example:
|
|
* nest(`
|
|
* a
|
|
* ...nest
|
|
* b
|
|
* `, 2)
|
|
*
|
|
* Output:
|
|
* `
|
|
* a
|
|
* a
|
|
* b
|
|
* b
|
|
* `
|
|
*/
|
|
export function nest(document, level) {
|
|
let result = '';
|
|
for (let x = 0; x < level; x++) {
|
|
if (x === 0) {
|
|
result += document;
|
|
continue;
|
|
}
|
|
result = result.replace('...nest', document);
|
|
}
|
|
return result.replace('...nest', '');
|
|
}
|