UNPKG

globular-mvc

Version:

Generic template to create web-application that made use of globular as backend and materialize as css (wrap in web-component's)

957 lines (776 loc) 42.8 kB
// I will made use of polymer instead of materialyze for the main // layout because materialyse dosen't react to well with the shadow doom. import '@polymer/iron-icon/iron-icon.js'; import '@polymer/iron-icons/social-icons' import '@polymer/iron-icons/editor-icons' import '@polymer/iron-icons/communication-icons' import '@polymer/iron-icons/iron-icons.js'; import '@polymer/paper-icon-button/paper-icon-button.js'; import '@polymer/paper-ripple/paper-ripple.js'; import '@polymer/paper-input/paper-input.js'; import '@polymer/paper-card/paper-card.js'; import '@polymer/paper-button/paper-button.js'; import '@polymer/paper-checkbox/paper-checkbox.js'; import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js'; import '@polymer/paper-tabs/paper-tabs.js'; import '@polymer/paper-tabs/paper-tab.js'; import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js'; import { Menu } from './Menu'; import { Account } from "../Account" import { generatePeerToken, getUrl, Model } from "../Model" import { ApplicationView } from '../ApplicationView'; import { Application } from '../Application'; import { ContactCard } from './Contact'; import { Notification as Notification_ } from '../Notification'; import { Call, ClearCallsRqst, CreateNotificationRqst, DeleteCallRqst, GetCallHistoryRqst, Notification, NotificationType, SetCallRqst } from 'globular-web-client/resource/resource_pb'; import { randomUUID } from './utility'; import { VideoConversation } from './WebRTC'; import { secondsToTime } from './Audio'; import * as getUuidByString from 'uuid-by-string'; import { TargetsRequest } from 'globular-web-client/monitoring/monitoring_pb'; /** * Display information about calls, missed calls etc... */ export class CallsHistoryMenu extends Menu { // attributes. // Create the contact view. constructor() { super("calls_history", "communication:call", "Call's") this.account = null; this.callContactInput = null this.calls = {}; this.width = 320; if (this.hasAttribute("width")) { this.width = parseInt(this.getAttribute("width")); } this.height = 550; if (this.hasAttribute("height")) { this.height = parseInt(this.getAttribute("height")); } } // Call search event. init(account) { this.account = account; let html = ` <style> #Calls-div { display: flex; flex-wrap: wrap; height: 100%; flex-direction: column; } #title{ display: none; justify-content: center; } #calls_history_menu_div{ overflow: auto; height: ${this.height}px; max-height: 70vh; overflow-y: auto; } @media (max-width: 700px) { #calls_history_menu_div{ margin-top: 5px; max-height: calc(100vh - 85px); } #title{ display: flex; } } #calls-list{ flex: 1; overflow: auto; } ::-webkit-scrollbar { width: 5px; height: 5px; } ::-webkit-scrollbar-track { background: var(--palette-background-default); } ::-webkit-scrollbar-thumb { background: var(--palette-divider); } /* Need to position the badge to look like a text superscript */ paper-tab { padding-right: 25px; } paper-tab paper-badge { --paper-badge-background: var(--palette-warning-main); --paper-badge-width: 16px; --paper-badge-height: 16px; --paper-badge-margin-left: 10px; } .tab-content{ display: flex; flex: 1; flex-direction: column; } #clear-outgoing-calls-btn, #clear-incomming-calls-btn{ padding: 10px; } paper-tabs { /* custom CSS property */ --paper-tabs-selection-bar-color: var(--palette-primary-main); color: var(--palette-text-primary); --paper-tab-ink: var(--palette-action-disabled); } paper-card{ background-color: var(--palette-background-paper); color: var(--palette-text-primary); padding: 10px; } paper-card h1 { font-size: 1.65rem; margin: 0px; margin-bottom: 10px; } @media (min-width: 500px) { .tab-content{ min-width: 450px; } } @media (max-width: 500px) { paper-tabs span{ font-size: .95rem; } #calls-list{ padding-bottom: 50px; } } </style> <div id="Calls-div"> <div id="header" style="width: 100%;"> <div id="title"> <h1 style="flex-grow: 1;">Call's</h1> <paper-icon-button id="close-btn" icon="icons:close" role="button" tabindex="0" aria-disabled="false"></paper-icon-button> </div> <globular-autocomplete type="email" label="Search Contact" id="call-contact-input" width="${this.width - 10}" style="flex-grow: 1;"></globular-autocomplete> <paper-tabs selected="0"> <paper-tab id="incomming-calls-tab"> <span id="incomming-calls-label" style="flex-grow: 1;">Incomming Call's</span> <paper-badge style="display: none;" for="incomming-calls-label"></paper-badge> <paper-icon-button id="clear-incomming-calls-btn" title="clear all incomming call's" icon="icons:delete-sweep"></paper-icon-button> </paper-tab> <paper-tab id="outgoing-calls-tab"> <span id="outgoing-calls-label" style="flex-grow: 1;">Outgoing Call's</span> <paper-badge style="display: none;" for="outgoing-calls-label"></paper-badge> <paper-icon-button id="clear-outgoing-calls-btn" title="clear all outgoing call's" icon="icons:delete-sweep"></paper-icon-button> </paper-tab> </paper-tabs> </div> <div id="calls-list"> <div class="tab-content" id="incomming-calls-div"> </div> <div class="tab-content" id="outgoing-calls-div"> </div> </div> </div> ` let range = document.createRange() this.getMenuDiv().innerHTML = "" // remove existing elements. this.getMenuDiv().appendChild(range.createContextualFragment(html)); this.getMenuDiv().querySelector("#close-btn").onclick = () => { this.getMenuDiv().parentNode.removeChild(this.getMenuDiv()) } let outgoingCallsTab = this.getMenuDiv().querySelector("#outgoing-calls-tab") let outgoingCallsDiv = this.getMenuDiv().querySelector("#outgoing-calls-div") this.callContactInput = this.getMenuDiv().querySelector("#call-contact-input") outgoingCallsTab.onclick = () => { outgoingCallsDiv.style.display = "flex" incommingCallsDiv.style.display = "none" } let incommingCallsTab = this.getMenuDiv().querySelector("#incomming-calls-tab") let incommingCallsDiv = this.getMenuDiv().querySelector("#incomming-calls-div") let clearIncommingCallsBtn = this.getMenuDiv().querySelector("#clear-incomming-calls-btn") clearIncommingCallsBtn.onclick = () => { // Here I will ask the user for confirmation before actually delete the contact informations. let toast = ApplicationView.displayMessage( ` <style> #yes-no-calls-clear-box{ display: flex; flex-direction: column; } #yes-no-calls-clear-box globular-contact-card{ padding-bottom: 10px; } #yes-no-calls-clear-box div{ display: flex; padding-bottom: 10px; } </style> <div id="yes-no-calls-clear-box"> <div>Your about to clear incomming call's history</div> <div>Is it what you want to do? </div> <div style="justify-content: flex-end;"> <paper-button raised id="yes-calls-clear">Yes</paper-button> <paper-button raised id="no-calls-clear">No</paper-button> </div> </div> `, 15000 // 15 sec... ); let yesBtn = document.querySelector("#yes-calls-clear") let noBtn = document.querySelector("#no-calls-clear") // On yes yesBtn.onclick = () => { toast.dismiss(); let rqst = new ClearCallsRqst rqst.setAccountId(this.account.id + "@" + this.account.domain) rqst.setFilter(`{"callee":"${this.account.id + "@" + this.account.domain}"}`) let globule = Model.getGlobule(this.account.domain) generatePeerToken(globule, token => { globule.resourceService.clearCalls(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { ApplicationView.displayMessage( "Incomming call's history was clear", 3000 ); this.refreshCalls() }) }) } noBtn.onclick = () => { toast.dismiss(); } } let clearOutgoingCallsBtn = this.getMenuDiv().querySelector("#clear-outgoing-calls-btn") clearOutgoingCallsBtn.onclick = () => { // Here I will ask the user for confirmation before actually delete the contact informations. let toast = ApplicationView.displayMessage( ` <style> #yes-no-calls-clear-box{ display: flex; flex-direction: column; } #yes-no-calls-clear-box globular-contact-card{ padding-bottom: 10px; } #yes-no-calls-clear-box div{ display: flex; padding-bottom: 10px; } </style> <div id="yes-no-calls-clear-box"> <div>Your about to clear outgoing call's history</div> <div>Is it what you want to do? </div> <div style="justify-content: flex-end;"> <paper-button raised id="yes-calls-clear">Yes</paper-button> <paper-button raised id="no-calls-clear">No</paper-button> </div> </div> `, 15000 // 15 sec... ); let yesBtn = document.querySelector("#yes-calls-clear") let noBtn = document.querySelector("#no-calls-clear") // On yes yesBtn.onclick = () => { toast.dismiss(); let rqst = new ClearCallsRqst rqst.setAccountId(this.account.id + "@" + this.account.domain) rqst.setFilter(`{"caller":"${this.account.id + "@" + this.account.domain}"}`) let globule = Model.getGlobule(this.account.domain) generatePeerToken(globule, token => { globule.resourceService.clearCalls(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { ApplicationView.displayMessage( "Outgoing call's history was clear", 3000 ); this.refreshCalls() }) }) } noBtn.onclick = () => { toast.dismiss(); } } incommingCallsTab.onclick = () => { outgoingCallsDiv.style.display = "none" incommingCallsDiv.style.display = "flex" } this.shadowRoot.appendChild(this.getMenuDiv()) // The call contact action. this.callContactInput.onkeyup = () => { let val = this.callContactInput.getValue(); if (val.length >= 3) { this.findAccountByEmail(val) } else { this.callContactInput.clear() } } // That function must return the div that display the value that we want. this.callContactInput.displayValue = (contact) => { let card = new ContactCard(account, contact, true); // Here depending if the contact is in contact list, in received invitation list or in sent invitation // list displayed action will be different. Account.getContacts(account, "{}", (contacts) => { const info = contacts.find(obj => { return obj._id === contact.name; }) if (contact._id != this.account._id) { if (info == undefined) { card.setCallButton((contact) => { this.onCallContact(contact); this.callContactInput.clear(); }) } } }, err => ApplicationView.displayMessage(err, 3000)) return card } // set active. incommingCallsTab.click(); window.dispatchEvent(new Event('resize')); // Here I will subscribe to call's event. Account.getContacts(this.account, `{}`, (contacts) => { // Set the list of contacts (received invitation, sent invitation and actual contact id's) contacts.forEach(contact => { // Connect other event... let contact_domain = contact._id.split("@")[1] // Outgoing calls. Model.getGlobule(this.account.domain).eventHub.subscribe("calling_" + contact._id + "_evt", uuid => { }, call => { // keep the call in map... this.calls[call.getUuid()] = call; Model.getGlobule(contact_domain).eventHub.subscribe(call.getUuid() + "_answering_call_evt", uuid => { }, evt => { this.callStart(call, contact_domain) }, false) Model.getGlobule(contact_domain).eventHub.subscribe(call.getUuid() + "_miss_call_evt", uuid => { }, evt => { call.setEndtime(-1) this.setCall(call) }, false) }, true) // Incomming call's Model.getGlobule(this.account.domain).eventHub.subscribe("calling_" + this.account.id + "@" + this.account.domain + "_evt", uuid => { }, evt => { let call = Call.deserializeBinary(Uint8Array.from(evt.split(","))) // keep the call in map... this.calls[call.getUuid()] = call; Model.getGlobule(this.account.domain).eventHub.subscribe(call.getUuid() + "_answering_call_evt", uuid => { }, evt => { this.callStart(call, contact_domain) }, false) Model.getGlobule(this.account.domain).eventHub.subscribe(call.getUuid() + "_miss_call_evt", uuid => { }, evt => { call.setEndtime(-1) this.setCall(call) }, false) }, false) }) }, err => ApplicationView.displayMessage(err, 3000)) // I will refresh the list of calls... Model.eventHub.subscribe("start_peer_evt_", uuid => { }, evt => { // populate infos. this.refreshCalls() }) // populate infos. this.refreshCalls() // Get the list of all accounts (mab). if (this.getMenuDiv().parentNode) this.getMenuDiv().parentNode.removeChild(this.getMenuDiv()) } onshow() { if (this.account) this.refreshCalls() } // save the call in the backend. setCall(call) { let rqst = new SetCallRqst rqst.setCall(call) // Set value on the callee... let globule = Model.getGlobule(this.account.domain) generatePeerToken(globule, token => { globule.resourceService.setCall(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { // releoad the history... this.refreshCalls() }).catch(err => { }) }) } // refresh the call history... refreshCalls() { let outgoingCallsDiv = this.getMenuDiv().querySelector("#outgoing-calls-div") let incommingCallsDiv = this.getMenuDiv().querySelector("#incomming-calls-div") // outgoingCallsDiv.innerHTML = "" incommingCallsDiv.innerHTML = "" let range = document.createRange() // Display the calls... let rqst = new GetCallHistoryRqst rqst.setAccountId(this.account.id + "@" + this.account.domain) let globule = Model.getGlobule(this.account.domain) generatePeerToken(globule, token => { globule.resourceService.getCallHistory(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { // releoad the history... let calls = rsp.getCallsList().sort((a, b) => { return b.getStarttime() - a.getStarttime() }) let index = 0 calls.forEach(call => { let html = ` <style> img{ height: 40px; width: 40px; border-radius: 20px; padding-right: 5px; } span{ font-size: 1.2rem; margin-left: 10px; } #call_date{ flex-grow: 1; font-size: 1.0rem; } #call_duration{ font-size: 1.0rem; } .call_entry_line { display: flex; flex-direction: column; padding: 5px 0px 5px; border-bottom: 1px solid var(--palette-divider); } .contact-infos{ display: flex; flex-grow: 1; align-items: center; } @media (max-width: 500px) { .call_entry_line { width: calc(100vw - 40px); padding-right: 5px; } .contact-infos{ flex-direction: column; } .contact-infos span{ font-size: 1.0rem; } } </style> <div id="_${call.getUuid()}" class="call_entry_line"> <div style="display: flex;"> <div id="call_date"></div> <div id="call_duration"></div> </div> <div style="display: flex; align-items: center;"> <div class="contact-infos"> <img id="account-img" style="display: none;"></img> <iron-icon id="account-icon" icon="account-circle" style="width: 40px; height: 40px; --iron-icon-fill-color:var(--palette-action-disabled);"></iron-icon> <span style="flex-grow: 1;"></span> </div> <paper-icon-button id="delete-btn" icon="icons:delete"></paper-icon-button> <paper-icon-button id="call-btn" icon="communication:call"></paper-icon-button> </div> </div> ` let fragment = range.createContextualFragment(html) let div = fragment.querySelector(`#_${call.getUuid()}`) let img = fragment.querySelector("#account-img") let icon = fragment.querySelector("#account-icon") let span = fragment.querySelector("span") let call_btn = fragment.querySelector("#call-btn") let delete_btn = fragment.querySelector("#delete-btn") let date_div = fragment.querySelector("#call_date") let duration_div = fragment.querySelector("#call_duration") div.style.order = ++index Account.getAccount(call.getCallee(), callee => { Account.getAccount(call.getCaller(), caller => { let contact = null if (caller.id == this.account.id) { contact = callee outgoingCallsDiv.appendChild(fragment) } else { contact = caller incommingCallsDiv.appendChild(fragment) } if (contact) { if (contact.profilePicture.length > 0) { img.src = contact.profilePicture img.style.display = "block" icon.style.display = "none" } span.innerHTML = contact.email let call_start = new Date(call.getStarttime() * 1000) date_div.innerHTML = call_start.toLocaleDateString() + " " + call_start.toLocaleTimeString() if (call.getEndtime() == -1) { duration_div.innerHTML = "missed" duration_div.style.color = "var(--palette-error-dark)" } else if (call.getEndtime() > 0) { let duration = call.getEndtime() - call.getStarttime() let obj = secondsToTime(duration) var hours = obj.h var min = obj.m var sec = obj.s let hours_ = (hours < 10) ? '0' + hours : hours; let minutes_ = (min < 10) ? '0' + min : min; let seconds_ = (sec < 10) ? '0' + sec : sec; duration_div.innerHTML = hours_ + ":" + minutes_ + ":" + seconds_; } call_btn.onclick = () => { this.onCallContact(contact) } delete_btn.onclick = () => { let rqst = new DeleteCallRqst rqst.setAccountId(this.account.id + "@" + this.account.domain) rqst.setUuid(call.getUuid()) // Set value on the callee... let globule = Model.getGlobule(this.account.domain) generatePeerToken(globule, token => { globule.resourceService.deleteCall(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { // this.refreshCalls() let div = this.getMenuDiv().querySelector(`#_${call.getUuid()}`) if (div) { div.parentNode.removeChild(div) } }) }) } } }, err => console.log("fail to get account infos with error ", err)) }, err => console.log("fail to get account infos with error ", err)) }) }).catch(err => { }) }) } // start callStart(call, contact_domain) { // save at 1 second interval. so if the conversation crash we will have converstion infos... let interval = setInterval(() => { call.setEndtime(parseInt(Date.now() / 1000)) this.setCall(call) }, 5000) // so here I will save the call at 5 second intterval... until the conversation end... Model.getGlobule(contact_domain).eventHub.subscribe(`video_conversation_close_${call.getUuid()}_evt`, uuid => { }, evt => { clearInterval(interval) this.setCall(call) // save last time... }, false) Model.getGlobule(this.account.domain).eventHub.subscribe(`video_conversation_close_${call.getUuid()}_evt`, uuid => { }, evt => { clearInterval(interval) this.setCall(call) // save last time... }, false) } findAccountByEmail(email) { Account.getAccounts(`{"email":{"$regex": "${email}", "$options": "im"}}`, (accounts) => { accounts = accounts.filter((obj) => { return obj.id !== this.account.id; }); if (this.callContactInput != undefined) { this.callContactInput.setValues(accounts) } }, (err) => { //callback([]) ApplicationView.displayMessage(err, 3000) }) } // When you call a contact... onCallContact(contact) { let id = "call_" + contact.id + "_div" if(document.querySelector(`#${id}`)){ return // already has a dialog... } let call = new Call() call.setUuid(randomUUID()) call.setCallee(contact.id + "@" + contact.domain) call.setCaller(Application.account.id + "@" + Application.account.domain) call.setStarttime(Math.floor(Date.now() / 1000)) // set unix timestamp... let rqst = new SetCallRqst rqst.setCall(call) // Set value on the callee... let globule = Model.getGlobule(Application.account.domain) generatePeerToken(globule, token => { globule.resourceService.setCall(rqst, { application: Application.application, domain: globule.domain, token: token }) .then(rsp => { Account.getAccount(call.getCaller(), caller => { Account.getAccount(call.getCallee(), callee => { if (!Application.getGlobule(callee.domain)) { ApplicationView.displayMessage(` <style> #call-icon, #call-img{ height: 48px; width: 48px; border-radius: 32px; padding-right: 5px; } </style> <div style="display: flex;"> <img id="call-img" style="display: ${callee.profilePicture.length == 0 ? "none" : "block"};" src="${callee.profilePicture}"></img> <iron-icon id="call-icon" icon="account-circle" style="--iron-icon-fill-color:var(--palette-action-disabled); display: ${callee.profilePicture.length != 0 ? "none" : "block"};"></iron-icon> <div style="display: flex; flex-direction: column;"> <span>fail to call ${callee.id}</span> <span>globule <span style="font-weight: bold;">${callee.domain}</span> is unreachable</span> </div> </div>`, 4500) return } else { let url = getUrl(globule) // so here I will found the caller ringtone... let path = callee.ringtone if (!path) { ApplicationView.displayMessage(callee.id + " must be in your contact list to be able to call him", 3000) return } path = path.replace(globule.config.WebRoot, "") path.split("/").forEach(item => { item = item.trim() if (item.length > 0) { url += "/" + encodeURIComponent(item) } }) url += "?application=" + Model.application url += "&token=" + token let audio = new Audio(url) audio.setAttribute("loop", "true") audio.setAttribute("autoplay", "true") // So now I will display the interface the user to ask... // So here I will get the information from imdb and propose to assciate it with the file. let toast = ApplicationView.displayMessage(` <style> .call-dialog{ display: flex; flex-direction: column; justify-content: center; width: 100%; } paper-icon-button { width: 40px; height: 40px; border-radius: 50%; } #call-icon, #call-img{ width: 185.31px; height: 100%; align-self: center; justify-self: center; padding-top: 10px; padding-bottom: 15px; } </style> <div id="${id}" class="call-dialog"> <div>Outgoing Call to </div> <div style="display: flex; flex-direction: column; align-items: center;"> <img id="call-img" style="display: ${callee.profilePicture.length == 0 ? "none" : "block"};" src="${callee.profilePicture}"></img> <iron-icon id="call-icon" icon="account-circle" style="--iron-icon-fill-color:var(--palette-action-disabled); display: ${callee.profilePicture.length != 0 ? "none" : "block"};"></iron-icon> <div stye="display: flex; align-items: center;"> <span style="max-width: 300px; font-size: 1.7rem; margin-right: 16px;">${callee.name}</span> <paper-icon-button id="cancel-button" style="background-color: red " icon="communication:call-end"></paper-icon-button> </div> </div> </div> `) // set timeout... let timeout = setTimeout(() => { audio.pause() toast.dismiss(); Model.getGlobule(caller.domain).eventHub.publish(call.getUuid() + "_miss_call_evt", call.serializeBinary(), false) if (caller.domain != callee.domain) Model.getGlobule(callee.domain).eventHub.publish(call.getUuid() + "_miss_call_evt", call.serializeBinary(), false) }, 30 * 1000) let cancelBtn = toast.el.querySelector("#cancel-button") cancelBtn.onclick = () => { toast.dismiss(); audio.pause() clearTimeout(timeout) // Here I will send miss call event... Model.getGlobule(caller.domain).eventHub.publish(call.getUuid() + "_miss_call_evt", call.serializeBinary(), false) if (caller.domain != callee.domain) Model.getGlobule(callee.domain).eventHub.publish(call.getUuid() + "_miss_call_evt", call.serializeBinary(), false) } // Here the call succeed... Model.getGlobule(contact.domain).eventHub.subscribe(call.getUuid() + "_answering_call_evt", uuid => { }, evt => { // The contact has answer the call! audio.pause() toast.dismiss(); clearTimeout(timeout) let call = Call.deserializeBinary(Uint8Array.from(evt.split(","))) // The contact has answer the call! let videoConversation = new VideoConversation(call.getUuid(), Application.account.domain) videoConversation.style.position = "fixed" videoConversation.style.left = "0px" videoConversation.style.top = "0px" // append it to the workspace. ApplicationView.layout.workspace().appendChild(videoConversation) // start the video conversation. globule.eventHub.publish("start_video_conversation_" + call.getUuid() + "_evt", contact, true) }, false) // Here the call was miss... Model.getGlobule(contact.domain).eventHub.subscribe(call.getUuid() + "_miss_call_evt", uuid => { }, evt => { // The contact has answer the call! audio.pause() toast.dismiss(); clearTimeout(timeout) generatePeerToken(Model.getGlobule(contact.domain), token => { let rqst = new CreateNotificationRqst let notification = new Notification notification.setDate(parseInt(Date.now() / 1000)) // Set the unix time stamp... notification.setId(call.getUuid()) notification.setRecipient(contact.id + "@" + contact.domain) notification.setSender(Application.account.id + "@" + Application.account.domain) notification.setNotificationType(NotificationType.USER_NOTIFICATION) notification.setMac(Model.getGlobule(Application.account.domain).config.Mac) let date = new Date() let msg = ` <div style="display: flex; flex-direction: column; padding: 16px;"> <div> ${date.toLocaleString()} </div> <div> Missed call from ${Application.account.name} </div> </div> ` notification.setMessage(msg) rqst.setNotification(notification) // Create the notification... Model.getGlobule(contact.domain).resourceService.createNotification(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp) => { /** nothing here... */ }).catch(err => { ApplicationView.displayMessage(err, 3000); console.log(err) }) // use the ts class to send notification... let notification_ = new Notification_ notification_.id = notification.getId() notification_.date = date notification_.sender = notification.getSender() notification_.recipient = notification.getRecipient() notification_.text = notification.getMessage() notification_.type = 0 notification_.mac = Model.getGlobule(Application.account.domain).config.Mac // Send notification... Model.getGlobule(contact.domain).eventHub.publish(contact.id + "@" + contact.domain + "_notification_event", notification_.toString(), false) }) }, false) // so here I will play the audio of the contact util it respond or the delay was done... Model.getGlobule(contact.domain).eventHub.publish("calling_" + contact.id + "@" + contact.domain + "_evt", call.serializeBinary(), false) Model.eventHub.publish("calling_" + contact.id + "@" + contact.domain + "_evt", call, true) } }) }, err => ApplicationView.displayMessage(err, 3000)) }, err => ApplicationView.displayMessage(err, 3000)) if (contact.domain != Application.account.domain) { let globule = Model.getGlobule(contact.domain) generatePeerToken(globule, token => { globule.resourceService.setCall(rqst, { application: Application.application, domain: globule.domain, token: token }) }, err => ApplicationView.displayMessage(err, 3000)) } }) } } customElements.define('calls-history-menu', CallsHistoryMenu)