CCXML 1.0-W3C Development GuideHome  |  Frameset Home

  Dialog Extension: x-recordaudio  |  TOC  |  F: Outbound Dialing  

Appendix E: Client Side Scripting

Most of the attribute values in CCXML 1.0 are treated as ECMAScript code, which basically presents it's own programming language in a small space. Usually such expressions are used to simply combine variable values or perform conditional operations. When writing ECMAScript code for CCXML 1.0, always focus on what's between the quotes and treat this as an isolated unit, which needs to be processed by the ECMAScript engine of the Prophecy CCXML 1.0 platform.

As a refresher, here are a few key points to keep in mind:


The result of an executed ECMAScript expression is a simple string value, for which the meaning, (obviously), depends on the attribute itself. This why you will see the already resolved values when viewing the Voxeo Log Viewer. The only exceptions here are conditional expressions. For instance, an <if> or an <elseif> where the result is a simple 'true' or 'false'.

log statements via ECMAScript

One of the cooler things that the Voxeo engineers have added in the Prophecy CCXML 1.0 platform is the ability to stream log statements to the application debugger, which was previously not available. As we all know, using log statements are really the best way to help debug applications, and implementing statements within your client-side scripting can save a lot of headaches when trying to track down errors when your function isn't working as designed. The simple syntax for using this within your applications is as follows:


<script>
<![CDATA[
  var myVariable ='some cool value'
  ccxmllog("myVariable = "+myVariable);
]]>
</script>



Sample ECMAScript code

Here, we are putting together useful little scripts that we have provided our developers with in the past, and sharing the wealth with everyone. If you have an idea for something that would be useful here, just let us know, and we can usually oblige.

Authentication by Hour

<?xml version="1.0" encoding="UTF-8"?>

<!--
This CCXML 1.0 sample application illustrates the usage of inline ECMAScript.
The purpose of this application is to allow, or disallow callers into the IVR system based on time of day.
If the call occurs between 8am, and 5pm we allow the caller into the application
If the call occurs between 5:01pm and 7:59am we lock the caller out
-->

<ccxml version="1.0">

  <var name="initState" expr="'state_1'"/>
  <var name="MyCallID"/>

  <script>
  <![CDATA[
// get date and time in GMT timezone
      var myDate = new Date();
      var myHour = myDate.getHours();
     
// define the initial variable that allows or disallows caller into the system
      var callerAllowed = 'true';
     
// if the call is not between 8am and 5pm Eastern time, then disallow the caller in the system
        if ((myHour >=22) || (myHour < 13)) callerAllowed = 'false';
    ]]>
  </script>

  <eventprocessor statevariable="initState">

    <transition event="connection.alerting" state="state_1">
      <assign name="MyCallID" expr="event$.connectionid"/>
     
      <log expr="'*** myDate = ' + new Date();"/>
      <log expr="'*** myDate.getHours = ' + myDate.getHours();"/>

      <log expr="'*** myHours = ' + myHour"/>
      <log expr="'*** callerAllowed = ' + callerAllowed"/>
 
      <send data="'MyEvent'" target="session.id"/>
    </transition>

    <transition event="MyEvent">
        <accept connectionid="MyCallID"/>
    </transition>

<!-- if the 'callerAllowed' variable defined in the ECMA above is set to 'true', play the 'business hours' dialog -->
    <transition event="connection.connected" cond="callerAllowed =='true'">
      <log expr="'***** CALL OCCURRED DURING BUSINESS HOURS *****'"/>
      <dialogstart src="'null://?text=You have reached the IVR system during business hours. If there were any other options here, you would be allowed to proceed.'" type="'application/x-texttospeech'"/>
    </transition>

<!-- if the 'callerAllowed' variable defined in the ECMA above is set to 'false', play the 'non business hours' dialog -->
    <transition event="connection.connected" cond="callerAllowed == 'false'">
      <log expr="'***** CALL OCCURRED DURING OFF HOURS *****'"/>
      <dialogstart src="'null://?text=You have reached the IVR system during non business hours. Therefore, we cannot proceed any further. Goodbye.'" type="'application/x-texttospeech'"/>
    </transition>

    <transition event="dialog.exit">
      <log expr="'***** CALL EXITING *****'"/>
      <exit/>
    </transition>
  </eventprocessor>
</ccxml>



Conference Timer

<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0">

