Commit 11cd6b83 authored by JC Brand's avatar JC Brand

Fixes #2193.

Translations called at the top of template files don't apply, since the
trnaslations aren't yet fetched at that point.
parent 3e8b3f73
...@@ -1544,7 +1544,7 @@ Object.assign(converse, { ...@@ -1544,7 +1544,7 @@ Object.assign(converse, {
/^converse\?loglevel=(debug|info|warn|error|fatal)$/, 'loglevel', /^converse\?loglevel=(debug|info|warn|error|fatal)$/, 'loglevel',
l => log.setLogLevel(l) l => log.setLogLevel(l)
); );
initLocale(); await initLocale();
_converse.connfeedback = new _converse.ConnectionFeedback(); _converse.connfeedback = new _converse.ConnectionFeedback();
/* When reloading the page: /* When reloading the page:
......
...@@ -4,40 +4,43 @@ import { __ } from '@converse/headless/i18n'; ...@@ -4,40 +4,43 @@ import { __ } from '@converse/headless/i18n';
import { modal_header_close_button } from "./buttons" import { modal_header_close_button } from "./buttons"
import xss from "xss/dist/xss"; import xss from "xss/dist/xss";
const i18n_join = __('Join');
const i18n_enter = __('Enter a new Groupchat');
const i18n_nickname = __('Nickname');
const i18n_required_field = __('This field is required');
const nickname_input = (o) => {
const nickname_input = (o) => html` const i18n_nickname = __('Nickname');
<div class="form-group" > const i18n_required_field = __('This field is required');
<label for="nickname">${i18n_nickname}:</label> return html`
<input type="text" title="${i18n_required_field}" required="required" name="nickname" value="${o.nick || ''}" class="form-control"/> <div class="form-group" >
</div> <label for="nickname">${i18n_nickname}:</label>
`; <input type="text" title="${i18n_required_field}" required="required" name="nickname" value="${o.nick || ''}" class="form-control"/>
</div>
`;
}
export default (o) => html` export default (o) => {
<div class="modal-dialog" role="document"> const i18n_join = __('Join');
<div class="modal-content"> const i18n_enter = __('Enter a new Groupchat');
<div class="modal-header"> return html`
<h5 class="modal-title" id="add-chatroom-modal-label">${i18n_enter}</h5> <div class="modal-dialog" role="document">
${modal_header_close_button} <div class="modal-content">
</div> <div class="modal-header">
<div class="modal-body"> <h5 class="modal-title" id="add-chatroom-modal-label">${i18n_enter}</h5>
<span class="modal-alert"></span> ${modal_header_close_button}
<form class="converse-form add-chatroom"> </div>
<div class="form-group"> <div class="modal-body">
<label for="chatroom">${o.label_room_address}:</label> <span class="modal-alert"></span>
${ (o.muc_roomid_policy_error_msg) ? html`<label class="roomid-policy-error">${o.muc_roomid_policy_error_msg}</label>` : '' } <form class="converse-form add-chatroom">
<input type="text" required="required" name="chatroom" class="form-control roomjid-input" placeholder="${o.chatroom_placeholder}"/> <div class="form-group">
</div> <label for="chatroom">${o.label_room_address}:</label>
${ o.muc_roomid_policy_hint ? html`<div class="form-group">${unsafeHTML(xss.filterXSS(o.muc_roomid_policy_hint, {'whiteList': {b: [], br: [], em: []}}))}</div>` : '' } ${ (o.muc_roomid_policy_error_msg) ? html`<label class="roomid-policy-error">${o.muc_roomid_policy_error_msg}</label>` : '' }
${ !o._converse.locked_muc_nickname ? nickname_input(o) : '' } <input type="text" required="required" name="chatroom" class="form-control roomjid-input" placeholder="${o.chatroom_placeholder}"/>
<input type="submit" class="btn btn-primary" name="join" value="${i18n_join || ''}" ?disabled=${o.muc_roomid_policy_error_msg}> </div>
</form> ${ o.muc_roomid_policy_hint ? html`<div class="form-group">${unsafeHTML(xss.filterXSS(o.muc_roomid_policy_hint, {'whiteList': {b: [], br: [], em: []}}))}</div>` : '' }
${ !o._converse.locked_muc_nickname ? nickname_input(o) : '' }
<input type="submit" class="btn btn-primary" name="join" value="${i18n_join || ''}" ?disabled=${o.muc_roomid_policy_error_msg}>
</form>
</div>
</div> </div>
</div> </div>
</div> `;
`; }
...@@ -2,51 +2,52 @@ import { html } from "lit-html"; ...@@ -2,51 +2,52 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
import { modal_header_close_button } from "./buttons" import { modal_header_close_button } from "./buttons"
const i18n_contact_placeholder = __('name@example.org');
const i18n_add = __('Add');
const i18n_error_message = __('Please enter a valid XMPP address');
const i18n_new_contact = __('Add a Contact');
const i18n_xmpp_address = __('XMPP Address');
const i18n_nickname = __('Nickname');
export default (o) => {
export default (o) => html` const i18n_contact_placeholder = __('name@example.org');
<div class="modal-dialog" role="document"> const i18n_add = __('Add');
<div class="modal-content"> const i18n_error_message = __('Please enter a valid XMPP address');
<div class="modal-header"> const i18n_new_contact = __('Add a Contact');
<h5 class="modal-title" id="addContactModalLabel">${i18n_new_contact}</h5> const i18n_xmpp_address = __('XMPP Address');
${modal_header_close_button} const i18n_nickname = __('Nickname');
</div> return html`
<form class="converse-form add-xmpp-contact"> <div class="modal-dialog" role="document">
<div class="modal-body"> <div class="modal-content">
<span class="modal-alert"></span> <div class="modal-header">
<div class="form-group add-xmpp-contact__jid"> <h5 class="modal-title" id="addContactModalLabel">${i18n_new_contact}</h5>
<label class="clearfix" for="jid">${i18n_xmpp_address}:</label> ${modal_header_close_button}
<div class="suggestion-box suggestion-box__jid"> </div>
<ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul> <form class="converse-form add-xmpp-contact">
<input type="text" name="jid" ?required=${(!o._converse.xhr_user_search_url)} <div class="modal-body">
value="${o.jid || ''}" <span class="modal-alert"></span>
class="form-control suggestion-box__input" <div class="form-group add-xmpp-contact__jid">
placeholder="${i18n_contact_placeholder}"/> <label class="clearfix" for="jid">${i18n_xmpp_address}:</label>
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span> <div class="suggestion-box suggestion-box__jid">
<ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
<input type="text" name="jid" ?required=${(!o._converse.xhr_user_search_url)}
value="${o.jid || ''}"
class="form-control suggestion-box__input"
placeholder="${i18n_contact_placeholder}"/>
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
</div>
</div> </div>
</div> <div class="form-group add-xmpp-contact__name">
<div class="form-group add-xmpp-contact__name"> <label class="clearfix" for="name">${i18n_nickname}:</label>
<label class="clearfix" for="name">${i18n_nickname}:</label> <div class="suggestion-box suggestion-box__name">
<div class="suggestion-box suggestion-box__name"> <ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
<ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul> <input type="text" name="name" value="${o.nickname || ''}"
<input type="text" name="name" value="${o.nickname || ''}" class="form-control suggestion-box__input"
class="form-control suggestion-box__input" placeholder="${i18n_nickname}"/>
placeholder="${i18n_nickname}"/> <span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span> </div>
</div> </div>
<div class="form-group">
<div class="invalid-feedback">${i18n_error_message}</div>
</div>
<button type="submit" class="btn btn-primary">${i18n_add}</button>
</div> </div>
<div class="form-group"> </form>
<div class="invalid-feedback">${i18n_error_message}</div> </div>
</div>
<button type="submit" class="btn btn-primary">${i18n_add}</button>
</div>
</form>
</div> </div>
</div> `;
`; }
...@@ -2,36 +2,38 @@ import { html } from "lit-html"; ...@@ -2,36 +2,38 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const desc_bookmarks = __('Click to toggle the bookmarks list'); const bookmark_item = (o) => {
const info_remove_bookmark = __('Unbookmark this groupchat'); const info_remove_bookmark = __('Unbookmark this groupchat');
const label_bookmarks = __('Bookmarks'); const open_title = __('Click to open this groupchat');
const open_title = __('Click to open this groupchat'); return html`
<div class="list-item controlbox-padded room-item available-chatroom d-flex flex-row ${ (o.is_hidden(o.bm)) ? 'hidden' : ''}" data-room-jid="${o.bm.get('jid')}">
<a class="list-item-link open-room w-100" data-room-jid="${o.bm.get('jid')}"
title="${open_title}"
@click=${o.openRoom}>${o.bm.getDisplayName()}</a>
<a class="list-item-action remove-bookmark fa fa-bookmark align-self-center ${ o.bm.get('bookmarked') ? 'button-on' : '' }"
data-room-jid="${o.bm.get('jid')}"
data-bookmark-name="${o.bm.getDisplayName()}"
title="${info_remove_bookmark}"
@click=${o.removeBookmark}></a>
</div>
`;
}
const bookmark_item = (o) => html` export default (o) => {
<div class="list-item controlbox-padded room-item available-chatroom d-flex flex-row ${ (o.is_hidden(o.bm)) ? 'hidden' : ''}" data-room-jid="${o.bm.get('jid')}"> const desc_bookmarks = __('Click to toggle the bookmarks list');
<a class="list-item-link open-room w-100" data-room-jid="${o.bm.get('jid')}" const label_bookmarks = __('Bookmarks');
title="${open_title}" return html`
@click=${o.openRoom}>${o.bm.getDisplayName()}</a> <div class="list-container list-container--bookmarks ${ !o.hidden && 'hidden' || '' }">
<a class="list-toggle bookmarks-toggle controlbox-padded"
<a class="list-item-action remove-bookmark fa fa-bookmark align-self-center ${ o.bm.get('bookmarked') ? 'button-on' : '' }" title="${desc_bookmarks}"
data-room-jid="${o.bm.get('jid')}" @click=${o.toggleBookmarksList}>
data-bookmark-name="${o.bm.getDisplayName()}"
title="${info_remove_bookmark}"
@click=${o.removeBookmark}></a>
</div>
`;
export default (o) => html`
<div class="list-container list-container--bookmarks ${ !o.hidden && 'hidden' || '' }">
<a class="list-toggle bookmarks-toggle controlbox-padded"
title="${desc_bookmarks}"
@click=${o.toggleBookmarksList}>
<span class="fa ${(o.toggle_state === o._converse.OPENED) ? 'fa-caret-down' : 'fa-caret-right' }"> <span class="fa ${(o.toggle_state === o._converse.OPENED) ? 'fa-caret-down' : 'fa-caret-right' }">
</span> ${label_bookmarks}</a> </span> ${label_bookmarks}</a>
<div class="items-list bookmarks rooms-list ${ (o.toggle_state !== o._converse.OPENED) ? 'hidden' : '' }"> <div class="items-list bookmarks rooms-list ${ (o.toggle_state !== o._converse.OPENED) ? 'hidden' : '' }">
${ o.bookmarks.map(bm => bookmark_item(Object.assign({bm}, o))) } ${ o.bookmarks.map(bm => bookmark_item(Object.assign({bm}, o))) }
</div>
</div> </div>
</div> `;
`; }
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
import { html } from "lit-html"; import { html } from "lit-html";
const i18n_close = __('Close');
export const modal_close_button = html`<button type="button" class="btn btn-secondary" data-dismiss="modal">${i18n_close}</button>`; export const modal_close_button = html`<button type="button" class="btn btn-secondary" data-dismiss="modal">${__('Close')}</button>`;
export const modal_header_close_button = html`<button type="button" class="close" data-dismiss="modal" aria-label="${i18n_close}"><span aria-hidden="true">×</span></button>`; export const modal_header_close_button = html`<button type="button" class="close" data-dismiss="modal" aria-label="${__('Close')}"><span aria-hidden="true">×</span></button>`;
...@@ -3,10 +3,8 @@ import { __ } from '@converse/headless/i18n'; ...@@ -3,10 +3,8 @@ import { __ } from '@converse/headless/i18n';
import { renderAvatar } from './../templates/directives/avatar'; import { renderAvatar } from './../templates/directives/avatar';
const i18n_new_messages = __('New messages');
export default (o) => { export default (o) => {
const i18n_new_messages = __('New messages');
return html` return html`
${ o.is_first_unread ? html`<div class="message date-separator"><hr class="separator"><span class="separator-text">${ i18n_new_messages }</span></div>` : '' } ${ o.is_first_unread ? html`<div class="message date-separator"><hr class="separator"><span class="separator-text">${ i18n_new_messages }</span></div>` : '' }
<div class="message chat-msg ${ o.getExtraMessageClasses() }" <div class="message chat-msg ${ o.getExtraMessageClasses() }"
......
...@@ -3,19 +3,17 @@ import { __ } from '@converse/headless/i18n'; ...@@ -3,19 +3,17 @@ import { __ } from '@converse/headless/i18n';
import { until } from 'lit-html/directives/until.js'; import { until } from 'lit-html/directives/until.js';
import avatar from "./avatar.js"; import avatar from "./avatar.js";
const i18n_profile = __('The User\'s Profile Image');
const avatar_data = {
'alt_text': i18n_profile,
'extra_classes': '',
'height': 40,
'width': 40,
}
const tpl_standalone_btns = (o) => o.standalone_btns.reverse().map(b => until(b, ''));
export default (o) => { export default (o) => {
const i18n_profile = __('The User\'s Profile Image');
const avatar_data = {
'alt_text': i18n_profile,
'extra_classes': '',
'height': 40,
'width': 40,
}
const tpl_standalone_btns = (o) => o.standalone_btns.reverse().map(b => until(b, ''));
return html` return html`
<div class="chatbox-title ${ o.status ? '' : "chatbox-title--no-desc"}"> <div class="chatbox-title ${ o.status ? '' : "chatbox-title--no-desc"}">
<div class="chatbox-title--row"> <div class="chatbox-title--row">
......
This diff is collapsed.
...@@ -5,14 +5,14 @@ import { until } from 'lit-html/directives/until.js'; ...@@ -5,14 +5,14 @@ import { until } from 'lit-html/directives/until.js';
import { converse } from "@converse/headless/converse-core"; import { converse } from "@converse/headless/converse-core";
const u = converse.env.utils; const u = converse.env.utils;
const i18n_hide_topic = __('Hide the groupchat topic');
const i18n_bookmarked = __('This groupchat is bookmarked');
const tpl_standalone_btns = (o) => o.standalone_btns.reverse().map(b => until(b, '')); const tpl_standalone_btns = (o) => o.standalone_btns.reverse().map(b => until(b, ''));
export default (o) => { export default (o) => {
const i18n_hide_topic = __('Hide the groupchat topic');
const i18n_bookmarked = __('This groupchat is bookmarked');
const subject = o.subject ? u.addHyperlinks(o.subject.text) : ''; const subject = o.subject ? u.addHyperlinks(o.subject.text) : '';
const show_subject = (subject && !o.subject_hidden); const show_subject = (subject && !o.subject_hidden);
return html` return html`
......
...@@ -4,10 +4,6 @@ import { html } from "lit-html"; ...@@ -4,10 +4,6 @@ import { html } from "lit-html";
const u = converse.env.utils; const u = converse.env.utils;
const i18n_search = __('Search');
const i18n_search_results = __('Search results');
const skintones = ['tone1', 'tone2', 'tone3', 'tone4', 'tone5'];
const emoji_category = (o) => { const emoji_category = (o) => {
return html` return html`
...@@ -37,14 +33,17 @@ const emoji_item = (o) => { ...@@ -37,14 +33,17 @@ const emoji_item = (o) => {
`; `;
} }
export const tpl_search_results = (o) => html` export const tpl_search_results = (o) => {
<span ?hidden=${!o.query} class="emoji-lists__container emojis-lists__container--search"> const i18n_search_results = __('Search results');
<a id="emoji-picker-search-results" class="emoji-category__heading">${i18n_search_results}</a> return html`
<ul class="emoji-picker"> <span ?hidden=${!o.query} class="emoji-lists__container emojis-lists__container--search">
${ o.search_results.map(emoji => emoji_item(Object.assign({emoji}, o))) } <a id="emoji-picker-search-results" class="emoji-category__heading">${i18n_search_results}</a>
</ul> <ul class="emoji-picker">
</span> ${ o.search_results.map(emoji => emoji_item(Object.assign({emoji}, o))) }
`; </ul>
</span>
`;
}
const emojis_for_category = (o) => { const emojis_for_category = (o) => {
return html` return html`
...@@ -72,6 +71,8 @@ const skintone_emoji = (o) => { ...@@ -72,6 +71,8 @@ const skintone_emoji = (o) => {
export const tpl_emoji_picker = (o) => { export const tpl_emoji_picker = (o) => {
const i18n_search = __('Search');
const skintones = ['tone1', 'tone2', 'tone3', 'tone4', 'tone5'];
return html` return html`
<div class="emoji-picker__header"> <div class="emoji-picker__header">
<input class="form-control emoji-search" name="emoji-search" placeholder="${i18n_search}" <input class="form-control emoji-search" name="emoji-search" placeholder="${i18n_search}"
......
...@@ -2,15 +2,16 @@ import { __ } from '@converse/headless/i18n'; ...@@ -2,15 +2,16 @@ import { __ } from '@converse/headless/i18n';
import { html } from "lit-html"; import { html } from "lit-html";
import { renderAvatar } from './../templates/directives/avatar'; import { renderAvatar } from './../templates/directives/avatar';
const i18n_uploading = __('Uploading file:')
export default (o) => {
export default (o) => html` const i18n_uploading = __('Uploading file:')
<div class="message chat-msg" data-isodate="${o.time}" data-msgid="${o.msgid}"> return html`
${ renderAvatar(this) } <div class="message chat-msg" data-isodate="${o.time}" data-msgid="${o.msgid}">
<div class="chat-msg__content"> ${ renderAvatar(this) }
<span class="chat-msg__text">${i18n_uploading} <strong>${o.filename}</strong>, ${o.filesize}</span> <div class="chat-msg__content">
<progress value="${o.progress}"/> <span class="chat-msg__text">${i18n_uploading} <strong>${o.filename}</strong>, ${o.filesize}</span>
<progress value="${o.progress}"/>
</div>
</div> </div>
</div> `;
`; }
import { html } from "lit-html"; import { html } from "lit-html";
import { __ } from '@converse/headless/i18n';
const tpl_headline_box = (o) => html` const tpl_headline_box = (o) => html`
<div class="list-item controlbox-padded d-flex flex-row" <div class="list-item controlbox-padded d-flex flex-row"
......
import { html } from "lit-html"; import { html } from "lit-html";
import { __ } from '@converse/headless/i18n';
import tpl_headline_list from "templates/headline_list.js"; import tpl_headline_list from "templates/headline_list.js";
......
...@@ -3,14 +3,11 @@ import { __ } from '@converse/headless/i18n'; ...@@ -3,14 +3,11 @@ import { __ } from '@converse/headless/i18n';
import { modal_close_button, modal_header_close_button } from "./buttons" import { modal_close_button, modal_header_close_button } from "./buttons"
const i18n_image = __('Image: ');
export default (o) => html` export default (o) => html`
<div class="modal-dialog fit-content" role="document"> <div class="modal-dialog fit-content" role="document">
<div class="modal-content fit-content"> <div class="modal-content fit-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title" id="message-versions-modal-label">${i18n_image}<a target="_blank" rel="noopener" href="${o.src}">${o.src}</a></h4> <h4 class="modal-title" id="message-versions-modal-label">${__('Image: ')}<a target="_blank" rel="noopener" href="${o.src}">${o.src}</a></h4>
${modal_header_close_button} ${modal_header_close_button}
</div> </div>
<div class="modal-body fit-content"> <div class="modal-body fit-content">
......
...@@ -4,66 +4,72 @@ import { repeat } from 'lit-html/directives/repeat.js'; ...@@ -4,66 +4,72 @@ import { repeat } from 'lit-html/directives/repeat.js';
import { modal_close_button, modal_header_close_button } from "./buttons" import { modal_close_button, modal_header_close_button } from "./buttons"
import spinner from "./spinner.js"; import spinner from "./spinner.js";
const i18n_info_title = __('Show more information on this groupchat');
const i18n_list_chatrooms = __('Query for Groupchats');
const i18n_open_title = __('Click to open this groupchat');
const i18n_query = __('Show groupchats');
const i18n_server_address = __('Server address');
const form = (o) => html` const form = (o) => {
<form class="converse-form list-chatrooms" const i18n_query = __('Show groupchats');
@submit=${o.submitForm}> const i18n_server_address = __('Server address');
<div class="form-group"> return html`
<label for="chatroom">${i18n_server_address}:</label> <form class="converse-form list-chatrooms"
<input type="text" @submit=${o.submitForm}>
@change=${o.setDomainFromEvent} <div class="form-group">
value="${o.muc_domain}" <label for="chatroom">${i18n_server_address}:</label>
required="required" <input type="text"
name="server" @change=${o.setDomainFromEvent}
class="form-control" value="${o.muc_domain}"
placeholder="${o.server_placeholder}"/> required="required"
</div> name="server"
<input type="submit" class="btn btn-primary" name="list" value="${i18n_query}"/> class="form-control"
</form> placeholder="${o.server_placeholder}"/>
`; </div>
<input type="submit" class="btn btn-primary" name="list" value="${i18n_query}"/>
</form>
`;
}
const tpl_item = (o, item) => html` const tpl_item = (o, item) => {
<li class="room-item list-group-item"> const i18n_info_title = __('Show more information on this groupchat');
<div class="available-chatroom d-flex flex-row"> const i18n_open_title = __('Click to open this groupchat');
<a class="open-room available-room w-100" return html`
@click=${o.openRoom} <li class="room-item list-group-item">
data-room-jid="${item.jid}" <div class="available-chatroom d-flex flex-row">
data-room-name="${item.name}" <a class="open-room available-room w-100"
title="${i18n_open_title}" @click=${o.openRoom}
href="#">${item.name || item.jid}</a> data-room-jid="${item.jid}"
<a class="right room-info icon-room-info" data-room-name="${item.name}"
@click=${o.toggleRoomInfo} title="${i18n_open_title}"
data-room-jid="${item.jid}" href="#">${item.name || item.jid}</a>
title="${i18n_info_title}" <a class="right room-info icon-room-info"
href="#"></a> @click=${o.toggleRoomInfo}
</div> data-room-jid="${item.jid}"
</li> title="${i18n_info_title}"
`; href="#"></a>
</div>
</li>
`;
}
export default (o) => html` export default (o) => {
<div class="modal-dialog" role="document"> const i18n_list_chatrooms = __('Query for Groupchats');
<div class="modal-content"> return html`
<div class="modal-header"> <div class="modal-dialog" role="document">
<h5 class="modal-title" id="list-chatrooms-modal-label">${i18n_list_chatrooms}</h5> <div class="modal-content">
${modal_header_close_button} <div class="modal-header">
</div> <h5 class="modal-title" id="list-chatrooms-modal-label">${i18n_list_chatrooms}</h5>
<div class="modal-body d-flex flex-column"> ${modal_header_close_button}
<span class="modal-alert"></span> </div>
${o.show_form ? form(o) : '' } <div class="modal-body d-flex flex-column">
<ul class="available-chatrooms list-group"> <span class="modal-alert"></span>
${ o.loading_items ? html`<li class="list-group-item"> ${spinner()} </li>` : '' } ${o.show_form ? form(o) : '' }
${ o.feedback_text ? html`<li class="list-group-item active">${ o.feedback_text }</li>` : '' } <ul class="available-chatrooms list-group">
${repeat(o.items, item => item.jid, item => tpl_item(o, item))} ${ o.loading_items ? html`<li class="list-group-item"> ${spinner()} </li>` : '' }
</ul> ${ o.feedback_text ? html`<li class="list-group-item active">${ o.feedback_text }</li>` : '' }
${repeat(o.items, item => item.jid, item => tpl_item(o, item))}
</ul>
</div>
<div class="modal-footer">${modal_close_button}</div>
</div> </div>
<div class="modal-footer">${modal_close_button}</div>
</div> </div>
</div> `;
`; }
...@@ -2,44 +2,45 @@ import { html } from "lit-html"; ...@@ -2,44 +2,45 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
import tpl_spinner from './spinner.js'; import tpl_spinner from './spinner.js';
const i18n_anon_login = __('Click here to log in anonymously');
const i18n_disconnected = __('Disconnected');
const i18n_login = __('Log in');
const i18n_hint_no_account = __("Don't have a chat account?");
const i18n_password = __('Password');
const i18n_trusted = __('This is a trusted device');
const i18n_xmpp_address = __("XMPP Address");
const i18n_create_account = __("Create an account");
const i18n_hint_trusted = __(
'To improve performance, we cache your data in this browser. '+
'Uncheck this box if this is a public computer or if you want your data to be deleted when you log out. '+
'It\'s important that you explicitly log out, otherwise not all cached data might be deleted. '+
'Please note, when using an untrusted device, OMEMO encryption is NOT available.')
const trust_checkbox = (o) => {
const i18n_hint_trusted = __(
'To improve performance, we cache your data in this browser. '+
'Uncheck this box if this is a public computer or if you want your data to be deleted when you log out. '+
'It\'s important that you explicitly log out, otherwise not all cached data might be deleted. '+
'Please note, when using an untrusted device, OMEMO encryption is NOT available.')
const i18n_trusted = __('This is a trusted device');
return html`
<div class="form-group form-check login-trusted">
<input id="converse-login-trusted" type="checkbox" class="form-check-input" name="trusted" ?checked=${o._converse.config.get('trusted')}>
<label for="converse-login-trusted" class="form-check-label login-trusted__desc">${i18n_trusted}</label>
<i class="fa fa-info-circle" data-toggle="popover"
data-title="Trusted device?"
data-content="${i18n_hint_trusted}"></i>
</div>
`;
}
const trust_checkbox = (o) => html` const password_input = () => {
<div class="form-group form-check login-trusted"> const i18n_password = __('Password');
<input id="converse-login-trusted" type="checkbox" class="form-check-input" name="trusted" ?checked=${o._converse.config.get('trusted')}> return html`
<label for="converse-login-trusted" class="form-check-label login-trusted__desc">${i18n_trusted}</label> <div class="form-group">
<i class="fa fa-info-circle" data-toggle="popover" <label for="converse-login-password">${i18n_password}</label>
data-title="Trusted device?" <input id="converse-login-password" class="form-control" required="required" type="password" name="password" placeholder="${i18n_password}"/>
data-content="${i18n_hint_trusted}"></i> </div>
</div> `;
`; }
const password_input = () => html`
<div class="form-group">
<label for="converse-login-password">${i18n_password}</label>
<input id="converse-login-password" class="form-control" required="required" type="password" name="password" placeholder="${i18n_password}"/>
</div>
`;
const register_link = () => html` const register_link = () => {
<fieldset class="switch-form"> const i18n_create_account = __("Create an account");
<p>${i18n_hint_no_account}</p> const i18n_hint_no_account = __("Don't have a chat account?");
<p><a class="register-account toggle-register-login" href="#converse/register">${i18n_create_account}</a></p> return html`
</fieldset> <fieldset class="switch-form">
`; <p>${i18n_hint_no_account}</p>
<p><a class="register-account toggle-register-login" href="#converse/register">${i18n_create_account}</a></p>
</fieldset>
`;
}
const show_register_link = (o) => { const show_register_link = (o) => {
const _converse = o._converse; const _converse = o._converse;
...@@ -49,25 +50,33 @@ const show_register_link = (o) => { ...@@ -49,25 +50,33 @@ const show_register_link = (o) => {
} }
const auth_fields = (o) => html` const auth_fields = (o) => {
<div class="form-group"> const i18n_login = __('Log in');
<label for="converse-login-jid">${i18n_xmpp_address}:</label> const i18n_xmpp_address = __("XMPP Address");
<input id="converse-login-jid" class="form-control" required="required" type="text" name="jid" placeholder="${o.placeholder_username}"/> return html`
</div> <div class="form-group">
${ (o.authentication !== o.EXTERNAL) ? password_input() : '' } <label for="converse-login-jid">${i18n_xmpp_address}:</label>
${ o.show_trust_checkbox ? trust_checkbox(o) : '' } <input id="converse-login-jid" class="form-control" required="required" type="text" name="jid" placeholder="${o.placeholder_username}"/>
<fieldset class="buttons"> </div>
<input class="btn btn-primary" type="submit" value="${i18n_login}"/> ${ (o.authentication !== o.EXTERNAL) ? password_input() : '' }
</fieldset> ${ o.show_trust_checkbox ? trust_checkbox(o) : '' }
${ show_register_link(o) ? register_link(o) : '' } <fieldset class="buttons">
`; <input class="btn btn-primary" type="submit" value="${i18n_login}"/>
</fieldset>
${ show_register_link(o) ? register_link(o) : '' }
`;
}
const form_fields = (o) => html` const form_fields = (o) => {
${ (o.authentication == o.LOGIN || o.authentication == o.EXTERNAL) ? auth_fields(o) : '' } const i18n_disconnected = __('Disconnected');
${ o.authentication == o.ANONYMOUS ? html`<input class="btn btn-primary login-anon" type="submit" value="${i18n_anon_login}">` : '' } const i18n_anon_login = __('Click here to log in anonymously');
${ o.authentication == o.PREBIND ? html`<p>${i18n_disconnected}</p>` : '' } return html`
`; ${ (o.authentication == o.LOGIN || o.authentication == o.EXTERNAL) ? auth_fields(o) : '' }
${ o.authentication == o.ANONYMOUS ? html`<input class="btn btn-primary login-anon" type="submit" value="${i18n_anon_login}">` : '' }
${ o.authentication == o.PREBIND ? html`<p>${i18n_disconnected}</p>` : '' }
`;
}
export default (o) => html` export default (o) => html`
......
...@@ -4,14 +4,11 @@ import dayjs from 'dayjs'; ...@@ -4,14 +4,11 @@ import dayjs from 'dayjs';
import { modal_close_button, modal_header_close_button } from "./buttons" import { modal_close_button, modal_header_close_button } from "./buttons"
const i18n_message_versions = __('Message versions');
export default (o) => html` export default (o) => html`
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title" id="message-versions-modal-label">${i18n_message_versions}</h4> <h4 class="modal-title" id="message-versions-modal-label">${__('Message versions')}</h4>
${modal_header_close_button} ${modal_header_close_button}
</div> </div>
<div class="modal-body"> <div class="modal-body">
......
...@@ -4,32 +4,6 @@ import spinner from "./spinner.js"; ...@@ -4,32 +4,6 @@ import spinner from "./spinner.js";
import { modal_header_close_button } from "./buttons" import { modal_header_close_button } from "./buttons"
const i18n_affiliation = __('Affiliation');
const i18n_change_affiliation = __('Change affiliation');
const i18n_change_role = __('Change role');
const i18n_moderator_tools = __('Moderator Tools');
const i18n_new_affiliation = __('New affiliation');
const i18n_new_role = __('New Role');
const i18n_no_users_with_aff = __('No users with that affiliation found.')
const i18n_no_users_with_role = __('No users with that role found.');
const i18n_reason = __('Reason');
const i18n_filter = __('Type here to filter the search results');
const i18n_role = __('Role');
const i18n_show_users = __('Show users');
const i18n_helptext_role = __(
"Roles are assigned to users to grant or deny them certain abilities in a multi-user chat. "+
"They're assigned either explicitly or implicitly as part of an affiliation. "+
"A role that's not due to an affiliation, is only valid for the duration of the user's session."
);
const i18n_helptext_affiliation = __(
"An affiliation is a long-lived entitlement which typically implies a certain role and which "+
"grants privileges and responsibilities. For example admins and owners automatically have the "+
"moderator role."
);
function getRoleHelpText (role) { function getRoleHelpText (role) {
if (role === 'moderator') { if (role === 'moderator') {
return __("Moderators are privileged users who can change the roles of other users (except those with admin or owner affiliations."); return __("Moderators are privileged users who can change the roles of other users (except those with admin or owner affiliations.");
...@@ -65,29 +39,34 @@ const affiliation_option = (o) => html` ...@@ -65,29 +39,34 @@ const affiliation_option = (o) => html`
`; `;
const tpl_set_role_form = (o) => html` const tpl_set_role_form = (o) => {
<form class="role-form hidden" @submit=${o.assignRole}> const i18n_change_role = __('Change role');
<div class="form-group"> const i18n_new_role = __('New Role');
<input type="hidden" name="jid" value="${o.item.jid}"/> const i18n_reason = __('Reason');
<input type="hidden" name="nick" value="${o.item.nick}"/> return html`
<div class="row"> <form class="role-form hidden" @submit=${o.assignRole}>
<div class="col"> <div class="form-group">
<label><strong>${i18n_new_role}:</strong></label> <input type="hidden" name="jid" value="${o.item.jid}"/>
<select class="custom-select select-role" name="role"> <input type="hidden" name="nick" value="${o.item.nick}"/>
${ o.assignable_roles.map(role => html`<option value="${role}" ?selected=${role === o.item.role}>${role}</option>`) } <div class="row">
</select> <div class="col">
</div> <label><strong>${i18n_new_role}:</strong></label>
<div class="col"> <select class="custom-select select-role" name="role">
<label><strong>${i18n_reason}:</strong></label> ${ o.assignable_roles.map(role => html`<option value="${role}" ?selected=${role === o.item.role}>${role}</option>`) }
<input class="form-control" type="text" name="reason"/> </select>
</div>
<div class="col">
<label><strong>${i18n_reason}:</strong></label>
<input class="form-control" type="text" name="reason"/>
</div>
</div> </div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <input type="submit" class="btn btn-primary" value="${i18n_change_role}"/>
<input type="submit" class="btn btn-primary" value="${i18n_change_role}"/> </div>
</div> </form>
</form> `;
`; }
const role_list_item = (o) => html` const role_list_item = (o) => html`
...@@ -108,29 +87,34 @@ const role_list_item = (o) => html` ...@@ -108,29 +87,34 @@ const role_list_item = (o) => html`
`; `;
const tpl_set_affiliation_form = (o) => html` const tpl_set_affiliation_form = (o) => {
<form class="affiliation-form hidden" @submit=${o.assignAffiliation}> const i18n_change_affiliation = __('Change affiliation');
<div class="form-group"> const i18n_new_affiliation = __('New affiliation');
<input type="hidden" name="jid" value="${o.item.jid}"/> const i18n_reason = __('Reason');
<input type="hidden" name="nick" value="${o.item.nick}"/> return html`
<div class="row"> <form class="affiliation-form hidden" @submit=${o.assignAffiliation}>
<div class="col"> <div class="form-group">
<label><strong>${i18n_new_affiliation}:</strong></label> <input type="hidden" name="jid" value="${o.item.jid}"/>
<select class="custom-select select-affiliation" name="affiliation"> <input type="hidden" name="nick" value="${o.item.nick}"/>
${ o.assignable_affiliations.map(aff => html`<option value="${aff}" ?selected=${aff === o.item.affiliation}>${aff}</option>`) } <div class="row">
</select> <div class="col">
</div> <label><strong>${i18n_new_affiliation}:</strong></label>
<div class="col"> <select class="custom-select select-affiliation" name="affiliation">
<label><strong>${i18n_reason}:</strong></label> ${ o.assignable_affiliations.map(aff => html`<option value="${aff}" ?selected=${aff === o.item.affiliation}>${aff}</option>`) }
<input class="form-control" type="text" name="reason"/> </select>
</div>
<div class="col">
<label><strong>${i18n_reason}:</strong></label>
<input class="form-control" type="text" name="reason"/>
</div>
</div> </div>
</div> </div>
</div> <div class="form-group">
<div class="form-group"> <input type="submit" class="btn btn-primary" name="change" value="${i18n_change_affiliation}"/>
<input type="submit" class="btn btn-primary" name="change" value="${i18n_change_affiliation}"/> </div>
</div> </form>
</form> `;
`; }
const affiliation_list_item = (o) => html` const affiliation_list_item = (o) => html`
...@@ -164,6 +148,23 @@ const tpl_navigation = (o) => html` ...@@ -164,6 +148,23 @@ const tpl_navigation = (o) => html`
export default (o) => { export default (o) => {
const i18n_affiliation = __('Affiliation');
const i18n_moderator_tools = __('Moderator Tools');
const i18n_no_users_with_aff = __('No users with that affiliation found.')
const i18n_no_users_with_role = __('No users with that role found.');
const i18n_filter = __('Type here to filter the search results');
const i18n_role = __('Role');
const i18n_show_users = __('Show users');
const i18n_helptext_role = __(
"Roles are assigned to users to grant or deny them certain abilities in a multi-user chat. "+
"They're assigned either explicitly or implicitly as part of an affiliation. "+
"A role that's not due to an affiliation, is only valid for the duration of the user's session."
);
const i18n_helptext_affiliation = __(
"An affiliation is a long-lived entitlement which typically implies a certain role and which "+
"grants privileges and responsibilities. For example admins and owners automatically have the "+
"moderator role."
);
const show_both_tabs = o.queryable_roles.length && o.queryable_affiliations.length; const show_both_tabs = o.queryable_roles.length && o.queryable_affiliations.length;
return html` return html`
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
......
import { html } from "lit-html"; import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_heading = __('Bookmark this groupchat');
const i18n_autojoin = __('Would you like this groupchat to be automatically joined upon startup?');
const i18n_cancel = __('Cancel');
const i18n_name = __('The name for this bookmark:');
const i18n_nick = __('What should your nickname for this groupchat be?');
const i18n_submit = __('Save');
export default (o) => {
export default (o) => html` const i18n_heading = __('Bookmark this groupchat');
<form class="converse-form chatroom-form" @submit=${o.onSubmit}> const i18n_autojoin = __('Would you like this groupchat to be automatically joined upon startup?');
<legend>${i18n_heading}</legend> const i18n_cancel = __('Cancel');
<fieldset class="form-group"> const i18n_name = __('The name for this bookmark:');
<label for="converse_muc_bookmark_name">${i18n_name}</label> const i18n_nick = __('What should your nickname for this groupchat be?');
<input class="form-control" type="text" value="${o.name}" name="name" required="required" id="converse_muc_bookmark_name"/> const i18n_submit = __('Save');
</fieldset> return html`
<fieldset class="form-group"> <form class="converse-form chatroom-form" @submit=${o.onSubmit}>
<label for="converse_muc_bookmark_nick">${i18n_nick}</label> <legend>${i18n_heading}</legend>
<input class="form-control" type="text" name="nick" value="${o.nick || ''}" id="converse_muc_bookmark_nick"/> <fieldset class="form-group">
</fieldset> <label for="converse_muc_bookmark_name">${i18n_name}</label>
<fieldset class="form-group form-check"> <input class="form-control" type="text" value="${o.name}" name="name" required="required" id="converse_muc_bookmark_name"/>
<input class="form-check-input" id="converse_muc_bookmark_autojoin" type="checkbox" name="autojoin"/> </fieldset>
<label class="form-check-label" for="converse_muc_bookmark_autojoin">${i18n_autojoin}</label> <fieldset class="form-group">
</fieldset> <label for="converse_muc_bookmark_nick">${i18n_nick}</label>
<fieldset class="form-group"> <input class="form-control" type="text" name="nick" value="${o.nick || ''}" id="converse_muc_bookmark_nick"/>
<input class="btn btn-primary" type="submit" value="${i18n_submit}"> </fieldset>
<input class="btn btn-secondary button-cancel" type="button" value="${i18n_cancel}" @click=${o.onCancel}> <fieldset class="form-group form-check">
</fieldset> <input class="form-check-input" id="converse_muc_bookmark_autojoin" type="checkbox" name="autojoin"/>
</form> <label class="form-check-label" for="converse_muc_bookmark_autojoin">${i18n_autojoin}</label>
`; </fieldset>
<fieldset class="form-group">
<input class="btn btn-primary" type="submit" value="${i18n_submit}">
<input class="btn btn-secondary button-cancel" type="button" value="${i18n_cancel}" @click=${o.onCancel}>
</fieldset>
</form>
`;
}
...@@ -2,20 +2,21 @@ import { html } from "lit-html"; ...@@ -2,20 +2,21 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
const i18n_save = __('Save'); export default (o) => {
const i18n_cancel = __('Cancel'); const i18n_save = __('Save');
const i18n_cancel = __('Cancel');
export default (o) => html` return html`
<form class="converse-form chatroom-form" autocomplete="off" @submit=${o.submitConfigForm}> <form class="converse-form chatroom-form" autocomplete="off" @submit=${o.submitConfigForm}>
<fieldset class="form-group"> <fieldset class="form-group">
<legend>${o.title}</legend> <legend>${o.title}</legend>
${ (o.title !== o.instructions) ? html`<p class="form-help">${o.instructions}</p>` : '' } ${ (o.title !== o.instructions) ? html`<p class="form-help">${o.instructions}</p>` : '' }
<!-- Fields are generated internally, with xForm2webForm --> <!-- Fields are generated internally, with xForm2webForm -->
${ o.fields.map(field => unsafeHTML(field)) } ${ o.fields.map(field => unsafeHTML(field)) }
</fieldset> </fieldset>
<fieldset> <fieldset>
<input type="submit" class="btn btn-primary" value="${i18n_save}"> <input type="submit" class="btn btn-primary" value="${i18n_save}">
<input type="button" class="btn btn-secondary button-cancel" value="${i18n_cancel}" @click=${o.closeConfigForm}> <input type="button" class="btn btn-secondary button-cancel" value="${i18n_cancel}" @click=${o.closeConfigForm}>
</fieldset> </fieldset>
</form> </form>
`; `;
}
...@@ -2,47 +2,48 @@ import { html } from "lit-html"; ...@@ -2,47 +2,48 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
import { modal_header_close_button } from "./buttons" import { modal_header_close_button } from "./buttons"
const i18n_invite = __('Invite');
const i18n_invite_heading = __('Invite someone to this groupchat');
const i18n_jid_placeholder = __('user@example.org');
const i18n_error_message = __('Please enter a valid XMPP address');
const i18n_invite_label = __('XMPP Address');
const i18n_reason = __('Optional reason for the invitation');
export default (o) => {
export default (o) => html` const i18n_invite = __('Invite');
<div class="modal-dialog" role="document"> const i18n_invite_heading = __('Invite someone to this groupchat');
<div class="modal-content"> const i18n_jid_placeholder = __('user@example.org');
<div class="modal-header"> const i18n_error_message = __('Please enter a valid XMPP address');
<h5 class="modal-title" id="add-chatroom-modal-label">${i18n_invite_heading}</h5> const i18n_invite_label = __('XMPP Address');
${modal_header_close_button} const i18n_reason = __('Optional reason for the invitation');
</div> return html`
<div class="modal-body"> <div class="modal-dialog" role="document">
<span class="modal-alert"></span> <div class="modal-content">
<div class="suggestion-box room-invite"> <div class="modal-header">
<form @submit=${o.submitInviteForm}> <h5 class="modal-title" id="add-chatroom-modal-label">${i18n_invite_heading}</h5>
<div class="form-group"> ${modal_header_close_button}
<label class="clearfix" for="invitee_jids">${i18n_invite_label}:</label> </div>
${ o.invalid_invite_jid ? html`<div class="error error-feedback">${i18n_error_message}</div>` : '' } <div class="modal-body">
<input class="form-control suggestion-box__input" <span class="modal-alert"></span>
required="required" <div class="suggestion-box room-invite">
name="invitee_jids" <form @submit=${o.submitInviteForm}>
id="invitee_jids" <div class="form-group">
placeholder="${i18n_jid_placeholder}" <label class="clearfix" for="invitee_jids">${i18n_invite_label}:</label>
type="text"/> ${ o.invalid_invite_jid ? html`<div class="error error-feedback">${i18n_error_message}</div>` : '' }
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span> <input class="form-control suggestion-box__input"
<ul class="suggestion-box__results suggestion-box__results--below" hidden=""></ul> required="required"
</div> name="invitee_jids"
<div class="form-group"> id="invitee_jids"
<label>${i18n_reason}:</label> placeholder="${i18n_jid_placeholder}"
<textarea class="form-control" name="reason"></textarea> type="text"/>
</div> <span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
<div class="form-group"> <ul class="suggestion-box__results suggestion-box__results--below" hidden=""></ul>
<button type="submit" class="btn btn-primary">${i18n_invite}</button> </div>
</div> <div class="form-group">
</form> <label>${i18n_reason}:</label>
<textarea class="form-control" name="reason"></textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">${i18n_invite}</button>
</div>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> `;
`; }
import { html } from "lit-html"; import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_heading = __('This groupchat requires a password');
const i18n_password = __('Password: ');
const i18n_submit = __('Submit');
export default (o) => {
export default (o) => html` const i18n_heading = __('This groupchat requires a password');
<form class="converse-form chatroom-form converse-centered-form" @submit=${o.submitPassword}> const i18n_password = __('Password: ');
<fieldset class="form-group"> const i18n_submit = __('Submit');
<label>${i18n_heading}</label> return html`
<p class="validation-message">${o.validation_message}</p> <form class="converse-form chatroom-form converse-centered-form" @submit=${o.submitPassword}>
<input class="hidden-username" type="text" autocomplete="username" value="${o.jid}"></input> <fieldset class="form-group">
<input type="password" <label>${i18n_heading}</label>
name="password" <p class="validation-message">${o.validation_message}</p>
required="required" <input class="hidden-username" type="text" autocomplete="username" value="${o.jid}"></input>
class="form-control ${o.validation_message ? 'error': ''}" <input type="password"
placeholder="${i18n_password}"/> name="password"
</fieldset> required="required"
<fieldset class="form-group"> class="form-control ${o.validation_message ? 'error': ''}"
<input class="btn btn-primary" type="submit" value="${i18n_submit}"/> placeholder="${i18n_password}"/>
</fieldset> </fieldset>
</form> <fieldset class="form-group">
`; <input class="btn btn-primary" type="submit" value="${i18n_submit}"/>
</fieldset>
</form>
`;
}
...@@ -13,27 +13,28 @@ const PRETTY_CHAT_STATUS = { ...@@ -13,27 +13,28 @@ const PRETTY_CHAT_STATUS = {
'online': 'Online' 'online': 'Online'
}; };
const i18n_occupant_hint = (occupant) => __('Click to mention %1$s in your message.', occupant.get('nick'))
const i18n_participants = __('Participants');
export default (o) => {
export default (o) => html` const i18n_occupant_hint = (occupant) => __('Click to mention %1$s in your message.', occupant.get('nick'))
<div class="occupants-header"> const i18n_participants = __('Participants');
<i class="hide-occupants fa fa-times"></i> return html`
<div class="occupants-header--title"> <div class="occupants-header">
<span class="occupants-heading">${i18n_participants}</span> <i class="hide-occupants fa fa-times"></i>
<div class="occupants-header--title">
<span class="occupants-heading">${i18n_participants}</span>
</div>
</div> </div>
</div> <div class="dragresize dragresize-occupants-left"></div>
<div class="dragresize dragresize-occupants-left"></div> <ul class="occupant-list">
<ul class="occupant-list"> ${ o.occupants.map(occupant => {
${ o.occupants.map(occupant => { return tpl_occupant(
return tpl_occupant( Object.assign({
Object.assign({ 'jid': '',
'jid': '', 'hint_show': PRETTY_CHAT_STATUS[occupant.get('show')],
'hint_show': PRETTY_CHAT_STATUS[occupant.get('show')], 'hint_occupant': i18n_occupant_hint(occupant)
'hint_occupant': i18n_occupant_hint(occupant) }, occupant.toJSON())
}, occupant.toJSON()) );
); }) }
}) } </ul>
</ul> `;
`; }
...@@ -2,16 +2,10 @@ import { html } from "lit-html"; ...@@ -2,16 +2,10 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_moderator_hint = __('This user is a moderator.');
const i18n_participant_hint = __('This user can send messages in this groupchat.');
const i18n_visitor_hint = __('This user can NOT send messages in this groupchat.')
const i18n_owner = __('Owner');
const i18n_admin = __('Admin');
const i18n_member = __('Member');
const i18n_moderator = __('Moderator');
const i18n_visitor = __('Visitor');
const occupant_title = (o) => { const occupant_title = (o) => {
const i18n_moderator_hint = __('This user is a moderator.');
const i18n_participant_hint = __('This user can send messages in this groupchat.');
const i18n_visitor_hint = __('This user can NOT send messages in this groupchat.')
if (o.role === "moderator") { if (o.role === "moderator") {
return `${o.jid} ${i18n_moderator_hint} ${o.hint_occupant}`; return `${o.jid} ${i18n_moderator_hint} ${o.hint_occupant}`;
} else if (o.role === "participant") { } else if (o.role === "participant") {
...@@ -24,22 +18,29 @@ const occupant_title = (o) => { ...@@ -24,22 +18,29 @@ const occupant_title = (o) => {
} }
export default (o) => html` export default (o) => {
<li class="occupant" id="${o.id}" title="${occupant_title(o)}"> const i18n_owner = __('Owner');
<div class="row no-gutters"> const i18n_admin = __('Admin');
<div class="col-auto"> const i18n_member = __('Member');
<div class="occupant-status occupant-${o.show} circle" title="${o.hint_show}"></div> const i18n_moderator = __('Moderator');
</div> const i18n_visitor = __('Visitor');
<div class="col occupant-nick-badge"> return html`
<span class="occupant-nick">${o.nick || o.jid}</span> <li class="occupant" id="${o.id}" title="${occupant_title(o)}">
<span class="occupant-badges"> <div class="row no-gutters">
${ (o.affiliation === "owner") ? html`<span class="badge badge-groupchat">${i18n_owner}</span>` : '' } <div class="col-auto">
${ (o.affiliation === "admin") ? html`<span class="badge badge-info">${i18n_admin}</span>` : '' } <div class="occupant-status occupant-${o.show} circle" title="${o.hint_show}"></div>
${ (o.affiliation === "member") ? html`<span class="badge badge-info">${i18n_member}</span>` : '' } </div>
${ (o.role === "moderator") ? html`<span class="badge badge-info">${i18n_moderator}</span>` : '' } <div class="col occupant-nick-badge">
${ (o.role === "visitor") ? html`<span class="badge badge-secondary">${i18n_visitor}</span>` : '' } <span class="occupant-nick">${o.nick || o.jid}</span>
</span> <span class="occupant-badges">
${ (o.affiliation === "owner") ? html`<span class="badge badge-groupchat">${i18n_owner}</span>` : '' }
${ (o.affiliation === "admin") ? html`<span class="badge badge-info">${i18n_admin}</span>` : '' }
${ (o.affiliation === "member") ? html`<span class="badge badge-info">${i18n_member}</span>` : '' }
${ (o.role === "moderator") ? html`<span class="badge badge-info">${i18n_moderator}</span>` : '' }
${ (o.role === "visitor") ? html`<span class="badge badge-secondary">${i18n_visitor}</span>` : '' }
</span>
</div>
</div> </div>
</div> </li>
</li> `;
`; }
...@@ -2,12 +2,11 @@ import { __ } from '@converse/headless/i18n'; ...@@ -2,12 +2,11 @@ import { __ } from '@converse/headless/i18n';
import { api } from "@converse/headless/converse-core"; import { api } from "@converse/headless/converse-core";
import { html } from "lit-html"; import { html } from "lit-html";
const i18n_logout = __('Log out');
const i18n_change_status = __('Click to change your chat status');
const i18n_details = __('Show details about this chat client');
export default (o) => { export default (o) => {
const i18n_logout = __('Log out');
const i18n_change_status = __('Click to change your chat status');
const i18n_details = __('Show details about this chat client');
const show_settings_button = api.settings.get('show_client_info') || api.settings.get('allow_adhoc_commands'); const show_settings_button = api.settings.get('show_client_info') || api.settings.get('allow_adhoc_commands');
return html` return html`
<div class="userinfo controlbox-padded"> <div class="userinfo controlbox-padded">
......
This diff is collapsed.
...@@ -2,10 +2,6 @@ import { html } from "lit-html"; ...@@ -2,10 +2,6 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_cancel = __('Cancel');
const i18n_ok = __('OK');
const tpl_field = (f) => html` const tpl_field = (f) => html`
<div class="form-group"> <div class="form-group">
<label> <label>
...@@ -37,8 +33,8 @@ export default (o) => html` ...@@ -37,8 +33,8 @@ export default (o) => html`
</div> </div>
${ o.fields.map(f => tpl_field(f)) } ${ o.fields.map(f => tpl_field(f)) }
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-primary">${i18n_ok}</button> <button type="submit" class="btn btn-primary">${__('OK')}</button>
<input type="button" class="btn btn-secondary" data-dismiss="modal" value="${i18n_cancel}"/> <input type="button" class="btn btn-secondary" data-dismiss="modal" value="${__('Cancel')}"/>
</div> </div>
</form> </form>
</div> </div>
......
...@@ -2,20 +2,9 @@ import { html } from "lit-html"; ...@@ -2,20 +2,9 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_desc_rooms = __('Click to toggle the list of open groupchats');
const i18n_add_bookmark = __('Bookmark this groupchat');
const i18n_leave_room = __('Leave this groupchat');
const i18n_remove_bookmark = __('Unbookmark this groupchat');
const i18n_title = __('Show more information on this groupchat');
const i18n_open = __('Click to open this groupchat');
// Note to translators, "Open Groupchats" refers to groupchats that are open, NOT a command.
const i18n_rooms = __('Open Groupchats');
const unread_indicator = (o) => html`<span class="list-item-badge badge badge--muc msgs-indicator">${ o.room.get('num_unread') }</span>`;
const bookmark = (o) => { const bookmark = (o) => {
const i18n_add_bookmark = __('Bookmark this groupchat');
const i18n_remove_bookmark = __('Unbookmark this groupchat');
if (o.bookmarked) { if (o.bookmarked) {
return html` return html`
<a class="list-item-action fa fa-bookmark remove-bookmark button-on" <a class="list-item-action fa fa-bookmark remove-bookmark button-on"
...@@ -34,37 +23,42 @@ const bookmark = (o) => { ...@@ -34,37 +23,42 @@ const bookmark = (o) => {
} }
const room_item = (o) => html` const room_item = (o) => {
<div class="list-item controlbox-padded available-chatroom d-flex flex-row ${ o.currently_open(o.room) ? 'open' : '' } ${ o.room.get('num_unread_general') ? 'unread-msgs' : '' }" const i18n_leave_room = __('Leave this groupchat');
data-room-jid="${o.room.get('jid')}"> const unread_indicator = (o) => html`<span class="list-item-badge badge badge--muc msgs-indicator">${ o.room.get('num_unread') }</span>`;
return html`
<div class="list-item controlbox-padded available-chatroom d-flex flex-row ${ o.currently_open(o.room) ? 'open' : '' } ${ o.room.get('num_unread_general') ? 'unread-msgs' : '' }"
data-room-jid="${o.room.get('jid')}">
${ o.room.get('num_unread') ? unread_indicator(o) : '' } ${ o.room.get('num_unread') ? unread_indicator(o) : '' }
<a class="list-item-link open-room available-room w-100" <a class="list-item-link open-room available-room w-100"
data-room-jid="${o.room.get('jid')}" data-room-jid="${o.room.get('jid')}"
title="${i18n_open}" title="${__('Click to open this groupchat')}"
@click=${o.openRoom}>${o.room.getDisplayName()}</a> @click=${o.openRoom}>${o.room.getDisplayName()}</a>
${ o.allow_bookmarks ? bookmark(o) : '' } ${ o.allow_bookmarks ? bookmark(o) : '' }
<a class="list-item-action room-info fa fa-info-circle" <a class="list-item-action room-info fa fa-info-circle"
data-room-jid="${o.room.get('jid')}" data-room-jid="${o.room.get('jid')}"
title="${i18n_title}" title="${__('Show more information on this groupchat')}"
@click=${o.showRoomDetailsModal}></a> @click=${o.showRoomDetailsModal}></a>
<a class="list-item-action fa fa-sign-out-alt close-room" <a class="list-item-action fa fa-sign-out-alt close-room"
data-room-jid="${o.room.get('jid')}" data-room-jid="${o.room.get('jid')}"
data-room-name="${o.room.getDisplayName()}" data-room-name="${o.room.getDisplayName()}"
title="${i18n_leave_room}" title="${i18n_leave_room}"
@click=${o.closeRoom}></a> @click=${o.closeRoom}></a>
</div> </div>`;
`; }
export default (o) => html` export default (o) => {
<div class="list-container list-container--openrooms ${ o.rooms.length ? '' : 'hidden' }"> const i18n_desc_rooms = __('Click to toggle the list of open groupchats');
<a class="list-toggle open-rooms-toggle controlbox-padded" title="${i18n_desc_rooms}" @click=${o.toggleRoomsList}> return html`
<span class="fa ${ (o.toggle_state === o._converse.OPENED) ? 'fa-caret-down' : 'fa-caret-right' }"></span> ${i18n_rooms}</a> <div class="list-container list-container--openrooms ${ o.rooms.length ? '' : 'hidden' }">
<div class="items-list rooms-list open-rooms-list ${ o.collapsed && 'collapsed' }"> <a class="list-toggle open-rooms-toggle controlbox-padded" title="${i18n_desc_rooms}" @click=${o.toggleRoomsList}>
${ o.rooms.map(room => room_item(Object.assign({room}, o))) } <span class="fa ${ (o.toggle_state === o._converse.OPENED) ? 'fa-caret-down' : 'fa-caret-right' }"></span> ${__('Open Groupchats')}</a>
</div> <div class="items-list rooms-list open-rooms-list ${ o.collapsed && 'collapsed' }">
</div> ${ o.rooms.map(room => room_item(Object.assign({room}, o))) }
`; </div>
</div>`;
}
...@@ -2,10 +2,7 @@ import { html } from "lit-html"; ...@@ -2,10 +2,7 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_minimized = __('Minimized')
export default (o) => html` export default (o) => html`
${o.num_minimized} ${i18n_minimized} ${o.num_minimized} ${__('Minimized')}
<span class="unread-message-count ${!o.num_unread ? 'unread-message-count-hidden' : ''}" href="#">${o.num_unread}</span> <span class="unread-message-count ${!o.num_unread ? 'unread-message-count-hidden' : ''}" href="#">${o.num_unread}</span>
`; `;
...@@ -2,14 +2,14 @@ import { html } from "lit-html"; ...@@ -2,14 +2,14 @@ import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
const i18n_tooltip = __('Click to restore this chat'); export default (o) => {
const i18n_tooltip = __('Click to restore this chat');
return html`
export default (o) => html` <div class="chat-head-${o.type} chat-head row no-gutters">
<div class="chat-head-${o.type} chat-head row no-gutters"> <a class="restore-chat w-100 align-self-center" title="${i18n_tooltip}">
<a class="restore-chat w-100 align-self-center" title="${i18n_tooltip}"> ${o.num_unread ? html`<span class="message-count badge badge-light">${o.num_unread}</span>` : '' }
${o.num_unread ? html`<span class="message-count badge badge-light">${o.num_unread}</span>` : '' } ${o.title}
${o.title} </a>
</a> <a class="chatbox-btn close-chatbox-button fa fa-times"></a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a> </div>`;
</div>`; }
...@@ -4,27 +4,9 @@ import avatar from "./avatar.js"; ...@@ -4,27 +4,9 @@ import avatar from "./avatar.js";
import { modal_close_button, modal_header_close_button } from "./buttons" import { modal_close_button, modal_header_close_button } from "./buttons"
const i18n_address = __('XMPP Address');
const i18n_email = __('Email');
const i18n_fingerprints = __('OMEMO Fingerprints');
const i18n_full_name = __('Full Name');
const i18n_nickname = __('Nickname');
const i18n_profile = __('The User\'s Profile Image');
const i18n_refresh = __('Refresh');
const i18n_role = __('Role');
const i18n_url = __('URL');
const i18n_remove_contact = __('Remove as contact');
const i18n_trusted = __('Trusted');
const i18n_untrusted = __('Untrusted');
const i18n_no_devices = __("No OMEMO-enabled devices found");
const avatar_data = {
'alt_text': i18n_profile,
'extra_classes': 'mb-3'
}
const device_fingerprint = (o) => { const device_fingerprint = (o) => {
const i18n_trusted = __('Trusted');
const i18n_untrusted = __('Untrusted');
if (o.device.get('bundle') && o.device.get('bundle').fingerprint) { if (o.device.get('bundle') && o.device.get('bundle').fingerprint) {
return html` return html`
<li class="list-group-item"> <li class="list-group-item">
...@@ -48,6 +30,8 @@ const device_fingerprint = (o) => { ...@@ -48,6 +30,8 @@ const device_fingerprint = (o) => {
const fingerprints = (o) => { const fingerprints = (o) => {
const i18n_fingerprints = __('OMEMO Fingerprints');
const i18n_no_devices = __("No OMEMO-enabled devices found");
const devices = o.view.devicelist.devices; const devices = o.view.devicelist.devices;
return html` return html`
<hr/> <hr/>
...@@ -61,6 +45,7 @@ const fingerprints = (o) => { ...@@ -61,6 +45,7 @@ const fingerprints = (o) => {
} }
const remove_button = (o) => { const remove_button = (o) => {
const i18n_remove_contact = __('Remove as contact');
return html` return html`
<button type="button" @click="${o.removeContact}" class="btn btn-danger remove-contact"> <button type="button" @click="${o.removeContact}" class="btn btn-danger remove-contact">
<i class="far fa-trash-alt"></i>${i18n_remove_contact} <i class="far fa-trash-alt"></i>${i18n_remove_contact}
...@@ -69,30 +54,45 @@ const remove_button = (o) => { ...@@ -69,30 +54,45 @@ const remove_button = (o) => {
} }
export default (o) => html` export default (o) => {
<div class="modal-dialog" role="document"> const i18n_address = __('XMPP Address');
<div class="modal-content"> const i18n_email = __('Email');
<div class="modal-header"> const i18n_full_name = __('Full Name');
<h5 class="modal-title" id="user-details-modal-label">${o.display_name}</h5> const i18n_nickname = __('Nickname');
${modal_header_close_button} const i18n_profile = __('The User\'s Profile Image');
</div> const i18n_refresh = __('Refresh');
<div class="modal-body"> const i18n_role = __('Role');
${ o.image ? avatar(Object.assign(avatar_data, o)) : '' } const i18n_url = __('URL');
${ o.fullname ? html`<p><label>${i18n_full_name}:</label> ${o.fullname}</p>` : '' } const avatar_data = {
<p><label>${i18n_address}:</label> <a href="xmpp:${o.jid}">${o.jid}</a></p> 'alt_text': i18n_profile,
${ o.nickname ? html`<p><label>${i18n_nickname}:</label> ${o.nickname}</p>` : '' } 'extra_classes': 'mb-3'
${ o.url ? html`<p><label>${i18n_url}:</label> <a target="_blank" rel="noopener" href="${o.url}">${o.url}</a></p>` : '' } }
${ o.email ? html`<p><label>${i18n_email}:</label> <a href="mailto:${o.email}">${o.email}</a></p>` : '' }
${ o.role ? html`<p><label>${i18n_role}:</label> ${o.role}</p>` : '' }
${ (o._converse.pluggable.plugins['converse-omemo'].enabled(o._converse)) ? fingerprints(o) : '' } return html`
</div> <div class="modal-dialog" role="document">
<div class="modal-footer"> <div class="modal-content">
${modal_close_button} <div class="modal-header">
<button type="button" class="btn btn-info refresh-contact"><i class="fa fa-refresh"> </i>${i18n_refresh}</button> <h5 class="modal-title" id="user-details-modal-label">${o.display_name}</h5>
${ (o.allow_contact_removal && o.is_roster_contact) ? remove_button(o) : '' } ${modal_header_close_button}
</div>
<div class="modal-body">
${ o.image ? avatar(Object.assign(avatar_data, o)) : '' }
${ o.fullname ? html`<p><label>${i18n_full_name}:</label> ${o.fullname}</p>` : '' }
<p><label>${i18n_address}:</label> <a href="xmpp:${o.jid}">${o.jid}</a></p>
${ o.nickname ? html`<p><label>${i18n_nickname}:</label> ${o.nickname}</p>` : '' }
${ o.url ? html`<p><label>${i18n_url}:</label> <a target="_blank" rel="noopener" href="${o.url}">${o.url}</a></p>` : '' }
${ o.email ? html`<p><label>${i18n_email}:</label> <a href="mailto:${o.email}">${o.email}</a></p>` : '' }
${ o.role ? html`<p><label>${i18n_role}:</label> ${o.role}</p>` : '' }
${ (o._converse.pluggable.plugins['converse-omemo'].enabled(o._converse)) ? fingerprints(o) : '' }
</div>
<div class="modal-footer">
${modal_close_button}
<button type="button" class="btn btn-info refresh-contact"><i class="fa fa-refresh"> </i>${i18n_refresh}</button>
${ (o.allow_contact_removal && o.is_roster_contact) ? remove_button(o) : '' }
</div>
</div> </div>
</div> </div>
</div> `;
`; }
...@@ -7,36 +7,36 @@ import { modal_header_close_button } from "./buttons" ...@@ -7,36 +7,36 @@ import { modal_header_close_button } from "./buttons"
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
const i18n_modal_title = __('Settings'); const tpl_navigation = (o) => {
const i18n_about = __('About'); const i18n_about = __('About');
const i18n_commands = __('Commands'); const i18n_commands = __('Commands');
return html`
const first_subtitle = __( <ul class="nav nav-pills justify-content-center">
'%1$s Open Source %2$s XMPP chat client brought to you by %3$s Opkode %2$s', <li role="presentation" class="nav-item">
'<a target="_blank" rel="nofollow" href="https://conversejs.org">', <a class="nav-link active" id="about-tab" href="#about-tabpanel" aria-controls="about-tabpanel" role="tab" data-toggle="tab" @click=${o.switchTab}>${i18n_about}</a>
'</a>', </li>
'<a target="_blank" rel="nofollow" href="https://opkode.com">' <li role="presentation" class="nav-item">
); <a class="nav-link" id="commands-tab" href="#commands-tabpanel" aria-controls="commands-tabpanel" role="tab" data-toggle="tab" @click=${o.switchTab}>${i18n_commands}</a>
</li>
const second_subtitle = __( </ul>
'%1$s Translate %2$s it into your own language', `;
'<a target="_blank" rel="nofollow" href="https://hosted.weblate.org/projects/conversejs/#languages">', }
'</a>'
);
const tpl_navigation = (o) => html`
<ul class="nav nav-pills justify-content-center">
<li role="presentation" class="nav-item">
<a class="nav-link active" id="about-tab" href="#about-tabpanel" aria-controls="about-tabpanel" role="tab" data-toggle="tab" @click=${o.switchTab}>${i18n_about}</a>
</li>
<li role="presentation" class="nav-item">
<a class="nav-link" id="commands-tab" href="#commands-tabpanel" aria-controls="commands-tabpanel" role="tab" data-toggle="tab" @click=${o.switchTab}>${i18n_commands}</a>
</li>
</ul>
`;
export default (o) => { export default (o) => {
const i18n_modal_title = __('Settings');
const first_subtitle = __(
'%1$s Open Source %2$s XMPP chat client brought to you by %3$s Opkode %2$s',
'<a target="_blank" rel="nofollow" href="https://conversejs.org">',
'</a>',
'<a target="_blank" rel="nofollow" href="https://opkode.com">'
);
const second_subtitle = __(
'%1$s Translate %2$s it into your own language',
'<a target="_blank" rel="nofollow" href="https://hosted.weblate.org/projects/conversejs/#languages">',
'</a>'
);
const show_client_info = api.settings.get('show_client_info'); const show_client_info = api.settings.get('show_client_info');
const allow_adhoc_commands = api.settings.get('allow_adhoc_commands'); const allow_adhoc_commands = api.settings.get('allow_adhoc_commands');
const show_both_tabs = show_client_info && allow_adhoc_commands; const show_both_tabs = show_client_info && allow_adhoc_commands;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
modtools_disable_assign: ['owner', 'moderator', 'participant', 'visitor'], modtools_disable_assign: ['owner', 'moderator', 'participant', 'visitor'],
modtools_disable_query: ['moderator', 'participant', 'visitor'], modtools_disable_query: ['moderator', 'participant', 'visitor'],
enable_smacks: true, enable_smacks: true,
i18n: 'en', i18n: 'af',
// connection_options: { 'worker': '/dist/shared-connection-worker.js' }, // connection_options: { 'worker': '/dist/shared-connection-worker.js' },
message_archiving: 'always', message_archiving: 'always',
muc_domain: 'conference.chat.example.org', muc_domain: 'conference.chat.example.org',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment