Commit 0c5f0e24 authored by Guus der Kinderen's avatar Guus der Kinderen Committed by JC Brand

Removed the mockups from the project. Recommended to use tests instead.

parent 061142e0
......@@ -26,6 +26,7 @@ Soon we'll deprecate the latter, so prepare now.
- #2006: fix rendering of emojis in case `use_system_emojis == false`
- #2028: Implement XEP-0333 `displayed` chat marker
- #2101: Improve contrast of text in control box
- Removed the mockups from the project. Recommended to use tests instead.
- The API method `api.settings.update` has been deprecated in favor of `api.settings.extend`.
- Filter roster contacts via all available information (JID, nickname and VCard full name).
- Allow ignoring of bootstrap modules at build using environment variable. For xample: `export BOOTSTRAP_IGNORE_MODULES="Modal,Dropdown" && make dist`
......
......@@ -34,17 +34,6 @@ However, when developing or changing the theme, you'll want to load all the
unminified JS and CSS resources as separate files. To do this, open http://localhost:8000/dev.html
instead.
Mockups
=======
Converse contains some mockups in the ``./mockup`` directory against which you
can preview and tweak your changes.
The ``./mockup/index.html`` file contains the most comprehensive mockup, while
the other files focus on particular UI aspects.
To see it in your browser, simply open: http://localhost:8000/mockup
Modifying the HTML templates of Converse
========================================
......@@ -63,6 +52,15 @@ To generate the CSS you can run::
make css
Testing your changes
=======
The recommended way to test your changes is to run the tests that are part of the Converse source code.
By executing ``make test`` you'll run all tests (which live in the ``spec`` folder) which will open a browser window in which tests are processed.
You can run a single test by changing ``it(`` to ``fit(`` so that only that one test runs. Then you click the "debug" button in the browser when the tests run. After the test has run, the opened chats will still be visible.
Creating dist files
===================
......
This diff is collapsed.
/*global Backbone, _, window */
const ChatBox = Backbone.NativeView.extend({
el: '.chatbox:not(.chatroom):not(#controlbox)',
initialize () {
this.render();
},
render () {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'chatbox.html', true);
xhr.onload = () => {
var parser = new DOMParser();
var doc = parser.parseFromString(xhr.responseText, "text/html");
this.el.innerHTML = doc.querySelector('.chatbox:not(.chatroom):not(#controlbox)').innerHTML;
window.renderAvatars(this.el);
}
xhr.send();
}
});
This diff is collapsed.
/*global Backbone, _, window */
const ChatRoom = Backbone.NativeView.extend({
el: '.chatroom',
initialize () {
this.render();
},
render () {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'chatroom.html', true);
xhr.onload = () => {
var parser = new DOMParser();
var doc = parser.parseFromString(xhr.responseText, "text/html");
this.el.innerHTML = doc.querySelector('.chatroom').innerHTML;
window.renderAvatars(this.el);
}
xhr.send();
}
});
This diff is collapsed.
/*global Backbone, _, window */
const UserPanel = Backbone.NativeView.extend({
el: '.controlbox-pane',
initialize () {
this.render();
},
render () {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'controlbox.html', true);
xhr.onload = () => {
this.el.innerHTML = xhr.responseText;
this.modals = _.map(this.el.querySelectorAll('[data-toggle="modal"]'), (modal_el) =>
new window.Modal(modal_el, {
backdrop: 'static', // we don't want to dismiss Modal when Modal or backdrop is the click event target
keyboard: true // we want to dismiss Modal on pressing Esc key
}));
window.renderAvatars();
window.initSpoilers();
}
xhr.send();
}
});
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login Fullscreen</title>
<link type="text/css" rel="stylesheet" media="screen" href="../../node_modules/bootstrap/dist/css/bootstrap.css" />
<link type="text/css" rel="stylesheet" media="screen" href="../../dist/converse.css" />
</head>
<body>
<div class="container converse-bg">
<h1 class="brand-heading">inVerse</h1>
</div>
<div id="conversejs" class="fullscreen">
<div class="converse-chatboxes row no-gutters">
<div id="controlbox" class="chatbox logged-out">
<div class="flyout box-flyout">
<div class="controlbox-panes">
<div class="row">
<div class="brand-heading-container">
<h1 class="brand-heading"><i class="icon-conversejs"></i> inVerse</h1>
<p class="brand-subtitle"><a target="_blank" rel="nofollow" href="https://conversejs.org">Open Source</a> XMPP chat client</p>
<p class="brand-subtitle"><a target="_blank" rel="nofollow" href="https://hosted.weblate.org/projects/conversejs/#languages">Translate</a> into your own language</p>
</div>
</div>
<div id="converse-login-panel" class="controlbox-pane fade-in row">
<form id="converse-login" class="converse-form" method="post">
<div class="form-group">
<label for="jid">XMPP Username:</label>
<input type="text" name="jid" class="form-control" placeholder="user@server" autocomplete="off">
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" name="password" class="form-control" placeholder="password" autocomplete="off">
</div>
<fieldset class="buttons">
<p><input class="btn btn-primary" type="submit" value="Log In"></p>
<div class="switch-form">
<p>Don't have an XMPP account?</p>
<p>Click <a href="#" data-toggle="modal" data-target="#registerModal">here</a> to register.</p>
</div>
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Converse.js Live Mockup</title>
<meta name="description" content="Converse.js: A chat client for your website" />
<link type="text/css" rel="stylesheet" media="screen" href="../dist/website.css" />
<link type="text/css" rel="stylesheet" media="screen" href="../dist/converse.css" />
</head>
<body>
<div id="header_wrap" class="outer">
<header class="inner">
<h1 id="project_title"><a href="https://conversejs.org">Converse.js</a></h1>
<h2 id="project_tagline">Mockups</h2>
</header>
</div>
<ul>
<li><a href="/mockup/fullscreen-login.html" class="btn btn-primary">1a. Fullscreen Login</a></li>
<li><a href="/mockup/overlayed-login.html" class="btn btn-primary">1b. Overlayed Login</a></li>
<li><a href="/mockup/chatbox.html" class="btn btn-primary">2. Fullscreen private chat</a></li>
<li><a href="/mockup/chatroom.html" class="btn btn-primary">3. Fullscreen MUC</a></li>
<li><a href="/mockup/overlayed.html" class="btn btn-primary">4. Overlayed chats</a></li>
</ul>
</body>
</html>
// Extra test dependencies
config.paths.mock = "tests/mock";
config.paths.test_utils = "tests/utils";
config.paths.jasmine = "components/jasmine/lib/jasmine-core/jasmine";
config.paths["jasmine-html"] = "components/jasmine/lib/jasmine-core/jasmine-html";
config.paths["console-runner"] = "node_modules/phantom-jasmine/lib/console-runner";
config.shim['jasmine-html'] = {
deps: ['jasmine'],
exports: 'jasmine'
};
require.config(config);
// Polyfill 'bind' which is not available in phantomjs < 2.0
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis ? this : oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
require([
"jquery",
"converse",
"mock",
"jasmine-html"
], function($, converse, mock, jasmine) {
// Set up converse.js
window.converse_api = converse;
window.localStorage.clear();
window.sessionStorage.clear();
converse.initialize({
i18n: window.locales.en,
auto_subscribe: false,
animate: false,
connection: mock.mock_connection,
no_trimming: true,
debug: false
}, function (converse) {
window.converse = converse;
window.crypto = {
getRandomValues: function (buf) {
var i;
for (i=0, len=buf.length; i<len; i++) {
buf[i] = Math.floor(Math.random()*256);
}
}
};
require([
"console-runner",
"mockup/mockup"
], function () {
// Make sure this callback is only called once.
delete converse.callback;
// Stub the trimChat method. It causes havoc when running with
// phantomJS.
converse.ChatBoxViews.prototype.trimChat = function () {};
// Jasmine stuff
var jasmineEnv = jasmine.getEnv();
var reporter;
if (/PhantomJS/.test(navigator.userAgent)) {
reporter = new jasmine.ConsoleReporter();
window.console_reporter = reporter;
jasmineEnv.addReporter(reporter);
jasmineEnv.updateInterval = 0;
} else {
reporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(reporter);
jasmineEnv.specFilter = function(spec) {
return reporter.specFilter(spec);
};
jasmineEnv.updateInterval = 0;
}
jasmineEnv.execute();
});
});
}
);
/*global converse */
(function (root, factory) {
define(["jquery", "mock", "test_utils"], factory);
} (this, function ($, mock, test_utils) {
var $msg = converse_api.env.$msg;
test_utils.clearBrowserStorage();
return describe("Live Mockup", $.proxy(function(mock, test_utils) {
describe("Click the links below to view the different elements", function () {
beforeEach(function () {
test_utils.initConverse();
test_utils.createContacts('all');
});
it("Show a chat room", function () {
test_utils.openChatRoom('lounge', 'mongague.lit', 'romeo');
var view = converse.chatboxviews.get('lounge@mongague.lit');
if (!view.$el.find('.chat-area').length) { view.renderChatArea(); }
var text = 'This is a sent message';
view.$el.find('.chat-textarea').text(text);
view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
var message = $msg({
from: 'lounge@mongague.lit/romeo',
to: 'romeo@mongague.lit.com',
type: 'groupchat',
id: view.model.messages.at(0).get('msgid')
}).c('body').t(text);
view.onChatRoomMessage(message.nodeTree);
var nick = mock.chatroom_names[0];
text = 'This is a received message';
message = $msg({
from: 'lounge@mongague.lit/'+nick,
id: '1',
to: 'romeo@mongague.lit',
type: 'groupchat'
}).c('body').t(text);
view.onChatRoomMessage(message.nodeTree);
});
it("Show the control box", function () {
test_utils.openControlBox();
test_utils.openContactsPanel();
});
it("Show a headlines box", function () {
converse.connection._dataRecv(
test_utils.createRequest(
$msg({
'type': 'headline',
'from': 'notify.example.com',
'to': 'romeo@mongague.lit',
'xml:lang': 'en'
})
.c('subject').t('MAIL').up()
.c('body').t('You got mail.').up()
)
);
});
xit("Show a private chat box", function () {
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@mongague.lit';
var chatbox = test_utils.openChatBoxFor(contact_jid);
var view = converse.chatboxviews.get(contact_jid);
var message = 'This message is sent from this chatbox';
test_utils.sendMessage(view, message);
message = 'This is a received message';
var msg = $msg({
from: contact_jid,
to: converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').t(message).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
converse.chatboxes.onMessage(msg);
});
});
}, window, mock, test_utils));
}));
<!-- Register Modal -->
<div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="registerModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="registerModalLabel">Register</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="converse-register">
<div class="form-group">
<label for="domain">Your XMPP provider's domain name:</label>
<input type="text" name="domain" class="form-control" placeholder=" e.g. conversejs.org">
</div>
<p>Tip: A list of public XMPP providers is available
<a href="https://xmpp.net/directory.php" class="url" target="_blank" rel="noopener">here</a>.</p>
<input class="btn btn-primary" type="submit" value="Fetch registration form">
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Contact Profile Modal -->
<div class="modal fade" id="contactProfileModal" tabindex="-1" role="dialog" aria-labelledby="contactProfileModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="contactProfileModalLabel">JC Brand User Profile</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- User Profile Modal -->
<div class="modal fade" id="userProfileModal" tabindex="-1" role="dialog" aria-labelledby="userProfileModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="userProfileModalLabel">Your profile</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Change status Modal -->
<div class="modal fade" id="changeStatusModal" tabindex="-1" role="dialog" aria-labelledby="changeStatusModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="changeStatusModalLabel">Change chat status</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form class="set-xmpp-status" id="set-xmpp-status">
<div class="modal-body">
<div class="form-group">
<div class="custom-control custom-radio">
<input type="radio" id="radio-online" value="online" name="chat_status" class="custom-control-input">
<label class="custom-control-label" for="radio-online">
<span class="fa fa-circle"></span>&nbsp;Online</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="radio-busy" value="busy" name="chat_status" class="custom-control-input">
<label class="custom-control-label" for="radio-busy">
<span class="fa fa-minus-circle"></span>&nbsp;Busy</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="radio-away" value="away" name="chat_status" class="custom-control-input">
<label class="custom-control-label" for="radio-away">
<span class="fa fa-dot-circle-o"></span>&nbsp;Away</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" id="radio-xa" value="xa" name="chat_status" class="custom-control-input">
<label class="custom-control-label" for="radio-xa">
<span class="fa fa-circle-o"></span>&nbsp;Away for long</label>
</div>
</div>
<div class="btn-group w-100">
<input type="text" class="form-control" value="" placeholder="Personal status message">
<span class="clear-input fa fa-times"></span>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add contact Modal -->
<div class="modal fade" id="addContactModal" tabindex="-1" role="dialog" aria-labelledby="addContactModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addContactModalLabel">Add a contact</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="converse-form add-xmpp-contact">
<div class="form-group">
<input type="text" name="identifier" class="form-control" placeholder="Contact username">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Add</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<!-- Chatrooms Modal -->
<div class="modal fade" id="chatroomsModal" tabindex="-1" role="dialog" aria-labelledby="chatroomsModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="chatroomsModalLabel">Enter a new Chatroom</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="converse-form add-chatroom">
<div class="form-group">
<label for="chatroom">Room address:</label>
<input type="text" name="chatroom" class="form-control" placeholder="room@conference.example.org">
</div>
<div class="form-group">
<label for="chatroom">Nickname:</label>
<input type="text" name="nickname" class="form-control">
</div>
<input type="submit" class="btn btn-primary" name="join" value="Join">
</form>
</div>
</div>
</div>
</div>
<!-- Settings Modal -->
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="settingsModalLabel">Settings</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
/*global Backbone, _, window */
const Modals = Backbone.NativeView.extend({
el: 'div.modals',
initialize () {
this.render();
},
render () {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'modals.html', true);
xhr.onload = () => {
this.el.innerHTML = xhr.responseText;
}
xhr.send();
}
});
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login Overlayed</title>
<link type="text/css" rel="stylesheet" media="screen" href="../../dist/converse.css" />
</head>
<body class="reset">
<div class="converse-bg container">
<h1 class="brand-heading">Converse</h1>
</div>
<div id="conversejs" class="converse-overlayed">
<div class="converse-chatboxes row no-gutters">
<div id="controlbox" class="chatbox logged-out">
<div class="flyout box-flyout">
<div class="chat-head controlbox-head">
<a class="chatbox-btn close-chatbox-button fa fa-close"></a>
<span class="brand-heading-container">
<div class="brand-heading">
<a href="https://conversejs.org" target="_blank" rel="noopener">
<i class="icon-conversejs"></i><span class="brand-name">converse</span>
</a>
</div>
</span>
</div>
<div class="controlbox-panes">
<div id="converse-login-panel" class="controlbox-pane fade-in row no-gutters">
<form id="converse-login" class="converse-form">
<div class="form-group">
<label for="jid">XMPP Username:</label>
<input type="text" name="jid" class="form-control" placeholder="user@server" autocomplete="off">
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" name="password" class="form-control" placeholder="password" autocomplete="off">
</div>
<div class="form-group form-check">
<input id="converse-login-trusted" class="form-check-input" type="checkbox" name="trusted" checked="">
<label class="form-check-label" for="converse-login-trusted">This is a trusted device</label>
</div>
<fieldset class="buttons">
<input class="btn btn-primary" type="submit" value="Log in">
<p>Click <a href="#" data-toggle="modal" data-target="#registerModal">here</a> to register.</p>
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="modals"></div>
</div>
<script type="text/javascript" src="../../node_modules/lodash/lodash.js"></script>
<script type="text/javascript" src="../../node_modules/backbone/backbone.js"></script>
<script type="text/javascript" src="../../node_modules/backbone.nativeview/backbone.nativeview.js"></script>
<script type="text/javascript" src="sidebar.js"></script>
<script type="text/javascript" src="controlbox.js"></script>
<script type="text/javascript" src="modals.js"></script>
<script type="text/javascript" src="../../node_modules/bootstrap.native/dist/bootstrap-native-v4.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
new Modals();
new Sidebar();
});
</script>
</body>
</html>
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Overlayed chats</title>
<link type="text/css" rel="stylesheet" media="screen" href="../../dist/converse.css" />
</head>
<body style="background-color: #578EA9">
<div class="converse-bg container">
<h1 class="brand-heading"><i class="icon-conversejs"></i>Converse.js</h1>
</div>
<div id="conversejs" class="converse-overlayed">
<div class="converse-chatboxes row no-gutters">
<div id="controlbox" class="chatbox">
<div class="flyout box-flyout">
<div class="controlbox-panes">
<div class="sidebar"></div>
<div class="controlbox-pane"></div>
</div>
</div>
</div>
<div class="chatbox" id="chatbox-37c0c87392010303765fe36b05c0967d62c6b70f"></div>
<div class="chatbox chatroom" id="chatbox-4a77380f1cd9d392627b0e1469688f9ca44e9392"></div>
<div id="minimized-chats">
<a id="toggle-minimized-chats" href="#" class="row no-gutters">
<span class="badge badge-light">322</span> Minimized
</a>
<div class="flyout minimized-chats-flyout row no-gutters">
<div class="chat-head chat-head-chatroom row no-gutters">
<a href="#" class="restore-chat w-100 align-self-center" title="Click to maximize this chat">
<span class="badge badge-light">42</span>
Restricted Chatroom
</a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a>
</div>
<div class="chat-head chat-head-chatbox row no-gutters">
<a href="#" class="restore-chat w-100 align-self-center" title="Click to maximize this chat">
<span class="badge badge-light">4</span>
JC Brand
</a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a>
</div>
<div class="chat-head chat-head-chatroom row no-gutters">
<a href="#" class="restore-chat w-100 align-self-center" title="Click to maximize this chat">My Chatroom</a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a>
</div>
<div class="chat-head chat-head-chatbox row no-gutters">
<a href="#" class="restore-chat w-100 align-self-center" title="Click to maximize this chat">Annegreet Gomez</a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a>
</div>
<div class="chat-head chat-head-chatbox row no-gutters">
<a href="#" class="restore-chat w-100 align-self-center" title="Click to maximize this chat">
<span class="badge badge-light">842</span>
Asmaa Haakman
</a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a>
</div>
<div class="chat-head chat-head-chatbox row no-gutters">
<a href="#" class="restore-chat w-100 align-self-center">Lena Grunewald</a>
<a class="chatbox-btn close-chatbox-button fa fa-times"></a>
</div>
</div>
</div>
<div id="converse-modals" class="modals"></div>
</div>
</div>
</body>
<script type="text/javascript" src="../../node_modules/lodash/lodash.js"></script>
<script type="text/javascript" src="../../node_modules/backbone/backbone.js"></script>
<script type="text/javascript" src="../../node_modules/backbone.nativeview/backbone.nativeview.js"></script>
<script type="text/javascript" src="../../node_modules/strophe.js/strophe.js"></script>
<script type="text/javascript" src="../../src/utils/core.js"></script>
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="sidebar.js"></script>
<script type="text/javascript" src="controlbox.js"></script>
<script type="text/javascript" src="modals.js"></script>
<script type="text/javascript" src="chatroom.js"></script>
<script type="text/javascript" src="chatbox.js"></script>
<script type="text/javascript" src="../../node_modules/bootstrap.native/dist/bootstrap-native-v4.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
new Modals();
new Sidebar();
new UserPanel();
new ChatRoom();
new ChatBox();
});
</script>
</html>
<!-- <div class="sidebar"> -->
<a class="hamburger chatbox-btn fa fa-bars"></a>
<!--
<a class="chatbox-btn fa fa-vcard" title="Your profile" data-toggle="modal" data-target="#userProfileModal"></a>
<a class="chatbox-btn fa fa-pencil" title="Click to change your chat status" data-toggle="modal" data-target="#changeStatusModal"></a>
<div class="bottom">
<a class="chatbox-btn fa fa-user-plus" title="Click to add new chat contacts" data-toggle="modal" data-target="#addContactModal"></a>
<a class="chatbox-btn fa fa-users" title="Click to change rooms" data-toggle="modal" data-target="#chatroomsModal"></a>
<a class="chatbox-btn fa fa-cog" title="Change settings" data-toggle="modal" data-target="#settingsModal"></a>
</div>
-->
<!-- </div> -->
/*global Backbone, _, window */
const Sidebar = Backbone.NativeView.extend({
el: 'div.sidebar',
events: {
'click .hamburger': 'onHamburgerClicked'
},
initialize () {
this.render();
},
onHamburgerClicked () {
const hamburger = document.querySelector('.hamburger');
const converse_el = document.querySelector('#conversejs');
if (_.includes(converse_el.classList, 'sidebar-open')) {
converse_el.classList.remove('sidebar-open');
hamburger.classList.remove('fa-times');
hamburger.classList.add('fa-bars');
} else {
converse_el.classList.add('sidebar-open');
hamburger.classList.remove('fa-bars');
hamburger.classList.add('fa-times');
}
},
render () {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'sidebar.html', true);
xhr.onload = () => {
this.el.innerHTML = xhr.responseText;
}
xhr.send();
}
});
/*global _, converse_utils */
const u = converse_utils;
window.renderAvatars = function (el) {
el = el || document;
const canvasses = el.querySelectorAll('canvas.chat-msg__avatar');
_.each(canvasses, (canvas_el) => {
const avatar_url = canvas_el.getAttribute('data-avatar');
if (!avatar_url) {
return;
}
const ctx = canvas_el.getContext('2d');
const img = new Image();
img.onload = function () {
const canvas = ctx.canvas ;
const hRatio = canvas.width / img.width ;
const vRatio = canvas.height / img.height ;
const ratio = Math.min ( hRatio, vRatio );
const centerShift_x = ( canvas.width - img.width*ratio ) / 2;
const centerShift_y = ( canvas.height - img.height*ratio ) / 2;
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.drawImage(img, 0,0, img.width, img.height, centerShift_x,centerShift_y,img.width*ratio, img.height*ratio);
};
img.src = avatar_url;
});
}
function toggleSpoilerMessage (ev) {
if (ev && ev.preventDefault) {
ev.preventDefault();
}
const toggle_el = ev.target,
icon_el = toggle_el.firstElementChild;
u.slideToggleElement(
toggle_el.parentElement.parentElement.querySelector('.spoiler')
);
if (toggle_el.getAttribute("data-toggle-state") == "closed") {
toggle_el.textContent = 'Show less';
icon_el.classList.remove("fa-eye");
icon_el.classList.add("fa-eye-slash");
toggle_el.insertAdjacentElement('afterBegin', icon_el);
toggle_el.setAttribute("data-toggle-state", "open");
} else {
toggle_el.textContent = 'Show more';
icon_el.classList.remove("fa-eye-slash");
icon_el.classList.add("fa-eye");
toggle_el.insertAdjacentElement('afterBegin', icon_el);
toggle_el.setAttribute("data-toggle-state", "closed");
}
}
window.initSpoilers = function () {
const spoilers = document.querySelectorAll('.spoiler-toggle');
_.each(spoilers, (spoiler_el) => {
spoiler_el.addEventListener('click', toggleSpoilerMessage);
});
}
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