<!--
THIS SCRIPT ILLUSTRATES THE USAGE OF AN EXTERNAL SCRIPT THAT CAN BE USED TO CAPTURE  A CONFERENCE DURATION
WHEN THERE IS ONLY ONE CALL LEFT ON THE LINE, (1 INDIAL CALLER, AND 2 CALLED PARTIES), THE LAST LINE WILL
BE PROGRAMMATICALLY DISCONNECTED, AND THE DURATION OF THE CONFERENCE PRINTED IN A LOG STATEMENT

NOTE THAT YOU CAN EAISLY GRAB THE *ENTIRE* CALL DURATION BY ACCESSING THE VOXEO SPECIFIC '_callstarttime'
AND '_callendtime' EXTENSION
PARAMETERS OF THE 'CONNECTION' OBJECT
-->


<script src="timer.js"/>

<!-- DECLARE TIMER VARIABLES FOR CONFERENCE START -->

<var name="startTime"/>
<var name="startHour"/>
<var name="startMinutes"/>
<var name="startSeconds"/>

<!-- DECLARE TIMER VARIABLES FOR CONFERENCE END -->
<var name="endTime"/>
<var name="endHour"/>
<var name="endMinutes"/>
<var name="endSeconds"/>



<var name="caller1id"/>
<var name="caller2id"/>
<var name="confid"/>
<var name="state0" expr="'not_inited'"/>
<var name="incomingcall"/>
<var name="callcount" expr="0"/>

<eventprocessor statevariable="state0">
  <transition event="ccxml.loaded">
  </transition>

  <transition event="connection.alerting">
    <assign name="state0" expr="'accepting'"/>
    <assign name="incomingcall" expr="event$.connectionid"/>
    <accept/>
  </transition >

  <transition event="connection.connected" state="accepting">
    <assign name="callcount" expr="callcount+1"/>
    <dialogstart src="'null://?text=Please wait for all parties to join&amp;termdigits=1'" type="'application/x-texttospeech'"/>
    <log expr="'*** CREATING CONFERENCE ***'"/>
    <createconference conferenceid="confid"/>
    </transition>

    <transition event="dialog.exit" state="accepting">
    <assign name="state0" expr="'joining0'"/>
    <join id1="confid" id2="incomingcall"/>
    </transition>

    <transition event="conference.created">
    </transition>

    <transition event="conference.joined" state="joining0">
    <assign name="state0" expr="'calling1'"/>
    <log expr="'*** DIALING FIRST PARTY ***'"/>
    <createcall dest="'tel:4078350053'" callerid="'1112223333'" connectionid="caller1id"/>
    </transition>

    <transition event="connection.connected" state="calling1">
    <assign name="callcount" expr="callcount+1"/>
    <assign name="state0" expr="'calling2'"/>
    <dialogstart src="'null://?text=Please wait for all parties to join&amp;termdigits=1'" type="'application/x-texttospeech'"/>
    </transition>

    <transition event="dialog.exit" state="calling2">
      <join id1="confid" id2="caller1id"/>
    </transition>

    <transition event="conference.joined" state="calling2">
    <log expr="'*** DIALING SECOND PARTY ***'"/>
    <createcall dest="'tel:4078350068'" callerid="'3334445555'" connectionid="caller2id"/>
    </transition>

    <transition event="connection.connected" state="calling2">
      <assign name="callcount" expr="callcount+1"/>
      <assign name="state0" expr="'joining2'"/>
      <log expr="'*** JOINING SECOND PARTY: ' + confid"/>


    <log expr="'*** START TIMER ***'"/>
    <assign name="startTime" expr="padZero(Hour) + ':' +  padZero(Minutes) + ':' + padZero(Seconds)"/>
    <assign name="startHour" expr="padZero(Hour)"/>
    <assign name="startMinutes" expr="padZero(Minutes)"/>
    <assign name="startSeconds" expr="padZero(Seconds)"/>

      <join id1="confid" id2="caller2id"/>
    </transition>

    <transition event="conference.joined" state="joining2">
    <log expr="'*** ALL PARTIES JOINED IN CONFERENCE ***'"/>

    </transition>

    <transition event="connection.disconnected">
    <assign name="callcount" expr="callcount-1"/>
    <if cond="callcount == 1">
      <!-- ONE PERSON STILL ON CONFERENCE; DISCONNECT HIM -->
      <destroyconference conferenceid="confid"/>
      <script src="timer.js"/>

      <assign name="endTime" expr="padZero(Hour) + ':' +  padZero(Minutes) + ':' + padZero(Seconds)"/>
      <assign name="endHour" expr="padZero(Hour)"/>
      <assign name="endMinutes" expr="padZero(Minutes)"/>
      <assign name="endSeconds" expr="padZero(Seconds)"/>

      <log expr="'*****  CALL DISCONNECTED, CAPTURING THE END TIME *****'"/>
      <log expr="'THE START TIME OF THIS CALL IS (GMT - hh:mm:ss): ' + startTime"/>
      <log expr="'THE END TIME OF THIS CALL IS (GMT - hh:mm:ss): ' + endTime"/>
      <log expr="'THE CALL DURATION IS (hh:mm:ss): ' + calculateLength(startHour, startMinutes, startSeconds, endHour, endMinutes, endSeconds)"/>


      <exit/>
    </if>
    </transition>

    <transition event="error.conference.join" state="joining1">
    <log expr="'*** ERROR CONNECTING SECOND PARTY ***'"/>
    <exit/>
    </transition>

    <transition event="error.conference.join" state="joining2">
    <log expr="'*** ERROR CONNECTING THIRD PARTY ***'"/>
    <exit/>
    </transition>

    <transition event="conference.destroyed">
    <log expr="'*** CONFERENCE DESTROYED ***'"/>
    <exit/>
    </transition>

    <transition event="error.*">
    <log expr="'*** ERROR DETECTED: '+ event$.name"/>
    <exit/>
    </transition>

    </eventprocessor>
