Procházet zdrojové kódy

Visual and functional updates.

fusionate před 1 rokem
rodič
revize
f651493759
5 změnil soubory, kde provedl 986 přidání a 522 odebrání
  1. 58 0
      app_config.php
  2. 285 0
      app_languages.php
  3. 110 522
      phone.php
  4. 416 0
      resources/scripts.js
  5. 117 0
      resources/styles.css

+ 58 - 0
app_config.php

@@ -0,0 +1,58 @@
+<?php
+
+//application details
+	$apps[$x]['name'] = "Phone";
+	$apps[$x]['uuid'] = "7051a36f-06f0-4489-a2fb-12b120e209b6";
+	$apps[$x]['category'] = "";
+	$apps[$x]['subcategory'] = "";
+	$apps[$x]['version'] = "1.0";
+	$apps[$x]['license'] = "Mozilla Public License 1.1";
+	$apps[$x]['url'] = "http://www.fusionpbx.com";
+	$apps[$x]['description']['en-us'] = "A browser-based softphone for FusionPBX.";
+	$apps[$x]['description']['en-gb'] = "A browser-based softphone for FusionPBX";
+	$apps[$x]['description']['ar-eg'] = "";
+	$apps[$x]['description']['de-at'] = "";
+	$apps[$x]['description']['de-ch'] = "";
+	$apps[$x]['description']['de-de'] = "";
+	$apps[$x]['description']['el-gr'] = "";
+	$apps[$x]['description']['es-cl'] = "";
+	$apps[$x]['description']['es-mx'] = "";
+	$apps[$x]['description']['fr-ca'] = "";
+	$apps[$x]['description']['fr-fr'] = "";
+	$apps[$x]['description']['he-il'] = "";
+	$apps[$x]['description']['it-it'] = "";
+	$apps[$x]['description']['nl-nl'] = "";
+	$apps[$x]['description']['pl-pl'] = "";
+	$apps[$x]['description']['pt-br'] = "";
+	$apps[$x]['description']['pt-pt'] = "";
+	$apps[$x]['description']['ro-ro'] = "";
+	$apps[$x]['description']['ru-ru'] = "";
+	$apps[$x]['description']['sv-se'] = "";
+	$apps[$x]['description']['uk-ua'] = "";
+
+//default settings
+// 	$y=0;
+// 	$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "54e3d956-c4a1-4de0-8560-709bddc3d9f8";
+// 	$apps[$x]['default_settings'][$y]['default_setting_category'] = "phone";
+// 	$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "";
+// 	$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+// 	$apps[$x]['default_settings'][$y]['default_setting_value'] = "";
+// 	$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+// 	$apps[$x]['default_settings'][$y]['default_setting_description'] = "";
+// 	$y++;
+// 	$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "824c1c5a-c6c2-4bcf-ac4a-6031626bd13e";
+// 	$apps[$x]['default_settings'][$y]['default_setting_category'] = "phone";
+// 	$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "";
+// 	$apps[$x]['default_settings'][$y]['default_setting_name'] = "boolean";
+// 	$apps[$x]['default_settings'][$y]['default_setting_value'] = "";
+// 	$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+// 	$apps[$x]['default_settings'][$y]['default_setting_description'] = "";
+
+//permission details
+	$y=0;
+	$apps[$x]['permissions'][$y]['name'] = "phone_view";
+	$apps[$x]['permissions'][$y]['menu']['uuid'] = "dff62ee9-f59e-4686-bc57-a4819ea303bf";
+	$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
+// 	$apps[$x]['permissions'][$y]['groups'][] = "admin";
+// 	$apps[$x]['permissions'][$y]['groups'][] = "user";
+	$y++;

+ 285 - 0
app_languages.php

