// Определение ОС
var OSName = 'Unknown';
if (navigator.appVersion.indexOf('Win') != -1) OSName = 'Windows';
if (navigator.appVersion.indexOf('Mac') != -1) OSName = 'MacOS';
if (navigator.appVersion.indexOf('X11') != -1) OSName = 'UNIX';
if (navigator.appVersion.indexOf('Linux') != -1) OSName = 'Linux';
console.log('Операционная система: ' + OSName);
var someTime = new Date().getTime();
var messengerFrameReload = true;
// Оболочку открывают в iframe на чужом домене (просмотрщик тепловых карт Я.Метрики —
// metrika.yandex.ru). Там браузер с заблокированными сторонними куками бросает на
// localStorage SecurityError: необработанное исключение обрывало window.onload,
// фрейм CRM не создавался и в просмотрщике был белый экран. Читаем/пишем через обёртки.
function lsGet(key) {
try { return localStorage.getItem(key); } catch (e) { return null; }
}
function lsSet(key, value) {
try { localStorage.setItem(key, value); } catch (e) {}
}
// Пропускаем только адреса нашего же сайта. Иначе в src фрейма попадал мусор:
// просмотрщик Метрики добавляет к URL свои параметры (?_ym_...&...), а старый разбор
// брал всё после первого '&' без проверки — фрейм уходил на несуществующий URL.
function sameOriginUrl(url) {
if (!url) return '';
url = String(url);
if (url.charAt(0) === '/') return url;
if (url.indexOf(location.origin + '/') === 0) return url;
return '';
}
// Глубокая ссылка вида /JustCRM&<полный URL страницы CRM> (см. tasks/controller.inc.php).
// Берём всё после ПЕРВОГО '&': в самом целевом URL тоже могут быть '&' (split их терял).
function deepLinkFromHref() {
var i = location.href.indexOf('&');
return (i === -1) ? '' : sameOriginUrl(location.href.slice(i + 1));
}
// Выполнение при загрузке
var first = false;
window.onload = function() {
var deepLink = deepLinkFromHref();
if (deepLink) lsSet('JustCRM_lastURL', deepLink);
// Необходимо для того, чтобы при обновлении страницы загружался фрейм с текущим URL CRM
var src = sameOriginUrl(lsGet('JustCRM_lastURL')) || 'index.php';
var fragment = create('');
document.body.insertBefore(fragment, document.body.childNodes[0]);
};
function loadChat() {
var fragment = create('');
document.body.insertBefore(fragment, document.body.childNodes[1]);
var fragment1 = create('');
document.body.insertBefore(fragment1, document.body.childNodes[2]);
}
function create(htmlStr) {
var frag = document.createDocumentFragment(),
temp = document.createElement('div');
temp.innerHTML = htmlStr;
while (temp.firstChild) {
frag.appendChild(temp.firstChild);
}
return frag;
}
// Операции с Websocket
var socket;
var timer;
var forbidden = false;
function socketConnect() {
//socket = new WebSocket('wss://'+window.location.hostname+'/ws');
socket = new WebSocket('wss://crm1.sskindustry.ru/ws');
//socket = new WebSocket('ws://46.0.207.45/ws');
socket.onmessage = function(event) {
// Ответ сервера
//console.log(event.data);
var serverEvent = {};
try {
serverEvent = JSON.parse(event.data);
} catch (err) {};
// Если авторизация отклонена, то удаляем таймер для попыток соединения
if (serverEvent.wssstatus && serverEvent.wssstatus == '0') {
clearTimeout(timer);
forbidden = true;
}
// Если обнаружен дубликат сессии, то завершаем соединение
if (serverEvent.wssstatus == '2') {
console.log('Отключаем соединение.');
socket.close();
// Аннулируем авторизацию в CRM
window.frames[0].deleteCookie('PHPSESSID');
window.location.reload();
}
// Если это первый ответ сервера с id пользователя, присвоенный сервером, то отправляем серверу настройки с методами
if (typeof serverEvent.first_responce_server != "undefined") {
var firstResponceClient = '{"first_responce_client":"true", "id":"' + window.frames[0].id + '", "id_client":"' + window.frames[0].guid + '", "id_client_server":"' + serverEvent.id_client_server + '", "client_name":"", "ext_client":"' + window.frames[0].ext_phone + '", "incoming_call":"true", "incoming_task":"true"}';
console.log('Ответ серверу отправлен.');
try {
socket.send(firstResponceClient);
} catch (err) {};
} else {
// Иначе это событие, которое надо обработать
if (JSON.stringify(serverEvent) != '{}') {
console.log('Получено событие.');
console.log(serverEvent);
noty(serverEvent);
}
}
};
socket.onopen = function() {
console.log('Соединение установлено.');
socketStatus(socket.readyState);
};
socket.onerror = function() {
console.log('Ошибка соединения с сервером уведомлений!');
socketStatus(socket.readyState);
};
socket.onclose = function() {
console.log('Соединение закрыто.');
socketStatus(socket.readyState);
delete socket;
if (!forbidden) {
if (window.frames[0].guid != '' && window.frames[0].system_type == '10') {
timer = setTimeout(function() {
console.log('Пробуем подключиться...');
socketConnect();
}, 5000);
}
}
};
}
// Оболочка открыта во фрейме на чужом домене — это просмотрщик тепловых карт Метрики.
function isForeignTop() {
try { void window.top.document; return false; } catch (e) { return true; }
}
function crmLoad() {
// В просмотрщике карт вебсокет уведомлений не нужен, и он там вреден: сервер событий
// считает дубликатом ЛЮБОЕ второе подключение того же пользователя (сверка по GUID,
// см. nodejs/events.server.js) и шлёт wssstatus:2. Обработчик делает reload, обе
// стороны — обычная вкладка и фрейм — начинают перезагружать друг друга по кругу
// (выйти из системы при этом не удаётся: deleteCookie зовут с именем PHPSESSID,
// а реальная кука SSKPHPSESSID). Во фрейме этот цикл и выглядит белым экраном.
if (isForeignTop()) {
// Внутренний фрейм загрузился и сообщает, авторизован ли пользователь.
// Если нет — предлагаем запросить доступ к куке сессии (Safari и любой браузер
// с заблокированными сторонними куками). Запрашивать умеет только оболочка:
// она прямой потомок чужого окна, вложенному фрейму Safari откажет.
try {
if (window.frames[0] && window.frames[0].guid === '' && window.JustCRMStorageAccess) {
window.JustCRMStorageAccess.promptIfNeeded();
}
} catch (e) {}
return;
}
if (typeof socket != 'undefined' && socket) socketStatus(socket.readyState);
// Если GUID отсутствует, но есть соединение с сокетом, значит был произведен выход из CRM, необходим реконнект
if ((window.frames[0].guid == '' && socket && socket.readyState == 1) || window.frames[0].system_type != '1' && typeof socket != 'undefined') {
// Закрываем сокет
socket.close();
location.reload();
}
// Вызываем сокет, только если соединение отсутствует
if (socket && socket.readyState == 1) {
forbidden = false;
return;
}
// Вызываем соединение если только имеется GUID
if (window.frames[0].guid != '' && window.frames[0].system_type == '10') {
console.log('Пользователь авторизован в JustCRM.');
delete socket;
socketConnect();
}
}
function socketStatus(status) {
var cls = (status == 1) ? 'green-b' : 'red-b';
var txt = (status == 1) ? 'Соединение установлено' : 'Нет соединения с сервером событий!';
try {
var sts = window.frames[0].document.getElementById('link-status');
sts.className = cls;
sts.parentElement.attributes[0].value = txt;
} catch (err) {}
}
// Операции с Websocket - Конец
// Отправка уведомлений
function noty(content) {
var f = window.frames[0];
// Cобытия PBX
if (content.eventPbx) {
switch (content.eventPbx) {
case 'IncomingCall':
if (content.clientId) {
f.notifyMe('Входящий вызов!', 'Клиент: ' + content.clientName + '.\nНомер: ' + content.clientNumber, '{"success" : "true", "clientId":"' + content.clientId + '", "clientName":"' + content.clientName + '", "clientNumber":"' + content.clientNumber + '", "clientType":"' + content.clientType + '", "lidasType":"' + content.lidasType + '"}');
} else {
f.notifyMe('Входящий вызов!', 'Клиент не идентифицирован.\nНомер: ' + content.clientNumber, '{"success" : "true", "clientId":"new", "clientNumber":"' + content.clientNumber + '"}');
}
break;
case 'BlindTransfer':
case 'AttendedTransfer':
if (content.clientId) {
f.notifyMe('Переадресация вызова от: ' + content.userNumber, 'Клиент: ' + content.clientName + '.\nНомер: ' + content.clientNumber, '{"success" : "true", "clientId":"' + content.clientId + '", "clientName":"' + content.clientName + '", "clientNumber":"' + content.clientNumber + '", "clientType":"' + content.clientType + '", "lidasType":"' + content.lidasType + '"}');
} else {
f.notifyMe('Переадресация вызова от: ' + content.userNumber, 'Клиент не идентифицирован.\nНомер: ' + content.clientNumber, '{"success" : "true", "clientId":"new", "clientNumber":"' + content.clientNumber + '"}');
}
break;
case 'DroppedCall':
if (content.clientId) {
f.notifyMe('Пропущенный вызов!', 'Клиент: ' + content.clientName + '.\nНомер: ' + content.clientNumber, '{"command" : "dropped_call", "clientName":"' + content.clientName + '", "clientNumber":"' + content.clientNumber + '", "clientType":"' + content.clientType + '", "lidasType":"' + content.lidasType + '"}');
} else {
f.notifyMe('Пропущенный вызов!', 'Номер: ' + content.clientNumber, '{"command" : "dropped_call", "clientNumber":"' + content.clientNumber + '"}');
}
break;
}
}
// События CRM
if (content.command) {
switch (content.command) {
case 'new_task':
f.notifyMe('Для Вас новая задача!', 'Автор: ' + content.client_name + '\nНажмите, чтобы перейти к документу.', '{"command" : "new_task", "task_url":"' + content.task_url + '"}');
break;
case 'new_task_api':
f.notifyMe(content.subject, 'Нажмите, чтобы перейти к документу.', '{"command" : "new_task_api"}');
break;
case 'new_eventslist_api':
f.notifyMe(content.subject, content.text, '{"command" : "new_eventslist_api"}');
break;
}
}
}