</ccxml>



Timer.js

tempTime = new Date();
Minutes = tempTime.getUTCMinutes();             
Hour = tempTime.getUTCHours();
Seconds = tempTime.getUTCSeconds();
//** ensure that any singular return values are padded with a preceding zero
function padZero (s) {
if(s < 10) {
s = "0" + s;
}

return s;
}
function calculateLength(sh, sm, ss, eh, em, es) {
//** account for clock rollover (hour/minute/seconds)
  if (eh < sh) {
    eh = (eh + 12);
}
  if (em < sm) {
      em = (em + 60);
}
  if (es < ss)  {
      es = (es + 60);
}
//** compute callend time minus callstart time
    timerH = padZero((eh - sh));
    timerM = padZero((em - sm));
    timerS = padZero((es - ss));
//** concatenate results to a single value
    call_length = timerH + ':' + timerM + ':' + timerS;
//** return call length to invoking application
return call_length;
}



JSON.stringify() and JSON.parse()

JSON is a simple exchange format for representing objects and similar data structures that can be leveraged to some extent when developing on the Voxeo platform. At present, we support the following functions in the Prophecy CCXML 1.0 browser:


While we have a full-blown tutorial that touches on this subject as well, we also present a stripped down example here for reference purposes:

JSON Example

<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<!-- DECLARE AN OBJECT -->
<script>
<![CDATA[
    var myObject = new Object();
    myObject.v1 = 'value_1';
    myObject.v2 = 'value_2';

    myObject.Arr = new Array();
    myObject.Arr.push('hello');
    myObject.Arr.push('world');

    myObject.Obj = new Object();
    myObject.Obj.Prop = 5;
]]>
</script>

<!-- TURN THE OBJECT INTO A STRING -->
  <var name="sendObj" expr="JSON.stringify(myObject)"/>


  <eventprocessor>
    <transition event="connection.alerting">
    <accept/>
    <log expr="'***** MYOBJECT = ' + myObject"/>
 
<!-- LOOP THRU THE PROPERTIES OF THE OBJECT ONE BY ONE -->
    <foreach object="myObject">
      <log expr="'*** MYOBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>

    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was accepted ***'"/>
      <log expr="'***** SENDING DATA ..... NOW! *****'"/>
      <log expr="'***** SENDOBJ = ' + sendObj"/>
      <log expr="'***** MYOBJ = ' + myObject"/>
<!-- SEND OUR STRINGIFIED OBJECT TO A PHP CATCHER SCRIPT WHICH POSTS BACK TO US -->
      <send name="'http.get'" target="'sendCatcher.php'" targettype="'basichttp'" namelist="sendObj"/>
    </transition>


    <transition event="myEvent">
<!-- TURN OUR STRING BACK INTO AN OBJECT -->
    <var name="reObj" expr="JSON.parse(event$.sendObj)"/>
    <log expr="'***** DATA RECIEVED FROM SERVER *****'"/>
      <log expr="'***** AFTER SEND: REOBJ = ' + reObj"/>
    <exit/>   
    </transition>

    <transition event="send.successful">
    <log expr="'***** SEND IS SUCCESSFUL *****'"/>
    </transition>

  <transition event="error.send.targetunavailable">
    <log expr="'***** SEND TARGET UNAVAILABLE *****'"/>
    <exit/>
  </transition>

    <transition event="connection.disconnected">
      <log expr="'*** Call was disconnected ***'"/>
      <exit/>
    </transition>
 
    <transition event="error.*">
      <voxeo:sendemail to="'youremail@somewhere.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body="'We had an error! \n Time to panic! \n
                            Flee the cities, abandon all hope!'"/>
    <exit/>
    </transition>
  </eventprocessor>
</ccxml>



E4X Scripting

The Prophecy CCXML 1.0 implementation also directly supports E4X client side scripting, which can save the developer quite a bit of work: in the past, we would have to use clunky DOM interfaces to access data contained in external XML document nodes, but E4X allows us to use a simpler, and more powerful alternative. So what the heck is this "E4X" stuff anyhow? Well, E4X is a somewhat cutesy acronym for "ECMAScript for XML", which, at it's core, is a language extension that adds native XML support to ECMAScript. The result is a much simpler means of accessing data contained in our external XML document. How much more simple? You can compare "Old School" retrieval of XML data via DOM by looking at the code samples available for the <data> element within the VoiceXML documentation, and comparing it to what we have below.


E4X.xml

<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">
    <var name="state0" expr="'init'"/>
    <eventprocessor statevariable="state0">
        <transition event="connection.alerting">
            <script>
                <![CDATA[

              // DECLARE THE VARIABLE
              var note;

          // DECLARE THE XML AS A STRING EMBEDDED IN THE ECMA
                note = "<note><date>2002-08-01</date><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>";

              // CREATE NEW XML OBJECT FROM THE STRING VALUE OF THE XML DATA DECLARED ABOVE
                var x = new XML(note);

              // NOTE: 'ccxml.log' IS A WAY GENERATING A LOG STATEMENT INSIDE OF ECMASCRIPT
                ccxmllog("from = "+x.from);

                // NEW XML OBJECT USING THE XML DIRECTLY EMBEDDED IN THE DOCUMENT
                var y = new XML();
                y=
                <note>
                <date>2002-08-01</date>
                <to>Tove</to>
                <from>Jani</from>
                <heading>Reminder</heading>
                <body>Don't forget me this weekend!</body>
                </note>


              // LOG: 'Y.FROM'  IS EQUAL TO 'X.FROM'
                ccxmllog("from2 = " +y.from);
                ccxmllog("type = " + typeof(y));
                    ]]>
            </script>
            <accept/>
        </transition>

        <transition event="connection.connected">
            <!-- LOAD THE DOCUMENT INTO THE NAMESPACE  -->
            <!-- NOTE THE FETCH 'TYPE' VALUE THAT IS SPECIFIED -->

            <fetch type="'text/xml+e4x'" next="'xmldata.xml'"/>
        </transition>

        <transition event="fetch.done">
            <!-- THE DATA IS NOW AVAILABLE AS event$.data, WHICH IS, IN THIS CASE, AN XML OBJECT -->
            <log expr="'from in fetch='+evt.data.from+'  = '+evt.data.body"/>
            <log expr="'data = '+JSON.stringify(evt)"/>
            <exit/>
        </transition>

        <transition event="error.fetch">
            <exit/>
        </transition>

        <transition event="connection.disconnected">
            <exit/>
        </transition>

        <transition event="dialog.exit">
            <exit/>
        </transition>

        <transition event="error.*">
            <log expr="'Houston, we have a problem: (' + event$.reason + ')'"/>
            <exit/>
        </transition>
    </eventprocessor>
</ccxml>



xmldata.xml

<note>
<date>2002-08-01</date>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>


  Download the CCXML 1.0 source code!




  ANNOTATIONS: EXISTING POSTS
0 posts - click the button below to add a note to this page

login
  Dialog Extension: x-recordaudio  |  TOC  |  F: Outbound Dialing  

© 2008 Voxeo Corporation  |  Voxeo IVR  |  VoiceXML & CCXML IVR Developer Site