UNPKG

@jsxc/jsxc

Version:

Real-time XMPP chat application with video calls, file transfer and encrypted communication

262 lines (196 loc) 8.13 kB
import Dialog from '../Dialog'; import Form from '../../connection/Form'; import Log from '../../util/Log'; import openContactDialog from './contact'; import Translation from '@util/Translation'; import Client from '../../Client'; import Account from '../../Account'; import JID from '../../JID'; import { IJID } from '@src/JID.interface'; import FormField from '@connection/FormField'; export const CANCELED = 'canceled'; const possibleSearchFields = ['first', 'last', 'nick', 'email']; let contactSearchTemplate = require('../../../template/contactsearch.hbs'); export default function () { let content = contactSearchTemplate(); let dialog = new Dialog(content); dialog.open(); let accounts = Client.getAccountManager().getAccounts(); accounts.forEach(account => { let accountoption = $('<option>').text(account.getJID().bare).val(account.getUid()); dialog.getDom().find('select[name="account"]').append(accountoption); }); dialog .getDom() .find('select[name="account"]') .on('change', ev => { let uid = $(ev.target).val().toString(); loadForm(Client.getAccountManager().getAccount(uid), dialog); }); loadForm(accounts[0], dialog); } function loadForm(account: Account, dialog: Dialog) { let searchService = account.getConnection().getSearchService(); getSearchService(account).then(async services => { if (!services || services.length === 0) { dialog.getDom().find('.jsxc-content').text(Translation.t('not_available')); return; } let searchFormElement = await searchService.getSearchForm(services[0]); let formElement = generateForm(searchFormElement); dialog.getDom().find('.jsxc-content').empty().append(formElement); dialog.getDom().find('.jsxc-results').empty(); formElement.find('.jsxc-js-close').on('click', () => dialog.close()); formElement.on('submit', ev => { ev.preventDefault(); formElement.find('input, button').prop('disabled', true); let form; if (formElement.hasClass('jsxc-simple-form')) { form = {}; possibleSearchFields.forEach(name => { form[name] = formElement.find(`input[name="${name}"]`).val(); }); } else { form = Form.fromHTML(formElement.get(0)); } searchService .executeSearchForm(services[0], form) .then(resultStanza => { appendSearchResults(resultStanza, dialog); }) .catch(err => {}) .then(() => { formElement.find('input, button').prop('disabled', false); }); }); }); } async function getSearchService(account: Account): Promise<IJID[]> { let connection = account.getConnection(); let ownJid = connection.getJID(); let serverJid = new JID('', ownJid.domain, ''); let discoInfoRepository = account.getDiscoInfoRepository(); return connection .getDiscoService() .getDiscoItems(serverJid) .then(stanza => { let promises = $(stanza) .find('item') .map((index, element) => { let jid = new JID('', $(element).attr('jid'), ''); return discoInfoRepository .requestDiscoInfo(jid) .then(discoInfo => { let hasSearch = discoInfo.hasFeature('jabber:iq:search'); let isMUC = discoInfo.hasFeature('http://jabber.org/protocol/muc'); return hasSearch && !isMUC ? jid : undefined; }) .catch(stanza => { const from = $(stanza).attr('from') || ''; Log.info(`Ignore ${from} as Search provider, because could not load disco info.`); return undefined; }); }) .get(); return Promise.all(promises).then(results => { return results.filter(jid => typeof jid !== 'undefined'); }); }); } function generateForm(stanza: Element) { let formElement = $(stanza).find('x[xmlns="jabber:x:data"]').length > 0 ? Form.fromXML(stanza).toHTML() : generateSimpleForm(stanza); formElement.append(`<div class="form-group"> <div class="col-sm-offset-4 col-sm-8"> <button class="jsxc-button jsxc-button--default jsxc-js-close" type="button">${Translation.t('Close')}</button> <button class="jsxc-button jsxc-button--primary" type="submit">${Translation.t('Search')}</button> </div> </div>`); return formElement; } function generateSimpleForm(element: Element) { let formElement = $('form'); formElement.attr('autocomplete', 'off'); formElement.addClass('form-horizontal jsxc-simple-form'); let queryElement = $(element).find('query[xmlns="jabber:iq:search"]'); let instructionsElement = queryElement.find('>instructions'); if (instructionsElement.length > 0) { $('<p>').text(instructionsElement.text()).appendTo(formElement); } possibleSearchFields.forEach(field => { let fieldElement = queryElement.find('>' + field); if (fieldElement.length > 0) { let formField = new FormField({ name: field }); formElement.append(formField.toHTML()); } }); return formElement; } function appendSearchResults(resultStanza: Element, dialog: Dialog) { let table: JQuery; let items = $(resultStanza).find('query>item'); if ($(resultStanza).find('x[xmlns="jabber:x:data"]').length > 0) { table = Form.fromXML(resultStanza).toHTML(); } else { table = generateTableForSimpleResult(items); } table.find('tr').each((index, row) => { let cell = $('<td>'); if (index > 0) { cell.append(`<input type="radio" name="jsxc-add-contact" value="${index - 1}" required="required"/>`); } $(row).prepend(cell); }); let dom = dialog.getDom(); table.addClass('jsxc-searchresults-table'); dialog.getDom().find('.jsxc-results').empty().append($('<form>').append(table)); dom.find('.jsxc-results form').append(`<div class="form-group"> <div class="col-sm-offset-4 col-sm-8"> <button class="jsxc-button jsxc-button--primary" type="submit">${Translation.t('Add')}</button> </div> </div>`); dom.find('.jsxc-results form').on('submit', function (ev) { ev.preventDefault(); let bareJid = ''; let alias = ''; let selectedIndex = parseInt(dom.find('input[name="jsxc-add-contact"]:checked').val().toString(), 10); if (!isNaN(selectedIndex)) { let extendedItem = $(resultStanza).find('x[xmlns="jabber:x:data"] > item').eq(selectedIndex); let simpleItem = $(resultStanza).find('item').eq(selectedIndex); if (extendedItem.length === 1) { bareJid = extendedItem.find('field[var="jid"]').text(); alias = extendedItem.find('field[var="first"]').text() + ' ' + extendedItem.find('field[var="last"]').text(); } else if (simpleItem.length === 1) { bareJid = simpleItem.attr('jid'); alias = simpleItem.find('first').text() + ' ' + simpleItem.find('last').text(); } } dialog.close(); openContactDialog(bareJid, alias); }); dom.find('.jsxc-js-close').on('click', () => { dialog.close(); }); } function generateTableForSimpleResult(items: JQuery) { let tableElement = $('<table>'); let tableHeader = $('<thead>'); let headerRow = $('<tr>'); tableElement.append(tableHeader); tableHeader.append(headerRow); const columnNames = ['First', 'Last', 'Nick', 'Email']; columnNames.forEach(name => $('<th>').text(Translation.t(name)).appendTo(headerRow)); let tableBody = $('<tbody>'); tableElement.append(tableBody); for (let item of items) { let row = $('<tr>'); columnNames.forEach(name => { $('<td>').text($(item).children(name.toLowerCase()).text()).appendTo(row); }); tableBody.append(row); } return tableElement; }