|
|
@ -80,6 +80,7 @@ define([
|
|
|
|
data.avatar = userData.avatar;
|
|
|
|
data.avatar = userData.avatar;
|
|
|
|
data.profile = userData.profile;
|
|
|
|
data.profile = userData.profile;
|
|
|
|
data.curvePublic = userData.curvePublic;
|
|
|
|
data.curvePublic = userData.curvePublic;
|
|
|
|
|
|
|
|
data.notifications = userData.notifications;
|
|
|
|
if (typeof(onChange) === "function" && Sortify(data) !== old) {
|
|
|
|
if (typeof(onChange) === "function" && Sortify(data) !== old) {
|
|
|
|
onChange();
|
|
|
|
onChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -92,17 +93,72 @@ define([
|
|
|
|
Env.metadataMgr.updateMetadata(md);
|
|
|
|
Env.metadataMgr.updateMetadata(md);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var sendReplyNotification = function (Env, uid) {
|
|
|
|
|
|
|
|
if (!Env.comments || !Env.comments.data || !Env.comments.authors) { return; }
|
|
|
|
|
|
|
|
if (!Env.common.isLoggedIn()) { return; }
|
|
|
|
|
|
|
|
var thread = Env.comments.data[uid];
|
|
|
|
|
|
|
|
if (!thread || !Array.isArray(thread.m)) { return; }
|
|
|
|
|
|
|
|
var userData = Env.metadataMgr.getUserData();
|
|
|
|
|
|
|
|
var privateData = Env.metadataMgr.getPrivateData();
|
|
|
|
|
|
|
|
var others = {};
|
|
|
|
|
|
|
|
// Get all the other registered users with a mailbox
|
|
|
|
|
|
|
|
thread.m.forEach(function (obj) {
|
|
|
|
|
|
|
|
var u = obj.u;
|
|
|
|
|
|
|
|
if (typeof(u) !== "number") { return; }
|
|
|
|
|
|
|
|
var author = Env.comments.authors[u];
|
|
|
|
|
|
|
|
if (!author || others[u] || !author.notifications || !author.curvePublic) { return; }
|
|
|
|
|
|
|
|
if (author.curvePublic === userData.curvePublic) { return; } // don't send to yourself
|
|
|
|
|
|
|
|
others[u] = {
|
|
|
|
|
|
|
|
curvePublic: author.curvePublic,
|
|
|
|
|
|
|
|
comment: obj.m,
|
|
|
|
|
|
|
|
content: obj.v,
|
|
|
|
|
|
|
|
notifications: author.notifications
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// Send the notification
|
|
|
|
|
|
|
|
Object.keys(others).forEach(function (id) {
|
|
|
|
|
|
|
|
var data = others[id];
|
|
|
|
|
|
|
|
Env.common.mailbox.sendTo("COMMENT_REPLY", {
|
|
|
|
|
|
|
|
channel: privateData.channel,
|
|
|
|
|
|
|
|
comment: data.comment,
|
|
|
|
|
|
|
|
content: data.content
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
channel: data.notifications,
|
|
|
|
|
|
|
|
curvePublic: data.curvePublic
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var cleanMentions = function ($el, full) {
|
|
|
|
|
|
|
|
$el.html('');
|
|
|
|
|
|
|
|
var el = $el[0];
|
|
|
|
|
|
|
|
var allowed = full ? ['data-profile', 'data-name', 'data-avatar', 'class']
|
|
|
|
|
|
|
|
: ['class'];
|
|
|
|
|
|
|
|
// Remove unnecessary/unsafe attributes
|
|
|
|
|
|
|
|
for (var i=el.attributes.length-1; i>0; i--) {
|
|
|
|
|
|
|
|
var name = el.attributes[i] && el.attributes[i].name;
|
|
|
|
|
|
|
|
if (allowed.indexOf(name) === -1) {
|
|
|
|
|
|
|
|
$el.removeAttr(name);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Messages.comments_submit = "Submit"; // XXX
|
|
|
|
Messages.comments_submit = "Submit"; // XXX
|
|
|
|
Messages.comments_reply = "Reply"; // XXX
|
|
|
|
Messages.comments_reply = "Reply"; // XXX
|
|
|
|
Messages.comments_resolve = "Resolve"; // XXX
|
|
|
|
Messages.comments_resolve = "Resolve"; // XXX
|
|
|
|
|
|
|
|
|
|
|
|
var getCommentForm = function (Env, reply, _cb) {
|
|
|
|
var getCommentForm = function (Env, reply, _cb) {
|
|
|
|
var cb = Util.once(_cb);
|
|
|
|
var cb = Util.once(_cb);
|
|
|
|
var userData = Env.metadataMgr.getUserData();
|
|
|
|
var userData = Env.metadataMgr.getUserData();
|
|
|
|
var name = Util.fixHTML(userData.name || Messages.anonymous);
|
|
|
|
var name = Util.fixHTML(userData.name || Messages.anonymous);
|
|
|
|
var avatar = h('span.cp-avatar');
|
|
|
|
var avatar = h('span.cp-avatar');
|
|
|
|
var textarea = h('textarea', {
|
|
|
|
var textarea = h('div.cp-textarea', {
|
|
|
|
tabindex: 1
|
|
|
|
tabindex: 1,
|
|
|
|
|
|
|
|
role: 'textbox',
|
|
|
|
|
|
|
|
'aria-multiline': true,
|
|
|
|
|
|
|
|
'aria-labelledby': 'cp-comments-label',
|
|
|
|
|
|
|
|
'aria-required': true,
|
|
|
|
|
|
|
|
contenteditable: true,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
Env.common.displayAvatar($(avatar), userData.avatar, name);
|
|
|
|
Env.common.displayAvatar($(avatar), userData.avatar, name);
|
|
|
|
|
|
|
|
|
|
|
@ -119,25 +175,80 @@ define([
|
|
|
|
Messages.comments_submit
|
|
|
|
Messages.comments_submit
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// List of allowed attributes in mentions
|
|
|
|
$(submit).click(function (e) {
|
|
|
|
$(submit).click(function (e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
e.stopPropagation();
|
|
|
|
cb(textarea.value);
|
|
|
|
var clone = textarea.cloneNode(true);
|
|
|
|
|
|
|
|
var notify = {};
|
|
|
|
|
|
|
|
var $clone = $(clone);
|
|
|
|
|
|
|
|
$clone.find('span.cp-mentions').each(function (i, el) {
|
|
|
|
|
|
|
|
var $el = $(el);
|
|
|
|
|
|
|
|
var curve = $el.attr('data-curve');
|
|
|
|
|
|
|
|
var notif = $el.attr('data-notifications');
|
|
|
|
|
|
|
|
cleanMentions($el, true);
|
|
|
|
|
|
|
|
if (!curve || !notif) { return; }
|
|
|
|
|
|
|
|
notify[curve] = notif;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
$clone.find('> *:not(.cp-mentions)').remove();
|
|
|
|
|
|
|
|
var content = clone.innerHTML.trim();
|
|
|
|
|
|
|
|
if (!content) { return; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send notification
|
|
|
|
|
|
|
|
var privateData = Env.metadataMgr.getPrivateData();
|
|
|
|
|
|
|
|
var userData = Env.metadataMgr.getUserData();
|
|
|
|
|
|
|
|
Object.keys(notify).forEach(function (curve) {
|
|
|
|
|
|
|
|
if (curve === userData.curvePublic) { return; }
|
|
|
|
|
|
|
|
Env.common.mailbox.sendTo("MENTION", {
|
|
|
|
|
|
|
|
channel: privateData.channel,
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
channel: notify[curve],
|
|
|
|
|
|
|
|
curvePublic: curve
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Push the content
|
|
|
|
|
|
|
|
cb(content);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
$(cancel).click(function (e) {
|
|
|
|
$(cancel).click(function (e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
e.stopPropagation();
|
|
|
|
cb();
|
|
|
|
cb();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
$(textarea).keydown(function (e) {
|
|
|
|
var $text = $(textarea).keydown(function (e) {
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
if (e.which === 27) {
|
|
|
|
if (e.which === 27) {
|
|
|
|
$(cancel).click();
|
|
|
|
$(cancel).click();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (e.which === 13 && !e.shiftKey) {
|
|
|
|
if (e.which === 13 && !e.shiftKey) {
|
|
|
|
|
|
|
|
// Submit form on Enter is the autocompelte menu is not visible
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
var visible = $text.autocomplete("instance").menu.activeMenu.is(':visible');
|
|
|
|
|
|
|
|
if (visible) { return; }
|
|
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
$(submit).click();
|
|
|
|
$(submit).click();
|
|
|
|
e.preventDefault();
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}).click(function (e) {
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (Env.common.isLoggedIn()) {
|
|
|
|
|
|
|
|
var authors = {};
|
|
|
|
|
|
|
|
Object.keys((Env.comments && Env.comments.authors) || {}).forEach(function (id) {
|
|
|
|
|
|
|
|
var obj = Util.clone(Env.comments.authors[id]);
|
|
|
|
|
|
|
|
authors[obj.curvePublic] = obj;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
Env.common.addMentions({
|
|
|
|
|
|
|
|
$input: $text,
|
|
|
|
|
|
|
|
contenteditable: true,
|
|
|
|
|
|
|
|
type: 'contacts',
|
|
|
|
|
|
|
|
sources: authors
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
setTimeout(function () {
|
|
|
|
$(textarea).focus();
|
|
|
|
$(textarea).focus();
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -168,6 +279,9 @@ define([
|
|
|
|
|
|
|
|
|
|
|
|
Env.$container.html('');
|
|
|
|
Env.$container.html('');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var label = h('label#cp-comments-label', Messages.comments_comment);
|
|
|
|
|
|
|
|
Env.$container.append(label);
|
|
|
|
|
|
|
|
|
|
|
|
var show = false;
|
|
|
|
var show = false;
|
|
|
|
|
|
|
|
|
|
|
|
if ($oldInput && !$oldInput.attr('data-uid')) {
|
|
|
|
if ($oldInput && !$oldInput.attr('data-uid')) {
|
|
|
@ -207,6 +321,40 @@ define([
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Build sanitized html with mentions
|
|
|
|
|
|
|
|
var m = h('div.cp-comment-content');
|
|
|
|
|
|
|
|
m.innerHTML = msg.m;
|
|
|
|
|
|
|
|
var $m = $(m);
|
|
|
|
|
|
|
|
$m.find('> *:not(span.cp-mentions)').remove();
|
|
|
|
|
|
|
|
$m.find('span.cp-mentions').each(function (i, el) {
|
|
|
|
|
|
|
|
var $el = $(el);
|
|
|
|
|
|
|
|
var name = $el.attr('data-name');
|
|
|
|
|
|
|
|
var avatarUrl = $el.attr('data-avatar');
|
|
|
|
|
|
|
|
var profile = $el.attr('data-profile');
|
|
|
|
|
|
|
|
if (!name && !avatar && !profile) {
|
|
|
|
|
|
|
|
$el.remove();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanMentions($el);
|
|
|
|
|
|
|
|
var avatar = h('span.cp-avatar');
|
|
|
|
|
|
|
|
Env.common.displayAvatar($(avatar), avatarUrl, name);
|
|
|
|
|
|
|
|
$el.append([
|
|
|
|
|
|
|
|
avatar,
|
|
|
|
|
|
|
|
h('span.cp-mentions-name', name)
|
|
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
if (profile) {
|
|
|
|
|
|
|
|
$el.attr('tabindex', 1);
|
|
|
|
|
|
|
|
$el.addClass('cp-mentions-clickable').click(function (e) {
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
Env.common.openURL(Hash.hashToHref(profile, 'profile'));
|
|
|
|
|
|
|
|
}).focus(function (e) {
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add the comment
|
|
|
|
content.push(h('div.cp-comment'+(i === 0 ? '' : '.cp-comment-reply'), [
|
|
|
|
content.push(h('div.cp-comment'+(i === 0 ? '' : '.cp-comment-reply'), [
|
|
|
|
h('div.cp-comment-header', [
|
|
|
|
h('div.cp-comment-header', [
|
|
|
|
avatar,
|
|
|
|
avatar,
|
|
|
@ -215,9 +363,7 @@ define([
|
|
|
|
h('span.cp-comment-time', date.toLocaleString())
|
|
|
|
h('span.cp-comment-time', date.toLocaleString())
|
|
|
|
])
|
|
|
|
])
|
|
|
|
]),
|
|
|
|
]),
|
|
|
|
h('div.cp-comment-content', [
|
|
|
|
m
|
|
|
|
msg.m
|
|
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
]));
|
|
|
|
]));
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -253,9 +399,9 @@ define([
|
|
|
|
e.stopPropagation();
|
|
|
|
e.stopPropagation();
|
|
|
|
$actions.hide();
|
|
|
|
$actions.hide();
|
|
|
|
var form = getCommentForm(Env, key, function (val) {
|
|
|
|
var form = getCommentForm(Env, key, function (val) {
|
|
|
|
$(form).remove();
|
|
|
|
|
|
|
|
$(form).closest('.cp-comment-container')
|
|
|
|
$(form).closest('.cp-comment-container')
|
|
|
|
.find('.cp-comment-actions').css('display', '');
|
|
|
|
.find('.cp-comment-actions').css('display', '');
|
|
|
|
|
|
|
|
$(form).remove();
|
|
|
|
|
|
|
|
|
|
|
|
if (!val) { return; }
|
|
|
|
if (!val) { return; }
|
|
|
|
var obj = Env.comments.data[key];
|
|
|
|
var obj = Env.comments.data[key];
|
|
|
@ -276,6 +422,9 @@ define([
|
|
|
|
v: value
|
|
|
|
v: value
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Notify other users
|
|
|
|
|
|
|
|
sendReplyNotification(Env, key);
|
|
|
|
|
|
|
|
|
|
|
|
// Send to chainpad
|
|
|
|
// Send to chainpad
|
|
|
|
updateMetadata(Env);
|
|
|
|
updateMetadata(Env);
|
|
|
|
Env.framework.localChange();
|
|
|
|
Env.framework.localChange();
|
|
|
@ -356,7 +505,7 @@ define([
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (Env.ready) {
|
|
|
|
} else if (Env.ready) {
|
|
|
|
// Everytime there is a metadata change, check if our user data have changed
|
|
|
|
// Everytime there is a metadata change, check if our user data have changed
|
|
|
|
// and puhs the update sif necessary
|
|
|
|
// and push the updates if necessary
|
|
|
|
updateAuthorData(Env, function () {
|
|
|
|
updateAuthorData(Env, function () {
|
|
|
|
updateMetadata(Env);
|
|
|
|
updateMetadata(Env);
|
|
|
|
Env.framework.localChange();
|
|
|
|
Env.framework.localChange();
|
|
|
|