mirror of https://github.com/xwiki-labs/cryptpad
New support: realtime update of admin and user views
This commit is contained in:
parent
43047ab326
commit
503bba974c
|
@ -59,10 +59,29 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
.cp-support-ispremium {
|
||||
padding: 0 5px;
|
||||
background-color: @cp_admin-premium-bg;
|
||||
}
|
||||
.cp-support-list-message {
|
||||
background-color: @msg-bg;
|
||||
padding: 5px 5px;
|
||||
border-radius: @variables_radius;
|
||||
&.cp-support-fromadmin {
|
||||
background-color: @cp_admin-isadmin-bg !important;
|
||||
.cp-support-message-from, .cp-support-showdata {
|
||||
color: @cryptpad_text_col;
|
||||
background-color: fade(@cp_admin-isadmin-bg, 10%) !important;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
&.cp-support-frompremium {
|
||||
background-color: @cp_admin-premium-bg;
|
||||
.cp-support-showdata {
|
||||
background-color: fade(@cp_admin-premium-bg, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.cp-support-fromme {
|
||||
background-color: @fromme-bg;
|
||||
}
|
||||
|
@ -86,6 +105,9 @@
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
.cp-support-list-actions {
|
||||
display: flex;
|
||||
|
|
|
@ -861,17 +861,20 @@ define([
|
|||
var content = msg.content;
|
||||
content.time = data.time;
|
||||
|
||||
if (!content.isAdmin) { // A user replied to an admin
|
||||
// Update admin chainpad
|
||||
let i = 0;
|
||||
let handle = function () {
|
||||
var support = Util.find(ctx, ['store', 'modules', 'support']);
|
||||
if (!support && i++ < 100) { setTimeout(handle, 600); }
|
||||
if (!support) { return; }
|
||||
let i = 0;
|
||||
let handle = function () {
|
||||
var support = Util.find(ctx, ['store', 'modules', 'support']);
|
||||
if (!support && i++ < 100) { setTimeout(handle, 600); }
|
||||
if (!support) { return; }
|
||||
if (!content.isAdmin) { // A user replied to an admin
|
||||
// Update admin chainpad
|
||||
support.updateAdminTicket(content);
|
||||
};
|
||||
handle();
|
||||
}
|
||||
} else {
|
||||
// Trigger realtime update of user support
|
||||
support.updateUserTicket(content);
|
||||
}
|
||||
};
|
||||
handle();
|
||||
|
||||
if (supportNotif) { return void cb(true); }
|
||||
supportNotif = content.channel;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
define([
|
||||
'/api/config',
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-realtime.js',
|
||||
|
@ -11,7 +12,7 @@ define([
|
|||
'chainpad-listmap',
|
||||
'/components/chainpad/chainpad.dist.js',
|
||||
'chainpad-netflux'
|
||||
], function (Util, Hash, Realtime, nThen, Crypto, Listmap, ChainPad, CpNetflux) {
|
||||
], function (ApiConfig, Util, Hash, Realtime, nThen, Crypto, Listmap, ChainPad, CpNetflux) {
|
||||
var Support = {};
|
||||
|
||||
// UTILS
|
||||
|
@ -20,6 +21,8 @@ define([
|
|||
var cb = Util.mkAsync(_cb);
|
||||
if (isAdmin && !ctx.adminRdyEvt) { return void cb('EFORBIDDEN'); }
|
||||
require(['/api/config?' + (+new Date())], function (NewConfig) {
|
||||
ctx.adminKeys = NewConfig.adminKeys; // Update admin keys // XXX MODERATOR
|
||||
|
||||
var supportKey = NewConfig.newSupportMailbox;
|
||||
if (!supportKey) { return void cb('E_NOT_INIT'); }
|
||||
|
||||
|
@ -222,6 +225,11 @@ define([
|
|||
var getMyTickets = function (ctx, data, cId, cb) {
|
||||
var all = [];
|
||||
var n = nThen;
|
||||
if (!ctx.clients[cId]) {
|
||||
ctx.clients[cId] = {
|
||||
admin: false
|
||||
};
|
||||
}
|
||||
Object.keys(ctx.supportData).forEach(function (ticket) {
|
||||
n = n((waitFor) => {
|
||||
var t = Util.clone(ctx.supportData[ticket]);
|
||||
|
@ -250,6 +258,11 @@ define([
|
|||
|
||||
var listTicketsAdmin = function (ctx, data, cId, cb) {
|
||||
if (!ctx.adminRdyEvt) { return void cb({ error: 'EFORBIDDEN' }); }
|
||||
if (!ctx.clients[cId]) {
|
||||
ctx.clients[cId] = {
|
||||
admin: true
|
||||
};
|
||||
}
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
var doc = ctx.adminDoc.proxy;
|
||||
cb(Util.clone(doc.tickets.active));
|
||||
|
@ -264,8 +277,22 @@ define([
|
|||
if (Array.isArray(res) && res.length) {
|
||||
res.sort((t1, t2) => { return t1.time - t2.time; });
|
||||
let last = res[res.length - 1];
|
||||
let premium = res.some((msg) => {
|
||||
let curve = Util.find(msg, ['sender', 'curvePublic']);
|
||||
if (data.curvePublic !== curve) { return; }
|
||||
return Util.find(msg, ['sender', 'quota', 'plan']);
|
||||
});
|
||||
var senderKey = last.sender && last.sender.edPublic;
|
||||
|
||||
var entry = doc.tickets.active[data.channel];
|
||||
if (entry) { entry.time = last.time; }
|
||||
if (entry) {
|
||||
entry.time = last.time;
|
||||
entry.premium = premium;
|
||||
|
||||
if (senderKey) {
|
||||
entry.lastAdmin = ctx.adminKeys.indexOf(senderKey) !== -1
|
||||
}
|
||||
}
|
||||
}
|
||||
cb(res);
|
||||
});
|
||||
|
@ -288,6 +315,14 @@ define([
|
|||
|
||||
// Mailbox events
|
||||
|
||||
var notifyClient = function (ctx, admin, type, channel) {
|
||||
let notifyList = Object.keys(ctx.clients).filter((cId) => {
|
||||
return Boolean(ctx.clients[cId].admin) === admin;
|
||||
});
|
||||
if (!notifyList.length) { return; }
|
||||
ctx.emit(type, { channel }, [notifyList]);
|
||||
};
|
||||
|
||||
var addAdminTicket = function (ctx, data, cb) {
|
||||
// Wait for the chainpad to be ready before adding the data
|
||||
if (!ctx.adminRdyEvt) { return void cb(false); } // XXX not an admin, delete mailbox?
|
||||
|
@ -310,6 +345,7 @@ define([
|
|||
Realtime.whenRealtimeSyncs(ctx.adminDoc.realtime, function () {
|
||||
cb(false);
|
||||
});
|
||||
notifyClient(ctx, true, 'NEW_TICKET', data.channel);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -325,10 +361,15 @@ define([
|
|||
if (!doc.tickets.active[data.channel] && !doc.tickets.pending[data.channel]) {
|
||||
return; }
|
||||
let t = doc.tickets.active[data.channel] || doc.tickets.pending[data.channel];
|
||||
t.time = data.time;
|
||||
if (data.time > (t.time + 2000)) { t.time = data.time; }
|
||||
t.lastAdmin = false;
|
||||
notifyClient(ctx, true, 'UPDATE_TICKET', data.channel);
|
||||
});
|
||||
});
|
||||
};
|
||||
var updateUserTicket = function (ctx, data) {
|
||||
notifyClient(ctx, false, 'UPDATE_TICKET', data.channel);
|
||||
};
|
||||
|
||||
// INITIALIZE ADMIN
|
||||
|
||||
|
@ -354,6 +395,7 @@ define([
|
|||
doc.tickets = doc.tickets || {};
|
||||
doc.tickets.active = doc.tickets.active || {};
|
||||
doc.tickets.closed = doc.tickets.closed || {};
|
||||
doc.tickets.pending = doc.tickets.pending || {};
|
||||
ctx.adminRdyEvt.fire();
|
||||
cb();
|
||||
});
|
||||
|
@ -405,11 +447,11 @@ define([
|
|||
var proxy = store.proxy.support = store.proxy.support || {};
|
||||
|
||||
var ctx = {
|
||||
adminKeys: ApiConfig.adminKeys,
|
||||
supportData: proxy,
|
||||
store: cfg.store,
|
||||
Store: cfg.Store,
|
||||
emit: emit,
|
||||
channels: {},
|
||||
clients: {}
|
||||
};
|
||||
|
||||
|
@ -419,7 +461,7 @@ define([
|
|||
|
||||
support.ctx = ctx;
|
||||
support.removeClient = function (clientId) {
|
||||
// XXX TODO
|
||||
delete ctx.clients[clientId];
|
||||
};
|
||||
support.leavePad = function (padChan) {
|
||||
// XXX TODO
|
||||
|
@ -430,6 +472,9 @@ define([
|
|||
support.updateAdminTicket = function (content) {
|
||||
updateAdminTicket(ctx, content);
|
||||
};
|
||||
support.updateUserTicket = function (content) {
|
||||
updateUserTicket(ctx, content);
|
||||
};
|
||||
support.execCommand = function (clientId, obj, cb) {
|
||||
var cmd = obj.cmd;
|
||||
var data = obj.data;
|
||||
|
|
|
@ -52,16 +52,27 @@ define([
|
|||
var Nacl = window.nacl;
|
||||
var common;
|
||||
var sFrameChan;
|
||||
var events = {
|
||||
'NEW_TICKET': Util.mkEvent(),
|
||||
'UPDATE_TICKET': Util.mkEvent()
|
||||
};
|
||||
|
||||
var andThen = function () {
|
||||
var andThen = function (linkedTicket) {
|
||||
var $body = $('#cp-content-container');
|
||||
var button = h('button.btn.btn-primary', 'refresh'); // XXX
|
||||
$body.append(h('div', button));
|
||||
var $container = $(h('div.cp-support-container')).appendTo($body);
|
||||
|
||||
|
||||
var refresh = () => {
|
||||
let open = [];
|
||||
let refresh = () => {
|
||||
APP.module.execCommand('LIST_TICKETS_ADMIN', {}, (tickets) => {
|
||||
let activeForms = {};
|
||||
$container.find('.cp-support-form-container').each((i, el) => {
|
||||
let id = $(el).attr('data-id');
|
||||
if (!id) { return; }
|
||||
activeForms[id] = el;
|
||||
});
|
||||
$container.empty();
|
||||
var col1 = h('div.cp-support-column', h('h1', [
|
||||
h('span', Messages.admin_support_premium),
|
||||
|
@ -80,24 +91,33 @@ define([
|
|||
return tickets[c2].time - tickets[c1].time;
|
||||
};
|
||||
|
||||
const onLoad = function (ticket, channel, data) {
|
||||
const onShow = function (ticket, channel, data, done) {
|
||||
APP.module.execCommand('LOAD_TICKET_ADMIN', {
|
||||
channel: channel,
|
||||
curvePublic: data.authorKey
|
||||
}, function (obj) {
|
||||
if (!Array.isArray(obj)) {
|
||||
console.error(obj && obj.error);
|
||||
done();
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
obj.forEach(function (msg) {
|
||||
console.error(msg);
|
||||
if (!data.notifications) {
|
||||
data.notifications = Util.find(msg, ['sender', 'notifications']);
|
||||
}
|
||||
$(ticket).append(APP.support.makeMessage(msg));
|
||||
});
|
||||
if (!open.includes(channel)) { open.push(channel); }
|
||||
done();
|
||||
});
|
||||
};
|
||||
const onHide = function (ticket, channel, data, done) {
|
||||
$(ticket).find('.cp-support-list-message').remove();
|
||||
open = open.filter((chan) => {
|
||||
return chan !== channel;
|
||||
});
|
||||
done();
|
||||
};
|
||||
const onClose = function (ticket, channel, data) {
|
||||
APP.module.execCommand('CLOSE_TICKET_ADMIN', {
|
||||
channel: channel,
|
||||
|
@ -120,26 +140,43 @@ define([
|
|||
return void UI.warn(Messages.error);
|
||||
}
|
||||
$(ticket).find('.cp-support-list-message').remove();
|
||||
refresh(); // XXX RE-open this ticket and scroll to?
|
||||
$(ticket).find('.cp-support-form-container').remove();
|
||||
refresh();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Object.keys(tickets).sort(sortTicket).forEach(function (channel) {
|
||||
var d = tickets[channel];
|
||||
var ticket = APP.support.makeTicket(channel, d, onLoad, onClose, onReply);
|
||||
var ticket = APP.support.makeTicket({
|
||||
id: channel,
|
||||
content: d,
|
||||
form: activeForms[channel],
|
||||
onShow, onHide, onClose, onReply
|
||||
});
|
||||
|
||||
var container;
|
||||
if (d.lastAdmin) { container = col3; }
|
||||
else if (d.premium) { container = col1; }
|
||||
else { container = col2; }
|
||||
$(container).append(ticket);
|
||||
|
||||
if (open.includes(channel)) { return void ticket.open(); }
|
||||
if (linkedTicket === channel) {
|
||||
linkedTicket = undefined;
|
||||
ticket.open();
|
||||
ticket.scrollIntoView();
|
||||
}
|
||||
});
|
||||
open = [];
|
||||
console.log(tickets);
|
||||
});
|
||||
};
|
||||
let _refresh = Util.throttle(refresh, 500);
|
||||
Util.onClickEnter($(button), function () {
|
||||
refresh();
|
||||
});
|
||||
events.NEW_TICKET.reg(_refresh);
|
||||
events.UPDATE_TICKET.reg(_refresh); // XXX dont refresh all?
|
||||
refresh();
|
||||
};
|
||||
|
||||
|
@ -177,10 +214,24 @@ define([
|
|||
APP.privateKey = privateData.supportPrivateKey;
|
||||
APP.origin = privateData.origin;
|
||||
APP.readOnly = privateData.readOnly;
|
||||
APP.module = common.makeUniversal('support');
|
||||
APP.module = common.makeUniversal('support', {
|
||||
onEvent: (obj) => {
|
||||
let cmd = obj.ev;
|
||||
let data = obj.data;
|
||||
if (!events[cmd]) { return; }
|
||||
events[cmd].fire(data);
|
||||
}
|
||||
});
|
||||
APP.support = Support.create(common, true);
|
||||
|
||||
andThen();
|
||||
let active = privateData.category || 'active';
|
||||
let linkedTicket;
|
||||
if (active.indexOf('-') !== -1) {
|
||||
linkedTicket = active.split('-')[1];
|
||||
active = active.split('-')[0];
|
||||
}
|
||||
|
||||
andThen(linkedTicket);
|
||||
UI.removeLoadingScreen();
|
||||
|
||||
});
|
||||
|
|
|
@ -16,20 +16,6 @@ define([
|
|||
}).nThen(function (waitFor) {
|
||||
SFCommonO.initIframe(waitFor);
|
||||
}).nThen(function (/*waitFor*/) {
|
||||
var addRpc = function (sframeChan, Cryptpad/*, Utils*/) {
|
||||
// Adding a new avatar from the profile: pin it and store it in the object
|
||||
sframeChan.on('Q_ADMIN_MAILBOX', function (data, cb) {
|
||||
Cryptpad.addAdminMailbox(data, cb);
|
||||
});
|
||||
sframeChan.on('Q_ADMIN_RPC', function (data, cb) {
|
||||
Cryptpad.adminRpc(data, cb);
|
||||
});
|
||||
sframeChan.on('Q_UPDATE_LIMIT', function (data, cb) {
|
||||
Cryptpad.updatePinLimit(function (e) {
|
||||
cb({error: e});
|
||||
});
|
||||
});
|
||||
};
|
||||
var category;
|
||||
if (window.location.hash) {
|
||||
category = window.location.hash.slice(1);
|
||||
|
@ -40,7 +26,6 @@ define([
|
|||
};
|
||||
SFCommonO.start({
|
||||
noRealtime: true,
|
||||
addRpc: addRpc,
|
||||
addData: addData
|
||||
});
|
||||
});
|
||||
|
|
|
@ -152,6 +152,9 @@ define([
|
|||
return $div;
|
||||
};
|
||||
|
||||
var events = {
|
||||
'UPDATE_TICKET': Util.mkEvent()
|
||||
};
|
||||
create['listnew'] = function () {
|
||||
var key = 'listnew';
|
||||
var $div = makeBlock(key); // Msg.support_listHint, .support_listTitle
|
||||
|
@ -159,6 +162,8 @@ define([
|
|||
var $list = $(list);
|
||||
|
||||
|
||||
let activeForm = {}; // .channel and .form
|
||||
|
||||
let refresh = function () {
|
||||
const onClose = function (ticket, channel, data) {
|
||||
APP.supportModule.execCommand('CLOSE_TICKET', {
|
||||
|
@ -176,7 +181,8 @@ define([
|
|||
ticket: formData
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { return void UI.warn(Messages.error); }
|
||||
refresh(); // XXX RE-open this ticket and scroll to?
|
||||
$(ticket).find('.cp-support-form-container').remove();
|
||||
refresh();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -185,6 +191,15 @@ define([
|
|||
return void UI.warn(Messages.error);
|
||||
}
|
||||
if (!Array.isArray(obj.tickets)) { return void UI.warn(Messages.error); }
|
||||
|
||||
// Recover forms
|
||||
let activeForms = {};
|
||||
$list.find('.cp-support-form-container').each((i, el) => {
|
||||
let id = $(el).attr('data-id');
|
||||
if (!id) { return; }
|
||||
activeForms[id] = el;
|
||||
});
|
||||
|
||||
$list.empty();
|
||||
obj.tickets.forEach((data) => {
|
||||
var title = data.title;
|
||||
|
@ -192,7 +207,12 @@ define([
|
|||
var messages = data.messages;
|
||||
var first = messages[0];
|
||||
first.id = data.id;
|
||||
var ticket = APP.support.makeTicket(data.id, data, null, onClose, onReply);
|
||||
var ticket = APP.support.makeTicket({
|
||||
id: data.id,
|
||||
content: data,
|
||||
form: activeForms[data.id],
|
||||
onClose, onReply
|
||||
});
|
||||
$list.append(ticket);
|
||||
messages.forEach(msg => {
|
||||
$(ticket).append(APP.support.makeMessage(msg));
|
||||
|
@ -205,6 +225,8 @@ define([
|
|||
Util.onClickEnter($(button), function () {
|
||||
refresh();
|
||||
});
|
||||
let _refresh = Util.throttle(refresh, 500);;
|
||||
events.UPDATE_TICKET.reg(_refresh);
|
||||
refresh();
|
||||
$div.append([
|
||||
button,
|
||||
|
@ -409,7 +431,14 @@ define([
|
|||
APP.origin = privateData.origin;
|
||||
APP.readOnly = privateData.readOnly;
|
||||
APP.support = Support.create(common, false, APP.pinUsage, APP.teamsUsage);
|
||||
APP.supportModule = common.makeUniversal('support');
|
||||
APP.supportModule = common.makeUniversal('support', {
|
||||
onEvent: (obj) => {
|
||||
let cmd = obj.ev;
|
||||
let data = obj.data;
|
||||
if (!events[cmd]) { return; }
|
||||
events[cmd].fire(data);
|
||||
}
|
||||
});
|
||||
|
||||
// Content
|
||||
var $rightside = APP.$rightside;
|
||||
|
|
|
@ -187,7 +187,7 @@ define([
|
|||
abuse: Pages.customURLs.terms,
|
||||
};
|
||||
|
||||
var makeForm = function (ctx, cb, title, hideNotice) {
|
||||
var makeForm = function (ctx, oldData, cb, title, hideNotice) {
|
||||
var button;
|
||||
|
||||
if (typeof(cb) === "function") {
|
||||
|
@ -253,7 +253,7 @@ define([
|
|||
cb ? undefined : h('br'),
|
||||
h('textarea.cp-support-form-msg', {
|
||||
placeholder: Messages.support_formMessage
|
||||
}),
|
||||
}, (oldData && oldData.message) || ''),
|
||||
h('label', Messages.support_attachments),
|
||||
attachments = h('div.cp-support-attachments'),
|
||||
addAttachment = h('button.btn', Messages.support_addAttachment),
|
||||
|
@ -262,6 +262,32 @@ define([
|
|||
cancel
|
||||
];
|
||||
|
||||
var _addAttachment = (name, href) => {
|
||||
var x, a;
|
||||
var span = h('span', {
|
||||
'data-name': name,
|
||||
'data-href': href
|
||||
}, [
|
||||
x = h('i.fa.fa-times'),
|
||||
a = h('a', {
|
||||
href: '#'
|
||||
}, name)
|
||||
]);
|
||||
$(x).click(function () {
|
||||
$(span).remove();
|
||||
});
|
||||
$(a).click(function (e) {
|
||||
e.preventDefault();
|
||||
ctx.common.openURL(href);
|
||||
});
|
||||
|
||||
$(attachments).append(span);
|
||||
};
|
||||
if (oldData && Array.isArray(oldData.attachments)) {
|
||||
oldData.attachments.forEach((data) => {
|
||||
_addAttachment(data.name, data.href);
|
||||
});
|
||||
}
|
||||
$(addAttachment).click(function () {
|
||||
var $input = $('<input>', {
|
||||
'type': 'file',
|
||||
|
@ -273,25 +299,7 @@ define([
|
|||
files.forEach(function (file) {
|
||||
var ev = {};
|
||||
ev.callback = function (data) {
|
||||
var x, a;
|
||||
var span = h('span', {
|
||||
'data-name': data.name,
|
||||
'data-href': data.url
|
||||
}, [
|
||||
x = h('i.fa.fa-times'),
|
||||
a = h('a', {
|
||||
href: '#'
|
||||
}, data.name)
|
||||
]);
|
||||
$(x).click(function () {
|
||||
$(span).remove();
|
||||
});
|
||||
$(a).click(function (e) {
|
||||
e.preventDefault();
|
||||
ctx.common.openURL(data.url);
|
||||
});
|
||||
|
||||
$(attachments).append(span);
|
||||
_addAttachment(data.name, data.url);
|
||||
};
|
||||
// The empty object allows us to bypass the file upload modal
|
||||
ctx.FM.handleFile(file, ev, {});
|
||||
|
@ -310,7 +318,8 @@ define([
|
|||
return form;
|
||||
};
|
||||
|
||||
var makeTicket = function (ctx, id, content, onShow, onClose, onReply) {
|
||||
var makeTicket = function (ctx, opts) {
|
||||
let { id, content, form, onShow, onHide, onClose, onReply, onForm } = opts;
|
||||
var common = ctx.common;
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
var privateData = metadataMgr.getPrivateData();
|
||||
|
@ -321,10 +330,10 @@ define([
|
|||
|
||||
var adminActions;
|
||||
var adminClasses = '';
|
||||
var adminOpen;
|
||||
if (ctx.isAdmin) {
|
||||
// Admin custom style
|
||||
let isPremium = content.premium ? '.cp-support-premium' : '';
|
||||
adminClasses = `.cp-not-loaded${isPremium}`;
|
||||
adminClasses = `.cp-not-loaded`;
|
||||
// Admin actions
|
||||
let show = h('button.btn.btn-primary.cp-support-expand', Messages.admin_support_open);
|
||||
let $show = $(show);
|
||||
|
@ -335,31 +344,49 @@ define([
|
|||
]);
|
||||
$(url).click(function (e) {
|
||||
e.stopPropagation();
|
||||
var link = privateData.origin + privateData.pathname + '#' + 'support-' + id;
|
||||
var link = privateData.origin + privateData.pathname + '#' + 'active-' + id;
|
||||
Clipboard.copy(link, (err) => {
|
||||
if (!err) { UI.log(Messages.shareSuccess); }
|
||||
});
|
||||
});
|
||||
Util.onClickEnter($show, function () {
|
||||
$ticket.removeClass('cp-not-loaded');
|
||||
$show.remove();
|
||||
onShow(ticket, id, content);
|
||||
});
|
||||
|
||||
|
||||
let visible = false;
|
||||
adminOpen = function (force) {
|
||||
$show.prop('disabled', 'disabled');
|
||||
if (visible && !force) {
|
||||
$ticket.toggleClass('cp-not-loaded', true);
|
||||
return onHide(ticket, id, content, function () {
|
||||
visible = false;
|
||||
$show.text(Messages.admin_support_open);
|
||||
$show.prop('disabled', '');
|
||||
});
|
||||
}
|
||||
$ticket.toggleClass('cp-not-loaded', false);
|
||||
onShow(ticket, id, content, function () {
|
||||
visible = true;
|
||||
$show.text(Messages.admin_support_collapse);
|
||||
$show.prop('disabled', '');
|
||||
});
|
||||
};
|
||||
Util.onClickEnter($show, adminOpen);
|
||||
adminActions = h('span.cp-support-title-buttons', [ url, show ])
|
||||
}
|
||||
|
||||
let isPremium = content.premium ? '.cp-support-ispremium' : '';
|
||||
var name = Util.fixHTML(content.author) || Messages.anonymous;
|
||||
var ticket = h(`div.cp-support-list-ticket${adminClasses}`, {
|
||||
'data-id': id
|
||||
}, [
|
||||
h('div.cp-support-ticket-header', [
|
||||
h('span', content.title),
|
||||
ctx.isAdmin ? UI.setHTML(h('span'), Messages._getKey('support_from', [name])) : '',
|
||||
ctx.isAdmin ? UI.setHTML(h(`span${isPremium}`), Messages._getKey('support_from', [name])) : '',
|
||||
h('span', new Date(content.time).toLocaleString()),
|
||||
adminActions,
|
||||
]),
|
||||
actions
|
||||
]);
|
||||
ticket.open = adminOpen;
|
||||
|
||||
// Add button handlers
|
||||
var $ticket = $(ticket);
|
||||
|
@ -369,17 +396,23 @@ define([
|
|||
$(close).remove();
|
||||
onClose(ticket, id, content);
|
||||
});
|
||||
$(answer).click(function () {
|
||||
|
||||
var addForm = function () {
|
||||
$ticket.find('.cp-support-form-container').remove();
|
||||
$(actions).hide();
|
||||
var form = makeForm(ctx, function () {
|
||||
onReply(ticket, id, content, form, function () {
|
||||
|
||||
var oldData = form ? getFormData(ctx, form) : {};
|
||||
form = undefined;
|
||||
var newForm = makeForm(ctx, oldData, function () {
|
||||
onReply(ticket, id, content, newForm, function () {
|
||||
$(actions).css('display', '');
|
||||
$(form).remove();
|
||||
});
|
||||
}, content.title, true);
|
||||
$ticket.append(form);
|
||||
});
|
||||
$(newForm).attr('data-id', id);
|
||||
$ticket.append(newForm);
|
||||
};
|
||||
if (form) { addForm(); }
|
||||
$(answer).click(addForm);
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
@ -446,7 +479,7 @@ define([
|
|||
$pre.text(displayed);
|
||||
|
||||
var adminClass = (fromAdmin? '.cp-support-fromadmin': '');
|
||||
var premiumClass = (fromPremium && !fromAdmin? '.cp-support-frompremium': '');
|
||||
var premiumClass = (ctx.isAdmin && fromPremium && !fromAdmin? '.cp-support-frompremium': '');
|
||||
var name = Util.fixHTML(content.sender.name) || Messages.anonymous;
|
||||
return h('div.cp-support-list-message' + adminClass + premiumClass, {
|
||||
'data-hash': hash
|
||||
|
@ -507,13 +540,13 @@ define([
|
|||
return getFormData(ctx, form);
|
||||
};
|
||||
ui.makeForm = function (cb, title, hideNotice) {
|
||||
return makeForm(ctx, cb, title, hideNotice);
|
||||
return makeForm(ctx, {}, cb, title, hideNotice);
|
||||
};
|
||||
ui.makeCategoryDropdown = function (container, onChange, all) {
|
||||
return makeCategoryDropdown(ctx, container, onChange, all);
|
||||
};
|
||||
ui.makeTicket = function (id, content, onShow, onClose, onReply) {
|
||||
return makeTicket(ctx, id, content, onShow, onClose, onReply);
|
||||
ui.makeTicket = function (opts) {
|
||||
return makeTicket(ctx, opts);
|
||||
};
|
||||
ui.makeMessage = function (content, hash) {
|
||||
return makeMessage(ctx, content, hash);
|
||||
|
|
Loading…
Reference in New Issue