diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index 8da6ede84..ccc540195 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -133,6 +133,26 @@ margin: 0; } } + .cp-sidebar-input-block { + display: inline-flex; + width: @sidebar_button-width; + max-width: 100%; + input { + flex: 1; + //border-radius: 0.25em 0 0 0.25em; + border: 1px solid @cryptpad_color_grey_500; + border-right: 0px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + } + button { + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; + border-left: 0px; + height: 40px; + margin: 0 !important; + } + } } .cp-sidebarlayout-description { diff --git a/www/admin/inner.js b/www/admin/inner.js index 3c0f43fc3..d5e2ec569 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -99,9 +99,6 @@ define([ ], 'support': [ // Msg.admin_cat_support 'cp-admin-support-new', - 'cp-admin-support-list', - 'cp-admin-support-init', - 'cp-admin-support-priv', ], 'broadcast': [ // Msg.admin_cat_broadcast 'cp-admin-maintenance', @@ -2623,301 +2620,6 @@ Example return $div; }; - var supportKey = ApiConfig.supportMailbox; - var checkAdminKey = function (priv) { - if (!supportKey) { return; } - return Hash.checkBoxKeyPair(priv, supportKey); - }; - - create['support-list'] = function () { - if (!supportKey || !APP.privateKey || !checkAdminKey(APP.privateKey)) { return; } - // XXX NO NEED ANYMORE - return; - var $container = makeBlock('support-list'); // Msg.admin_supportListHint, .admin_supportListTitle - var $div = $(h('div.cp-support-container')).appendTo($container); - - var catContainer = h('div.cp-dropdown-container'); - var col1 = h('div.cp-support-column', h('h1', [ - h('span', Messages.admin_support_premium), - h('span.cp-support-count'), - h('button.btn.cp-support-column-button', Messages.admin_support_collapse) - ])); - var col2 = h('div.cp-support-column', h('h1', [ - h('span', Messages.admin_support_normal), - h('span.cp-support-count'), - h('button.btn.cp-support-column-button', Messages.admin_support_collapse) - ])); - var col3 = h('div.cp-support-column', h('h1', [ - h('span', Messages.admin_support_answered), - h('span.cp-support-count'), - h('button.btn.cp-support-column-button', Messages.admin_support_collapse) - ])); - var col4 = h('div.cp-support-column', h('h1', [ - h('span', Messages.admin_support_closed), - h('span.cp-support-count'), - h('button.btn.cp-support-column-button', Messages.admin_support_collapse) - ])); - var $col1 = $(col1), $col2 = $(col2), $col3 = $(col3), $col4 = $(col4); - $div.append([ - //catContainer - col1, - col2, - col3, - col4 - ]); - $div.find('.cp-support-column-button').click(function () { - var $col = $(this).closest('.cp-support-column'); - $col.toggleClass('cp-support-column-collapsed'); - if ($col.hasClass('cp-support-column-collapsed')) { - $(this).text(Messages.admin_support_open); - $(this).toggleClass('btn-primary'); - } else { - $(this).text(Messages.admin_support_collapse); - $(this).toggleClass('btn-primary'); - } - }); - var category = 'all'; - var $drop = APP.support.makeCategoryDropdown(catContainer, function (key) { - category = key; - if (key === 'all') { - $div.find('.cp-support-list-ticket').show(); - return; - } - $div.find('.cp-support-list-ticket').hide(); - $div.find('.cp-support-list-ticket[data-cat="'+key+'"]').show(); - }, true); - $drop.setValue('all'); - - var metadataMgr = common.getMetadataMgr(); - var privateData = metadataMgr.getPrivateData(); - var cat = privateData.category || ''; - var linkedId = cat.indexOf('-') !== -1 && cat.slice(8); - - var hashesById = {}; - - var getTicketData = function (id) { - var t = hashesById[id]; - if (!Array.isArray(t) || !t.length) { return; } - var ed = Util.find(t[0], ['content', 'msg', 'content', 'sender', 'edPublic']); - // If one of their ticket was sent as a premium user, mark them as premium - var premium = t.some(function (msg) { - var _ed = Util.find(msg, ['content', 'msg', 'content', 'sender', 'edPublic']); - if (ed !== _ed) { return; } - return Util.find(msg, ['content', 'msg', 'content', 'sender', 'plan']) || - Util.find(msg, ['content', 'msg', 'content', 'sender', 'quota', 'plan']); - }); - var lastMsg = t[t.length - 1]; - var lastMsgEd = Util.find(lastMsg, ['content', 'msg', 'content', 'sender', 'edPublic']); - return { - lastMsg: lastMsg, - time: Util.find(lastMsg, ['content', 'msg', 'content', 'time']), - lastMsgEd: lastMsgEd, - lastAdmin: lastMsgEd !== ed && ApiConfig.adminKeys.indexOf(lastMsgEd) !== -1, - premium: premium, - authorEd: ed, - closed: Util.find(lastMsg, ['content', 'msg', 'type']) === 'CLOSE' - }; - }; - - var addClickHandler = function ($ticket) { - $ticket.on('click', function () { - $ticket.toggleClass('cp-support-open', true); - $ticket.off('click'); - }); - }; - var makeOpenButton = function ($ticket) { - var button = h('button.btn.btn-primary.cp-support-expand', Messages.admin_support_open); - var collapse = h('button.btn.cp-support-collapse', Messages.admin_support_collapse); - $(button).click(function () { - $ticket.toggleClass('cp-support-open', true); - }); - addClickHandler($ticket); - $(collapse).click(function (e) { - $ticket.toggleClass('cp-support-open', false); - e.stopPropagation(); - setTimeout(function () { - addClickHandler($ticket); - }); - }); - $ticket.find('.cp-support-title-buttons').prepend([button, collapse]); - $ticket.append(h('div.cp-support-collapsed')); - }; - var updateTicketDetails = function ($ticket, isPremium) { - var $first = $ticket.find('.cp-support-message-from').first(); - var user = $first.find('span').first().html(); - var time = $first.find('.cp-support-message-time').text(); - var last = $ticket.find('.cp-support-message-from').last().find('.cp-support-message-time').text(); - var $c = $ticket.find('.cp-support-collapsed'); - var txtClass = isPremium ? ".cp-support-ispremium" : ""; - $c.html('').append([ - UI.setHTML(h('span'+ txtClass), user), - h('span', [ - h('b', Messages.admin_support_first), - h('span', time) - ]), - h('span', [ - h('b', Messages.admin_support_last), - h('span', last) - ]) - ]); - - }; - - var sort = function (id1, id2) { - var t1 = getTicketData(id1); - var t2 = getTicketData(id2); - if (!t1) { return 1; } - if (!t2) { return -1; } - /* - // If one is answered and not the other, put the unanswered first - if (t1.lastAdmin && !t2.lastAdmin) { return 1; } - if (!t1.lastAdmin && t2.lastAdmin) { return -1; } - */ - // Otherwise, sort them by time - return t1.time - t2.time; - }; - - var _reorder = function () { - var orderAnswered = []; - var orderPremium = []; - var orderNormal = []; - var orderClosed = []; - - Object.keys(hashesById).forEach(function (id) { - var d = getTicketData(id); - if (!d) { return; } - if (d.closed) { - return void orderClosed.push(id); - } - if (d.lastAdmin /* && !d.closed */) { - return void orderAnswered.push(id); - } - if (d.premium /* && !d.lastAdmin && !d.closed */) { - return void orderPremium.push(id); - } - orderNormal.push(id); - //if (!d.premium && !d.lastAdmin && !d.closed) { return void orderNormal.push(id); } - }); - - var cols = [$col1, $col2, $col3, $col4]; - [orderPremium, orderNormal, orderAnswered, orderClosed].forEach(function (list, j) { - list.sort(sort); - list.forEach(function (id, i) { - var $t = $div.find('[data-id="'+id+'"]'); - var d = getTicketData(id); - $t.css('order', i).appendTo(cols[j]); - updateTicketDetails($t, d.premium); - }); - var len; - try { - len = cols[j].find('div.cp-support-list-ticket').length; - } catch (err) { - UI.warn(Messages.error); - return void console.error(err); - } - if (!len) { - cols[j].hide(); - } else { - cols[j].show(); - cols[j].find('.cp-support-count').text(len); - } - }); - }; - var reorder = Util.throttle(_reorder, 150); - - var to = Util.throttle(function () { - var $ticket = $div.find('.cp-support-list-ticket[data-id="'+linkedId+'"]'); - $ticket.addClass('cp-support-open'); - $ticket[0].scrollIntoView(); - linkedId = undefined; - }, 200); - - // Register to the "support" mailbox - common.mailbox.subscribe(['supportadmin'], { - onMessage: function (data) { - /* - Get ID of the ticket - If we already have a div for this ID - Push the message to the end of the ticket - If it's a new ticket ID - Make a new div for this ID - */ - var msg = data.content.msg; - var hash = data.content.hash; - var content = msg.content; - var id = content.id; - var $ticket = $div.find('.cp-support-list-ticket[data-id="'+id+'"]'); - - hashesById[id] = hashesById[id] || []; - if (hashesById[id].indexOf(hash) === -1) { - hashesById[id].push(data); - } - - if (msg.type === 'CLOSE') { - // A ticket has been closed by the admins... - if (!$ticket.length) { return; } - $ticket.addClass('cp-support-list-closed'); - $ticket.append(APP.support.makeCloseMessage(content, hash)); - reorder(); - return; - } - if (msg.type !== 'TICKET') { return; } - $ticket.removeClass('cp-support-list-closed'); - - if (!$ticket.length) { - $ticket = APP.support.makeTicket($div, content, function (hideButton) { - // the ticket will still be displayed until the worker confirms its deletion - // so make it unclickable in the meantime - hideButton.setAttribute('disabled', true); - var error = false; - nThen(function (w) { - hashesById[id].forEach(function (d) { - common.mailbox.dismiss(d, w(function (err) { - if (err) { - error = true; - console.error(err); - } - })); - }); - }).nThen(function () { - if (!error) { - $ticket.remove(); - delete hashesById[id]; - reorder(); - return; - } - // if deletion failed then reactivate the button and warn - hideButton.removeAttribute('disabled'); - // and show a generic error message - UI.alert(Messages.error); - }); - }); - makeOpenButton($ticket); - if (category !== 'all' && $ticket.attr('data-cat') !== category) { - $ticket.hide(); - } - } - $ticket.append(APP.support.makeMessage(content, hash)); - reorder(); - - if (linkedId) { to(); } - } - }); - return $container; - }; - - create['support-priv'] = function () { - if (!supportKey || !APP.privateKey || !checkAdminKey(APP.privateKey)) { return; } - - var $div = makeBlock('support-priv', true); // Msg.admin_supportPrivHint, .admin_supportPrivTitle, .admin_supportPrivButton - var $button = $div.find('button').click(function () { - $button.remove(); - var $selectable = $(UI.dialog.selectable(APP.privateKey)).css({ 'max-width': '28em' }); - $div.append($selectable); - }); - return $div; - }; - // XXX Messages.admin_supportNewHint = "Create or update the current support keys."; Messages.admin_supportNewTitle = "Initialize support"; @@ -3183,48 +2885,6 @@ Example refresh(); return $block; }; - create['support-init'] = function () { - var $div = makeBlock('support-init'); // Msg.admin_supportInitHint, .admin_supportInitTitle - if (!supportKey) { - (function () { - return; // XXX old support can't be created anymore - })(); - return $div; - } - if (!APP.privateKey || !checkAdminKey(APP.privateKey)) { - $div.append(h('p', Messages.admin_supportInitPrivate)); - - var error = h('div.cp-admin-support-error'); - var input = h('input.cp-admin-add-private-key'); - var button = h('button.btn.btn-primary', Messages.admin_supportAddKey); - - if (APP.privateKey && !checkAdminKey(APP.privateKey)) { - $(error).text(Messages.admin_supportAddError); - } - - $div.append(h('div', [ - error, - input, - button - ])); - - $(button).click(function () { - var key = $(input).val(); - if (!checkAdminKey(key)) { - $(input).val(''); - return void $(error).text(Messages.admin_supportAddError); - } - sFrameChan.query("Q_ADMIN_MAILBOX", key, function () { - APP.privateKey = key; - $('.cp-admin-support-init').hide(); - APP.$rightside.append(create['support-list']()); - APP.$rightside.append(create['support-priv']()); - }); - }); - return $div; - } - return; - }; var getApi = function (cb) { return function () { diff --git a/www/common/inner/sidebar-layout.js b/www/common/inner/sidebar-layout.js index a9deaf84c..3087eb882 100644 --- a/www/common/inner/sidebar-layout.js +++ b/www/common/inner/sidebar-layout.js @@ -34,13 +34,13 @@ define([ const items = {}; let blocks = sidebar.blocks = {}; - blocks.labelledInput = (label, input) => { + blocks.labelledInput = (label, input, inputBlock) => { let uid = Util.uid(); let id = `cp-${app}-item-${uid}`; input.setAttribute('id', id); return [ h('label', { for: id }, label), - input, + inputBlock || input, ]; }; blocks.button = (type, icon, text) => { @@ -63,6 +63,16 @@ define([ blocks.input = (attr) => { return h('input', attr); }; + blocks.inputButton = (input, button, opts) => { + if (opts.onEnterDelegate) { + $(input).on('keypress', e => { + if (e.which === 13) { + $(button).click(); + } + }); + } + return h('div.cp-sidebar-input-block', [input, button]); + }; blocks.text = (value) => { return h('span', value); }; diff --git a/www/common/outer/support.js b/www/common/outer/support.js index cfb87d853..c69757f09 100644 --- a/www/common/outer/support.js +++ b/www/common/outer/support.js @@ -647,6 +647,45 @@ define([ }); }; + var searchAdmin = (ctx, data, cId, cb) => { + if (!ctx.adminRdyEvt) { return void cb({ error: 'EFORBIDDEN' }); } + let tags = data.tags || []; + let text = (data.text || '').toLowerCase(); + console.error(tags, text); + ctx.adminRdyEvt.reg(() => { + let doc = ctx.adminDoc.proxy; + let t = doc.tickets; + + let all = {}; + let add = (id, data, category) => { + let clone = Util.clone(data); + clone.category = category; + all[id] = clone; + }; + ['active', 'pending', 'closed'].some(cat => { + let tickets = t[cat]; + return Object.keys(tickets).some(id => { + let ticket = tickets[id]; + // Check if this ticket uses at least one selected tag + let hasTag = !tags.length || (ticket.tags || []).some(tag => { + return tags.includes(tag); + }); + if (!hasTag) { return; } + // Filter by searched text within these tags + let id64 = Util.hexToBase64(id).slice(0,10); + if (text === id64) { // If ticket ID found, stop search and return result + all = {}; + add(id, ticket, cat); + return true; + } + let hasText = !text || ticket.title.toLowerCase().includes(text); + if (!hasText) { return; } + add(id, ticket, cat); + }); + }); + cb({ tickets: all }); + }); + }; var setTagsAdmin = (ctx, data, cId, cb) => { if (!ctx.adminRdyEvt) { return void cb({ error: 'EFORBIDDEN' }); } ctx.adminRdyEvt.reg(() => { @@ -1284,6 +1323,9 @@ define([ if (cmd === 'USE_RECORDED') { return void useRecorded(ctx, data, clientId, cb); } + if (cmd === 'SEARCH_ADMIN') { + return void searchAdmin(ctx, data, clientId, cb); + } if (cmd === 'FILTER_TAGS_ADMIN') { return void filterTagsAdmin(ctx, data, clientId, cb); } diff --git a/www/moderation/app-moderation.less b/www/moderation/app-moderation.less index 08e9a6a8b..46e4f61bd 100644 --- a/www/moderation/app-moderation.less +++ b/www/moderation/app-moderation.less @@ -78,5 +78,10 @@ } } } + .cp-support-search-container { + display: flex; + flex-flow: column; + + } } diff --git a/www/moderation/inner.js b/www/moderation/inner.js index ab2305c7b..2359b18fe 100644 --- a/www/moderation/inner.js +++ b/www/moderation/inner.js @@ -55,6 +55,9 @@ define([ // XXX Messages.support_pending = "Pending tickets:"; + Messages.support_pending_tag = "Pending"; + Messages.support_active_tag = "Active"; + Messages.support_closed_tag = "Closed"; /* Messages.support_activeListTitle = "Active tickets"; Messages.support_pendingListTitle = "Pending tickets"; @@ -89,6 +92,8 @@ define([ Messages.support_legacyDump = "Export all"; Messages.support_legacyClear = "Delete from my account"; + Messages.support_searchLabel = "Search (title or ticketId)"; + var andThen = function (common, $container, linkedTicket) { const sidebar = Sidebar.create(common, 'support', $container); const blocks = sidebar.blocks; @@ -96,6 +101,42 @@ define([ APP.allTags = []; APP.openTicketCategory = Util.mkEvent(); + var sortTicket = tickets => (c1, c2) => { + return tickets[c2].time - tickets[c1].time; + }; + const onShowTicket = function (ticket, channel, data, done) { + APP.module.execCommand('LOAD_TICKET_ADMIN', { + channel: channel, + curvePublic: data.authorKey, + supportKey: data.supportKey + }, function (obj) { + if (!Array.isArray(obj)) { + console.error(obj && obj.error); + done(false); + return void UI.warn(Messages.error); + } + var $ticket = $(ticket); + obj.forEach(function (msg) { + // Only add notifications channel if this is coming from the other user + if (!data.notifications && msg.sender.drive) { + data.notifications = Util.find(msg, ['sender', 'notifications']); + } + if (msg.close) { + $ticket.addClass('cp-support-list-closed'); + return $ticket.append(APP.support.makeCloseMessage(msg)); + } + if (msg.legacy && msg.messages) { + msg.messages.forEach(c => { + $ticket.append(APP.support.makeMessage(c)); + }); + return; + } + $ticket.append(APP.support.makeMessage(msg)); + }); + done(true); + }); + }; + // Support panel functions let open = []; let refreshAll = function () {}; @@ -154,40 +195,12 @@ define([ col1 = col2 = col3 = col5; } $container.append([col1, col2, col3]); - var sortTicket = function (c1, c2) { - return tickets[c2].time - tickets[c1].time; - }; const onShow = function (ticket, channel, data, done) { - APP.module.execCommand('LOAD_TICKET_ADMIN', { - channel: channel, - curvePublic: data.authorKey, - supportKey: data.supportKey - }, function (obj) { - if (!Array.isArray(obj)) { - console.error(obj && obj.error); - done(); - return void UI.warn(Messages.error); + onShowTicket(ticket, channel, data, (success) => { + if (success) { + if (!open.includes(channel)) { open.push(channel); } } - var $ticket = $(ticket); - obj.forEach(function (msg) { - // Only add notifications channel if this is coming from the other user - if (!data.notifications && msg.sender.drive) { - data.notifications = Util.find(msg, ['sender', 'notifications']); - } - if (msg.close) { - $ticket.addClass('cp-support-list-closed'); - return $ticket.append(APP.support.makeCloseMessage(msg)); - } - if (msg.legacy && msg.messages) { - msg.messages.forEach(c => { - $ticket.append(APP.support.makeMessage(c)); - }); - return; - } - $ticket.append(APP.support.makeMessage(msg)); - }); - if (!open.includes(channel)) { open.push(channel); } done(); }); }; @@ -272,7 +285,7 @@ define([ // Show tickets, reload the previously open ones and cal back // once everything is loaded let n = nThen; - Object.keys(tickets).sort(sortTicket).forEach(function (channel) { + Object.keys(tickets).sort(sortTicket(tickets)).forEach(function (channel) { // Update allTags var d = tickets[channel]; (d.tags || []).forEach(tag => { @@ -386,12 +399,30 @@ define([ 'closed-list' ] }, + 'search': { + icon: undefined, + content: [ + 'filter', + 'search' + ], + onOpen: () => { + APP.searchAutoRefresh = true; + setTimeout(() => { + $('.cp-support-search-input').focus(); + }); + } + }, 'settings': { icon: undefined, content: [ 'notifications', 'recorded' - ] + ], + onOpen: () => { + setTimeout(() => { + $('.cp-support-recorded-id').focus(); + }); + } }, 'ticket': { icon: undefined, @@ -400,6 +431,9 @@ define([ ], onOpen: () => { APP.openTicketCategory.fire(); + setTimeout(() => { + $('.cp-support-newticket-paste').focus(); + }); } }, 'legacy': { @@ -450,6 +484,81 @@ define([ } }); + sidebar.addItem('search', cb => { + + let inputSearch = blocks.input({type:'text', class: 'cp-support-search-input'}); + let button = blocks.button('primary', 'fa-search'); + let inputBlock = blocks.inputButton(inputSearch, button, { onEnterDelegate: true }); + let searchBlock = blocks.labelledInput(Messages.support_searchLabel, + inputSearch, inputBlock); + + let list = blocks.box([], 'cp-support-container'); + let container = blocks.box([searchBlock, list], 'cp-support-search-container'); + let $list = $(list); + let searchText = ''; + APP.searchAutoRefresh = false; + + let redraw = (_cb) => { + let cb = _cb || function () {}; + $list.empty(); + let tags = APP.filterTags || []; + let text = searchText; + if (!text.length && !tags.length) { return void cb(); } + APP.module.execCommand('SEARCH_ADMIN', { text, tags }, function (obj) { + cb(); + if (obj && obj.error) { + console.error(obj && obj.error); + return void UI.warn(Messages.error); + } + $list.empty(); + let tickets = obj.tickets || {}; + + const onShow = onShowTicket; + const onHide = function (ticket, channel, data, done) { + $(ticket).find('.cp-support-list-message').remove(); + done(); + }; + const onTag = () => {}; + onTag.readOnly = true; + onTag.getAllTags = () => []; + Object.keys(tickets).sort(sortTicket(tickets)).forEach(id => { + let content = tickets[id]; + content.tags = content.tags || []; + + let catTag = Messages[`support_${content.category}_tag`]; + if (catTag) { + // Msg.support_active_tag.support_pending_tag.support_closed_tag + content.tags.unshift(catTag.toUpperCase()); + } + + var ticket = APP.support.makeTicket({ + id, + content, + onTag, onShow, onHide + }); + $list.append(ticket); + }); + }); + }; + + let $input = $(inputSearch); + let $button = $(button); + Util.onClickEnter($button, function () { + $button.prop('disabled', 'disabled'); + searchText = $input.val().trim(); + redraw(() => { + APP.searchAutoRefresh = true; + $button.prop('disabled', false); + }); + }); + + events.REFRESH_FILTER.reg(() => { + if (!APP.searchAutoRefresh) { return; } + redraw(); + }); + cb(container); + }, { noTitle: true, noHint: true }); + sidebar.addItem('filter', cb => { let container = blocks.box([], 'cp-support-filter-container'); let $container = $(container); @@ -532,7 +641,8 @@ define([ Messages.kanban_delete ], []); let labelledList = blocks.labelledInput(Messages.support_recordedList, list); - let inputId = blocks.input({type:'text', maxlength: 20 }); + let inputId = blocks.input({type:'text', class: 'cp-support-recorded-id', + maxlength: 20 }); let inputContent = blocks.textArea(); let labelId = blocks.labelledInput(Messages.support_recordedId, inputId); let labelContent = blocks.labelledInput(Messages.support_recordedContent, inputContent); @@ -637,6 +747,7 @@ define([ let reset = blocks.button('danger-alt', 'fa-times', Messages.form_reset); let paste = blocks.textArea({ + class: 'cp-support-newticket-paste', placeholder: Messages.support_pasteUserData }); let inputs = h('div.cp-moderation-userdata-inputs', [ labelName, labelChan, labelKey ]); @@ -817,6 +928,7 @@ Attachments:${JSON.stringify(msg.attachments, 0, 2)}`; }); }; if (!$ticket.length) { + content.category = 'closed'; // Consider ticket closed $ticket = APP.support.makeTicket({id, content, onMove}); $div.append($ticket); } diff --git a/www/support/ui.js b/www/support/ui.js index 01a141de6..bb76ec7c4 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -421,6 +421,7 @@ define([ if (!err) { UI.log(Messages.shareSuccess); } }); }); + if (content.category === 'closed') { url = undefined; } // Load & open ticket @@ -448,6 +449,7 @@ define([ }); }; Util.onClickEnter($show, adminOpen); + if (!onShow) { show = undefined; } // Move active/pending let move; @@ -465,6 +467,7 @@ define([ tag = h('button.btn.btn-secondary.fa.fa-tags', { title: Messages.fm_tagsName }); + if (onTag.readOnly) { tag = undefined; } tagsContainer = h('div'); tagsList = h('div.cp-tags-list'); let $list = $(tagsList); @@ -475,6 +478,7 @@ define([ }); }; redrawTags(content.tags); + console.error(content.tags); let $tags = $(tagsContainer).hide(); let input = UI.dialog.textInput({id: `cp-${Util.uid()}`}); @@ -538,6 +542,7 @@ define([ $(close).remove(); onClose(ticket, id, content); }); + if (!onClose) { $(close).remove(); } UI.confirmButton(remove, { classes: 'btn-danger' @@ -564,7 +569,8 @@ define([ $ticket.append(newForm); }; if (form) { addForm(); } - $(answer).click(addForm); + Util.onClickEnter($(answer), addForm); + if (!onReply) { $(answer).remove(); } return ticket; };