@@ -0,0 +1,285 @@
+<?php
+
+$text['title-phone']['en-us'] = "Phone";
+$text['title-phone']['en-gb'] = "Phone";
+$text['title-phone']['ar-eg'] = "هاتف";
+$text['title-phone']['de-at'] = "Telefon";
+$text['title-phone']['de-ch'] = "Telefon";
+$text['title-phone']['de-de'] = "Telefon";
+$text['title-phone']['el-gr'] = "Τηλέφωνο";
+$text['title-phone']['es-cl'] = "Teléfono";
+$text['title-phone']['es-mx'] = "Teléfono";
+$text['title-phone']['fr-ca'] = "Téléphone";
+$text['title-phone']['fr-fr'] = "Téléphone";
+$text['title-phone']['he-il'] = "טלפון";
+$text['title-phone']['it-it'] = "Telefono";
+$text['title-phone']['nl-nl'] = "Telefoon";
+$text['title-phone']['pl-pl'] = "Telefon";
+$text['title-phone']['pt-br'] = "Telefone";
+$text['title-phone']['pt-pt'] = "Telefone";
+$text['title-phone']['ro-ro'] = "Telefon";
+$text['title-phone']['ru-ru'] = "Телефон";
+$text['title-phone']['sv-se'] = "Telefon";
+$text['title-phone']['uk-ua'] = "Телефон";
+$text['title-phone']['tr-tr'] = "Telefon";
+$text['title-phone']['zh-cn'] = "电话";
+$text['title-phone']['ja-jp'] = "電話";
+$text['title-phone']['ko-kr'] = "핸드폰";
+
+$text['label-clear']['en-us'] = "CLEAR";
+$text['label-clear']['en-gb'] = "CLEAR";
+$text['label-clear']['ar-eg'] = "واضح";
+$text['label-clear']['de-at'] = "Zurücksetzen";
+$text['label-clear']['de-ch'] = "Zurücksetzen";
+$text['label-clear']['de-de'] = "Zurücksetzen";
+$text['label-clear']['el-gr'] = "Εκκαθάριση";
+$text['label-clear']['es-cl'] = "Limpiar";
+$text['label-clear']['es-mx'] = "Limpiar";
+$text['label-clear']['fr-ca'] = "Effacer";
+$text['label-clear']['fr-fr'] = "Effacer";
+$text['label-clear']['he-il'] = "נקה";
+$text['label-clear']['it-it'] = "Pulisci";
+$text['label-clear']['nl-nl'] = "Duidelijk";
+$text['label-clear']['pl-pl'] = "Wyczyść";
+$text['label-clear']['pt-br'] = "Limpar";
+$text['label-clear']['pt-pt'] = "Apagar";
+$text['label-clear']['ro-ro'] = "Curătă";
+$text['label-clear']['ru-ru'] = "Очистить";
+$text['label-clear']['sv-se'] = "Rensa";
+$text['label-clear']['uk-ua'] = "ясно";
+$text['label-clear']['tr-tr'] = "Temizle";
+$text['label-clear']['zh-cn'] = "明确";
+$text['label-clear']['ja-jp'] = "クリア";
+$text['label-clear']['ko-kr'] = "분명한";
+
+$text['label-delete']['en-us'] = "DELETE";
+$text['label-delete']['en-gb'] = "DELETE";
+$text['label-delete']['ar-eg'] = "يمسح";
+$text['label-delete']['de-at'] = "Löschen";
+$text['label-delete']['de-ch'] = "Löschen";
+$text['label-delete']['de-de'] = "Löschen";
+$text['label-delete']['el-gr'] = "Διαγραφή";
+$text['label-delete']['es-cl'] = "Eliminar";
+$text['label-delete']['es-mx'] = "Eliminar";
+$text['label-delete']['fr-ca'] = "Supprimer";
+$text['label-delete']['fr-fr'] = "Supprimer";
+$text['label-delete']['he-il'] = "לִמְחוֹק";
+$text['label-delete']['it-it'] = "Cancella";
+$text['label-delete']['nl-nl'] = "Verwijderen";
+$text['label-delete']['pl-pl'] = "Usuń";
+$text['label-delete']['pt-br'] = "Remover";
+$text['label-delete']['pt-pt'] = "Remover";
+$text['label-delete']['ro-ro'] = "Șterge";
+$text['label-delete']['ru-ru'] = "Удалить";
+$text['label-delete']['sv-se'] = "Ta Bort";
+$text['label-delete']['uk-ua'] = "Видалити";
+$text['label-delete']['tr-tr'] = "Sil";
+$text['label-delete']['zh-cn'] = "删除";
+$text['label-delete']['ja-jp'] = "消去";
+$text['label-delete']['ko-kr'] = "삭제";
+
+$text['label-call']['en-us'] = "CALL";
+$text['label-call']['en-gb'] = "CALL";
+$text['label-call']['ar-eg'] = "يتصل";
+$text['label-call']['de-at'] = "Anruf";
+$text['label-call']['de-ch'] = "Anruf";
+$text['label-call']['de-de'] = "Anruf";
+$text['label-call']['el-gr'] = "Κλήση";
+$text['label-call']['es-cl'] = "Llamar";
+$text['label-call']['es-mx'] = "Llamar";
+$text['label-call']['fr-ca'] = "Appel";
+$text['label-call']['fr-fr'] = "Appel";
+$text['label-call']['he-il'] = "שִׂיחָה";
+$text['label-call']['it-it'] = "Chiamata";
+$text['label-call']['nl-nl'] = "Telefoongesprek";
+$text['label-call']['pl-pl'] = "Dzwonić";
+$text['label-call']['pt-br'] = "Chamar";
+$text['label-call']['pt-pt'] = "Chamada";
+$text['label-call']['ro-ro'] = "Apel";
+$text['label-call']['ru-ru'] = "Вызов";
+$text['label-call']['sv-se'] = "Ring upp";
+$text['label-call']['uk-ua'] = "Телефонуйте";
+$text['label-call']['tr-tr'] = "Arama";
+$text['label-call']['zh-cn'] = "称呼";
+$text['label-call']['ja-jp'] = "電話";
+$text['label-call']['ko-kr'] = "부르다";
+
+$text['label-answer']['en-us'] = "ANSWER";
+$text['label-answer']['en-gb'] = "ANSWER";
+$text['label-answer']['ar-eg'] = "إجابة";
+$text['label-answer']['de-at'] = "Antwort";
+$text['label-answer']['de-ch'] = "Antwort";
+$text['label-answer']['de-de'] = "Antwort";
+$text['label-answer']['el-gr'] = "Απάντηση";
+$text['label-answer']['es-cl'] = "Respuesta";
+$text['label-answer']['es-mx'] = "Respuesta";
+$text['label-answer']['fr-ca'] = "Réponse";
+$text['label-answer']['fr-fr'] = "Réponse";
+$text['label-answer']['he-il'] = "תשובה";
+$text['label-answer']['it-it'] = "Rispondi";
+$text['label-answer']['nl-nl'] = "Antwoord";
+$text['label-answer']['pl-pl'] = "Odbierz";
+$text['label-answer']['pt-br'] = "Resposta";
+$text['label-answer']['pt-pt'] = "Resposta";
+$text['label-answer']['ro-ro'] = "Răspuns";
+$text['label-answer']['ru-ru'] = "Ответ";
+$text['label-answer']['sv-se'] = "Besvarat";
+$text['label-answer']['uk-ua'] = "Відповідь";
+$text['label-answer']['tr-tr'] = "Cevap";
+$text['label-answer']['zh-cn'] = "回答";
+$text['label-answer']['ja-jp'] = "答え";
+$text['label-answer']['ko-kr'] = "답변";
+
+$text['label-decline']['en-us'] = "DECLINE";
+$text['label-decline']['en-gb'] = "DECLINE";
+$text['label-decline']['ar-eg'] = "انخفاض";
+$text['label-decline']['de-at'] = "Abfall";
+$text['label-decline']['de-ch'] = "Abfall";
+$text['label-decline']['de-de'] = "Abfall";
+$text['label-decline']['el-gr'] = "Rechazar";
+$text['label-decline']['es-cl'] = "Rechazar";
+$text['label-decline']['es-mx'] = "Rechazar";
+$text['label-decline']['fr-ca'] = "Déclin";
+$text['label-decline']['fr-fr'] = "Déclin";
+$text['label-decline']['he-il'] = "יְרִידָה";
+$text['label-decline']['it-it'] = "Declino";
+$text['label-decline']['nl-nl'] = "Afwijzen";
+$text['label-decline']['pl-pl'] = "Spadek";
+$text['label-decline']['pt-br'] = "Declínio";
+$text['label-decline']['pt-pt'] = "Recusar";
+$text['label-decline']['ro-ro'] = "Declin";
+$text['label-decline']['ru-ru'] = "Отклонить";
+$text['label-decline']['sv-se'] = "Nedgång";
+$text['label-decline']['uk-ua'] = "відхилити";
+$text['label-decline']['tr-tr'] = "Reddetmek";
+$text['label-decline']['zh-cn'] = "衰退";
+$text['label-decline']['ja-jp'] = "衰退";
+$text['label-decline']['ko-kr'] = "감소";
+
+$text['label-mute']['en-us'] = "MUTE";
+$text['label-mute']['en-gb'] = "MUTE";
+$text['label-mute']['ar-eg'] = "صامت";
+$text['label-mute']['de-at'] = "Stummschalten";
+$text['label-mute']['de-ch'] = "Stummschalten";
+$text['label-mute']['de-de'] = "Stummschalten";
+$text['label-mute']['el-gr'] = "Βουβός";
+$text['label-mute']['es-cl'] = "Silenciar";
+$text['label-mute']['es-mx'] = "Silenciar";
+$text['label-mute']['fr-ca'] = "muet";
+$text['label-mute']['fr-fr'] = "muet";
+$text['label-mute']['he-il'] = "לְהַשְׁתִיק";
+$text['label-mute']['it-it'] = "Silenzia";
+$text['label-mute']['nl-nl'] = "Stil";
+$text['label-mute']['pl-pl'] = "Wycisz";
+$text['label-mute']['pt-br'] = "Silenciar";
+$text['label-mute']['pt-pt'] = "Silenciar";
+$text['label-mute']['ro-ro'] = "Mut";
+$text['label-mute']['ru-ru'] = "Отключить микрофон";
+$text['label-mute']['sv-se'] = "Stäng av mikrofon";
+$text['label-mute']['uk-ua'] = "Вимкнути звук";
+$text['label-mute']['zh-cn'] = "沉默的";
+$text['label-mute']['ja-jp'] = "無音";
+$text['label-mute']['ko-kr'] = "무음";
+
+$text['label-unmute']['en-us'] = "UNMUTE";
+$text['label-unmute']['en-gb'] = "UNMUTE";
+$text['label-unmute']['ar-eg'] = "سحاب";
+$text['label-unmute']['de-at'] = "Stummschaltung deaktivieren";
+$text['label-unmute']['de-ch'] = "Stummschaltung deaktivieren";
+$text['label-unmute']['de-de'] = "Stummschaltung deaktivieren";
+$text['label-unmute']['el-gr'] = "μη σιγασμένα";
+$text['label-unmute']['es-cl'] = "Desilenciar";
+$text['label-unmute']['es-mx'] = "Desilenciar";
+$text['label-unmute']['fr-ca'] = "sonore";
+$text['label-unmute']['fr-fr'] = "sonore";
+$text['label-unmute']['he-il'] = "עננים";
+$text['label-unmute']['it-it'] = "Desilenzia";
+$text['label-unmute']['nl-nl'] = "Spraak geven";
+$text['label-unmute']['pl-pl'] = "Wyłącz wyciszenie";
+$text['label-unmute']['pt-br'] = "Com som";
+$text['label-unmute']['pt-pt'] = "Com som";
+$text['label-unmute']['ro-ro'] = "nori";
+$text['label-unmute']['ru-ru'] = "Включить микрофон";
+$text['label-unmute']['sv-se'] = "Mikrofon Aktiv";
+$text['label-unmute']['uk-ua'] = "Unmute ";
+$text['label-unmute']['zh-cn'] = "云";
+$text['label-unmute']['ja-jp'] = "雲霧て";
+$text['label-unmute']['ko-kr'] = "구름 안개";
+
+$text['label-hold']['en-us'] = "HOLD";
+$text['label-hold']['en-gb'] = "HOLD";
+$text['label-hold']['ar-eg'] = "عقد";
+$text['label-hold']['de-at'] = "Warte.";
+$text['label-hold']['de-ch'] = "Warte.";
+$text['label-hold']['de-de'] = "Warte.";
+$text['label-hold']['el-gr'] = "Κρατήστε";
+$text['label-hold']['es-cl'] = "Espera.";
+$text['label-hold']['es-mx'] = "Espera.";
+$text['label-hold']['fr-ca'] = "En attente";
+$text['label-hold']['fr-fr'] = "En attente";
+$text['label-hold']['he-il'] = "Hold Hold";
+$text['label-hold']['it-it'] = "Attesa";
+$text['label-hold']['nl-nl'] = "Aanhouden";
+$text['label-hold']['pl-pl'] = "trzymać";
+$text['label-hold']['pt-br'] = "Espera";
+$text['label-hold']['pt-pt'] = "Espere.";
+$text['label-hold']['ro-ro'] = "Ține";
+$text['label-hold']['ru-ru'] = "Стойте.";
+$text['label-hold']['sv-se'] = "Håll";
+$text['label-hold']['uk-ua'] = "Прованс";
+$text['label-hold']['zh-cn'] = "抓住";
+$text['label-hold']['ja-jp'] = "所有";
+$text['label-hold']['ko-kr'] = "잡고 있다";
+
+$text['label-resume']['en-us'] = "RESUME";
+$text['label-resume']['en-gb'] = "RESUME";
+$text['label-resume']['ar-eg'] = "سيرة ذاتية";
+$text['label-resume']['de-at'] = "Wieder aufnehmen";
+$text['label-resume']['de-ch'] = "Wieder aufnehmen";
+$text['label-resume']['de-de'] = "Wieder aufnehmen";
+$text['label-resume']['el-gr'] = "ΒΙΟΓΡΑΦΙΚΟ";
+$text['label-resume']['es-cl'] = "Reanudar";
+$text['label-resume']['es-mx'] = "Reanudar";
+$text['label-resume']['fr-ca'] = "Retenir";
+$text['label-resume']['fr-fr'] = "Retenir";
+$text['label-resume']['he-il'] = "קורות חיים";
+$text['label-resume']['it-it'] = "קורות חיים";
+$text['label-resume']['nl-nl'] = "Niet vasthouden";
+$text['label-resume']['pl-pl'] = "Wznawiać";
+$text['label-resume']['pt-br'] = "Retomar";
+$text['label-resume']['pt-pt'] = "Retomar";
+$text['label-resume']['ro-ro'] = "Relua";
+$text['label-resume']['ru-ru'] = "Резюме";
+$text['label-resume']['sv-se'] = "Återuppta";
+$text['label-resume']['uk-ua'] = "Резюме";
+$text['label-resume']['zh-cn'] = "恢复";
+$text['label-resume']['ja-jp'] = "再開する";
+$text['label-resume']['ko-kr'] = "재개하다";
+
+$text['label-end']['en-us'] = "END CALL";
+$text['label-end']['en-gb'] = "END CALL";
+$text['label-end']['ar-eg'] = "نهاية";
+$text['label-end']['de-at'] = "Ende";
+$text['label-end']['de-ch'] = "Ende";
+$text['label-end']['de-de'] = "Ende";
+$text['label-end']['el-gr'] = "Τέλος";
+$text['label-end']['es-cl'] = "Fin";
+$text['label-end']['es-mx'] = "Fin";
+$text['label-end']['fr-ca'] = "Fin";
+$text['label-end']['fr-fr'] = "Fin";
+$text['label-end']['he-il'] = "סוֹף";
+$text['label-end']['it-it'] = "Fine";
+$text['label-end']['nl-nl'] = "Einde";
+$text['label-end']['pl-pl'] = "Koniec";
+$text['label-end']['pt-br'] = "Fim";
+$text['label-end']['pt-pt'] = "Fim";
+$text['label-end']['ro-ro'] = "Sfârşit";
+$text['label-end']['ru-ru'] = "Конец";
+$text['label-end']['sv-se'] = "Slut";
+$text['label-end']['uk-ua'] = "Кінець";
+$text['label-end']['tr-tr'] = "Son";
+$text['label-end']['zh-cn'] = "结尾";
+$text['label-end']['ja-jp'] = "終わり";
+$text['label-end']['ko-kr'] = "끝";
+
+?>

+ 110 - 522
phone.php

@@ -1,14 +1,35 @@
 <?php
 <?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2024
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+*/
 
 
 //includes files
 //includes files
 	require_once dirname(__DIR__, 2) . "/resources/require.php";
 	require_once dirname(__DIR__, 2) . "/resources/require.php";
 	require_once "resources/check_auth.php";
 	require_once "resources/check_auth.php";
 
 
 //check permissions
 //check permissions
-	if (permission_exists('extension_add') || permission_exists('extension_edit')) {
-		//access granted
-	}
-	else {
+	if (!permission_exists('phone_view')) {
 		echo "access denied";
 		echo "access denied";
 		exit;
 		exit;
 	}
 	}
@@ -34,521 +55,88 @@
 		$user_password = $row['password'];
 		$user_password = $row['password'];
 	}
 	}
 
 
-?>
-
-<style type="text/css">
-body {
-	background-color: #333;
-}
-
-.inner {
-	position: absolute;
-}
-
-.buttons{
-	position: fixed;
-	bottom: 0;
-	right: 0;
-	/*width: 200px;*/
-	border: 10px solid rgba(255, 255, 255, 0);
-}
-</style>
-
-<div class="">
-	<div style="position: absolute;"><video id="remote_video" width="640" height="480" style="display: none;"></video></div>
-	<div style="position: absolute;display: none;"><video id="local_video" width="160" height="120" style="display: none;"></video></div>
-	<!--<input id='send' name="send" type="button" class='btn btn-success' onclick="send();" value="Send" />-->
-</div>
-
-<audio id="ringtone" preload="auto" style="display: none;">
-	<source src="resources/ringtones/ringtone.mp3" type="audio/mpeg" loop="loop" />
-</audio>
-
-<script src="resources/sip-0.7.8.js"></script>
-<script language="JavaScript" type="text/javascript">
-
-function sanitize_string(str) {
-	let temp = document.createElement('div');
-	temp.textContent = str;
-	return temp.innerHTML;
-}
-
-<?php
-echo "	let user_agent;\n";
-echo "	let session;\n";
-echo "	let answer_time;\n";
-echo "	var config = {\n";
-echo "		uri: '".$user_extension."@".$domain_name."',\n";
-echo "		ws_servers: 'wss://".$domain_name.":7443',\n";
-echo "		authorizationUser: '".$user_extension."',\n";
-echo "		password: atob('".base64_encode($user_password)."'),\n";
-echo "		registerExpires: 120,\n";
-echo "		displayName: \"".$user_extension."\"\n";
-echo "	};\n";
-?>
-
-	user_agent = new SIP.UA(config);
-
-	//here you determine whether the call has video and audio
-	var options = {
-		media: {
-			constraints: {
-				audio: true,
-				video: false
-			},
-			render: {
-				remote: document.getElementById('remote_video'),
-				local: document.getElementById('local_video')
-			},
-			RTCConstraints: {
-				"optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]
-			}
-		}
-	};
-
-	//answer
-	user_agent.on('invite', function (s) {
-
-		if (typeof session !== "undefined" && session.display_name != s.remoteIdentity.displayName) {
-			return;
-		}
-
-		//save the session to the global session
-		session = s;
-		session.display_name = session.remoteIdentity.displayName;
-		session.uri_user = session.remoteIdentity.uri.user;
-
-		//send the object to the browser console
-		//console.log(session);
-
-		//play the ringtone
-		document.getElementById('ringtone').play();
-
-		//add the caller ID
-		document.getElementById('ringing_caller_id').innerHTML = sanitize_string(session.display_name) + "<br /><a href='https://<?php echo $_SESSION['domain_name']; ?>/app/contacts/contacts.php?search=" + sanitize_string(session.uri_user) + "' target='_blank'>" + sanitize_string(session.uri_user) + "</a>";
-		document.getElementById('active_caller_id').innerHTML = sanitize_string(session.display_name) + "<br /><a href='https://<?php echo $_SESSION['domain_name']; ?>/app/contacts/contacts.php?search=" + sanitize_string(session.uri_user) + "' target='_blank'>" + sanitize_string(session.uri_user) + "</a>";
-
-		//show or hide the panels
-		document.getElementById('dialpad').style.display = "none";
-		document.getElementById('ringing').style.display = "inline";
-
-		//show or hide the buttons
-		document.getElementById('answer').style.display = "inline";
-		document.getElementById('decline').style.display = "inline";
-		document.getElementById('hangup').style.display = "none";
-		document.getElementById('mute_audio').style.display = "inline";
-		document.getElementById('mute_video').style.display = "none";
-
-		session.on('cancel', function (s) {
-			//play the ringtone
-			document.getElementById('ringtone').pause();
-
-			//show or hide the panels
-			document.getElementById('dialpad').style.display = "grid";
-			document.getElementById('ringing').style.display = "none";
-			document.getElementById('active').style.display = "none";
-
-			//show or hide the buttons
-			document.getElementById('answer').style.display = "none";
-			document.getElementById('decline').style.display = "none";
-			document.getElementById('hangup').style.display = "none";
-
-			//clear the caller id
-			document.getElementById('ringing_caller_id').innerHTML = '';
-			document.getElementById('active_caller_id').innerHTML = '';
-
-			//clear the answer time
-			answer_time = null;
-			
-			//end the call
-			hangup();
-		});
-
-		session.on('bye', function (s) {
-			//play the ringtone
-			document.getElementById('ringtone').pause();
-
-			//show or hide the panels
-			document.getElementById('dialpad').style.display = "grid";
-			document.getElementById('ringing').style.display = "none";
-			document.getElementById('active').style.display = "none";
-
-			//show or hide the buttons
-			document.getElementById('answer').style.display = "none";
-			document.getElementById('decline').style.display = "none";
-			document.getElementById('hangup').style.display = "none";
-
-			//clear the answer time
-			answer_time = null;
-
-			//end the call
-			hangup();
-		});
-
-		session.on('failed', function (s) {
-			//play the ringtone
-			document.getElementById('ringtone').pause();
-
-			//show or hide the panels
-			document.getElementById('dialpad').style.display = "grid";
-			document.getElementById('ringing').style.display = "none";
-			document.getElementById('active').style.display = "none";
-
-			//show or hide the buttons
-			document.getElementById('answer').style.display = "none";
-			document.getElementById('decline').style.display = "none";
-			document.getElementById('hangup').style.display = "none";
-
-			//clear the answer time
-			answer_time = null;
-
-			//end the call
-			hangup();
-		});
-
-		session.on('rejected', function (s) {
-			//play the ringtone
-			document.getElementById('ringtone').pause();
-
-			//show or hide the panels
-			document.getElementById('dialpad').style.display = "grid";
-			document.getElementById('ringing').style.display = "none";
-			document.getElementById('active').style.display = "none";
-
-			//show or hide the buttons
-			document.getElementById('answer').style.display = "none";
-			document.getElementById('decline').style.display = "none";
-			document.getElementById('hangup').style.display = "none";
-
-			//clear the answer time
-			answer_time = null;
-
-			//end the call
-			hangup();
-		});
-
-	});
-
-	function answer() {
-
-		//continue if the session exists
-		if (!session) {
-			return false;
-		}
-
-		//start the answer time
-		answer_time = Date.now();
-
-		//pause the ringtone
-		document.getElementById('ringtone').pause();
-
-		//answer the call
-		session.accept({
-			media: {
-				constraints: {
-					audio: true,
-					video: false
-				},
-				render: {
-					remote: document.getElementById('remote_video'),
-					local: document.getElementById('local_video')
-				},
-				RTCConstraints: {
-					"optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]
-				}
-			}
-		});
-
-		//show the or hide the panels
-		document.getElementById('dialpad').style.display = "none";
-		document.getElementById('ringing').style.display = "none";
-		document.getElementById('active').style.display = "grid";
-
-		//show or hide the buttons
-		document.getElementById('answer').style.display = "none";
-		document.getElementById('decline').style.display = "none";
-		document.getElementById('unhold').style.display = "none";
-		document.getElementById('hangup').style.display = "inline";
-	}
-
-	// Function to pad numbers with leading zeros
-	function pad(number, length) {
-		return (number < 10 ? '0' : '') + number;
-	}
-
-	//function to get the current time in seconds
-	function get_session_time() {
-		if (answer_time) {
-			// get the elapsed time using the answer time
-			elapsed_time = Date.now() - answer_time;
-
-			// Calculate hours, minutes, and seconds
-			var hours = Math.floor(elapsed_time / (1000 * 60 * 60));
-			var minutes = Math.floor((elapsed_time % (1000 * 60 * 60)) / (1000 * 60));
-			var seconds = Math.floor((elapsed_time % (1000 * 60)) / 1000);
-
-			// Format the time with leading zeros if necessary
-			var formatted_time = pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2);
-
-			// Update the element with id="elapsed-time" to display the formatted elapsed time
-			document.getElementById("answer_time").textContent = "Time Elapsed: " + formatted_time;
-		} else {
-			console.log('Call has not been answered yet');
-			return null;
-		}
-	}
-
-	//update elapsed time every second
-	setInterval(get_session_time, 1000);
-
-	//function used to end the session
-	function hangup() {
-
-		//end the session
-		//session.bye();
-		session.terminate();
-
-		//show or hide the panels
-		document.getElementById('dialpad').style.display = "grid";
-		document.getElementById('ringing').style.display = "none";
-		document.getElementById('active').style.display = "none";
-
-		//show or hide the buttons
-		document.getElementById('answer').style.display = "none";
-		document.getElementById('decline').style.display = "none";
-		document.getElementById('hangup').style.display = "none";
-
-		document.getElementById('local_video').style.display = "none";
-		document.getElementById('remote_video').style.display = "none";
-
-		document.getElementById('mute_audio').style.display = "none";
-		//document.getElementById('mute_video').style.display = "none";
-		document.getElementById('unmute_audio').style.display = "none";
-		//document.getElementById('unmute_video').style.display = "none";
-
-		//clear the caller id
-		document.getElementById('ringing_caller_id').innerHTML = '';
-		document.getElementById('active_caller_id').innerHTML = '';
-
-		//mute the audio
-		session.mute({audio: true});
-	}
-
-	function hold() {
-		document.getElementById('hold').style.display = "none";
-		document.getElementById('unhold').style.display = "grid";
-		session.hold();
-	}
-
-	function unhold() {
-		document.getElementById('hold').style.display = "grid";
-		document.getElementById('unhold').style.display = "none";
-		session.unhold();
-	}
-
-	function send() {
-
-		//get the destination number
-		destination = document.getElementById('destination').value;
-
-		//return immediately if there is no destination
-		if (destination.length == 0) {
-			return;
-		}
-
-		//show or hide the panels
-		document.getElementById('dialpad').style.display = "none";
-		document.getElementById('ringing').style.display = "none";
-		document.getElementById('active').style.display = "grid";
-
-		document.getElementById('answer').style.display = "none";
-		document.getElementById('decline').style.display = "none";
-		document.getElementById('hangup').style.display = "inline";
-		//document.getElementById('local_video').style.display = "inline";
-		//document.getElementById('remote_video').style.display = "inline";
-		document.getElementById('mute_audio').style.display = "inline";
-		//document.getElementById('mute_video').style.display = "inline";
-
-		//make a call using a sip invite
-		session = user_agent.invite('sip:'+destination+'@<?php echo $domain_name; ?>', options);
-
-		var remote_video = document.getElementById("remote_video");
-		remote_video.setAttribute("controls","controls");
-
-		//unmute the audio
-		session.unmute({audio: true});
-
-		//start the answer time
-		answer_time = Date.now();
-
-		//set the caller ID to the destination
-		document.getElementById('ringing_caller_id').innerHTML = destination;
-		document.getElementById('active_caller_id').innerHTML = destination;
-
-	}
-
-	function mute_audio(destination) {
-		session.mute({audio: true});
-		document.getElementById('mute_audio').style.display = "none";
-		document.getElementById('unmute_audio').style.display = "inline";
-	}
-
-	function mute_video(destination) {
-		session.mute({video: true});
-		document.getElementById('local_video').style.display = "none";
-		document.getElementById('mute_video').style.display = "none";
-		document.getElementById('unmute_video').style.display = "inline";
-	}
-
-	function unmute_audio(destination) {
-		session.unmute({audio: true});
-		document.getElementById('mute_audio').style.display = "inline";
-		document.getElementById('unmute_audio').style.display = "none";
-	}
-
-	function unmute_video(destination) {
-		session.unmute({video: true});
-		document.getElementById('local_video').style.display = "inline";
-		document.getElementById('mute_video').style.display = "inline";
-		document.getElementById('unmute_video').style.display = "none";
-	}
-
-	function digit_add($digit) {
-		document.getElementById('destination').value = document.getElementById('destination').value + $digit;
-	}
-
-	function digit_delete($digit) {
-		destination = document.getElementById('destination').value;
-		document.getElementById('destination').value = destination.substring(0, destination.length -1);
-	}
-
-	function digit_clear($digit) {
-		document.getElementById('destination').value = '';
-	}
-
-    //function to check for Enter key press
-	function send_enter_key(event) {
-		if (event.key === "Enter") {
-			send();
-		}
-	}
-
-	//add event listener for keydown event on input field
-	document.addEventListener("DOMContentLoaded", function() {
-		document.getElementById("destination").addEventListener("keydown", send_enter_key);
-	});
-
-</script>
-
-<div id='dialpad' class='dialpad' style='position:absolute;z-index:999;'>
-	<div style="align: left">
-		<input type="text" id="destination" name="destination" class="destination" value="" />
-	</div>
-	<div class="dialpad_wrapper">
-		<div class="dialpad_box" onclick="digit_add('1');"><strong>1</strong><sup>&nbsp;&nbsp;&nbsp;</sup></div>
-		<div class="dialpad_box"onclick="digit_add('2');"><strong>2</strong><sup>ABC</sup></div>
-		<div class="dialpad_box" onclick="digit_add('3');"><strong>3</strong><sup>DEF</sup></div>
-
-		<div class="dialpad_box" onclick="digit_add('4');"><strong>4</strong><sup>GHI</sup></div>
-		<div class="dialpad_box" onclick="digit_add('5');"><strong>5</strong><sup>JKL</sup></div>
-		<div class="dialpad_box" onclick="digit_add('6');"><strong>6</strong><sup>MNO</sup></div>
-
-		<div class="dialpad_box" onclick="digit_add('7');"><strong>7</strong><sup>PQRS</sup></div>
-		<div class="dialpad_box" onclick="digit_add('8');"><strong>8</strong><sup>TUV</sup></div>
-		<div class="dialpad_box" onclick="digit_add('9');"><strong>9</strong><sup>WXYZ</sup></div>
-
-		<div class="dialpad_box" onclick="digit_add('*');"><strong>*</strong><sup></sup></div>
-		<div class="dialpad_box" onclick="digit_add('0');"><strong>0</strong><sup></sup></div>
-		<div class="dialpad_box" onclick="digit_add('#');"><strong>#</strong><sup></sup></div>
-
-		<div class="dialpad_box" onclick="digit_clear();"><strong></strong><sup>CLEAR</sup></div>
-		<div class="dialpad_box" onclick="digit_delete();"><strong></strong><sup>DELETE</sup></div>
-		<div class="dialpad_box" onclick="send();"><strong></strong><sup>SEND</sup></div>
-	</div>
-</div>
-
-<div id='ringing' class='dialpad' style='position:absolute;z-index:100;display: none;'>
-	<div id="ringing_caller_id" class="caller_id"></div>
-	<div class="dialpad_wrapper">
-		<div id='answer' class="button_box" onclick="answer();"><sup>Answer</sup></div>
-		<div id='decline' class="button_box" onclick="hangup();"><sup>Decline</sup></div>
-	</div>
-</div>
-
-<div id='active' class='dialpad' style='position:absolute;z-index:100;display: none;'>
-	<div id="active_caller_id" class="caller_id"></div>
-	<div id="answer_time" class="button_box"></div>
-	<div class="dialpad_wrapper">
-		<div id='mute_audio' class="button_box" onclick="mute_audio();">Mute Audio</div>
-		<div id='unmute_audio' style='display: none;' class="button_box" onclick="unmute_audio();">Unmute Audio</div>
-
-		<div id='hold' class="button_box" onclick="hold();">Hold</div>
-		<div id='unhold' class="button_box" style='display: none;' onclick="unhold();">Unhold</div>
-
-		<div id='hangup' class="button_box" onclick="hangup();">Hangup</div>
-
-		<div id='mute_video' class="button_box" style='display: none;' onclick="mute_video()">&nbsp;</div>
-		<div id='umute_video' class="button_box" style='display: none;' onclick="unmute_video()">&nbsp;</div>
-	</div>
-</div>
-
-<style type="text/css" style="display: none;">
-
-	.destination {
-		/*background-color: #333333;*/
-		background-color: rgba(255, 255, 255, 0.5);
-		color: #333333;
-		border-radius: 5px;
-		padding: 10px;
-		margin: 3px;
-		width: 305px;
-	}
-
-	.dialpad_wrapper {
-		display: grid;
-		grid-template-columns: 100px 100px 100px;
-		grid-gap: 5px;
-		color: #444444;
-	}
-
-	.dialpad_box {
-		/*background-color: #333333;*/
-		background-color: rgba(0, 0, 0, 0.7);
-		color: #FFFFFF;
-		border-radius: 5px;
-		padding: 10px;
-	}
-
-	strong {
-		padding: 5px 5px;
-		color: #FFFFFF;
-		font-size: 30px;
-	}
-
-	sup {
-		padding: 3px 3px;
-		color: #FFFFFF;
-		font-size: 10px;
-	}
-
-	.button_box {
-		/*background-color: #333333;*/
-		background-color: rgba(0, 0, 0, 0.7);
-		color: #FFFFFF;
-		border-radius: 5px;
-		padding: 10px;
-		font-size: 12px;
-	}
-
-	.caller_id {
-		/*background-color: #333333;*/
-		text-align: center;
-		background-color: rgba(0, 0, 0, 0.7);
-		color: #FFFFFF;
-		border-radius: 5px;
-		padding: 100px;
-		font-size: 12px;
-		margin-bottom: 50px;
-	}
-
-</style>
+//set the title
+	$document['title'] = $text['title-phone'];
+
+//output
+echo "<html>\n";
+
+echo "<head>\n";
+echo "	<title>".$text['title-phone'].(!empty($_SESSION['theme']['title']['text']) ? ' - '.$_SESSION['theme']['title']['text'] : null)."</title>\n";
+echo "	<meta charset='utf-8'>\n";
+echo "	<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n";
+echo "	<meta http-equiv='X-UA-Compatible' content='IE=edge'>\n";
+echo "	<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' />\n";
+echo "	<meta name='robots' content='noindex, nofollow, noarchive' />\n";
+echo "	<link rel='stylesheet' type='text/css' href='".PROJECT_PATH."/resources/fontawesome/css/all.min.css.php'>\n";
+echo "	<link rel='stylesheet' type='text/css' href='resources/styles.css'>\n";
+echo "	<script language='JavaScript' type='text/javascript'>window.FontAwesomeConfig = { autoReplaceSvg: false }</script>\n";
+echo "	<script language='JavaScript' type='text/javascript' src='resources/sip-0.7.8.js'></script>\n";
+echo "	<script language='JavaScript' type='text/javascript'>";
+require 'resources/scripts.js';
+echo "	</script>\n";
+echo "</head>\n";
+
+echo "<body>\n";
+echo "	<div>\n";
+echo "		<div style='position: absolute;'><video id='remote_video' width='640' height='480' style='display: none;'></video></div>\n";
+echo "		<div style='position: absolute; display: none;'><video id='local_video' width='160' height='120' style='display: none;'></video></div>\n";
+//echo "	<input id='send' name='send' type='button' class='btn btn-success' onclick='send();' value='Send' />\n";
+echo "	</div>\n";
+
+echo "	<audio id='ringtone' preload='auto' style='display: none;'>\n";
+echo "		<source src='resources/ringtones/ringtone.mp3' type='audio/mpeg' loop='loop' />\n";
+echo "	</audio>\n";
+
+echo "	<div class='dialpad' id='dialpad'>\n";
+echo "		<input type='text' class='destination' id='destination' name='destination' />\n";
+echo "		<div class='dialpad_wrapper'>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('1');\"><strong>1</strong><br><sup>&nbsp;</sup></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('2');\"><strong>2</strong><br><sup>ABC</sup></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('3');\"><strong>3</strong><br><sup>DEF</sup></div>\n";
+
+echo "			<div class='dialpad_box' onclick=\"digit_add('4');\"><strong>4</strong><br><sup>GHI</sup></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('5');\"><strong>5</strong><br><sup>JKL</sup></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('6');\"><strong>6</strong><br><sup>MNO</sup></div>\n";
+
+echo "			<div class='dialpad_box' onclick=\"digit_add('7');\"><strong>7</strong><br><sup>PQRS</sup></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('8');\"><strong>8</strong><br><sup>TUV</sup></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('9');\"><strong>9</strong><br><sup>WXYZ</sup></div>\n";
+
+echo "			<div class='dialpad_box' onclick=\"digit_add('*');\" style='margin-bottom: 8px; padding-top: 20px; padding-bottom: 0;'><strong>*</strong></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('0');\" style='margin-bottom: 8px; padding-top: 15px; padding-bottom: 5px;'><strong>0</strong></div>\n";
+echo "			<div class='dialpad_box' onclick=\"digit_add('#');\" style='margin-bottom: 8px; padding-top: 15px; padding-bottom: 5px;'><strong>#</strong></div>\n";
+
+echo "			<div class='dialpad_box clear' onclick='digit_clear();' title=\"".$text['label-clear']."\"><i class='fas fa-times'></i><br><sup>".$text['label-clear']."</sup></div>\n";
+echo "			<div class='dialpad_box' onclick='send();' style='background-color: #147e00;' title=\"".$text['label-call']."\"><i class='fas fa-phone-alt'></i><br><sup>".$text['label-call']."</sup></div>\n";
+echo "			<div class='dialpad_box delete' onclick='digit_delete();' title=\"".$text['label-delete']."\"><i class='fas fa-chevron-left'></i><br><sup>".$text['label-delete']."</sup></div>\n";
+echo "		</div>\n";
+echo "	</div>\n";
+
+echo "	<div class='dialpad' id='ringing' style='display: none;'>\n";
+echo "		<div id='ringing_caller_id' class='caller_id'></div>\n";
+echo "		<div class='dialpad_wrapper'>\n";
+echo "			<div class='dialpad_box' id='answer' onclick='answer();' style='min-height: 20px; background-color: #147e00;'><i class='fas fa-phone' title=\"".$text['label-answer']."\"></i></div>\n";
+echo "			<div class='dialpad_box' id='decline' onclick='hangup();' style='min-height: 20px; background-color: #ba0000;'><i class='fas fa-phone-slash' title=\"".$text['label-decline']."\"></i></div>\n";
+echo "		</div>\n";
+echo "	</div>\n";
+
+echo "	<div class='dialpad' id='active' style='display: none;'>\n";
+echo "		<div class='caller_id' id='active_caller_id'></div>\n";
+echo "		<div id='answer_time' style='margin-bottom: 8px; text-align: center; color: #ccc; font-family: monospace; font-size: 14px; text-transform: uppercase;'>00:00:00</div>\n";
+echo "		<div class='dialpad_wrapper'>\n";
+echo "			<div class='dialpad_box mute' id='mute_audio' onclick='mute_audio();'><i class='fas fa-microphone' title=\"".$text['label-mute']."\"></i><br><sup>".$text['label-mute']."</sup></div>\n";
+echo "			<div class='dialpad_box' id='unmute_audio' style='color: #ba0000; display: none;' onclick='unmute_audio();'><i class='fas fa-microphone-slash' title=\"".$text['label-unmute']."\"></i><br><sup>".$text['label-unmute']."</sup></div>\n";
+
+echo "			<div class='dialpad_box' id='hangup' onclick='hangup();' style='background-color: #ba0000;'><i class='fas fa-phone-slash' title=\"".$text['label-end']."\"></i><br><sup>".$text['label-end']."</sup></div>\n";
+
+echo "			<div class='dialpad_box hold' id='hold' onclick='hold();'><i class='fas fa-pause' title=\"".$text['label-hold']."\"></i><br><sup>".$text['label-hold']."</sup></div>\n";
+echo "			<div class='dialpad_box' id='unhold' style='color: #1ba800; display: none;' onclick='unhold();'><i class='fas fa-play' title=\"".$text['label-resume']."\"></i><br><sup>".$text['label-resume']."</sup></div>\n";
+
+echo "			<div class='dialpad_box' id='mute_video' style='display: none;' onclick='mute_video();'>&nbsp;</div>\n";
+echo "			<div class='dialpad_box' id='umute_video' style='display: none;' onclick='unmute_video();'>&nbsp;</div>\n";
+echo "		</div>\n";
+echo "	</div>\n";
+echo "</body>\n";
+
+echo "</html>\n";

+ 416 - 0
resources/scripts.js

@@ -0,0 +1,416 @@
+function sanitize_string(str) {
+	let temp = document.createElement('div');
+	temp.textContent = str;
+	return temp.innerHTML;
+}
+
+let user_agent;
+let session;
+let answer_time;
+var config = {
+	uri: '<?php echo $user_extension.'@'.$domain_name; ?>',
+	ws_servers: 'wss://<?php echo $domain_name; ?>:7443',
+	authorizationUser: '<?php echo $user_extension; ?>',
+	password: atob('<?php echo base64_encode($user_password); ?>'),
+	registerExpires: 120,
+	displayName: "<?php echo $user_extension; ?>"
+};
+
+user_agent = new SIP.UA(config);
+
+//here you determine whether the call has video and audio
+var options = {
+	media: {
+		constraints: {
+			audio: true,
+			video: false
+		},
+		render: {
+			remote: document.getElementById('remote_video'),
+			local: document.getElementById('local_video')
+		},
+		RTCConstraints: {
+			"optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]
+		}
+	}
+};
+
+//answer
+user_agent.on('invite', function (s) {
+
+	if (typeof session !== "undefined" && session.display_name != s.remoteIdentity.displayName) {
+		return;
+	}
+
+	//save the session to the global session
+	session = s;
+	session.display_name = session.remoteIdentity.displayName;
+	session.uri_user = session.remoteIdentity.uri.user;
+
+	//send the object to the browser console
+	//console.log(session);
+
+	//play the ringtone
+	document.getElementById('ringtone').play();
+
+	//add the caller ID
+	document.getElementById('ringing_caller_id').innerHTML = sanitize_string(session.display_name) + "<br /><a href='https://<?php echo $_SESSION['domain_name']; ?>/app/contacts/contacts.php?search=" + sanitize_string(session.uri_user) + "' target='_blank'>" + sanitize_string(session.uri_user) + "</a>";
+	document.getElementById('active_caller_id').innerHTML = sanitize_string(session.display_name) + "<br /><a href='https://<?php echo $_SESSION['domain_name']; ?>/app/contacts/contacts.php?search=" + sanitize_string(session.uri_user) + "' target='_blank'>" + sanitize_string(session.uri_user) + "</a>";
+
+	//show or hide the panels
+	document.getElementById('dialpad').style.display = "none";
+	document.getElementById('ringing').style.display = "inline";
+
+	//show or hide the buttons
+	document.getElementById('answer').style.display = "inline";
+	document.getElementById('decline').style.display = "inline";
+	document.getElementById('hangup').style.display = "none";
+	document.getElementById('mute_audio').style.display = "inline";
+	document.getElementById('mute_video').style.display = "none";
+
+	session.on('cancel', function (s) {
+		//play the ringtone
+		document.getElementById('ringtone').pause();
+
+		//show or hide the panels
+		document.getElementById('dialpad').style.display = "grid";
+		document.getElementById('ringing').style.display = "none";
+		document.getElementById('active').style.display = "none";
+
+		//show or hide the buttons
+		document.getElementById('answer').style.display = "none";
+		document.getElementById('decline').style.display = "none";
+		document.getElementById('hangup').style.display = "none";
+
+		//clear the caller id
+		document.getElementById('ringing_caller_id').innerHTML = '';
+	document.getElementById('active_caller_id').innerHTML = '';
+
+	//clear the answer time
+	answer_time = null;
+
+	//end the call
+	hangup();
+	});
+
+	session.on('bye', function (s) {
+		//play the ringtone
+		document.getElementById('ringtone').pause();
+
+		//show or hide the panels
+		document.getElementById('dialpad').style.display = "grid";
+		document.getElementById('ringing').style.display = "none";
+		document.getElementById('active').style.display = "none";
+
+		//show or hide the buttons
+		document.getElementById('answer').style.display = "none";
+		document.getElementById('decline').style.display = "none";
+		document.getElementById('hangup').style.display = "none";
+
+		//clear the answer time
+		answer_time = null;
+
+		//end the call
+		hangup();
+	});
+
+	session.on('failed', function (s) {
+		//play the ringtone
+		document.getElementById('ringtone').pause();
+
+		//show or hide the panels
+		document.getElementById('dialpad').style.display = "grid";
+		document.getElementById('ringing').style.display = "none";
+		document.getElementById('active').style.display = "none";
+
+		//show or hide the buttons
+		document.getElementById('answer').style.display = "none";
+		document.getElementById('decline').style.display = "none";
+		document.getElementById('hangup').style.display = "none";
+
+		//clear the answer time
+		answer_time = null;
+
+		//end the call
+		hangup();
+	});
+
+	session.on('rejected', function (s) {
+		//play the ringtone
+		document.getElementById('ringtone').pause();
+
+		//show or hide the panels
+		document.getElementById('dialpad').style.display = "grid";
+		document.getElementById('ringing').style.display = "none";
+		document.getElementById('active').style.display = "none";
+
+		//show or hide the buttons
+		document.getElementById('answer').style.display = "none";
+		document.getElementById('decline').style.display = "none";
+		document.getElementById('hangup').style.display = "none";
+
+		//clear the answer time
+		answer_time = null;
+
+		//end the call
+		hangup();
+	});
+
+});
+
+function answer() {
+
+	//continue if the session exists
+	if (!session) {
+		return false;
+	}
+
+	//start the answer time
+	answer_time = Date.now();
+
+	//pause the ringtone
+	document.getElementById('ringtone').pause();
+
+	//answer the call
+	session.accept({
+		media: {
+			constraints: {
+				audio: true,
+				video: false
+			},
+				render: {
+					remote: document.getElementById('remote_video'),
+					local: document.getElementById('local_video')
+				},
+				RTCConstraints: {
+					"optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]
+				}
+		}
+	});
+
+	//show the or hide the panels
+	document.getElementById('dialpad').style.display = "none";
+	document.getElementById('ringing').style.display = "none";
+	document.getElementById('active').style.display = "grid";
+	document.getElementById('destination').value = '';
+
+	//show or hide the buttons
+	document.getElementById('answer').style.display = "none";
+	document.getElementById('decline').style.display = "none";
+	document.getElementById('unhold').style.display = "none";
+	document.getElementById('hangup').style.display = "inline";
+}
+
+// Function to pad numbers with leading zeros
+function pad(number, length) {
+	return (number < 10 ? '0' : '') + number;
+}
+
+//function to get the current time in seconds
+function get_session_time() {
+	if (answer_time) {
+		// get the elapsed time using the answer time
+		elapsed_time = Date.now() - answer_time;
+
+		// Calculate hours, minutes, and seconds
+		var hours = Math.floor(elapsed_time / (1000 * 60 * 60));
+		var minutes = Math.floor((elapsed_time % (1000 * 60 * 60)) / (1000 * 60));
+		var seconds = Math.floor((elapsed_time % (1000 * 60)) / 1000);
+
+		// Format the time with leading zeros if necessary
+		var formatted_time = pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2);
+
+		// Update the element with id="elapsed-time" to display the formatted elapsed time
+		document.getElementById("answer_time").textContent = formatted_time;
+	}
+	else {
+		console.log('Call has not been answered yet');
+		return null;
+	}
+}
+
+//update elapsed time every second
+setInterval(get_session_time, 1000);
+
+//function used to end the session
+function hangup() {
+
+	//end the session
+	//session.bye();
+	session.terminate();
+
+	//show or hide the panels
+	document.getElementById('dialpad').style.display = "grid";
+	document.getElementById('ringing').style.display = "none";
+	document.getElementById('active').style.display = "none";
+
+	//show or hide the buttons
+	document.getElementById('answer').style.display = "none";
+	document.getElementById('decline').style.display = "none";
+	document.getElementById('hangup').style.display = "none";
+
+	document.getElementById('local_video').style.display = "none";
+	document.getElementById('remote_video').style.display = "none";
+
+	document.getElementById('mute_audio').style.display = "none";
+	//document.getElementById('mute_video').style.display = "none";
+	document.getElementById('unmute_audio').style.display = "none";
+	//document.getElementById('unmute_video').style.display = "none";
+
+	document.getElementById('unhold').style.display = "none";
+	document.getElementById('hold').style.display = "inline";
+
+	//clear the caller id and timer
+	document.getElementById('ringing_caller_id').innerHTML = '';
+	document.getElementById('active_caller_id').innerHTML = '';
+	document.getElementById('answer_time').innerHTML = '00:00:00';
+
+	//mute the audio
+	session.mute({audio: true});
+}
+
+function hold() {
+	document.getElementById('hold').style.display = "none";
+	document.getElementById('unhold').style.display = "inline";
+	session.hold();
+}
+
+function unhold() {
+	document.getElementById('hold').style.display = "inline";
+	document.getElementById('unhold').style.display = "none";
+	session.unhold();
+}
+
+function send() {
+
+	//get the destination number
+	destination = document.getElementById('destination').value;
+
+	//return immediately if there is no destination
+	if (destination.length == 0) {
+		return;
+	}
+
+	//show or hide the panels
+	document.getElementById('dialpad').style.display = "none";
+	document.getElementById('ringing').style.display = "none";
+	document.getElementById('active').style.display = "grid";
+
+	document.getElementById('answer').style.display = "none";
+	document.getElementById('decline').style.display = "none";
+	document.getElementById('hangup').style.display = "inline";
+	//document.getElementById('local_video').style.display = "inline";
+	//document.getElementById('remote_video').style.display = "inline";
+	document.getElementById('mute_audio').style.display = "inline";
+	//document.getElementById('mute_video').style.display = "inline";
+
+	//make a call using a sip invite
+	session = user_agent.invite('sip:'+destination+'@<?php echo $domain_name; ?>', options);
+
+	var remote_video = document.getElementById("remote_video");
+	remote_video.setAttribute("controls","controls");
+
+	//unmute the audio
+	session.unmute({audio: true});
+
+	//start the answer time
+	answer_time = Date.now();
+
+	//set the caller ID to the destination
+	document.getElementById('ringing_caller_id').innerHTML = destination;
+	document.getElementById('active_caller_id').innerHTML = destination;
+
+}
+
+function mute_audio(destination) {
+	session.mute({audio: true});
+	document.getElementById('mute_audio').style.display = "none";
+	document.getElementById('unmute_audio').style.display = "inline";
+}
+
+function mute_video(destination) {
+	session.mute({video: true});
+	document.getElementById('local_video').style.display = "none";
+	document.getElementById('mute_video').style.display = "none";
+	document.getElementById('unmute_video').style.display = "inline";
+}
+
+function unmute_audio(destination) {
+	session.unmute({audio: true});
+	document.getElementById('mute_audio').style.display = "inline";
+	document.getElementById('unmute_audio').style.display = "none";
+}
+
+function unmute_video(destination) {
+	session.unmute({video: true});
+	document.getElementById('local_video').style.display = "inline";
+	document.getElementById('mute_video').style.display = "inline";
+	document.getElementById('unmute_video').style.display = "none";
+}
+
+//function to center entered digits until full, then right-align and change text direction so last entered digits are always visible
+function correct_alignment() {
+	if (document.getElementById('destination').scrollWidth > document.getElementById('destination').clientWidth) {
+		document.getElementById('destination').style.textAlign = 'right';
+		document.getElementById('destination').style.direction = 'rtl';
+	}
+	else {
+		document.getElementById('destination').style.textAlign = 'center';
+		document.getElementById('destination').style.direction = 'ltr';
+	}
+}
+
+function digit_add($digit) {
+	document.getElementById('destination').value = document.getElementById('destination').value + $digit;
+	correct_alignment();
+}
+
+function digit_delete() {
+	destination = document.getElementById('destination').value;
+	document.getElementById('destination').value = destination.substring(0, destination.length -1);
+	correct_alignment();
+}
+
+function digit_clear() {
+	document.getElementById('destination').value = '';
+	correct_alignment();
+}
+
+//function to check for Enter key press
+function send_enter_key(event) {
+	if (event.key === "Enter") {
+		send();
+	}
+}
+
+//function to detect numberpad keypresses
+document.addEventListener('keyup', function(e) {
+	if (document.getElementById('destination')) { //destination field is visible
+		if (
+			(e.which >= 48 && e.which <= 57) || //numbers
+			(e.which >= 96 && e.which <= 105) || //number pad
+			(e.which == 56 || e.which == 106) || //asterisk
+			(e.which == 51) //pound
+			) {
+			e.preventDefault();
+			digit_add(e.key);
+		}
+		if (e.which == 8 || e.which == 46) { //backspace or delete
+			e.preventDefault();
+			digit_delete();
+		}
+		if (e.which == 27) { //escape
+			e.preventDefault();
+			digit_clear();
+		}
+		if (e.which == 13) { //enter
+			e.preventDefault();
+			send();
+		}
+	}
+});
+
+//add event listener for keydown event on input field
+document.addEventListener("DOMContentLoaded", function() {
+	document.getElementById("destination").addEventListener("keydown", send_enter_key);
+});

+ 117 - 0
resources/styles.css

@@ -0,0 +1,117 @@
+.dialpad {
+	z-index: 999;
+	}
+
+body {
+	background-color: #333;
+	}
+
+.inner {
+	position: absolute;
+	}
+
+.buttons{
+	position: fixed;
+	bottom: 0;
+	right: 0;
+	border: 10px solid rgba(255, 255, 255, 0);
+	}
+
+.destination {
+	background-color: rgba(0, 0, 0, 0.8);
+	color: #fff;
+	border-radius: 6px;
+	padding: 10px;
+	width: 100%;
+	margin-bottom: 8px;
+	font-size: 45px;
+	font-weight: bold;
+	border: 3px solid #333;
+	text-align: center;
+	min-height: 10%;
+	display: inline-block;
+	}
+
+.dialpad_wrapper {
+	display: grid;
+	grid-template-columns: 33.33% 33.33% 33.33%;
+	grid-gap: 0;
+	color: #444;
+	}
+
+.dialpad_box {
+	background-color: rgba(0, 0, 0, 0.6);
+	color: #fff;
+	border-radius: 6px;
+	padding: 10px;
+	min-height: 42px;
+	text-align: center;
+	cursor: pointer;
+	-webkit-user-select: none;
+	-moz-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+	border: 3px solid #333;
+	}
+
+.dialpad_box::selection {
+	background: transparent;
+	}
+
+.dialpad_box > strong {
+	font-size: 25px;
+	line-height: 27px;
+	}
+
+.dialpad_box > i.fas {
+	font-size: 20px;
+	line-height: 15px;
+	padding: 5px 0 5px 0;
+	}
+
+.dialpad_box.delete {
+	background-color: #333;
+	}
+
+.dialpad_box.clear {
+	background-color: #333;
+	}
+
+.dialpad_box.mute {
+	background-color: #333;
+	}
+
+.dialpad_box.hold {
+	background-color: #333;
+	}
+
+strong {
+	font-family: monospace;
+	padding: 5px 5px;
+	color: #fff;
+	font-size: 30px;
+	}
+
+sup {
+	font-family: monospace;
+	letter-spacing: 0;
+	padding: 3px 3px;
+	color: #fff;
+	font-size: 10px;
+	}
+
+.caller_id {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	background-color: rgba(0, 0, 0, 0.7);
+	font-size: 45px;
+	font-weight: bold;
+	font-family: sans-serif;
+	border: 3px solid #333;
+	border-radius: 5px;
+	color: #fff;
+	padding: 20px;
+	margin-bottom: 8px;
+	min-height: 295px;
+	}