cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2303
Views
1
Helpful
11
Replies

salesforce and jabber CTI feature

arupsarkar1
Level 1
Level 1

Hi:

We downloaded the jabber sdk and web plugin from the following site.

https://developer.cisco.com/site/collaboration/jabber/websdk/develop-and-test/voice-and-video/downloads-and-docs/

All the sdk files have been put in as static resources and we built a custom visualforce page to login. Username, password, CUP server and CUCM server are all stored in user profile object.

Our biggest problem was holding the jabber logged in session during navigation from tab to the other, we have been able to solve the problem in chrome, how ever it is not working in IE.

Q1)

Can we solve in IE in any way?

Q2)

If we do jabber SSO ( I do not know how to integrate jabber SSO), does the users need to login?

Our SFDC instance is single sign on.

11 Replies 11

Geevarghese Cheria
Cisco Employee
Cisco Employee

Hi Arup,

  Ans1) Known Issues with Internet Explorer

  • There is a known issue with the Internet Explorer 8 rendering engine on Microsoft Windows XP. This issue might cause unexpected behavior with Cisco Jabber for Windows. You should apply the update for Internet Explorer 8 from the Microsoft website at: http:/​/​technet.microsoft.com/​en-us/​security/​bulletin/​MS10-018 This issue affects users on Microsoft Windows XP 32 bit with Service Pack 3 only. Users on Microsoft Windows Vista or Microsoft Windows 7 should not encounter this issue while using Cisco Jabber for Windows.
  • In cloud-based deployments that use single sign-on (SSO), an issue exists with Internet Explorer 9. Users with Internet Explorer 9 get security alerts when they sign in to Cisco Jabber for Windows. To resolve this issue, add webexconnect.com to the list of websites in the Compatibility View Settings window.

Reference - Microsoft Internet Explorer

  Ans2)  Jabber single sign on is not possible as of now. It will be in future releases - Reference - Jabber single sign on | Jabber Clients | Cisco Support Community | 5831 | 12257756

Thanks and Regards,

Geevarghese

Thanks Geevarghese,

we have added webexconnect.com in "Compatibility View Settings" but still could not make it work, can we please have a webex session to show you what we have done.

Email: arup.sarkar@nb.com

Phone: 6464974164

Regards,

Arup

amoherek
Cisco Employee
Cisco Employee

Hi Arup,

Can you tell us the OS and version of IE you are using? Are you using the latest version of IE? I can only assume older versions will have more issues.

Thanks,

Adrienne

OS : Windows 7 Enterprise (64-bit)

IE 9

Hi Arup,

I found useful information regarding multiple tabs on this page: https://developer.cisco.com/site/collaboration/jabber/websdk/learn/voice-and-video-how-to/jabber-voice-best-practices/

For IE, if you have Jabber SDK (phone) running on the first tab then subsequent tabs running the same process should work fine. This seems to be a limitation with IE. It's probably best practice to avoid using the Jabber SDK (phone) on multiple tabs if possible.

Thanks,

Adrienne

Can we do a quick demo (webex) with you to show what we have done, you will have a better perspective of our problem, we will show chrome and IE instance each. If you confirm, I will send a meeting invite.

Hi Arup,

Yes you can send me the meeting invite.

Thanks,

Adrienne

arupsarkar1
Level 1
Level 1

JabberController - ApexClass

public with sharing class JabberController {

  public static User loggedInUser {

  get{

  loggedInUser=[Select id,firstname,cnxccm__Agent_Device_Name__c,Jabber_Password__c,Jabber_ID__c,CUCM_Address__c from User where id=:Userinfo.getuserId()];

  return loggedInUser;

  }

  set;}

  public void JabberController(){

  }

}

arupsarkar1
Level 1
Level 1

JabberPage - Visualforce Page

<apex:page showHeader="false" sidebar="false" controller="JabberController">

<html>

  <head>

    <title>Voice Call Demo</title>

    <!--<link href="https://community.cisco.com/resource/1235794002000/JabberSDK/samples/css/style.css" rel="stylesheet" type="text/css" media="screen" />-->

   

    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

   

    <apex:includeScript value="{!URLFOR($Resource.JabberSDK, '/src/ciscobase.js')}"/>

    <apex:includeScript value="{!URLFOR($Resource.JabberSDK, '/src/cwic/cwic.js')}"/>

    <apex:includeScript value="{!URLFOR($Resource.JabberSDK, '/samples/js/fullscreen.js')}"/>

    <apex:includeScript value="{!URLFOR($Resource.JabberSDK, '/samples/js/sample_helpers.js')}"/>

    <apex:includeScript value="/support/api/29.0/interaction.js"/>

    <script type="text/javascript">

    var popupwindow = null;

    var pinpwin = null;

    var thiswindow = window;

    var globalreg = null;

    var result = null;

   

    function pinpLoaded(win,id) {

        thiswindow.pinpwin = win;

        if(id) {

            thiswindow.pinpVideoObject = $('#'+id,win.document)[0];

        var currentClass = $('#showpinpvideo').attr('class');

        var classId = pinpsequence.indexOf(currentClass);

        if(classId !==0) {

            $(document).cwic('addPreviewWindow',{previewWindow: thiswindow.pinpVideoObject, "window": thiswindow.pinpwin});

        }

        } else {

            if(jQuery(document).cwic('about').capabilities.video && !thiswindow.pinpVideoObject) {

                win.createVideoWindow();

            }

        }

    }

    function pinpUnloaded(win,id) {

        thiswindow.pinpwin = null;

        $(document).cwic('removePreviewWindow',{previewWindow: id, "window": win});

    }

    function popupLoaded(win,id) {

        thiswindow.popupwindow = win;

        calls.getCallDiv().cwic('updateConversation', {addRemoteVideoWindow: id,"window":win});

    }

    function popupUnloaded(win,id) {

        thiswindow.popupwindow = null;

    }

    /**

     * These settings are passed into the 'init' method.

     */

    var settings = {

        ready: phoneReadyCallback, /* Callback when phone is ready for use */

        error: phoneErrorCallback, /* Error callback */

        encodeBase64: ciscobase.util.crypto.b64Encode,

        verbose: true,

        log: function (msg, context) {

            //console.trace();

            if (typeof console !== "undefined" && console.log) {

                var current = new Date();

                var timelog = current.getDate() + "/" +

                                ('0' + (current.getMonth()+1)).slice(-2)  + "/" +

                                current.getFullYear() + " " +

                                ('0' + current.getHours()).slice(-2) + ":" +

                                ('0' + current.getMinutes()).slice(-2) + ":" +

                                ('0' + current.getSeconds()).slice(-2) + "." +

                                ('00' + current.getMilliseconds()).slice(-3) + " ";           

                console.log(timelog + msg)

                if (context) {

                    if(console.dir) {

                        console.log(context);

                    } else if(typeof JSON !== "undefined" && JSON.stringify) {

                        console.log(JSON.stringify(context,null,2));

                    } else {

                        console.log(context);

                    }

                }

            };

        },

        contactLookupJsonpHost: ""

    };

    // Array containing DTMF characters that we want to allow

    var dtmfchars = { '0' : '0', '1' : '1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', '#':'#', '*':'*' };

    /*

     * Multiple-call settings

     */

    var calls = multiCallContainer('call', 'calllist');

    var videoObject = null;

    var previewVideoObject = null;

    var pinpVideoObject = null;

    var showLocalVideo = false;

    // Used to track a conversation id that does not yet have a video window to associate to

    var delayedVideoConversation = null;

    function popoutVideo() {

        var height = 520;

        var width = 700;

        if(popupwindow === null || popupwindow.closed) {

            var l = (screen.width-width)-16; // offset by 16 pixels for IE borders

            var t = 0;

            var windowsettings='height=' + height + ',width=' + width + ',top=' + t + ',left=' + l + ',location=no,resizable=yes,scrollbars=no,status=no,toolbar=no,menubar=no';

            var popupUrl="/resource/1235794002000/JabberSDK/samples/popout.html";

            popupwindow = window.open(popupUrl, "_cwicvideo", windowsettings);

            if(popupwindow !== null) {

                popupwindow.focus();

            }

        }

        else {

            popupwindow.focus();

        }

    }

    /**

     * This callback is invoked when the phone plugin is available for use.

     */

    function phoneReadyCallback(defaults,phoneRegistered, phoneMode) {

        $('#remotevideocontainer').cwic('createVideoWindow',{id: 'videocallobject', success: function(id) {

            videoObject = document.getElementById(id);

            if (delayedVideoConversation) {

                // The update for the conversation that video is ready can occur before the createVideoWindow() call 

                // returns asynchronously on some browsers, especially on Safari and background tabs.  Add the video

                // window to the call now.

                calls.getCallDiv(delayedVideoConversation.callId).cwic('updateConversation',{'addRemoteVideoWindow':videoObject});

                delayedVideoConversation = null;

            }

        }});

        $('#localvidcontainer').cwic('createVideoWindow',{id: 'localPreviewVideo', success: function(id) {

            previewVideoObject = $('#'+id)[0];

        }});

        if(pinpwin && pinpwin.createVideoWindow) {

            pinpwin.createVideoWindow();

        }

        var about = $('#phonecontainer').cwic('about');

        $('#jsversion').text(about.javascript.version);

        $('#jssystem_release').text(about.javascript.system_release);

        $('#jqueryversion').text(about.jquery.version);

        if (about.plugin) {

            $('#pluginversion').text(about.plugin.version.plugin);

            $('#eccversion').text(about.plugin.version.ecc);

            $('#pluginsystem_release').text(about.plugin.version.system_release);

        }

      

        if ((jQuery(document).cwic('about').capabilities.certValidation)) {

            // the sample app disables cert validation by default.

            jQuery(document).cwic('disableCertValidation');           

        } else {

            // disable the validate checkbox if the plug-in does not have the capability.

            $('#validateCerts').attr('disabled' , true);

        }

        setupUIHandlers();

        refreshMMDevices();

       

        // Handle the login button's behavior

        $('#loginbtn').click(function() {

        /**

        * If we're in Deskphone mode, password is required. Not currently required for Softphone mode.

        */

            var authNeeded = !!($('#mode').val() === "DeskPhone" || $('#auth').attr('checked'));

            login($('#username').val(),$('#password').val(),'{!loggedInUser.CUCM_Address__c}',authNeeded ,'DeskPhone');

            $('#loginbtn').hide();

            $('#usernameLabel').hide();

            $('#passwordLabel').hide();

            $('#username').hide();

            $('#password').hide();

            $('#devicedetails').show();

            popitup('/apex/jabberPage');

        });

        function popitup(url) {

            var left = (screen.width/2-(100/2));

            var top = (screen.height/2)-(100/2);

            newwindow=window.open(url,'name','height=100,width=100,location=No,menubar=No,toolbar=No,scrollbars=Yes,resizable=Yes,top='+top+',left='+left);

            if (window.focus) {newwindow.focus()}

            return false;

        }

        // Handle the logout button's behavior

        $('#logoutbtn').click(function() {

            settings.log('logout clicked');

            $('#incomingcontainer, #callcontainer').hide();

            $('#logoutbtn').hide();

            $('#loginbtn').show();

            $('#usernameLabel').show();

            $('#passwordLabel').show();

            $('#username').show();

            $('#password').show();

            logout();

        });

        if(phoneRegistered) {

            $('#mode').val(phoneMode);

            setUILoggedIn();

        }

    };

    function phoneErrorCallback(error, exception) {

        if (error) {

            settings.log('phone error: ', error);

            var about = $().cwic('about');

            var msg = 'ERROR: cannot initialize phone: ' + error.message + ' (code ' + error.code + ')<br/>';

            msg += 'cwic javascript version is ' + about.javascript.version + '<br/>';

            if (about.upgrade) {

                if (about.upgrade.plugin) { msg += 'plugin upgrade ' + about.upgrade.plugin + '<br/>'; }

                if (about.upgrade.javascript) { msg += 'cwic javascript upgrade ' + about.upgrade.javascript + '<br/>'; }

            }

            $('#msgcontainer').empty().html('<b style="color:red">' + msg + '</b>');

        }

        if (exception) {

            settings.log('exception: ',exception);

        }

    };

   

    function handleMMDeviceChange() {

        refreshMMDevices();

    };

   

    /*

     * When page is loaded, initialize the plugin.

     */

    $(document).ready(function() {

        $('window').cwic('unregisterPhone', {

            forceLogout: true

        });

        $('#devicedetails').hide();

        $('#logoutbtn').hide();

        function onCwicLoaded() {

            var sfdcSessionId = '{!$Api.Session_ID}';

            settings.log('onCwicLoaded');

            // set the source of the picture-in-picture iframe (requires cwic to be available)

            $('#pinpwindow').attr('src', '/resource/1235794002000/JabberSDK/samples/pinp.html');

            $('#calllist').click(calls.callListClick);

            $('#mode').change(function() {

                $('#auth').attr('disabled',$(this).val() === 'DeskPhone');

            });

            $('#phonecontainer').cwic('init', settings);

            /**

             * Add handlers for conversationStart and conversationIncoming events

             */

            $('#phonecontainer')

            .bind('conversationStart.cwic', handleConversationStart)

            .bind('conversationIncoming.cwic', handleConversationIncoming)

            /**

             * Handle system events - these are issued when the webphone plugin is handling things like

             * IP address changes.

             */

            .bind('system.cwic', handleSystemEvent)

            .bind('mmDeviceChange.cwic', handleMMDeviceChange);

            $(document).bind('error.cwic', handleError);

            $('#switchmodebtn').click(switchModeClick);

            $('#showpinpvideo').click(switchPinPVideo);

            $('input:radio[name=showlocalvideo]').click(switchPreviewVideo);

            $('#togglepreview').click(switchPreviewVideo1);

            /**

            * Conference Feature

            */

            $('#conferencebtn').click(conferenceButtonClick);

            $('#transferbtn').click(transferButtonClick);

        } // onCwicLoaded

        // use static loading for now, cwic.js is included at the top of this file

        // and call onCwicLoaded straight away

        onCwicLoaded();

       

       //Invokes API method

        //sforce.interaction.cti.enableClickToDial(callbackenable);

              //OpenCTI!!             

        //alert('Working...')

            sforce.interaction.cti.enableClickToDial();

            var listener = function (response) {

                    if (response.result) {

                        result = JSON.parse(response.result);

                        var Number = result.number.replace('(','').replace(')','').replace(' ','').replace('-','');

                        document.getElementById('dntodial').value = Number;

                        callButtonClick();

                    }

            };

            sforce.interaction.cti.onClickToDial(listener);

              //alert('executed !!!!');

        //sforce.interaction.getPageInfo(getPageInfoCallback);

    });

    function handleLoggedOut() {

        calls.removeAll();

        $('#username').attr('disabled', false);

        $('#cucm').attr('disabled', false);

        $('#mode').attr('disabled', false);

        $('#auth').attr('disabled', false);               

        $('#validateCerts').attr('disabled' , !(jQuery(document).cwic('about').capabilities.certValidation));

        $('#dntodial').attr('disabled', true);

        $('#loginbtn').attr('disabled', false);

        $('#logoutbtn').attr('disabled', true);

        $('#callbtn').attr('disabled', true);

        $('#switchmodebtn').attr('disabled', true);

        // Once logout has completed, unbind all handlers that are bound in login

        // On second thought, don't

    }

    function unbindCallHandlers() {

        $('#callbtn').unbind();

        $('#callcontainer').unbind();

        $('#callcontainer :button').unbind();

    }

    /**

     * Helper function to logout

     */

    function logout(){

        $('#phonecontainer').cwic('unregisterPhone', {

            forceLogout: true,

            // the complete callback is always called after unregistering

            complete: function(){

                handleLoggedOut();

            }

        });

    };

    function refreshMMDevices(){

        var recordingDevicesSelect = $('#mmDevices #recordingDevicesSelect');

        recordingDevicesSelect.empty();

        var captureDevicesSelect = $('#mmDevices #captureDevicesSelect');

        captureDevicesSelect.empty();

        var playoutDevicesSelect = $('#mmDevices #playoutDevicesSelect');

        playoutDevicesSelect.empty();

        var devices = $().cwic('getMultimediaDevices');

        if(devices.multimediadevices)

        {

            for(var i=0; i < devices.multimediadevices.length; i++) 

            {

               if (devices.multimediadevices[i].canRecord)

               {

                   // In order to set a device as a recording device, send in the clientRecordingID to setRecordingDevice().

                   // Depending on the platform, it may match other fields, but it will always be the value that works for

                   // setRecordingDevice.  We save it here as clientID, so we can send it when the Set Recording Device button

                   // is pushed.

                   recordingDevicesSelect.append($("<option></option>")

                                                   .attr("value", devices.multimediadevices[i].clientRecordingID)

                                                   .text(devices.multimediadevices[i].deviceName + ((devices.multimediadevices[i].isDefault) ? " *" : "")));

               }       

              

               if (devices.multimediadevices[i].canPlayout)           

               {

                   playoutDevicesSelect.append($("<option></option>")

                                       .attr("value", devices.multimediadevices[i].clientPlayoutID)

                                       .text(devices.multimediadevices[i].deviceName + ((devices.multimediadevices[i].isDefault) ? " *" : "")));

               }

              

               if (devices.multimediadevices[i].canCapture)           

               {

                   captureDevicesSelect.append($("<option></option>")

                                       .attr("value", devices.multimediadevices[i].clientCaptureID)

                                       .text(devices.multimediadevices[i].deviceName + ((devices.multimediadevices[i].isDefault) ? " *" : "")));

               }

              

               if (devices.multimediadevices[i].isSelectedRecordingDevice)

               {

                   recordingDevicesSelect.val(devices.multimediadevices[i].clientRecordingID);

               }

              

               if (devices.multimediadevices[i].isSelectedPlayoutDevice)

               {

                   playoutDevicesSelect.val(devices.multimediadevices[i].clientPlayoutID);

               }

              

               if (devices.multimediadevices[i].isSelectedCaptureDevice)

               {

                   captureDevicesSelect.val(devices.multimediadevices[i].clientCaptureID);

               }

            }

        }

    };

   

    function setCaptureDevice()

    {

        var capSelect = $('#captureDevicesSelect');

        var optSel = $('#captureDevicesSelect option:selected');

       

        if (optSel && optSel.val())

        {

            $().cwic('setCaptureDevice', optSel.val());

            refreshMMDevices();

        }

    }

   

    function setRecordingDevice()

    {

        var capSelect = $('#recordingDevicesSelect');

        var optSel = $('#recordingDevicesSelect option:selected');

       

        if (optSel && optSel.val())

        {

            $().cwic('setRecordingDevice', optSel.val());

            refreshMMDevices();

        }

    }

    function setPlayoutDevice()

    {

        var capSelect = $('#playoutDevicesSelect');

        var optSel = $('#playoutDevicesSelect option:selected');

       

        if (optSel && optSel.val())

        {

            $().cwic('setPlayoutDevice', optSel.val());

            refreshMMDevices();

        }

    }

    /**

    * Set up the UI's handlers for clicks and cwic events. Doing this once prevents bugs from multiple

    * events being fired

    */

    function setupUIHandlers() {

        $('#popoutbtn').click(popoutVideo);

        $('#callbtn').click(callButtonClick);

        $('#callcontainer .holdresumebtn').click(holdResumeButtonClick);

        $('#callcontainer .muteaudiobtn').click(muteButtonClick);

        $('#callcontainer .mutevideobtn').click(muteButtonClick);

        $('#callcontainer .escalatebtn').click(escalateButtonClick);

        $('#dntodial').keypress( function (event) {

            var conversation = calls.getSelectedCall();

            if(conversation && conversation.capabilities.canSendDigit) {

                var char = String.fromCharCode(event.charCode || event.keyCode);

                if(dtmfchars[char]) {

                    calls.getCallDiv().cwic('sendDTMF', char);

                }

            }

        });

               

        $("#validateCerts").change(function() {

            if (this.checked) {           

                jQuery(document).cwic('enableCertValidation');

            } else {

                jQuery(document).cwic('disableCertValidation');

            }

        });

       

        $('#callcontainer .endbtn').click(endButtonClick);

       

        $('#mmDevices .refreshMMDevices').click(function() {

            refreshMMDevices();

        });      

       

        $('#mmDevices #captureDevicesSelect').change(function() {

            setCaptureDevice();

            refreshMMDevices();

        });

        $('#mmDevices #recordingDevicesSelect').change(function() {

            setRecordingDevice();

            refreshMMDevices();

        });

        $('#mmDevices #playoutDevicesSelect').change(function() {

            setPlayoutDevice();

            refreshMMDevices();

        });

    };

    /**

     * preview video radio toggle handler

     */

    function switchPreviewVideo(evt) {

        if(showLocalVideo !== evt.target.value) {

            showLocalVideo = evt.target.value;

            if(showLocalVideo === "On") {

                $('#localPreviewVideo').css('width','');

                $('#localPreviewVideo').css('height','');

                $(document).cwic('addPreviewWindow',{previewWindow: 'localPreviewVideo' /*previewVideoObject*/});

            } else {

                $(document).cwic('removePreviewWindow',{previewWindow: 'localPreviewVideo' /*previewVideoObject*/});

                $('#localPreviewVideo').css('height','0px');

                $('#localPreviewVideo').css('width','0px');

            }

        }

    }

    function switchPreviewVideo1() {

        if(showLocalVideo === "Off") {

            $('#localPreviewVideo').css('display','');

            $(document).cwic('addPreviewWindow',{previewWindow: previewVideoObject});

            showLocalVideo = "On";

        } else {

            $(document).cwic('removePreviewWindow',{previewWindow: previewVideoObject});

            $('#localPreviewVideo').css('display','none');

            showLocalVideo = "Off";

        }

    }

    /**

     * switch position/visibility of picture-in-picture

     */

    var pinpsequence = ['off','bottomright','bottomleft','topleft','topright'];

    function switchPinPVideo(evt) {

        var currentClass = $('#showpinpvideo').attr('class');

        var classId = pinpsequence.indexOf(currentClass) + 1;

        if(classId >= pinpsequence.length) {

            classId = 0;

        }

        $('#showpinpvideo').attr('class',pinpsequence[classId]);

        $('#pinpwindow').attr('class',pinpsequence[classId]);

        if(classId ===0) {

            $(document).cwic('removePreviewWindow',{previewWindow: pinpVideoObject, "window": pinpwin});

        } else {

            $(document).cwic('addPreviewWindow',{previewWindow: pinpVideoObject, "window": pinpwin});

        }

    }

    /**

     * Set the UI state to logged in

     */

    function setUILoggedIn() {

        $('#msgcontainer').empty();

       

        $('#dntodial').attr('disabled', false);

        $('#cucm').attr('disabled', true);

        $('#mode').attr('disabled', true);

        $('#auth').attr('disabled', true);

        $('#validateCerts').attr('disabled', true);

        $('#switchmodebtn').removeAttr('disabled');

        $('#callbtn').removeAttr('disabled');

        $('#devicedetails').hide();

    };

    /**

     * Login the webphone.

     */

    function login(user,password,cucm,auth,phoneMode){

        // magic number for encoded password length and trailing char, may break in the future

        // original password must be short <16 chars to produce something that matches

        if(password.length === 44 && password[43] === '=') {

            password = { "cipher" : "cucm", "encrypted": password};

        }

        //$('#loginbtn').attr('disabled', true);

        var forcereg = $('#forcereg').attr('checked');

       

        $('#phonecontainer').cwic('registerPhone', {

            user: user,

            password: password,

            cucm: (cucm || '').split(','), // array of string

            mode: phoneMode,

            authenticate: auth,

            forceRegistration: forcereg,

            devicesAvailable: function(devices,phoneMode,callback,automatic) {

                $('#devices').children().remove();

                var deviceSelected = false;

                for(var i=0;i<devices.length;i++)  {

                    if((phoneMode === "SoftPhone" && devices[i].isSoftPhone) || (phoneMode === "DeskPhone" && devices[i].isDeskPhone)) {

                        if(automatic && !deviceSelected) {

                            callback(phoneMode,devices[i].name,'');

                            deviceSelected = true;

                        }

                        if(phoneMode === "SoftPhone") {

                            $('#devices').append($('<option>', {value: devices[i].name+":"}).text(devices[i].name).attr('title',devices[i].modelDescription));

                        } else {

                            for(var j=-1;j<devices[i].lineDNs.length;j++) {

                                $('#devices').append($('<option>', {value: devices[i].name+":"+(j>=0 ? devices[i].lineDNs[j] : '')}).text((j>=0 ? devices[i].lineDNs[j]+' : ' : '')+devices[i].name).attr('title',devices[i].modelDescription));

                            }

                        }

                    }

                }

                $('#connectbtn').unbind('click').attr('disabled', false);

                $('#connectbtn').bind('click', function() {

                    $(this).attr('disabled', true);

                    $('#logoutbtn').show();

                    var device= $('#devices').val().split(':');

                    if(device) {

                        callback(phoneMode, device[0],device[1]);

                    }

                }).removeAttr('disabled');

            },

            /**

             * Callback that's invoked when phone is successfully registered.

             * Use this callback to enable UI controls etc to enable calls to be made.

             */

            success: function(registration) {

                settings.log('Registration succeeded. Registration: ',registration);

                globalreg = registration;

            },

            /**

             * Callback that's invoked if registration fails for some reason.

             */

            error: handleLoginFailure

        }); // End of registerPhone

    } // End of login

    function updateConversationInfo(conversation, callcontainer){

        if(!calls.getSelectedCall() || calls.getSelectedCall().callId !== conversation.callId) {           

            // special case where hold shows up for previous call after the current call is answered if the

            // previous call was in process when the user clicked answer to a new incoming call.

            // Remove the video window so it blanks out correctly

            if (conversation && conversation.callState && (conversation.callState === 'Hold' || conversation.callState === 'RemHold')) {

                settings.log("Hold received for non-current call, checking for video");

                if (videoObject) {

                    settings.log("Hold received for non-current call, removing video conversation.callId: " + conversation.callId);

                    calls.getCallDiv(conversation.callId).cwic('updateConversation',{'removeRemoteVideoWindow':videoObject});

                }

            }

            else {

                settings.log("updateConversationInfo() event not for current call, ignoring");

            }

            return;

        }

        var $callcontainer = $(callcontainer);

        updateTransferConferenceLists(conversation);

        $callcontainer.css('display','inline-block');

        if(conversation.isConference) {

            $callcontainer.find('.remotename').text("Conference");

        }

        else if(conversation.callType === "Outgoing") {

            $callcontainer.find('.remotename').text(conversation.calledPartyDirectoryNumber);

        }

        else if (conversation.callType === "Incoming") {

            $callcontainer.find('.remotename').text(conversation.callingPartyDirectoryNumber);

        }

        $callcontainer.find('.callinfo').text(conversation.callState);

        if (conversation.callState === 'Hold' || conversation.callState === 'RemHold') {

            // In some cases, if the video window is not removed on hold, it cannot be re-added

            // on resume.

            // remove the video window from a call on hold to blank out the video window

            // and to allow the video to be re-added properly when the call is resumed later

            settings.log("Hold received, removing video");

            $callcontainer.find('.holdresumebtn').attr('disabled', !conversation.capabilities.canResume).text('Resume').addClass('held');

            if (videoObject) {

                calls.getCallDiv().cwic('updateConversation',{'removeRemoteVideoWindow':videoObject});

            }

        } else {

            $callcontainer.find('.holdresumebtn').attr('disabled', !conversation.capabilities.canHold).text('Hold').removeClass('held');

        }

        $callcontainer.find('.endbtn').attr('disabled', !conversation.capabilities.canEndCall);

        if (conversation.state === 'Reorder') {

            $callcontainer.find('.callinfo').text('Call failed');

        }

        if(conversation && conversation.callState === "Connected" && (conversation.videoDirection === "RecvOnly" ||  conversation.videoDirection === "SendRecv")) {

            if(videoObject) {

                calls.getCallDiv().cwic('updateConversation',{'addRemoteVideoWindow':videoObject});

            }

            else {

                // The update for the conversation that video is ready can occur before the createVideoWindow() call 

                // returns asynchronously on some browsers, especially on Safari and background tabs.  Save off the

                // conversation so that we can add the window to it when it is ready.

                delayedVideoConversation = conversation;

            }

            if(popupwindow && !popupwindow.closed && popupwindow.videoObject) {

                calls.getCallDiv().cwic('updateConversation',{'addRemoteVideoWindow':popupwindow.videoObject,window:popupwindow});

            }

        }

        if(conversation.audioMuted) {

            $callcontainer.find('.muteaudiobtn').attr('disabled', !conversation.capabilities.canUnmuteAudio);

            $callcontainer.find('.muteaudiobtn').text('Unmute Audio').addClass('muted');

        } else {

            $callcontainer.find('.muteaudiobtn').attr('disabled', !conversation.capabilities.canMuteAudio);

            $callcontainer.find('.muteaudiobtn').text('Mute Audio').removeClass('muted');

        }

        if(conversation.videoMuted) {

            $callcontainer.find('.mutevideobtn').attr('disabled', !conversation.capabilities.canUnmuteVideo);

            $callcontainer.find('.mutevideobtn').text('Unmute Video').addClass('muted');

        } else {

            $callcontainer.find('.mutevideobtn').attr('disabled', !conversation.capabilities.canMuteVideo);

            $callcontainer.find('.mutevideobtn').text('Mute Video').removeClass('muted');

        }

        if(conversation.videoDirection === "Inactive" || conversation.videoDirection === "RecvOnly") {

            $callcontainer.find('.escalatebtn').text('Escalate').attr('disabled',!conversation.capabilities.canUpdateVideoCapability);

        } else {

            $callcontainer.find('.escalatebtn').text('De-escalate').attr('disabled',!conversation.capabilities.canUpdateVideoCapability);

        }

    }

    function getCwicClasses(el) {

        var classes = jQuery(el).attr('class');

        var classestoadd = [];

        if(classes) {

            classes = classes.split(' ');

            for(var i=0;i<classes.length;i++) {

                if(classes[i].substring(4,0) === 'cwic') {

                    classestoadd.push(classes[i]);

                }

            }

        }

        return classestoadd.join(' ');

    }

    function handleConversationStart(event, conversation, containerdiv) {

        calls.addCall(conversation, containerdiv);

        updateConversationInfo(conversation, '#callcontainer');

    };

    function handleConversationIncoming(event, conversation, containerdiv) {

        calls.addCall(conversation, containerdiv);

    };

    function handleSystemEvent(event) {

        var reason = event.phone.status || null;

        settings.log('system event with reason=' + reason);

        settings.log('system event phone.ready=' + event.phone.ready);

        if (reason == 'eRecoveryPending') {

            settings.log('recovery pending, end any active call and disable make call');

            //handleLoggedOut();

            $('#msgcontainer').empty().text('System recovery is pending ...');

            $('#callbtn').attr('disabled', true);

        }

        else if (reason == 'eIdle') {

            handleLoggedOut();

        }

        else if (reason == 'eReady') {

            $('#msgcontainer').empty();

            $('#username').hide();

            $('#usernameLabel').hide();

            $('#password').hide();

            $('#passwordLabel').hide();

            $('#loginbtn').hide();

            $('#logoutbtn').show();

            $('#logoutbtn').attr('disabled', false);

            settings.log('phone is ready, enable make call');

            setUILoggedIn();

        }

        else if (reason == 'ePhoneModeChanged') {

            $('#mode').val(event.phone.registration.mode);

        }

        else if (reason == 'eConnectionTerminated') {

            $('#msgcontainer').empty().text("Logged in elsewhere - disconnecting....");

            logout();

        }

        else {

            settings.log('ignoring system.cwic event with reason=' + reason);

        }

    };

    function handleError(error) {

        var msg = (error.message || '') + '<br/>';

        msg += error.details.join('<br/>');

        try {

            if (error.nativeError) {

                msg += '<br/> native error: ' + (typeof JSON !== 'undefined' && JSON.stringify) ? JSON.stringify(error.nativeError) : error.nativeError;

            }

        }

        catch(e) {

            if(typeof console !== "undefined" && console.trace) {

                console.trace();

            }

        }

        $('#msgcontainer').empty().html(msg);

    };

    function incomingAnswerClick() {

        var videodirection = $('#videocall').is(':checked');

        var $call = $(this).parent().parent();

        var answerObject = $call.data('cwic');

        if (videodirection) {

            answerObject.videoDirection = 'SendRecv';

        } else {

            answerObject.videoDirection = (jQuery(document).cwic('about').capabilities.video ? 'RecvOnly' : 'Inactive');

        }

        answerObject.remoteVideoWindow = 'videocallobject';

        $call.cwic('startConversation', answerObject);

   };

   function incomingDivertClick() {

        var $call = $(this).parent().parent();

        $call.cwic('endConversation',true);

   };

   function switchModeClick(){

        var modechange;

        if($('#mode').val()=='SoftPhone') {

            modechange="DeskPhone";

        }

        else {

            modechange='SoftPhone';

        }

        authNeeded = ($('#mode').val() === "DeskPhone" || $('#auth').attr('checked'));

        $('#callbtn').attr('disabled', true);

        $('#switchmodebtn').attr('disabled', true);

        var forcereg = $('#forcereg').attr('checked');

        $('#switchmodebtn').cwic('switchPhoneMode', {

            mode: modechange,

            error: handleLoginFailure,

            forceRegistration: forcereg

        });

        calls.removeAll();

    };

   function callButtonClick() {

        var dn = $('#dntodial').val();

       

        var videodirection = $('#videocall').is(':checked');

        var originateObject = {participant: {recipient: dn}, videoDirection: (videodirection ? 'SendRecv':(jQuery(document).cwic('about').capabilities.video ? 'RecvOnly' : 'Inactive')),remoteVideoWindow: 'videocallobject'};

        if (dn !=""){

        $('#phonecontainer').cwic('startConversation',originateObject);

        $('#switchmodebtn').attr('disabled', true);

        }

    };

    function holdResumeButtonClick() {

        if($(this).hasClass('held')) {

            calls.getCallDiv().cwic('updateConversation', 'resume');

        } else {

            calls.getCallDiv().cwic('updateConversation', 'hold');

        }

    };

    function muteButtonClick() {

        var muteIsAudio = true;

        if($(this).hasClass('mutevideobtn')) {

            muteIsAudio = false;

        }

        if($(this).hasClass('muted')) {

            calls.getCallDiv().cwic('updateConversation', muteIsAudio? 'unmuteAudio' : 'unmuteVideo');

        } else {

            calls.getCallDiv().cwic('updateConversation', muteIsAudio? 'muteAudio' : 'muteVideo');

        }

    };

    function endButtonClick() {

        calls.getCallDiv().cwic('endConversation');

    };

    function handleConversationUpdate(event, conversation, container) {

        settings.log('conversationUpdate Event for conversation:'+conversation.callId+' on Dom node: ' + event.target.id, conversation);

        calls.addCall(conversation, container);

        updateConversationInfo(conversation, $('#callcontainer'));

    };

    function handleConversationEnd(event, conversation) {

        $('#callcontainer').hide();

        calls.removeCall(conversation.callId);

        settings.log('conversationEnd Event for conversation:'+conversation.callId);

        delayedVideoConversation = null;

    };

    function handleLoginFailure(error) {

        var msg = 'Unable to login: ' + error.message+' ';

        msg += error.details.join(', ');

        $('#msgcontainer').html(msg);

        $('#phonecontainer').cwic('unregisterPhone', {

            forceLogout: true

        });

        $('#username').attr('disabled', false);

        $('#cucm').attr('disabled', false);

        $('#mode').attr('disabled', false);

        $('#auth').attr('disabled', false);

        $('#loginbtn').attr('disabled', false);

        $('#logoutbtn').attr('disabled', true);

        $('#callbtn').attr('disabled', true);

        $('#switchmodebtn').attr('disabled', true);

        $('#callbtn').attr('disabled', true);

    };

    function transferButtonClick() {

        var transferCallId = $("#transferlist option:selected").val();

        var currentCall = calls.getSelectedCall();

        if(currentCall.callId !== transferCallId) {

            calls.getCallDiv().cwic('updateConversation', {'transferCall':transferCallId});

        }

    }

    function conferenceButtonClick() {

        var joinCallId = $("#conferencelist option:selected").val();

        var joinCall = calls.getCall(joinCallId);

        var currentCall = calls.getSelectedCall();

        if(!joinCall || !currentCall) {

            settings.log("Call does not exist");

            return;

        }

        var currentParticipants = (currentCall.isConference ? currentCall.participants.length : 1);

        var joinParticipants = (joinCall.isConference ? joinCall.participants.length : 1);

        // if 2 conference calls are joined, we get a conference with n+1 participants one of whom is a conference, not n+m participants

        if(currentCall.isConference && joinCall.isconference) {

            joinParticipants = 1;

        }

        // maxParticipants is either 0 (if not a conference), a positive number if the call is a conference, or -1 if it cannot be determined

        // if -1, we attempt to conference anyway - at worst it just won't conference and the calls are left as is

        if((joinCall.isConference && joinCall.maxParticipants > 0 && (currentParticipants + joinParticipants > joinCall.maxParticipants)) || (currentCall.isConference && currentCall.maxParticipants > 0 && (currentParticipants + joinParticipants > currentCall.maxParticipants))) {

            settings.log("Cannot join calls, max participants exceeded.");

            return;

        }

        calls.getCallDiv().cwic('updateConversation', {'joinCall':joinCallId});

    };

    function updateTransferConferenceLists(conversation) {

        var existingCalls = calls.getCalls();

        var text = '';

        $('#conferencelist').empty();

        $('#transferlist').empty();

        var conferenceAvailable = false;

        var transferAvailable = false;

        if(conversation && conversation.callState === "Connected") {

            for(var call in existingCalls) {

                if(existingCalls.hasOwnProperty(call)) {

                    if(conversation.capabilities.canJoinAcrossLine && existingCalls[call].callId !== conversation.callId && existingCalls[call].capabilities.canJoinAcrossLine) {

                        if(existingCalls[call].isConference) {

                            text = "Conference";

                        } else if(existingCalls[call].callType === "Outgoing") {

                            text=existingCalls[call].calledPartyDirectoryNumber;

                        } else {

                            text=existingCalls[call].callingPartyDirectoryNumber;

                        }

                        $('#conferencelist').append("<option value='" + existingCalls[call].callId + "'>" + text + "</option>");

                        conferenceAvailable = true;

                    }

                    if(conversation.capabilities.canDirectTransfer && existingCalls[call].callId !== conversation.callId && existingCalls[call].capabilities.canDirectTransfer) {

                        if(existingCalls[call].isConference) {

                            text = "Conference";

                        } else if(existingCalls[call].callType === "Outgoing") {

                            text=existingCalls[call].calledPartyDirectoryNumber;

                        } else {

                            text=existingCalls[call].callingPartyDirectoryNumber;

                        }

                        $('#transferlist').append("<option value='" + existingCalls[call].callId + "'>" + text + "</option>");

                        transferAvailable = true;

                    }

                }

            }

        }

        $('#conferencebtn').attr('disabled', !conferenceAvailable);

        $('#transferbtn').attr('disabled', !transferAvailable);

    };

    function escalateButtonClick() {

        var currentCall = calls.getSelectedCall();

        var $callcontainer = $('#callcontainer');

        if (currentCall.videoDirection === "Inactive" || currentCall.videoDirection === "RecvOnly") {

            calls.getCallDiv().cwic('updateConversation', {videoDirection:'SendRecv'});

            $callcontainer.find('.escalatebtn').text('De-escalate');

        }

        else if (currentCall.videoDirection === "SendRecv") {

            calls.getCallDiv().cwic('updateConversation', {videoDirection:'RecvOnly'});

            $callcontainer.find('.escalatebtn').text('Escalate');

        }

        else if (currentCall.videoDirection === "SendOnly") {

            calls.getCallDiv().cwic('updateConversation', {videoDirection:'RecvOnly'});

            $callcontainer.find('.escalatebtn').text('Escalate');

        }

        else {

            alert("invalid value for video direction!");

        }

    }

    </script>

  </head>

  <body>

    <div id="doc_wrapper">

    <!--  begin header -->

    <div id="header">

        <div id="headerLeft">

            <div id="title">

               <h2 style="display:inline;">Voice Call Demo</h2>

            </div>

            <div style="clear:both"></div>

        </div>

        <div id="headerRight">

            <div id="header_links">

                <!--<a target="_blank" href="http://jabberdeveloper.com/start-here">What Next?</a>-->

            </div>

        </div>

        <div class="title"></div>

    </div><!-- header -->

    <div class="alignright">

        <br/><br/>

        <div id="logindetails">

            <label for="username" id="usernameLabel">User Name:</label>

            <input type="text" id="username" value="{!loggedInUser.Jabber_ID__c}"/>

            <br/>

            <label for="password" id="passwordLabel">Password:</label>

            <input type="password" id="password" value="{!loggedInUser.Jabber_Password__c}"/>

            <br/>

            <!--<label for="cucm">CUCM:</label>

            <input type="text" id="cucm" value="{!loggedInUser.CUCM_Address__c}"/>

            <br/>

            <label for="mode">Mode:</label>

            <select id="mode">

                    <option value="SoftPhone">SoftPhone</option>

                    <option value="DeskPhone" selected="selected">DeskPhone</option>

            </select>

            <br/>

            <label for="auth" title="Additional server-side Authorisation">Server Auth:</label>

            <input type="checkbox" id="auth" /><br />

           

            <label for="validateCerts" title="Validate certs for authentication">Validate Cert:</label>

            <input type="checkbox" id="validateCerts" /><br />-->

            <label for="loginbtn"></label>

            <button id="loginbtn" type="button">Login</button>

            <button id="logoutbtn" type="button" disabled="true">Logout</button>

            <!--<div id="aboutcontainer">

                <div><span>cwic version: </span><span id="jsversion"></span></div>

                <div><span id="jssystem_release"></span></div>

                <div><span>jQuery version: </span><span id="jqueryversion"></span></div>

                <hr/>

                <div><span>plugin Version: </span><span id="pluginversion"></span></div>

                <div><span id="pluginsystem_release"></span></div>

                <div><span>ecc version: </span><span id="eccversion"></span></div>

            </div>-->

            <div id="devicedetails">

                <label for="devices">Device:</label><select id="devices"><option value="{!loggedInUser.cnxccm__Agent_Device_Name__c}" selected="selected">{!loggedInUser.cnxccm__Agent_Device_Name__c}</option></select>

                <!--<label for="forcereg">Force Reg:</label>

                <input type="checkbox" id="forcereg" />-->

                <label for="connectbtn"></label>

                <button id="connectbtn" type="button" disabled="disabled">Connect</button><br/>

            </div>

        </div>

    </div>

    <div id="phonecontainer"></div>

    <label for="dntodial" id="dnlabel">Number (and DTMF):</label>

    <input type="text" id="dntodial"/>

    <button type="button" id="callbtn" disabled="true">Make Call</button>

    <!--<input type="checkbox" id="videocall"/>with Video

    <button type="button" id="switchmodebtn" disabled="true">Switch Phonemode</button><br/>-->

    <ul id="calllist" class="calllist"></ul>

    <div id="msgcontainer"></div>

    <div class="alignleft">

        <!--<div id="localPreviewContainer">Local Preview

            <div id="localvidcontainer" tabindex="998"></div>

            <input name="showlocalvideo" type="radio" value="On"/>On

            <input name="showlocalvideo" type="radio" checked="checked" value="Off"/>Off

    <!-- enable to have one-click preview switch toggle <button type="button" id="togglepreview">toggle</button></span>         </div>-->

       <!-- <div id="mmDevices" class="mmDevices">

            <h3>Multimedia Devices<button type="button">Refresh Devices</button></h3>

            <label for="recordingDevicesSelect">Recording Device:</label>

            <select name="recordingDevicesSelect" id="recordingDevicesSelect"></select>

            <label for="playoutDevicesSelect">Playout Device:</label>

            <select name="playoutDevicesSelect" id="playoutDevicesSelect"></select>

            <label for="captureDevicesSelect">Capture Device:</label>

            <select name="captureDevicesSelect" id="captureDevicesSelect"></select>

        </div>-->

    </div>

    <div id="callcontainer" class="callcontainer">

        <div class="remotename"></div>

        <div class="callinfo"></div>

        <div id="videocontainer"></div>

        <!--<div class="videocontainer">

        <div id="remotevideocontainer" class="videocontainer" tabindex="999"></div>

        <iframe class="off" id="pinpwindow"></iframe></div></div>

        <button type="button" class="muteaudiobtn">Mute Audio</button>

        <button type="button" class="mutevideobtn">Mute Video</button>

        <button type="button" class="holdresumebtn">Hold</button>

        <button type="button" class="endbtn">End Call</button>

        <button type="button" id="fullscreenbtn">Fullscreen!</button>

        <button type="button" id="popoutbtn">Popout</button>

        <button id="showpinpvideo" type="button" class="off"><div class="pinp"></div></button>

        <br/>

        <select id="conferencelist"></select>

        <button type="button" id="conferencebtn" disabled="true">Conference</button>

        <br/><select id="transferlist"></select>

        <button type="button" id="transferbtn" disabled="true">Transfer</button>

        <br/>

        <button type="button" class="escalatebtn" >Escalate</button>-->

    </div>

  

    <div id="incomingcontainer" class="incomingcontainer" style="display:none">

        <div class="message"></div>

        <button type="button" class="answerbtn">Answer</button>

        <button type="button" class="divertbtn">Decline</button>

    </div>

    </div><!-- doc_wrapper -->

  </body>

</html>

</apex:page>

arupsarkar1
Level 1
Level 1

All:

Wanted to update that we tested with IE11, the behavior is the same as IE9. Every time user navigates to a different tab new instance id is getting generated, user is logged out of jabber and has to login again.

Please let us know if you found any workaround.

raulmora21
Level 1
Level 1

Hi Arup,

I'm a Salesforce consultan, I'm trying to implement a CTI in a project with Cisco, the customer uses Cisco Jabber v9-7-6. Could you please point me in the right direction on how to do this, I been reading about this for a couple of days now and don't know where to start.

I'll be really thankful if you could give me some tips to implement it base on the posts that you had made.

In advance, thank you for your time.

Have a great day!