A trending theme: more work related stuff.
The Problem:
We moved from a real efficient system (3cx) that was always visible, always one click and even auto answered, to another one that was hidden away in a browser tab, required many clicks to answer/hold/mute/etc
The Solution:
I created some extensions for chrome that were always visible, always one away, and even hotkeyed to get back to having a usable workflow.
Features/Benefits:
- I can be mid email, ALT+A and answer a call without stopping my typing or slowing down at all! or a quick ALT+S+2 to go to busy so I don't need to answer next call if I'm still doing something
- bindable: anywhere inside chrome use key to answer/hangup, mute, etc
- always visible, one click away if you don't like hotkeys
- status icons, that mostly work!
- adds context menu to quick look up orders, search tracking etc, anywhere from chrome ie from emails, from salesforce
- does not interfere with anything, just looks for a particular element and clicks it if possible
Answering calls: ignore the class name
class HandleHold {
constructor() {
this.onPhone = false;
this.phoneNumber = null;
this.omniButton = null;
this.omniBar = null;
}
async handlePhoneCall() {
this.phoneNumber = null;
await this.handleOpenMenu();
this.onPhone = this.answerCall();
if(!this.onPhone){
this.endCall();
}
await this.handleCloseMenu();
}
answerCall() {
if (this.getOmniBar() != null) {
let answerButton = this.omniBar.querySelector('[title^="Accept Voice Call"]');
if (answerButton != null) {
answerButton.click();
return true;
}
}
return false;
}
endCall() {
if (this.getOmniBar() == null)
return;
let endButton = this.omniBar.querySelector('[title="End Call"]');
if (endButton != null) {
endButton.click();
}
}
isOmniOpen() {
if (this.getOmniBar() != null) {
if (this.omniBar.classList.contains('MINIMIZED')) {
return false;
}
}
return true;
}
getOmniBar() {
if (this.omniBar != null)
return this.omniBar;
//is closed
let bar = document.querySelectorAll('.MINIMIZED');
for (let i = 0; i < bar.length; i++) {
if (bar[i].textContent.search('Omni-Channel') > -1) {
this.omniBar = bar[i];
return bar[i];
}
}
//is open
bar = document.querySelectorAll('.DOCKED');
for (let i = 0; i < bar.length; i++) {
if (bar[i].textContent.search('Omni-Channel') > -1) {
this.omniBar = bar[i];
return bar[i];
}
}
//cannot find
return null;
}
getOmniButton() {
return this.getQuerySelectorByInnerHtml('button', 'Omni-Channel');
}
async handleOpenMenu() {
if (!this.isOmniOpen()) {
this.toggleOmniPopUp(); //open pop up if we need
await this.sleep(100); //rest
}
}
async handleCloseMenu() {
if (this.isOmniOpen()) {
this.toggleOmniPopUp(); //open pop up if we need
}
}
toggleOmniPopUp() {
if (this.omniButton == null) {
this.omniButton = this.getOmniButton();
}
if (this.omniButton != null) {
this.omniButton.click();
}
}
getQuerySelectorByInnerHtml(type, innerHTML) {
let types = document.querySelectorAll(type);
let ret = null;
//backward loop as most buttons are later in the list
for (let i = types.length - 1; i >= 0; i--) {
if (types[i].innerHTML.search(innerHTML) > -1) {
ret = types[i];
break;
}
}
return ret;
}
getQuerySelectorByInnerText(type, innerText) {
let types = document.querySelectorAll(type);
let ret = null;
//backward loop as most buttons are later in the list
for (let i = types.length - 1; i >= 0; i--) {
if (types[i].innerText == innerText) {
ret = types[i];
break;
}
}
return ret;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
let answerCall = new HandleHold();
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.method === 'handlePhoneCall') {
answerCall.handlePhoneCall();
}
sendResponse({ answered: answerCall.onPhone, phone: answerCall.phoneNumber });
});
Context Menus:
const keys = {
"^1234\\d{5}$": "https://www.....com/?externalSearchQuery={}",
"^(\\d[a-zA-Z]{3}|[a-zA-Z]\\d[a-zA-Z]{2})\\d{8}$" : "https://....com/?id={}",
.........
}
const trackID = chrome.contextMenus.create({
"id": "trackID",
"title": "search: " + "%s",
"contexts": ["selection"]
});
//function genericOnClick(info, tab) {
chrome.contextMenus.onClicked.addListener((info, tab)=>{
if(info.menuItemId == trackID){
track(info.selectionText.trim());
}
});
function track(con){
for (var key in keys) {
const found = con.match(new RegExp(key));
if(found){
if(key === '^\\+?614\\d{7}|^04\\d{8}$'){
const regex = /^\+614|^614/i;
con = con.replace(regex, '04');
}
else if(key === '^(\\d{1,2}-[oO0]-\\d{8}|\\d{10,13})$' || key === '^125-[oO0]-\\d{8}$'){
con = con.replace('-0-', '-O-');
}
chrome.tabs.create({ url: keys[key].replace("{}", con) });
break;
}
}
}
Changing Status:
const tabURL = 'https://x.xxxx.com/*';
const queryOptions = {pinned : true, url: tabURL};
document.onkeydown = function(e){
if(e.key === '1'){
document.getElementById("status-available").click();
window.close();
}
else if(e.key === '2'){
document.getElementById("status-busy").click();
window.close();
}
else if(e.key === '3'){
document.getElementById("status-busy-lunch").click();
window.close();
}
else if(e.key === '4'){
document.getElementById("status-offline").click();
window.close();
}
}
document.querySelector('#status-available').onclick = () => {
chrome.tabs.query(queryOptions, function (tabs) {
if (tabs && tabs[0] != null) {
chrome.tabs.sendMessage(tabs[0].id, { method: "changeOmniStatus", status: "Available" }, function (response) { });
}
});
window.close();
};
document.querySelector('#status-busy').onclick = () => {
chrome.tabs.query(queryOptions, function (tabs) {
if (tabs && tabs[0] != null) {
chrome.tabs.sendMessage(tabs[0].id, { method: "changeOmniStatus", status: "Busy" }, function (response) { });
}
});
window.close();
};
document.querySelector('#status-busy-lunch').onclick = () => {
chrome.tabs.query(queryOptions, function (tabs) {
if (tabs && tabs[0] != null) {
chrome.tabs.sendMessage(tabs[0].id, { method: "changeOmniStatus", status: "Busy - Lunch" }, function (response) { });
}
});
window.close();
};
document.querySelector('#status-offline').onclick = () => {
chrome.tabs.query(queryOptions, function (tabs) {
if (tabs && tabs[0] != null) {
chrome.tabs.sendMessage(tabs[0].id, { method: "changeOmniStatus", status: "Offline" }, function (response) { });
}
});
window.close();
};