Skip to content

Instantly share code, notes, and snippets.

@rationalthinker1
Created February 15, 2023 04:43
Show Gist options
  • Save rationalthinker1/8e0b40053f94060fd055af2b21937918 to your computer and use it in GitHub Desktop.
Save rationalthinker1/8e0b40053f94060fd055af2b21937918 to your computer and use it in GitHub Desktop.
MightyCall.ts Rewritten
const MIGHTYCALL_API_URL = 'https://api.mightycall.com/v4/webphone';
const MIGHTYCALL_CORE_URL = 'https://api.mightycall.com/v4/webphone/JavaScriptSDK/mightycall.webphone.core.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
declare let MightyCallWebPhoneCore: any;
const MIGHTYCALL_EVENT = 'mightycall_event';
const MIGHTYCALL_WEBPHONE_STATUS = 'mightycall_webphone_status';
enum CallStatus {
INACTIVE = 'inactive',
OFFLINE = 'offline',
READY = 'ready',
CALL_INCOMING = 'call_incoming',
CALL_OUTGOING = 'call_outgoing',
CALL_STARTED = 'call_started',
}
interface Config {
login?: string,
password?: string,
integrationType?: string,
}
let INTEGRATION_CONFIG: Config = {};
let SDK_CONFIG = {};
export class Utility {
public getWebPhoneWindowReference: () => Window;
protected platform: string;
constructor() {
this.getWebPhoneWindowReference = this.getWindowReference;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.platform = navigator?.vendor ?? navigator?.userAgentData?.platform ?? navigator?.platform ?? 'unknown';
}
initWebPhoneWindow = () => {
this.getWindowReference();
};
initWebPhoneInline = (containerId: string) => {
this.getWebPhoneWindowReference = this.noopReturnWindow;
this.initWebPhoneFrame(containerId);
this.appendCoreJsToDocument();
};
getWindowReference = () => {
const reference = window.open('', 'mightycall_webphone_expand', 'width=345,height=500,location=false,status=false');
if (this.platform.indexOf('Apple') == 0 && /\sSafari\//.test(navigator.userAgent)) {
window.resizeTo(360, 550);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
window.resizeTo(360, 565);
}
const location = this.getFrameSrc();
console.log('wf location = ', location);
try {
if (this.isEmptyReference(reference)) {
reference.location = location;
}
} catch (e) {
console.log(e);
}
return reference;
};
initWebPhoneFrame = (containerId: string) => {
const frame = document.createElement('iframe');
frame.id = 'mightyCallWebPhoneFrame';
frame.src = this.getFrameSrc();
frame.allow = 'microphone; autoplay';
console.log('wf location = ', frame.src);
let style = 'width:345px;height:500px;';
frame.name = 'mightycall_webphone_expand';
if (this.platform.indexOf('Apple') == 0 && /\sSafari\//.test(navigator.userAgent)) {
style = 'width:360px;height:550px;';
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
style = 'width:360px;height:565px;';
}
frame.setAttribute('style', style);
document.getElementById(containerId).appendChild(frame);
};
appendCoreJsToDocument = () => {
const script = document.createElement('script');
script.src = MIGHTYCALL_CORE_URL;
script.type = 'text/javascript';
document.head.appendChild(script);
};
noopReturnWindow = () => {
return window;
};
getLocation = () => {
return location.origin;
};
getFrameSrc = () => {
const config = INTEGRATION_CONFIG;
if ((!config.login || !config.password) && !config.integrationType) {
throw 'Config is empty. May you forget to call applyConfig?';
}
const uriParams = [ `integration=${encodeURIComponent(this.getLocation())}` ];
if (config.login) {
uriParams.push(
`client_id=${encodeURIComponent(config.login)}`,
`client_secret=${encodeURIComponent(config.password)}`);
}
if (config.integrationType) {
uriParams.push(`integration_type=${encodeURIComponent(config.integrationType)}`);
}
return `${MIGHTYCALL_API_URL}/Oauth/StartBuiltInIntegration?${uriParams.join('&')}#enable`;
};
guid = () => {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
};
addEventHandler = (eventName: string, handler: (this: Window, ev: Event) => void) => {
if (window.addEventListener) {
window.addEventListener(eventName, handler);
} else if ('attachEvent' in window && typeof window.attachEvent === 'function') {
window.attachEvent('on' + eventName, handler);
}
};
isEmptyReference = (ref: Window = null) => {
const reference = ref || window.open('', 'mightycall_webphone_expand', 'width=345,height=500,location=false,status=false');
//iframe case
if (reference.self !== reference.top) {
//special check for yandex case
try {
if (reference.location.href) {
return true;
}
} catch (e) {
console.warn(e);
}
return false;
}
try {
if (
reference.location.href && reference.location.host !== location.host
) {
return true;
}
} catch (e) {
console.warn(e);
}
return false;
};
}
export class EventObserver {
protected handlers: Array<(...args) => unknown> = [];
subscribe = (fn: (...args) => unknown) => {
this.handlers.push(fn);
};
unsubscribe = (fn: (...args) => unknown) => {
this.handlers = this.handlers.filter((item) => item !== fn);
};
fire = (o: unknown, thisObj: Window & typeof globalThis) => {
const scope = thisObj || window;
this.handlers.forEach((item) => item.call(scope, o));
};
}
export class MightyCallProfile {
public OnStatusChange = new EventObserver();
protected utility = new Utility();
profileGetUserStatusPromise = () => {
this.utility.getWebPhoneWindowReference();
return MightyCallWebPhoneCore.Profile.GetUserStatus();
};
profileSetUserStatusPromise = (statusStr: string) => {
this.utility.getWebPhoneWindowReference();
return MightyCallWebPhoneCore.Profile.SetUserStatus(statusStr);
};
}
export class MightyCallPhone {
public OnStatusChange = new EventObserver();
public OnInactive = new EventObserver();
public OnOffline = new EventObserver();
public OnReady = new EventObserver();
public OnCallIncoming = new EventObserver();
public OnLoadConfig = new EventObserver();
public CallPartiesChanged = new EventObserver();
public OnCallOutgoing = new EventObserver();
public OnCallStarted = new EventObserver();
public OnCallCompleted = new EventObserver();
public OnAccept = new EventObserver();
public OnReject = new EventObserver();
public OnHangUp = new EventObserver();
public OnMute = new EventObserver();
public OnUnMute = new EventObserver();
public OnHold = new EventObserver();
public OnUnHold = new EventObserver();
public OnFail = new EventObserver();
protected utility = new Utility();
Init = (containerId: string) => {
if (containerId) {
this.utility.initWebPhoneInline(containerId);
} else {
this.utility.initWebPhoneWindow();
}
this.overrideSetItem();
this.appendCoreJsToDocument();
};
overrideSetItem = () => {
const originalSetItem = Storage.prototype.setItem;
const handleNotifications = this.handleNotifications;
Storage.prototype.setItem = function(key, data) {
handleNotifications({key: key, newValue: data});
originalSetItem.apply(this, [ key, data ]);
};
};
appendCoreJsToDocument = () => {
const script = document.createElement('script');
script.src = MIGHTYCALL_CORE_URL;
script.type = 'text/javascript';
document.head.appendChild(script);
};
handleNotifications = (event) => {
if (event.key == MIGHTYCALL_EVENT) {
const data = JSON.parse(event.newValue);
this.fireEvent(data);
}
};
fireEvent = (data) => {
try {
if (this[data.type] != undefined && this[data.type][data.event] != undefined) {
this[data.type][data.event].fire(data.info);
}
} catch (exc) {
console.warn(`error firing ${data.type} ${data.event}`);
console.warn(exc);
}
};
Focus = () => {
const webPhoneInstanceReference = this.utility.getWebPhoneWindowReference();
webPhoneInstanceReference.focus();
};
Call = (number: string) => {
console.log(`call number: ${number}`);
const callUrgent = () => {
MightyCallWebPhoneCore.Phone.Call(number);
this.OnReady.unsubscribe(callUrgent);
};
if (this.utility.isEmptyReference()) {
this.utility.getWebPhoneWindowReference();
this.OnReady.subscribe(callUrgent);
} else {
callUrgent();
}
};
SetNumber = (number: string, isTurnOn = true) => {
MightyCallWebPhoneCore.Phone.SetNumber(number, isTurnOn);
};
SwitchOff = () => {
MightyCallWebPhoneCore.Phone.SwitchOff();
};
SwitchOn = () => {
MightyCallWebPhoneCore.Phone.SwitchOn();
};
PhoneStatus = (): CallStatus => {
let status = localStorage.getItem(MIGHTYCALL_WEBPHONE_STATUS) as CallStatus;
if (status == undefined) {
status = CallStatus.INACTIVE;
}
return status;
};
PhoneAccept = () => {
MightyCallWebPhoneCore.Phone.Accept();
};
PhoneReject = () => {
MightyCallWebPhoneCore.Phone.Reject();
};
PhoneHangUp = () => {
this.utility.getWebPhoneWindowReference();
MightyCallWebPhoneCore.Phone.HangUp();
};
PhoneMute = () => {
this.utility.getWebPhoneWindowReference();
MightyCallWebPhoneCore.Phone.Mute();
};
PhoneUnMute = () => {
this.utility.getWebPhoneWindowReference();
MightyCallWebPhoneCore.Phone.UnMute();
};
PhoneHold = () => {
this.utility.getWebPhoneWindowReference();
MightyCallWebPhoneCore.Phone.Hold();
};
PhoneUnHold = () => {
this.utility.getWebPhoneWindowReference();
MightyCallWebPhoneCore.Phone.UnHold();
};
initLocalStorageListener = () => {
this.utility.addEventHandler('storage', this.handleNotifications);
};
}
class MightyCallWebPhone {
public Phone = new MightyCallPhone();
public Profile = new MightyCallProfile();
protected utility = new Utility();
protected id: string;
protected debug = false;
constructor() {
this.id = this.utility.guid();
this.initLocalStorageListener();
}
enableDebug = (isEnable) => {
this.debug = isEnable !== false;
};
ApplyConfig = (cfg: Config) => {
console.log(`apply config: ${JSON.stringify(cfg)}`);
INTEGRATION_CONFIG = cfg;
};
ApplySDKConfig = (cfg: Record<string, unknown>) => {
SDK_CONFIG = cfg;
};
handleNotifications = (event) => {
if (event.key == MIGHTYCALL_EVENT) {
const data = JSON.parse(event.newValue);
this.fireEvent(data);
}
};
fireEvent = (data) => {
try {
if (this[data.type] != undefined && this[data.type][data.event] != undefined) {
this[data.type][data.event].fire(data.info);
}
} catch (exc) {
console.warn(`error firing ${data.type} ${data.event}`);
console.warn(exc);
}
};
initLocalStorageListener = () => {
this.utility.addEventHandler('storage', this.handleNotifications);
};
}
const mightyCallWebPhone = new MightyCallWebPhone();
export default mightyCallWebPhone;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment