Issue
Code backup
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
(function (root, factory) {
|
||||
"use strict";
|
||||
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
}
|
||||
else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory();
|
||||
}
|
||||
else {
|
||||
root.webphone_api.picoModal = factory();
|
||||
}
|
||||
}(this, function () {
|
||||
|
||||
/**
|
||||
* A self-contained modal library
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/** Returns whether a value is a dom node */
|
||||
function isNode(value) {
|
||||
if ( typeof Node === "object" ) {
|
||||
return value instanceof Node;
|
||||
}
|
||||
else {
|
||||
return value &&
|
||||
typeof value === "object" &&
|
||||
typeof value.nodeType === "number";
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns whether a value is a string */
|
||||
function isString(value) {
|
||||
return typeof value === "string";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates observable objects that can be watched and triggered
|
||||
*/
|
||||
function observable() {
|
||||
var callbacks = [];
|
||||
return {
|
||||
watch: callbacks.push.bind(callbacks),
|
||||
trigger: function( modal ) {
|
||||
|
||||
var unprevented = true;
|
||||
var event = {
|
||||
preventDefault: function preventDefault () {
|
||||
unprevented = false;
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0; i < callbacks.length; i++) {
|
||||
callbacks[i](modal, event);
|
||||
}
|
||||
|
||||
return unprevented;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A small interface for creating and managing a dom element
|
||||
*/
|
||||
function Elem( elem ) {
|
||||
this.elem = elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new div
|
||||
*/
|
||||
Elem.div = function ( parent ) {
|
||||
var elem = document.createElement('div');
|
||||
(parent || document.body).appendChild(elem);
|
||||
return new Elem(elem);
|
||||
};
|
||||
|
||||
Elem.prototype = {
|
||||
|
||||
/** Creates a child of this node */
|
||||
child: function () {
|
||||
return Elem.div(this.elem);
|
||||
},
|
||||
|
||||
/** Applies a set of styles to an element */
|
||||
stylize: function(styles) {
|
||||
styles = styles || {};
|
||||
|
||||
if ( typeof styles.opacity !== "undefined" ) {
|
||||
styles.filter =
|
||||
"alpha(opacity=" + (styles.opacity * 100) + ")";
|
||||
}
|
||||
|
||||
for (var prop in styles) {
|
||||
if (styles.hasOwnProperty(prop)) {
|
||||
this.elem.style[prop] = styles[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Adds a class name */
|
||||
clazz: function (clazz) {
|
||||
this.elem.className += " " + clazz;
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Sets the HTML */
|
||||
html: function (content) {
|
||||
if ( isNode(content) ) {
|
||||
this.elem.appendChild( content );
|
||||
}
|
||||
else {
|
||||
this.elem.innerHTML = content;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Adds a click handler to this element */
|
||||
onClick: function(callback) {
|
||||
this.elem.addEventListener('click', callback);
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Removes this element from the DOM */
|
||||
destroy: function() {
|
||||
document.body.removeChild(this.elem);
|
||||
},
|
||||
|
||||
/** Hides this element */
|
||||
hide: function() {
|
||||
this.elem.style.display = "none";
|
||||
},
|
||||
|
||||
/** Shows this element */
|
||||
show: function() {
|
||||
this.elem.style.display = "block";
|
||||
},
|
||||
|
||||
/** Sets an attribute on this element */
|
||||
attr: function ( name, value ) {
|
||||
this.elem.setAttribute(name, value);
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Executes a callback on all the ancestors of an element */
|
||||
anyAncestor: function ( predicate ) {
|
||||
var elem = this.elem;
|
||||
while ( elem ) {
|
||||
if ( predicate( new Elem(elem) ) ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
elem = elem.parentNode;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Generates the grey-out effect */
|
||||
function buildOverlay( getOption, close ) {
|
||||
return Elem.div()
|
||||
.clazz("pico-overlay")
|
||||
.clazz( getOption("overlayClass", "") )
|
||||
.stylize({
|
||||
display: "none",
|
||||
position: "fixed",
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
zIndex: 10000
|
||||
})
|
||||
.stylize(getOption('overlayStyles', {
|
||||
opacity: 0.5,
|
||||
background: "#000"
|
||||
}))
|
||||
.onClick(function () {
|
||||
if ( getOption('overlayClose', true) ) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Builds the content of a modal */
|
||||
function buildModal( getOption, close ) {
|
||||
var width = getOption('width', 'auto');
|
||||
if ( typeof width === "number" ) {
|
||||
width = "" + width + "px";
|
||||
}
|
||||
|
||||
var elem = Elem.div()
|
||||
.clazz("pico-content")
|
||||
.clazz( getOption("modalClass", "") )
|
||||
.stylize({
|
||||
display: 'none',
|
||||
position: 'fixed',
|
||||
zIndex: 10001,
|
||||
left: "50%",
|
||||
top: "50px",
|
||||
width: width,
|
||||
'-ms-transform': 'translateX(-50%)',
|
||||
'-moz-transform': 'translateX(-50%)',
|
||||
'-webkit-transform': 'translateX(-50%)',
|
||||
'-o-transform': 'translateX(-50%)',
|
||||
'transform': 'translateX(-50%)'
|
||||
})
|
||||
.stylize(getOption('modalStyles', {
|
||||
backgroundColor: "white",
|
||||
padding: "20px",
|
||||
borderRadius: "5px"
|
||||
}))
|
||||
.html( getOption('content') )
|
||||
.attr("role", "dialog")
|
||||
.onClick(function (event) {
|
||||
var isCloseClick = new Elem(event.target)
|
||||
.anyAncestor(function (elem) {
|
||||
return /\bpico-close\b/.test(elem.elem.className);
|
||||
});
|
||||
if ( isCloseClick ) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
/** Builds the close button */
|
||||
function buildClose ( elem, getOption ) {
|
||||
if ( getOption('closeButton', true) ) {
|
||||
return elem.child()
|
||||
.html( getOption('closeHtml', "×") )
|
||||
.clazz("pico-close")
|
||||
.clazz( getOption("closeClass") )
|
||||
.stylize( getOption('closeStyles', {
|
||||
borderRadius: "2px",
|
||||
cursor: "pointer",
|
||||
height: "15px",
|
||||
width: "15px",
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
right: "5px",
|
||||
fontSize: "16px",
|
||||
textAlign: "center",
|
||||
lineHeight: "15px",
|
||||
background: "#CCC"
|
||||
}) );
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds a method that calls a method and returns an element */
|
||||
function buildElemAccessor( builder ) {
|
||||
return function () {
|
||||
return builder().elem;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays a modal
|
||||
*/
|
||||
return function picoModal(options) {
|
||||
|
||||
if ( isString(options) || isNode(options) ) {
|
||||
options = { content: options };
|
||||
}
|
||||
|
||||
var afterCreateEvent = observable();
|
||||
var beforeShowEvent = observable();
|
||||
var afterShowEvent = observable();
|
||||
var beforeCloseEvent = observable();
|
||||
var afterCloseEvent = observable();
|
||||
|
||||
/**
|
||||
* Returns a named option if it has been explicitly defined. Otherwise,
|
||||
* it returns the given default value
|
||||
*/
|
||||
function getOption ( opt, defaultValue ) {
|
||||
var value = options[opt];
|
||||
if ( typeof value === "function" ) {
|
||||
value = value( defaultValue );
|
||||
}
|
||||
return value === undefined ? defaultValue : value;
|
||||
}
|
||||
|
||||
/** Hides this modal */
|
||||
function forceClose () {
|
||||
shadowElem().hide();
|
||||
modalElem().hide();
|
||||
afterCloseEvent.trigger(iface);
|
||||
}
|
||||
|
||||
/** Gracefully hides this modal */
|
||||
function close () {
|
||||
if ( beforeCloseEvent.trigger(iface) ) {
|
||||
forceClose();
|
||||
}
|
||||
}
|
||||
|
||||
/** Wraps a method so it returns the modal interface */
|
||||
function returnIface ( callback ) {
|
||||
return function () {
|
||||
callback.apply(this, arguments);
|
||||
return iface;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// The constructed dom nodes
|
||||
var built;
|
||||
|
||||
/** Builds a method that calls a method and returns an element */
|
||||
function build ( name ) {
|
||||
if ( !built ) {
|
||||
var modal = buildModal(getOption, close);
|
||||
built = {
|
||||
modal: modal,
|
||||
overlay: buildOverlay(getOption, close),
|
||||
close: buildClose(modal, getOption)
|
||||
};
|
||||
afterCreateEvent.trigger(iface);
|
||||
}
|
||||
return built[name];
|
||||
}
|
||||
|
||||
var modalElem = build.bind(window, 'modal');
|
||||
var shadowElem = build.bind(window, 'overlay');
|
||||
var closeElem = build.bind(window, 'close');
|
||||
|
||||
|
||||
var iface = {
|
||||
|
||||
/** Returns the wrapping modal element */
|
||||
modalElem: buildElemAccessor(modalElem),
|
||||
|
||||
/** Returns the close button element */
|
||||
closeElem: buildElemAccessor(closeElem),
|
||||
|
||||
/** Returns the overlay element */
|
||||
overlayElem: buildElemAccessor(shadowElem),
|
||||
|
||||
/** Builds the dom without showing the modal */
|
||||
buildDom: returnIface(build),
|
||||
|
||||
/** Shows this modal */
|
||||
show: function () {
|
||||
if ( beforeShowEvent.trigger(iface) ) {
|
||||
shadowElem().show();
|
||||
closeElem();
|
||||
modalElem().show();
|
||||
afterShowEvent.trigger(iface);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** Hides this modal */
|
||||
close: returnIface(close),
|
||||
|
||||
/**
|
||||
* Force closes this modal. This will not call beforeClose
|
||||
* events and will just immediately hide the modal
|
||||
*/
|
||||
forceClose: returnIface(forceClose),
|
||||
|
||||
/** Destroys this modal */
|
||||
destroy: function () {
|
||||
modalElem = modalElem().destroy();
|
||||
shadowElem = shadowElem().destroy();
|
||||
closeElem = undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the options for this modal. This will only let you
|
||||
* change options that are re-evaluted regularly, such as
|
||||
* `overlayClose`.
|
||||
*/
|
||||
options: function ( opts ) {
|
||||
options = opts;
|
||||
},
|
||||
|
||||
/** Executes after the DOM nodes are created */
|
||||
afterCreate: returnIface(afterCreateEvent.watch),
|
||||
|
||||
/** Executes a callback before this modal is closed */
|
||||
beforeShow: returnIface(beforeShowEvent.watch),
|
||||
|
||||
/** Executes a callback after this modal is shown */
|
||||
afterShow: returnIface(afterShowEvent.watch),
|
||||
|
||||
/** Executes a callback before this modal is closed */
|
||||
beforeClose: returnIface(beforeCloseEvent.watch),
|
||||
|
||||
/** Executes a callback after this modal is closed */
|
||||
afterClose: returnIface(afterCloseEvent.watch)
|
||||
};
|
||||
|
||||
return iface;
|
||||
};
|
||||
|
||||
}));
|
||||
@@ -0,0 +1 @@
|
||||
JavaScript files for the techdemo_example.html sample
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,786 @@
|
||||
var serveraddress_input = null; // serveraddress input field
|
||||
var sipusername_input = null; // sip account username input field
|
||||
var username_input = null; // sip account username input field
|
||||
var password_input = null; // sip account password input field
|
||||
var destination_input = null; // destination number or SIP URI input field
|
||||
var td_started = false;
|
||||
|
||||
function InitializeTextInputs()
|
||||
{
|
||||
if (isNull(serveraddress_input))
|
||||
{
|
||||
serveraddress_input = document.getElementById('serveraddress');
|
||||
sipusername_input = document.getElementById('sipusername');
|
||||
username_input = document.getElementById('username');
|
||||
password_input = document.getElementById('password');
|
||||
destination_input = document.getElementById('destinationnr');
|
||||
}
|
||||
}
|
||||
|
||||
function Start() // function called on "Register" button click to start the webphone
|
||||
{
|
||||
td_started = true;
|
||||
InitializeTextInputs();
|
||||
|
||||
SaveSettings();
|
||||
|
||||
DisplayStatus('EVENT, Initializing...');
|
||||
|
||||
webphone_api.start();
|
||||
|
||||
// populate advanced settings form
|
||||
PopulateSettings();
|
||||
}
|
||||
|
||||
// Wait until the webphone is loaded, before calling any API functions
|
||||
// if automatic start is required, then webphone_api.start() should be called "onLoaded" event like this:
|
||||
// webphone_api.onAppStateChange(function (state)
|
||||
// {
|
||||
// if (state === 'loaded')
|
||||
// {
|
||||
// webphone_api.start();
|
||||
// }
|
||||
// });
|
||||
webphone_api.onAppStateChange(function (state)
|
||||
{
|
||||
if (state === 'loaded')
|
||||
{
|
||||
InitializeTextInputs();
|
||||
PopulateSettings();
|
||||
|
||||
var autostart = webphone_api.getparameter('autostart');
|
||||
if(1 == 1 || autostart.length < 1)
|
||||
{
|
||||
webphone_api.setparameter('autostart',0); //precent auto-start by default
|
||||
}
|
||||
|
||||
var serveraddress = webphone_api.getparameter('serveraddress');
|
||||
if (serveraddress.length < 1) { serveraddress = webphone_api.getparameter('serveraddress_user'); } // only for demo
|
||||
var sipusername = webphone_api.getparameter('sipusername');
|
||||
var password = webphone_api.getparameter('password');
|
||||
var destination = webphone_api.getparameter('destination');
|
||||
|
||||
if (serveraddress.length > 0) { serveraddress_input.value = serveraddress; }
|
||||
if (sipusername.length > 0) { sipusername_input.value = sipusername; }
|
||||
if (password.length > 0) { password_input.value = password; }
|
||||
if (destination.length > 0) { destination_input.value = destination; }
|
||||
|
||||
var rcolumn = document.getElementById('right_column');
|
||||
var btnadv = document.getElementById('btn_advanced_sett');
|
||||
if (isNull(rcolumn) || isNull(btnadv)) { return; }
|
||||
|
||||
if (rcolumn.style.display === 'none')
|
||||
{
|
||||
btnadv.innerHTML = 'Show more settings';
|
||||
}else
|
||||
{
|
||||
btnadv.innerHTML = 'Hide Other Settings';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** Initiate call to a number, sip username or SIP URI.*/
|
||||
function Call()
|
||||
{
|
||||
InitializeTextInputs();
|
||||
if(!td_started)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
var destnr = destination_input.value;
|
||||
|
||||
if (isNull(destnr) || (Trim(destnr)).length < 1)
|
||||
{
|
||||
DisplayStatus('ERROR Invalid destination number');
|
||||
return;
|
||||
}
|
||||
webphone_api.setparameter('destination', destnr, false);
|
||||
|
||||
webphone_api.call(Trim(destnr));
|
||||
}
|
||||
|
||||
/** Disconnect current call(s).*/
|
||||
function Hangup()
|
||||
{
|
||||
webphone_api.hangup();
|
||||
}
|
||||
|
||||
/** Connect incoming call*/
|
||||
function Accept()
|
||||
{
|
||||
webphone_api.accept();
|
||||
}
|
||||
|
||||
/** Disconnect incoming call.*/
|
||||
function Reject(reason)
|
||||
{
|
||||
webphone_api.reject(null, reason);
|
||||
}
|
||||
|
||||
/** This callback function will be called on every call state change.
|
||||
* --PARAMETERS --
|
||||
* status: can have following values: callSetup, callRinging, callConnected, callDisconnected
|
||||
* direction: 1 (outgoing), 2 (incoming)
|
||||
* peername: is the other party username
|
||||
* peerdisplayname: is the other party display name if any
|
||||
* line: the status refers to this line*/
|
||||
webphone_api.onCallStateChange(function (status, direction, peername, peerdisplayname, line)
|
||||
{
|
||||
if (status === 'setup')
|
||||
{
|
||||
ringingNumber = peername;
|
||||
|
||||
// if it's an incoming call, then display popup with Accept/Reject buttons
|
||||
if (direction === 2)
|
||||
{
|
||||
AcceptRejectPopup(ringingNumber);
|
||||
}
|
||||
}
|
||||
else if (status === 'disconnected')
|
||||
{
|
||||
// close AcceptReseject popup on call finished, if it's still open
|
||||
if (!isNull(armodal))
|
||||
{
|
||||
armodal.close();
|
||||
armodal = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** display / hide chat form*/
|
||||
function ShowHideChat()
|
||||
{
|
||||
if ($('#chat_box').is(':visible')) { $('#chat_box').hide(); } else { $('#chat_box').show(); }
|
||||
}
|
||||
|
||||
/** Send a chat message. (SIP MESSAGE method after RFC 3428)*/
|
||||
function SendChat()
|
||||
{
|
||||
InitializeTextInputs();
|
||||
var msgF = document.getElementById('message');
|
||||
|
||||
var to = destination_input.value;
|
||||
var msg = msgF.value;
|
||||
|
||||
if (isNull(to) || (Trim(to)).length < 1)
|
||||
{
|
||||
DisplayStatus('ERROR, Invalid chat destination number');
|
||||
destination_input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNull(msg) || (Trim(msg)).length < 1)
|
||||
{
|
||||
DisplayStatus('ERROR, Enter chat message to be sent');
|
||||
msgF.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
msgF.value = '';
|
||||
|
||||
// Displays messages in chat form window
|
||||
AddMessageToHistory('Me', msg);
|
||||
|
||||
webphone_api.sendchat(to, msg);
|
||||
}
|
||||
|
||||
/** Receive incoming messages*/
|
||||
webphone_api.onChat(function (from, msg, line)
|
||||
{
|
||||
InitializeTextInputs();
|
||||
if (isNull(from) || isNull(msg)) { return; }
|
||||
|
||||
var currdest = destination_input.value;
|
||||
|
||||
if (isNull(currdest) || (Trim(currdest)).length < 1)
|
||||
{
|
||||
destination_input.value = from;
|
||||
}else
|
||||
{
|
||||
if (Trim(currdest) !== from)
|
||||
{
|
||||
AddMessageToHistory('', '<br />###############################<br />');
|
||||
destination_input.value = from;
|
||||
}
|
||||
}
|
||||
|
||||
// Displays messages in chat form window
|
||||
AddMessageToHistory(from, msg);
|
||||
});
|
||||
|
||||
/** Displays sent/received messages in chat form window*/
|
||||
function AddMessageToHistory(to, message)
|
||||
{
|
||||
var sentmsgF = document.getElementById('msg_list');
|
||||
var msgconttent = sentmsgF.innerHTML;
|
||||
|
||||
if (isNull(msgconttent)) { msgconttent = ''; }
|
||||
|
||||
var item = '';
|
||||
|
||||
if (!isNull(to) && to.length > 0)
|
||||
{
|
||||
item = '<b>' + to + ':</b><p>' + message + '</p><p class="date">' + GetDateForMessage() + '</p>';
|
||||
}else
|
||||
{
|
||||
item = '<p>' + message + '</p>';
|
||||
}
|
||||
|
||||
msgconttent = msgconttent + item + '<br />';
|
||||
|
||||
sentmsgF.innerHTML = msgconttent;
|
||||
// scroll to bottom
|
||||
var d = $('#msg_list');
|
||||
d.scrollTop(d.prop("scrollHeight"));
|
||||
}
|
||||
|
||||
/** helper function; returns the current date and time in string displayable format*/
|
||||
function GetDateForMessage()
|
||||
{
|
||||
var month = new Array();
|
||||
month[0] = 'Jan'; month[1] = 'Feb'; month[2] = 'Mar'; month[3] = 'Apr'; month[4] = 'May'; month[5] = 'Jun';
|
||||
month[6] = 'Jul'; month[7] = 'Aug'; month[8] = 'Sep'; month[9] = 'Oct'; month[10] = 'Nov'; month[11] = 'Dec';
|
||||
try{
|
||||
var date = new Date();
|
||||
|
||||
var minutes = date.getMinutes();
|
||||
if (minutes < 10) { minutes = '0' + minutes; }
|
||||
|
||||
var day = date.getDate(); // getDay returns the day of the week
|
||||
if (day < 10) { day = '0' + day; }
|
||||
|
||||
var datestr = month[date.getMonth()] + ', ' + day + ' ' + date.getFullYear()+ ' '
|
||||
+ date.getHours() + ':' + minutes;
|
||||
|
||||
return datestr;
|
||||
|
||||
} catch(err) { PutToDebugLogException(2, "_message: GetDateForMessage", err); }
|
||||
return '';
|
||||
}
|
||||
|
||||
/** receive important events from webphone, which will be displayed for the user and parsed to perform other actions*/
|
||||
webphone_api.onEvent(function (type, evt)
|
||||
{
|
||||
if (type === 'event')
|
||||
{
|
||||
ProcessNotifications(evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
//webphone_api.common.PutToDebugLog(5, 'EVENT, skip not event: '+type+':'+evt);
|
||||
}
|
||||
});
|
||||
|
||||
/** parse received notifications*/
|
||||
var ringingNumber = '';
|
||||
function ProcessNotifications(not)
|
||||
{
|
||||
try{
|
||||
if (isNull(not) || not.length < 1) { return; }
|
||||
|
||||
not = Trim(not);
|
||||
|
||||
var type = '';
|
||||
var line = '';
|
||||
var notifyword = '';
|
||||
|
||||
//STATUS,1,Ringing,8888,9999,2,8888
|
||||
var pos = not.indexOf(',');
|
||||
if (pos > 0)
|
||||
{
|
||||
type = Trim(not.substring(0, pos));
|
||||
not = Trim(not.substring(pos + 1));
|
||||
}
|
||||
|
||||
// get line
|
||||
pos = not.indexOf(',');
|
||||
if (pos > 0)
|
||||
{
|
||||
line = Trim(not.substring(0, pos));
|
||||
notifyword = Trim(not.substring(pos + 1));
|
||||
}else
|
||||
{
|
||||
notifyword = not;
|
||||
}
|
||||
|
||||
var notifywordcontent = '';
|
||||
|
||||
// clear junk of notifyword's end
|
||||
pos = notifyword.indexOf(',');
|
||||
if (pos > 0)
|
||||
{
|
||||
notifywordcontent = Trim(notifyword.substring(pos + 1));
|
||||
notifyword = Trim(notifyword.substring(0, pos));
|
||||
}
|
||||
pos = notifyword.indexOf('[');
|
||||
if (pos > 0) { notifyword = Trim(notifyword.substring(0, pos)); }
|
||||
pos = notifywordcontent.indexOf('[');
|
||||
if (pos > 0) { notifywordcontent = Trim(notifywordcontent.substring(0, pos)); }
|
||||
|
||||
|
||||
// handle incoming call
|
||||
if (type === 'STATUS')
|
||||
{
|
||||
// you can futher process/use the received status event messages
|
||||
// check the documentation for more details
|
||||
}
|
||||
|
||||
DisplayStatus(type + ',' + notifyword);
|
||||
|
||||
} catch(err)
|
||||
{
|
||||
PutToDebugLogException(2, 'live_demo: ProcessNotifications', err);
|
||||
}
|
||||
}
|
||||
|
||||
/** Custom popup with Accept/Reject buttons displayed on incoming call
|
||||
* This is just an example, you can design/use your own custom popup*/
|
||||
var armodal = null;
|
||||
function AcceptRejectPopup(from)
|
||||
{
|
||||
try{
|
||||
if (!isNull(armodal))
|
||||
{
|
||||
armodal.show();
|
||||
return;
|
||||
}
|
||||
armodal = webphone_api.picoModal(
|
||||
{
|
||||
content:
|
||||
'<div id="ce_modal" class="modal" style="color: #212121;">'+
|
||||
'<div id="ce_modal_header" class="modal_header_custom" style="height: 2.2em; line-height: 2.2em; margin: 0; background: #e8e8e8; text-align: center; color: #212121; font-weight: bold;">' +
|
||||
'Incoming call' +
|
||||
'</div>' +
|
||||
'<div id="ce_modal_content" class="modal_content" style="font-size: .8em; padding: 1em;">' +
|
||||
'<div id="ce_modal_content_inner">' +
|
||||
'Incoming call from: ' + from +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div id="ce_modal_footer" class="modal_footer" style="height: 2.2em; margin: 0; background: #e8e8e8; text-align: center; color: #ffffff; font-weight: bold;">' +
|
||||
'<button id="btn_np_positive" style="width: 50%; height: 2.28em; margin-top: .1em; font-size: .9em; color: #212121; font-weight: bold; background: #cecece; border: .1em solid #b8b8b8; border-radius: .2em; cursor: pointer;">Accept</button>' +
|
||||
'<button id="btn_np_negative" style="width: 50%; height: 2.28em; margin-top: .1em; font-size: .9em; color: color: #212121; font-weight: bold; background: #cecece; border: .1em solid #b8b8b8; border-radius: .2em; cursor: pointer;">Reject</button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
//content: "Ah, the pitter patter of tiny feet in huge combat boots.<br><button>Test</button>",
|
||||
overlayStyles: { backgroundColor: "#565656", opacity: 0.6 },
|
||||
modalStyles:
|
||||
{
|
||||
padding: "0",
|
||||
margin: "0",
|
||||
//top: "0",
|
||||
border: ".2em solid #d8d8d8",
|
||||
borderRadius: ".4em",
|
||||
//width: '65%',
|
||||
width: 'auto',
|
||||
//height: '100%',
|
||||
background: "#ffffff", fontFamily: "sans-serif"
|
||||
},
|
||||
//closeHtml: "<span>Close</span>",
|
||||
closeButton: false,
|
||||
overlayClose: false,
|
||||
closeStyles:
|
||||
{
|
||||
background: "#eeeeee", position: "absolute", top: ".2em", right: ".3em", textAlign: "center",
|
||||
fontSize: "1.2em", fontWeight: "bold", border: ".15em solid #bbb", borderRadius: ".8em",
|
||||
paddingLeft: ".25em", paddingRight: ".25em", cursor: "pointer"
|
||||
}
|
||||
|
||||
//comment: custom classes
|
||||
//overlayClass: "customShadow",
|
||||
//modalClass: "customModal",
|
||||
//closeClass: "customClose"
|
||||
|
||||
// events
|
||||
}).afterCreate(function (modal)
|
||||
{
|
||||
;
|
||||
})
|
||||
.beforeShow(function (modal, event)
|
||||
{
|
||||
;
|
||||
})
|
||||
.afterShow(function (modal)
|
||||
{
|
||||
;
|
||||
})
|
||||
.beforeClose(function (modal, event)
|
||||
{
|
||||
;
|
||||
})
|
||||
.afterClose(function(modal)
|
||||
{
|
||||
modal.destroy(); // must be called, otherwise on next show() the onclick will not work
|
||||
armodal = null;
|
||||
});
|
||||
|
||||
armodal.show();
|
||||
|
||||
$("#btn_np_positive").on("click", function ()
|
||||
{
|
||||
armodal.close();
|
||||
PutToDebugLog(5,"EVENT, live_demo AcceptRejectPopup Accept onclick");
|
||||
Accept();
|
||||
});
|
||||
|
||||
$("#btn_np_negative").on("click", function ()
|
||||
{
|
||||
armodal.close();
|
||||
PutToDebugLog(5,"EVENT, live_demo AcceptRejectPopup Reject onclick");
|
||||
Reject(6);
|
||||
});
|
||||
|
||||
} catch(err) { PutToDebugLogException(2, 'live_demo: AcceptRejectPopup', err); }
|
||||
}
|
||||
|
||||
/** display events/status messages for the user*/
|
||||
var status_e = null;
|
||||
function DisplayStatus(msg_orig)
|
||||
{
|
||||
try{
|
||||
var msg = msg_orig;
|
||||
if (isNull(status_e)) { status_e = document.getElementById('status'); }
|
||||
|
||||
if (isNull(msg) || msg.length < 1) { msg = ' '; }
|
||||
if (msg.toLowerCase().indexOf('subscribe') >= 0) { return; }
|
||||
|
||||
if (msg.indexOf('ERROR') >= 0)
|
||||
{
|
||||
msg = msg.replace('ERROR', '');
|
||||
msg = Trim(msg);
|
||||
|
||||
if (msg.indexOf(',') === 0)
|
||||
{
|
||||
msg = msg.replace(',', '');
|
||||
msg = Trim(msg);
|
||||
}
|
||||
|
||||
msg = '<span style="color:red;">' + msg + '</span>';
|
||||
}
|
||||
else if (msg.indexOf('WARNING') >= 0)
|
||||
{
|
||||
msg = msg.replace('WARNING', '');
|
||||
msg = Trim(msg);
|
||||
|
||||
if (msg.indexOf(',') === 0)
|
||||
{
|
||||
msg = msg.replace(',', '');
|
||||
msg = Trim(msg);
|
||||
}
|
||||
|
||||
msg = '<span style="color: #ff6600;">' + msg + '</span>';
|
||||
}
|
||||
else if (msg.indexOf('STATUS') >= 0 || msg.indexOf('EVENT') >= 0)
|
||||
{
|
||||
msg = msg.replace('STATUS', '');
|
||||
msg = msg.replace('EVENT', '');
|
||||
msg = Trim(msg);
|
||||
|
||||
if (msg.indexOf(',') === 0)
|
||||
{
|
||||
msg = msg.replace(',', '');
|
||||
msg = Trim(msg);
|
||||
}
|
||||
}
|
||||
|
||||
status_e.innerHTML = msg;
|
||||
PutToDebugLog(2, 'NOT: ' + msg_orig);
|
||||
|
||||
} catch(err) { PutToDebugLogException(2, 'live_demo: DisplayStatus', err); }
|
||||
}
|
||||
|
||||
|
||||
// ------------------ helper functions
|
||||
|
||||
|
||||
|
||||
/** this function is used to build the form for the Other settings
|
||||
* if you wish to display/present these setting to the user, you should build your own simple html*/
|
||||
function PopulateSettings()
|
||||
{
|
||||
try{
|
||||
PutToDebugLog(2,"EVENT, populate settings");
|
||||
if ( isNull(webphone_api.global.settmap2) || isNull( webphone_api.global.settmap2['magicnumber'] ))
|
||||
{
|
||||
PutToDebugLog(2, 'live_demo: PopulateSettings, webphone_api.global.settmap is NULL');
|
||||
return;
|
||||
}
|
||||
// callerid, displayname, proxyaddress, webrtcserveraddress
|
||||
var callerid_description = 'This will not be used for authentication. Specify if not the same with the Username for authentication setting. Some VoIP servers will reject if not the same with the username!';
|
||||
var displayname_description = 'Specify display name. This is an optional setting and it should be your full name';
|
||||
var proxyaddress_description = 'Outbound SIP proxy address. Leave it empty if you don’t have a stateless/outbound proxy';
|
||||
var webrtcserveraddress_description = 'Optional setting to indicate the domain name or IP address of your websocket service used for WebRTC if any.';
|
||||
var content = '' +
|
||||
'<div class="sett_form">' +
|
||||
'<label for="username" title="' + callerid_description + '">Caller ID:</label>' +
|
||||
'<input type="text" placeholder="Caller ID" id="username" value="' + webphone_api.getparameter('username') + '" title="' + callerid_description + '" autocapitalize="off" />' +
|
||||
'</div>' +
|
||||
|
||||
'<div class="sett_form">' +
|
||||
'<label for="displayname" title="' + displayname_description + '">Display name:</label>' +
|
||||
'<input type="text" placeholder="Display name" id="displayname" value="' + webphone_api.getparameter('displayname') + '" title="' + displayname_description + '" autocapitalize="off" />' +
|
||||
'</div>' +
|
||||
|
||||
'<div class="sett_form">' +
|
||||
'<label for="proxyaddress" title="' + proxyaddress_description + '">Proxy address:</label>' +
|
||||
'<input type="text" placeholder="Proxy address" id="proxyaddress" value="' + webphone_api.getparameter('proxyaddress') + '" title="' + proxyaddress_description + '" autocapitalize="off" />' +
|
||||
'</div>' +
|
||||
|
||||
'<div class="sett_form">' +
|
||||
'<label for="webrtcserveraddress" title="' + webrtcserveraddress_description + '">WebRTC Server:</label>' +
|
||||
'<input type="text" placeholder="WebRTC Server" id="webrtcserveraddress" value="' + webphone_api.getparameter('webrtcserveraddress') + '" title="' + webrtcserveraddress_description + '" autocapitalize="off" />' +
|
||||
//'<span>*WebRTC Server Address is optional. If not set, then the built in WebRTC gateway will be used.</span>' +
|
||||
'</div>';
|
||||
|
||||
var settings_list = document.getElementById('settings_list');
|
||||
if (!isNull(settings_list))
|
||||
{
|
||||
settings_list.innerHTML = content;
|
||||
}else
|
||||
{
|
||||
PutToDebugLog(5,"EVENT, live_demo PopulateSettings list element is NULL");
|
||||
}
|
||||
} catch(err) { PutToDebugLogException(2, 'live_demo: PopulateSettings', err); }
|
||||
}
|
||||
|
||||
/** called on "Save settings" button clicked
|
||||
* Save settings from Advanced Settings form*/
|
||||
function SaveSettings()
|
||||
{
|
||||
var lastoop = 0;
|
||||
try{
|
||||
lastoop = 1;
|
||||
var serveraddress = serveraddress_input.value;
|
||||
lastoop = 2;
|
||||
var sipusername = sipusername_input.value;
|
||||
var password = password_input.value;
|
||||
var destination = destination_input.value;
|
||||
lastoop = 3;
|
||||
if ((isNull(sipusername) || (Trim(sipusername)).length < 1) && !isNull(username_input))
|
||||
{
|
||||
lastoop = 4;
|
||||
sipusername = username_input.value;
|
||||
}
|
||||
|
||||
lastoop = 5;
|
||||
if (isNull(serveraddress) || (Trim(serveraddress)).length < 1)
|
||||
{
|
||||
lastoop = 6;
|
||||
DisplayStatus('ERROR Invalid serveraddress');
|
||||
serveraddress_input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
lastoop = 7;
|
||||
if (isNull(sipusername) || (Trim(sipusername)).length < 1)
|
||||
{
|
||||
lastoop = 8;
|
||||
DisplayStatus('ERROR Invalid auth username');
|
||||
sipusername_input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
lastoop = 9;
|
||||
if (isNull(password) || (Trim(password)).length < 1)
|
||||
{
|
||||
lastoop = 10;
|
||||
DisplayStatus('ERROR Invalid password');
|
||||
password_input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
lastoop = 11;
|
||||
if (!isNull(serveraddress) && serveraddress.length > 0)
|
||||
{
|
||||
lastoop = 12;
|
||||
webphone_api.setparameter('serveraddress', serveraddress, false);
|
||||
}
|
||||
lastoop = 13;
|
||||
webphone_api.setparameter('sipusername', sipusername, false);
|
||||
lastoop = 14;
|
||||
webphone_api.setparameter('password', password, false);
|
||||
lastoop = 15;
|
||||
webphone_api.setparameter('destination', destination, false);
|
||||
|
||||
lastoop = 16;
|
||||
function SaveSett(id)
|
||||
{
|
||||
lastoop = 17;
|
||||
var input = document.getElementById(id);
|
||||
if (!isNull(input))
|
||||
{
|
||||
lastoop = 18;
|
||||
var val = input.value;
|
||||
if (isNull(val)) { val = ''; }
|
||||
val = Trim(val);
|
||||
|
||||
lastoop = 19;
|
||||
webphone_api.setparameter(id, val, false);
|
||||
}
|
||||
}
|
||||
|
||||
lastoop = 20;
|
||||
SaveSett('username');
|
||||
lastoop = 21;
|
||||
SaveSett('displayname');
|
||||
lastoop = 22;
|
||||
SaveSett('proxyaddress');
|
||||
lastoop = 23;
|
||||
SaveSett('webrtcserveraddress');
|
||||
lastoop = 24;
|
||||
|
||||
DisplayStatus('EVENT,Saved');
|
||||
|
||||
} catch(err)
|
||||
{
|
||||
PutToDebugLogException(2, 'live_demo: SaveSettings '+lastoop.toString(), err);
|
||||
}
|
||||
}
|
||||
|
||||
/** Display/hide Advanced Settings form*/
|
||||
function ShowHideAdvancedSettings()
|
||||
{
|
||||
var rcolumn = document.getElementById('right_column');
|
||||
var btnadv = document.getElementById('btn_advanced_sett');
|
||||
if (isNull(rcolumn) || isNull(btnadv)) { return; }
|
||||
|
||||
btnadv.style.display = 'none';
|
||||
|
||||
if (rcolumn.style.display === 'none')
|
||||
{
|
||||
document.getElementById('left_column').style.marginLeft = '0';
|
||||
document.getElementById('right_column').style.display = 'block';
|
||||
btnadv.innerHTML = 'Hide Advanced Settings';
|
||||
}else
|
||||
{
|
||||
document.getElementById('right_column').style.display = 'none';
|
||||
btnadv.innerHTML = 'Show Advanced Settings';
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper function which returns "true" if the passed valiable is not NULL and it's not UNDEFINED*/
|
||||
function isNull (variable)
|
||||
{
|
||||
try{
|
||||
if (typeof (variable) === 'undefined' || variable === null)
|
||||
{
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} catch(err) { PutToDebugLogException(2, "common: isNull", err); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function Trim(str)
|
||||
{
|
||||
try{
|
||||
if (isNull(str) || str.length < 1) { return ''; }
|
||||
|
||||
str = str.toString();
|
||||
return str.replace(/^\s+|\s+$/g, '');
|
||||
|
||||
} catch(err) { PutToDebugLogException(2, "common: Trim", err); }
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/** Helper function which returns current browser name*/
|
||||
var browserName = null; // browser family
|
||||
var browserName2 = null; // browser name
|
||||
function GetBrowser ()
|
||||
{
|
||||
try{
|
||||
|
||||
if (isNull(browserName) || isNull(browserName2))
|
||||
{
|
||||
var browser = navigator.userAgent.toLowerCase();
|
||||
|
||||
PutToDebugLog(2, "EVENT, common: GetBrowser name: " + browser);
|
||||
|
||||
// order is important here. Safari userAgent contains mozilla,
|
||||
// IE 11 userAgent contains mozilla and netscape,
|
||||
// and Chrome userAgent contains both mozilla and safari.
|
||||
if ((browser.indexOf('edge') !== -1))
|
||||
{
|
||||
browserName = 'Edge';
|
||||
browserName2 = 'Edge';
|
||||
}
|
||||
else if ((browser.indexOf('msie') !== -1) && (browser.indexOf('opera') === -1))
|
||||
{
|
||||
browserName = 'MSIE';
|
||||
browserName2 = 'MSIE';
|
||||
}
|
||||
else if (browser.indexOf('trident') !== -1 || browser.indexOf('Trident') !== -1)
|
||||
{
|
||||
browserName = 'MSIE';
|
||||
browserName2 = 'MSIE';
|
||||
}
|
||||
else if (browser.indexOf('iphone') !== -1)
|
||||
{
|
||||
// this included both iPhone and iPad
|
||||
if (browser.indexOf('fxios') !== -1 || browser.indexOf('firefox') !== -1)
|
||||
{
|
||||
browserName2 = 'Firefox';
|
||||
}
|
||||
else if (browser.indexOf('crios') !== -1 || browser.indexOf('chrome') !== -1)
|
||||
{
|
||||
browserName2 = 'Chrome';
|
||||
}else
|
||||
{
|
||||
browserName2 = 'iPhone';
|
||||
}
|
||||
browserName = 'Netscape Family';
|
||||
}
|
||||
else if ((browser.indexOf('firefox') !== -1) && (browser.indexOf('opera') === -1))
|
||||
{
|
||||
browserName = 'Netscape Family';
|
||||
browserName2 = 'Firefox';
|
||||
}
|
||||
else if (browser.indexOf('chrome') !== -1)
|
||||
{
|
||||
browserName = 'Netscape Family';
|
||||
browserName2 = 'Chrome';
|
||||
}
|
||||
else if (browser.indexOf('safari') !== -1)
|
||||
{
|
||||
browserName = 'Netscape Family';
|
||||
browserName2 = 'Safari';
|
||||
}
|
||||
else if ((browser.indexOf('mozilla') !== -1) && (browser.indexOf('opera') === -1))
|
||||
{
|
||||
browserName = 'Netscape Family';
|
||||
browserName2 = 'Other';
|
||||
}
|
||||
else if (browser.indexOf('opera') !== -1)
|
||||
{
|
||||
browserName = 'Netscape Family';
|
||||
browserName2 = 'Opera';
|
||||
}else
|
||||
{
|
||||
browserName = '?';
|
||||
browserName2 = 'unknown';
|
||||
}
|
||||
|
||||
PutToDebugLog(2, "EVENT, common: GetBrowser Detected browser name: " + browserName + "; " + browserName2);
|
||||
}
|
||||
} catch(err) { PutToDebugLogException(2, "common: GetBrowser", err); }
|
||||
|
||||
return browserName2;
|
||||
}
|
||||
|
||||
/** helper functions: write logs to browser console*/
|
||||
function PutToDebugLogException(level, msg, err) { PutToDebugLog(level, 'ERROR,' + msg + ' ' + err); }
|
||||
function PutToDebugLog(level, msg)
|
||||
{
|
||||
if (msg.indexOf("ERROR") > -1)
|
||||
{
|
||||
try { console.error(msg); } catch (e1) { }
|
||||
}else
|
||||
{
|
||||
try { console.log(msg); } catch (e2) { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user