You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					126 lines
				
				3.8 KiB
			
		
		
			
		
	
	
					126 lines
				
				3.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								var _ = require('underscore');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Escape XML entites in a given string
							 | 
						||
| 
								 | 
							
								function esc(str) {
							 | 
						||
| 
								 | 
							
								    return String(str).replace(/&/g, '&')
							 | 
						||
| 
								 | 
							
								        .replace(/\"/g, '"')
							 | 
						||
| 
								 | 
							
								        .replace(/\'/g, ''')
							 | 
						||
| 
								 | 
							
								        .replace(/</g, '<')
							 | 
						||
| 
								 | 
							
								        .replace(/>/g, '>');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//helper to generate a helper function which returns XML node for a given parent
							 | 
						||
| 
								 | 
							
								function addTwimlFunction(node, twimlName) {
							 | 
						||
| 
								 | 
							
								    //Generate a function on the parent node
							 | 
						||
| 
								 | 
							
								    node[twimlName.charAt(0).toLowerCase() + twimlName.slice(1)] = function() {
							 | 
						||
| 
								 | 
							
								        var text, attributes, builder, legalNodes = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Get XML components from the caller
							 | 
						||
| 
								 | 
							
								        for (var i = 0, l = arguments.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								            var arg = arguments[i];
							 | 
						||
| 
								 | 
							
								            if (typeof arg === 'string') {
							 | 
						||
| 
								 | 
							
								                text = arg;
							 | 
						||
| 
								 | 
							
								            } else if (typeof arg === 'function') {
							 | 
						||
| 
								 | 
							
								                builder = arg;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                attributes = arg;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //determine legal sub-nodes based on the node name
							 | 
						||
| 
								 | 
							
								        switch(twimlName) {
							 | 
						||
| 
								 | 
							
								            case 'Gather': legalNodes = ['Say','Play','Pause']; break;
							 | 
						||
| 
								 | 
							
								            case 'Dial': legalNodes = ['Number','Client','Conference','Queue','Sip']; break;
							 | 
						||
| 
								 | 
							
								            case 'Message': legalNodes = ['Media', 'Body']; break;
							 | 
						||
| 
								 | 
							
								            case 'Enqueue': legalNodes = ['Task']; break;
							 | 
						||
| 
								 | 
							
								            default: break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //create new node object
							 | 
						||
| 
								 | 
							
								        var newNode = new Node({
							 | 
						||
| 
								 | 
							
								            name:twimlName,
							 | 
						||
| 
								 | 
							
								            attributes:attributes,
							 | 
						||
| 
								 | 
							
								            text:text,
							 | 
						||
| 
								 | 
							
								            legalNodes:legalNodes
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //create node's API for subnodes and call builder function, if need be
							 | 
						||
| 
								 | 
							
								        if (!text && legalNodes.length > 0 && builder) {
							 | 
						||
| 
								 | 
							
								            legalNodes.forEach(function(legalNodeName) {
							 | 
						||
| 
								 | 
							
								                addTwimlFunction(newNode, legalNodeName);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								            builder.call(newNode, newNode);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Assemble the proper XML node and add to parent node
							 | 
						||
| 
								 | 
							
								        node.children.push(newNode);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //return the node, to allow for chaining
							 | 
						||
| 
								 | 
							
								        return node;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 A TwiML response node - nestable with other TwiML nodes
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 @param {object} config - options for HTTP request
							 | 
						||
| 
								 | 
							
								 - name {string}: name of this node
							 | 
						||
| 
								 | 
							
								 - attributes {object}: key-value pairs for XML attributes for this node
							 | 
						||
| 
								 | 
							
								 - text {string}: text content, if any, for this node
							 | 
						||
| 
								 | 
							
								 - topLevel {boolean}: indicates a top level node which should also print an XML instruction
							 | 
						||
| 
								 | 
							
								 - legalNodes {array<string>}: a list of child functions which should be allowable for this node
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function Node(config) {
							 | 
						||
| 
								 | 
							
								    _.extend(this,config);
							 | 
						||
| 
								 | 
							
								    this.children = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //create child adder functions based on legal nodes
							 | 
						||
| 
								 | 
							
								    var that = this;
							 | 
						||
| 
								 | 
							
								    this.legalNodes.forEach(function(val) {
							 | 
						||
| 
								 | 
							
								        addTwimlFunction(that,val);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//Output the contents of this XML node as a string
							 | 
						||
| 
								 | 
							
								Node.prototype.toString = function() {
							 | 
						||
| 
								 | 
							
								    var buffer = [];
							 | 
						||
| 
								 | 
							
								    if (this.topLevel) {
							 | 
						||
| 
								 | 
							
								        buffer.push('<?xml version="1.0" encoding="UTF-8"?>');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //Start node
							 | 
						||
| 
								 | 
							
								    buffer.push('<'+this.name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //handle attributes
							 | 
						||
| 
								 | 
							
								    for (var attr in this.attributes) {
							 | 
						||
| 
								 | 
							
								        buffer.push(' ' + attr + '="' + esc(this.attributes[attr]) + '"');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //Close start tag
							 | 
						||
| 
								 | 
							
								    buffer.push('>');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //process contents of tag
							 | 
						||
| 
								 | 
							
								    if (this.text) {
							 | 
						||
| 
								 | 
							
								        buffer.push(esc(this.text));
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        //process child tags
							 | 
						||
| 
								 | 
							
								        for (var i = 0, l = this.children.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								            buffer.push(this.children[i]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //close tag
							 | 
						||
| 
								 | 
							
								    buffer.push('</'+this.name+'>');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return buffer.join('');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//Public interface is a Response node with the initial set of TwiML child nodes available
							 | 
						||
| 
								 | 
							
								module.exports = function() {
							 | 
						||
| 
								 | 
							
								    return new Node({
							 | 
						||
| 
								 | 
							
								        topLevel:true,
							 | 
						||
| 
								 | 
							
								        name:'Response',
							 | 
						||
| 
								 | 
							
								        legalNodes:['Say', 'Play', 'Gather', 'Record', 'Sms', 'Dial', 'Enqueue', 'Task', 'Leave', 'Hangup', 'Redirect', 'Reject', 'Pause', 'Message']
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								};
							 |