av6@0: <!DOCTYPE html> av6@0: <html lang="en"> av6@0: <head> av6@0: <meta charset="utf-8"> av6@0: <meta http-equiv="X-UA-Compatible" content="IE=edge"> av6@0: <meta name="viewport" content="width=device-width, initial-scale=1"> av6@0: <title>Tram IM</title> av6@297: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.5/css/uikit.min.css" integrity="sha384-wVQRrvgN1LAYKb1u9PW+mJFbkpvq+1dLy25E7yVI0iELZg48DAwZK+0+SciVoSYo" crossorigin="anonymous"> av6@297: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.5/css/components/form-advanced.min.css" integrity="sha384-d68duPSswDvu/d874j9hBg162RHJaQPtQzCpaym88pbKkuZZdSvURpEHkDIq5cWn" crossorigin="anonymous"> av6@297: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.5/css/components/progress.min.css" integrity="sha384-3xNmd+nJWguhQzEzYoo6h+Zi4T+5MZRJ41Zd7hEY7iQ5wtSZF1I6wEgr4HCxt1E3" crossorigin="anonymous"> av6@0: <link rel="stylesheet" href="/css/tram-im.css"> av6@296: <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script> av6@298: <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js" integrity="sha384-5DWzr9S4agqS3WKvPrhFKJagpYyHOBsf3/DxuDKORyqCv2sYer9c/ExdhPOL8CGh" crossorigin="anonymous"></script> av6@197: <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js" integrity="sha384-NNt9ocJfZhIg2c5PbM5G2a3tTaeXhEfqCHWHNB7htzaWKn8MwFkzVyGdzLA8QMX7" crossorigin="anonymous"></script> av6@197: <script src="https://cdnjs.cloudflare.com/ajax/libs/rivets/0.8.1/rivets.bundled.min.js" integrity="sha384-KIB/b1UL6HC6He/9mc3AYNV0GjyVXGWnwqbSo3hoD6BOYi+XPtqjLtZ99Mevz4I4" crossorigin="anonymous"></script> av6@197: <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" integrity="sha384-MV8AwEgYXLMw5ZPj4763CSPk+tYGoUZGdwr/+EfkAZ1Dl2rGHxOMpQ1IW7VtyUPn" crossorigin="anonymous"></script> av6@297: <script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.5/js/uikit.min.js" integrity="sha384-Im89RaxIjW92nIeS9CnSp8tMU/70dwWdHUDaSaOAPnJ8JBWuE4PdBxqrWcopj1x8" crossorigin="anonymous"></script> av6@22: <script src="/vendor/strophejs/strophe.min.js"></script> av6@67: <script src="/vendor/strophejs-plugins/disco/strophe.disco.js"></script> av6@68: <script src="/vendor/strophejs-plugins/ping/strophe.ping.js"></script> av6@124: <script src="/vendor/strophejs-plugins/register/strophe.register.js"></script> av6@51: <script src="/vendor/strophejs-plugins/roster/strophe.roster.js"></script> av6@28: <script src="/vendor/strophejs-plugins/vcard/strophe.vcard.js"></script> av6@59: <script src="/vendor/webrtc-adapter-1.0.4.js"></script> av6@0: </head> av6@0: <body> av6@120: <div class="uk-progress uk-progress-mini page-progress" data-app="progress" rv-hide="model:progress | eq undefined"> av6@232: <div class="uk-progress-bar" rv-style-width="model:progress | percent"></div> av6@120: </div> av6@120: av6@0: <div class="smart-container" data-step="noscript"> av6@0: <div class="uk-alert"> av6@0: <p class="uk-text-center">This page needs JavaScript to work.</p> av6@0: <hr> av6@296: <small>It uses resources from code.jquery.com and cdnjs.cloudflare.com.</small> av6@0: </div> av6@0: </div> av6@0: av6@0: <div class="smart-container uk-hidden" data-step="login"> av6@22: <div class="uk-form uk-form-horizontal" data-form="connect"> av6@0: <div class="uk-form-row"> av6@0: <label for="username" class="uk-form-label">Username</label> av6@0: <div class="uk-form-controls"> av6@47: <input id="username" type="text" class="uk-width-1-1" required autofocus av6@170: rv-value="form:username" rv-class-uk-form-danger="form:username-errors"> av6@170: <div class="uk-text-danger" rv-each-error="form:username-errors">{ error }</div> av6@0: </div> av6@0: </div> av6@0: <div class="uk-form-row"> av6@0: <label for="password" class="uk-form-label">Password</label> av6@0: <div class="uk-form-controls"> av6@47: <input id="password" type="password" class="uk-width-1-1" required av6@170: rv-value="form:password" rv-class-uk-form-danger="form:password-errors"> av6@170: <div class="uk-text-danger" rv-each-error="form:password-errors">{ error }</div> av6@0: </div> av6@0: </div> av6@0: <div class="uk-form-row"> av6@0: <div class="uk-form-controls"> av6@170: <div class="uk-alert uk-alert-danger" rv-each-error="form:auth-errors">{ error }</div> av6@47: <button type="button" class="uk-button uk-button-primary" rv-on-click="connect"> av6@47: <i class="uk-icon-sign-in"></i> Log in av6@47: </button> av6@0: <a class="uk-float-right uk-button uk-button-link" href="/register.html">Register</a> av6@0: </div> av6@0: </div> av6@0: </div> av6@0: </div> av6@0: <script> av6@0: $('[data-step="noscript"]').addClass('uk-hidden'); av6@0: </script> av6@23: av6@266: <div class="has-sidebar full-height uk-flex uk-flex-column uk-hidden" data-step="main"> av6@87: <div class="sidebar" data-app="sidebar" rv-class-mini="model:sidebar/minified"> av6@231: <ul class="uk-nav uk-nav-offcanvas uk-text-nowrap"> av6@87: <li class="uk-text-center"> av6@87: <a rv-on-click="view.minify"> av6@87: <i class="uk-icon-chevron-right" rv-if="model:sidebar/minified"></i> av6@87: <i class="uk-icon-chevron-left" rv-unless="model:sidebar/minified"></i> av6@87: </a> av6@87: </li> av6@87: <li class="uk-nav-divider"></li> av6@83: <li rv-class-uk-active="model:show | eq 'chat'"> av6@83: <a data-show="chat" rv-on-click="view.show"> av6@87: <div class="status-pip" rv-style="'chat' | fn view.getPipColor"></div> av6@87: <span class="label">Ready to chat</span> av6@83: </a> av6@83: </li> av6@80: <li rv-class-uk-active="model:show | eq 'online'"> av6@80: <a data-show="online" rv-on-click="view.show"> av6@87: <div class="status-pip" rv-style="'online' | fn view.getPipColor"></div> av6@87: <span class="label">Online</span> av6@80: </a> av6@80: </li> av6@80: <li rv-class-uk-active="model:show | eq 'away'"> av6@80: <a data-show="away" rv-on-click="view.show"> av6@87: <div class="status-pip" rv-style="'away' | fn view.getPipColor"></div> av6@87: <span class="label">Away</span> av6@80: </a> av6@80: </li> av6@80: <li rv-class-uk-active="model:show | eq 'xa'"> av6@80: <a data-show="xa" rv-on-click="view.show"> av6@87: <div class="status-pip" rv-style="'xa' | fn view.getPipColor"></div> av6@87: <span class="label">Gone</span> av6@80: </a> av6@80: </li> av6@80: <li class="uk-nav-divider"></li> av6@87: <li> av6@163: <a data-uk-modal="{target:'#settings-modal'}"> av6@234: <i class="uk-icon-cog fixed-width"></i> av6@163: <span class="label">Settings</span> av6@163: </a> av6@163: </li> av6@163: <li> av6@124: <a data-uk-modal="{target:'#profile-modal'}"> av6@234: <i class="uk-icon-info-circle fixed-width"></i> av6@124: <span class="label">Profile</span> av6@124: </a> av6@124: </li> av6@124: <li class="uk-nav-divider"></li> av6@124: <li> av6@113: <a rv-on-click="view.disconnect"> av6@234: <i class="uk-icon-sign-out fixed-width"></i> av6@87: <span class="label">Log out</span> av6@87: </a> av6@87: </li> av6@76: </ul> av6@76: </div> av6@25: av6@266: <div class="uk-flex-item-none" data-app="calls"></div> av6@27: av6@266: <div class="uk-grid uk-flex-item-auto main-grid"> av6@268: <div class="uk-width-xlarge-1-4 uk-width-large-1-3 uk-width-medium-1-2 uk-flex uk-flex-column contact-list-block"> av6@268: <ul class="uk-list uk-flex-item-auto contact-list" data-app="contacts"></ul> av6@281: <div class="uk-form uk-flex-item-none input-group separate"> av6@145: <input id="new-contact" type="text" value="" placeholder="add a contact" required> av6@52: <span class="input-group-button"> av6@52: <button type="button" class="uk-button uk-button-success" data-add-button> av6@145: <i class="uk-icon-user-plus"></i> av6@52: </button> av6@52: </span> av6@52: </div> av6@27: </div> av6@76: av6@270: <div class="uk-width-xlarge-3-4 uk-width-large-2-3 uk-width-medium-1-2 uk-flex uk-flex-column"> av6@270: <div class="uk-flex-item-auto message-area" data-app="logs"></div> av6@281: <div class="uk-form uk-flex-item-none input-group separate uk-hidden" data-form="send"> av6@145: <input id="msg" type="text" value="" placeholder="send a message" required> av6@104: <span class="input-group-button"> av6@145: <button class="uk-button uk-button-primary" data-send-button> av6@145: <i class="uk-icon-paper-plane"></i> av6@145: </button> av6@104: </span> av6@104: </div> av6@27: </div> av6@27: </div> av6@23: </div> av6@24: av6@163: <div id="settings-modal" class="uk-modal"> av6@163: <div class="uk-modal-dialog"> av6@163: <button type="button" class="uk-modal-close uk-close"></button> av6@163: <div class="uk-modal-header"><h2>Settings</h2></div> av6@166: <div class="uk-form" data-app="settings"> av6@166: <div class="uk-form-row"> av6@166: <label> av6@166: <input type="checkbox" rv-checked="settings:chatstates"> av6@166: Send chat state notifications (XEP-0085) av6@166: </label> av6@166: </div> av6@166: </div> av6@163: <div class="uk-modal-footer" data-app="server-info"> av6@163: <p rv-if="server:name"> av6@163: Server: { server:name } { server:version } on { server:os } av6@163: </p> av6@163: <p rv-if="server:name"> av6@163: Message carbons (XEP-0280): av6@163: <span class="uk-text-success" rv-if="server:carbons">enabled</span> av6@163: <span class="uk-text-danger" rv-unless="server:carbons">not supported</span> av6@163: </p> av6@173: <p rv-if="server:name"> av6@173: Client state indication (XEP-0352): av6@173: <span class="uk-text-success" rv-if="server:csi">enabled</span> av6@173: <span class="uk-text-danger" rv-unless="server:csi">not supported</span> av6@173: </p> av6@163: </div> av6@163: </div> av6@163: </div> av6@163: av6@124: <div id="profile-modal" class="uk-modal"> av6@124: <div class="uk-modal-dialog"> av6@124: <button type="button" class="uk-modal-close uk-close"></button> av6@124: <div class="uk-modal-header"><h2>Profile</h2></div> av6@147: <dl data-app="profile"> av6@147: <dt>Full Name</dt> av6@260: <dd>{ contact:profile:fullname }</dd> av6@147: <dt>Nickname</dt> av6@260: <dd>{ contact:profile:nickname }</dd> av6@147: <dt>Avatar</dt> av6@260: <dd><img rv-if="contact:profile:avatar/url" rv-src="contact:profile:avatar/url"></dd> av6@147: </dl> av6@124: <div class="uk-text-right"> av6@124: <button class="uk-button uk-button-danger uk-modal-close" data-unregister-button>Remove account</button> av6@124: </div> av6@124: </div> av6@124: </div> av6@124: av6@58: <script type="text/template" id="video-block-template"> av6@191: <div class="video-block"> av6@250: <video class="remote" autoplay></video> av6@250: <video class="local" autoplay muted></video> av6@192: <div class="buttons uk-text-center"> av6@192: <button type="button" class="uk-button uk-button-success autofade" data-mute-cam av6@261: rv-if="call:local/stream" rv-hide="call:local/video/muted"> av6@192: <i class="uk-icon-eye"></i> av6@192: </button> av6@192: <button type="button" class="uk-button uk-button-danger" data-unmute-cam av6@261: rv-if="call:local/stream" rv-show="call:local/video/muted"> av6@192: <i class="uk-icon-eye-slash"></i> av6@192: </button> av6@192: <button type="button" class="uk-button uk-button-success autofade" data-mute-mic av6@261: rv-if="call:local/stream" rv-hide="call:local/audio/muted"> av6@192: <i class="uk-icon-microphone"></i> av6@192: </button> av6@192: <button type="button" class="uk-button uk-button-danger" data-unmute-mic av6@261: rv-if="call:local/stream" rv-show="call:local/audio/muted"> av6@192: <i class="uk-icon-microphone-slash"></i> av6@192: </button> av6@192: <button type="button" class="uk-button uk-button-success autofade" data-mute-audio av6@261: rv-if="call:remote/stream" rv-hide="call:remote/audio/muted"> av6@192: <i class="uk-icon-volume-up"></i> av6@192: </button> av6@192: <button type="button" class="uk-button uk-button-danger" data-unmute-audio av6@261: rv-if="call:remote/stream" rv-show="call:remote/audio/muted"> av6@192: <i class="uk-icon-volume-off"></i> av6@192: </button> av6@273: <button type="button" class="uk-button uk-button-danger autofade" data-hang-up> av6@273: <i class="uk-icon-phone"></i> av6@273: </button> av6@192: </div> av6@191: </div> av6@58: </script> av6@31: <script type="text/template" id="avatar-template"> av6@191: <div class="vignette"> av6@260: <img class="avatar" rv-if="contact:profile:avatar/url" rv-src="contact:profile:avatar/url"> av6@260: <div class="avatar" rv-unless="contact:profile:avatar/url" rv-style="contact:bjid | dumb-hash | fn view.getColors"> av6@260: { contact:profile:d/handle | first-letter } av6@192: </div> av6@191: </div> av6@31: </script> av6@24: <script type="text/template" id="message-template"> av6@258: <div class="message" rv-data-id="message:id"> av6@258: <div class="splitter" rv-if="message:d/split"></div> av6@258: <div class="column avatar-column" rv-class-uk-invisible="message:d/fold"></div> av6@192: <div class="column text-column"> av6@258: <div rv-hide="message:d/fold"> av6@260: <strong rv-if="message:contact:profile:d/handle">{ message:contact:profile:d/handle }</strong> av6@260: <strong rv-unless="message:contact:profile:d/handle">{ message:from }</strong> av6@192: </div> av6@258: <div rv-class="message:cls"> av6@192: <span class="uk-float-right uk-text-muted"> av6@258: <i class="uk-icon-pencil" rv-if="message:corrected" title="Edited (XEP-0308)"></i> av6@258: <i class="uk-icon-files-o" rv-if="message:carbon" title="Carbon (XEP-0280)"></i> av6@192: <time class="stamp" av6@258: rv-datetime="message:d/mstamp | iso-date" av6@258: rv-title="message:d/mstamp | format-date 'HH:mm:ss'"> av6@258: { message:d/mstamp | from-now } av6@192: </time> av6@192: </span> av6@258: <div rv-unless="message:html">{ message:text }</div> av6@258: <div class="xhtml-body" rv-if="message:html" rv-html="message:html"></div> av6@192: </div> av6@73: </div> av6@191: </div> av6@24: </script> av6@27: <script type="text/template" id="contact-template"> av6@279: <li class="contact" rv-class-active="contact:active" rv-data-jid="contact:jid" rv-style="contact:show | fn view.getBorderColor"> av6@192: <div class="column avatar-column"> av6@279: <div class="status-pip" rv-title="contact:show" rv-style="contact:show | fn view.getPipColor"></div> av6@279: <div class="uk-badge uk-badge-notification uk-badge-warning" rv-if="contact:d/unread">{ contact:d/unread }</div> av6@27: </div> av6@192: <div class="column uk-width-1-1"> av6@279: <div class="uk-text-bold">{ contact:profile:d/handle }</div> av6@192: <div class="uk-text-nowrap"> av6@279: <span>{ contact:status }</span> av6@279: <span rv-hide="contact:type | eq 'self'">{ contact:chatstate | only 'composing' }</span> av6@55: </div> av6@55: </div> av6@192: <div class="column uk-text-nowrap"> av6@279: <i class="uk-icon-phone calling-icon" rv-if="contact:d/actions | has 'wait'"></i> av6@279: <button type="button" class="uk-button" data-call="av" rv-if="contact:d/actions | has 'call'"> av6@192: <i class="uk-icon-video-camera"></i> av6@192: </button> av6@279: <button type="button" class="uk-button" data-call="a" rv-if="contact:d/actions | has 'call'"> av6@192: <i class="uk-icon-phone"></i> av6@192: </button> av6@279: <button type="button" class="uk-button uk-button-success" data-accept="av" rv-if="contact:d/actions | has 'accept'"> av6@192: <i class="uk-icon-video-camera"></i> av6@192: </button> av6@279: <button type="button" class="uk-button uk-button-success" data-accept="a" rv-if="contact:d/actions | has 'accept'"> av6@192: <i class="uk-icon-phone"></i> av6@192: </button> av6@279: <button type="button" class="uk-button uk-button-danger" data-decline rv-if="contact:d/actions | has 'decline'"> av6@192: <i class="uk-icon-times"></i> av6@192: </button> av6@279: <button type="button" class="uk-button uk-button-danger" data-hang-up rv-if="contact:d/actions | has 'hang-up'"> av6@192: <i class="uk-icon-phone"></i> Hang up av6@192: </button> av6@192: <button type="button" class="uk-button" data-chat> av6@192: <i class="uk-icon-comments-o"></i> av6@192: </button> av6@279: <div class="uk-button-dropdown" data-uk-dropdown="{mode:'click',pos:'bottom-right'}" rv-if="contact:d/actions | has 'remove'"> av6@192: <button class="uk-button"><i class="uk-icon-caret-down"></i></button> av6@192: <div class="uk-dropdown uk-dropdown-small"> av6@192: <ul class="uk-nav uk-nav-dropdown"> av6@279: <li><a data-remove rv-if="contact:d/actions | has 'remove'">Remove</a></li> av6@192: </ul> av6@192: </div> av6@192: </div> av6@192: </div> av6@192: <div class="uk-text-center"> av6@279: <button type="button" class="uk-button uk-button-success" data-authorize rv-if="contact:d/actions | has 'authorize'"> av6@192: <i class="uk-icon-plus"></i> Authorize av6@192: </button> av6@192: <button type="button" class="uk-button uk-button-danger" data-unauthorize rv-if="model:d/actions | has 'unauthorize'"> av6@192: <i class="uk-icon-times"></i> Decline av6@192: </button> av6@192: </div> av6@191: </li> av6@191: </script> av6@191: <script type="text/template" id="chat-template"> av6@191: <div class="chat"> av6@191: <div class="log"></div> av6@191: </div> av6@27: </script> av6@22: <script src='/js/tram.js'></script> av6@24: <script src='/js/rivets.js'></script> av6@22: <script src='/js/xmpp.js'></script> av6@60: <script src='/js/webrtc.js'></script> av6@27: <script src='/js/contacts.js'></script> av6@24: <script src='/js/messages.js'></script> av6@58: <script src='/js/calls.js'></script> av6@43: <script src='/js/favicon.js'></script> av6@79: <script src='/js/sidebar.js'></script> av6@120: <script src='/js/progress.js'></script> av6@169: <script src='/js/forms.js'></script> av6@22: <script src='/config.js'></script> av6@22: <script src='/js/index.js'></script> av6@53: <script> av6@53: $('[data-step="login"]').removeClass('uk-hidden'); av6@53: </script> av6@0: </body> av6@0: </html>