check in raw verto js files and directory structure for development
No files matched your search
@@ -0,0 +1,3 @@
|
||||
This needs to be fleshed out more.
|
||||
It would be nice to develop a web app here that implements a web phone.
|
||||
Do not base it on the demo because it was just tossed together.
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,12 @@
|
||||
/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
|
||||
|
||||
/*!
|
||||
* jQuery Mobile 1.3.2
|
||||
* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
|
||||
* http://jquerymobile.com
|
||||
*
|
||||
* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
*/.ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:700;text-shadow:0 -1px 0 #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#111));background-image:-webkit-linear-gradient(#3c3c3c,#111);background-image:-moz-linear-gradient(#3c3c3c,#111);background-image:-ms-linear-gradient(#3c3c3c,#111);background-image:-o-linear-gradient(#3c3c3c,#111);background-image:linear-gradient(#3c3c3c,#111)}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a a.ui-link{color:#7cc4e7;font-weight:700}.ui-bar-a a.ui-link:visited{color:#2489ce}.ui-bar-a a.ui-link:hover{color:#2489ce}.ui-bar-a a.ui-link:active{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 0 #111;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#222));background-image:-webkit-linear-gradient(#444,#222);background-image:-moz-linear-gradient(#444,#222);background-image:-ms-linear-gradient(#444,#222);background-image:-o-linear-gradient(#444,#222);background-image:linear-gradient(#444,#222)}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:700}.ui-body-a .ui-link:visited{color:#2489ce}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#2d2d2d));background-image:-webkit-linear-gradient(#444,#2d2d2d);background-image:-moz-linear-gradient(#444,#2d2d2d);background-image:-ms-linear-gradient(#444,#2d2d2d);background-image:-o-linear-gradient(#444,#2d2d2d);background-image:linear-gradient(#444,#2d2d2d)}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#383838));background-image:-webkit-linear-gradient(#555,#383838);background-image:-moz-linear-gradient(#555,#383838);background-image:-ms-linear-gradient(#555,#383838);background-image:-o-linear-gradient(#555,#383838);background-image:linear-gradient(#555,#383838)}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#202020),to(#2c2c2c));background-image:-webkit-linear-gradient(#202020,#2c2c2c);background-image:-moz-linear-gradient(#202020,#2c2c2c);background-image:-ms-linear-gradient(#202020,#2c2c2c);background-image:-o-linear-gradient(#202020,#2c2c2c);background-image:linear-gradient(#202020,#2c2c2c)}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:700;text-shadow:0 1px 0 #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#497bae));background-image:-webkit-linear-gradient(#6facd5,#497bae);background-image:-moz-linear-gradient(#6facd5,#497bae);background-image:-ms-linear-gradient(#6facd5,#497bae);background-image:-o-linear-gradient(#6facd5,#497bae);background-image:linear-gradient(#6facd5,#497bae)}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b a.ui-link{color:#ddf0f8;font-weight:700}.ui-bar-b a.ui-link:visited{color:#ddf0f8}.ui-bar-b a.ui-link:hover{color:#ddf0f8}.ui-bar-b a.ui-link:active{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#ccc));background-image:-webkit-linear-gradient(#ddd,#ccc);background-image:-moz-linear-gradient(#ddd,#ccc);background-image:-ms-linear-gradient(#ddd,#ccc);background-image:-o-linear-gradient(#ddd,#ccc);background-image:linear-gradient(#ddd,#ccc)}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:700}.ui-body-b .ui-link:visited{color:#2489ce}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:700;coloLine truncated
|
||||
@@ -0,0 +1,64 @@
|
||||
.nthChildTest > div:nth-child(odd) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.jsDataTable > thead > tr > th {
|
||||
|
||||
border-width:4px;
|
||||
padding: 2px;
|
||||
font-size:10pt;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
.jsDataTable > thead > tr > th.notSortable {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.jsDataTable > tbody > tr > td {
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.jsDataTable {
|
||||
font-family: verdana;
|
||||
font-size:10pt;
|
||||
|
||||
}
|
||||
|
||||
.jsDataTable > tbody > tr:nth-child(odd),
|
||||
.jsDataTable > tbody > tr.odd {
|
||||
background-color: #ffffee;
|
||||
}
|
||||
.jsDataTable > tbody > tr:nth-child(even),
|
||||
.jsDataTable > tbody > tr.even {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.jsDataTable > thead th.sortAsc,
|
||||
.jsDataTable > thead th.sortDesc {
|
||||
color:ffffff;
|
||||
|
||||
background-color: #7777ff;
|
||||
background-position: right center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.jsDataTable > thead th.sortAsc {
|
||||
background-image: url(/images/table/asc.png);
|
||||
}
|
||||
|
||||
.jsDataTable > thead th.sortDesc {
|
||||
background-image: url(/images/table/desc.png);
|
||||
}
|
||||
|
||||
.jsDataTable.clickable > tbody > tr,
|
||||
.clickable > .jsDataTable > tbody > tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.jsDataTable.clickable > tbody > tr.nonDataRow,
|
||||
.clickable > .jsDataTable > tbody > tr.nonDataRow {
|
||||
cursor: auto;
|
||||
}
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 773 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,5 @@
|
||||
<script>
|
||||
document.location = "https://" + window.location.hostname + "/verto/verto.html";
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
|
||||
//# sourceMappingURL=jquery-2.0.3.min.map
|
||||
*/
|
||||
(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(tLine truncated
|
||||
};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:functLine truncated
|
||||
},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>Line truncated
|
||||
@@ -0,0 +1,90 @@
|
||||
/*!
|
||||
* jQuery Cookie Plugin v1.3.1
|
||||
* https://github.com/carhartl/jquery-cookie
|
||||
*
|
||||
* Copyright 2013 Klaus Hartl
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function ($, document, undefined) {
|
||||
|
||||
var pluses = /\+/g;
|
||||
|
||||
function raw(s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
function decoded(s) {
|
||||
return unRfc2068(decodeURIComponent(s.replace(pluses, ' ')));
|
||||
}
|
||||
|
||||
function unRfc2068(value) {
|
||||
if (value.indexOf('"') === 0) {
|
||||
// This is a quoted cookie as according to RFC2068, unescape
|
||||
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function fromJSON(value) {
|
||||
return config.json ? JSON.parse(value) : value;
|
||||
}
|
||||
|
||||
var config = $.cookie = function (key, value, options) {
|
||||
|
||||
// write
|
||||
if (value !== undefined) {
|
||||
options = $.extend({}, config.defaults, options);
|
||||
|
||||
if (value === null) {
|
||||
options.expires = -1;
|
||||
}
|
||||
|
||||
if (typeof options.expires === 'number') {
|
||||
var days = options.expires, t = options.expires = new Date();
|
||||
t.setDate(t.getDate() + days);
|
||||
}
|
||||
|
||||
value = config.json ? JSON.stringify(value) : String(value);
|
||||
|
||||
return (document.cookie = [
|
||||
encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
|
||||
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
||||
options.path ? '; path=' + options.path : '',
|
||||
options.domain ? '; domain=' + options.domain : '',
|
||||
options.secure ? '; secure' : ''
|
||||
].join(''));
|
||||
}
|
||||
|
||||
// read
|
||||
var decode = config.raw ? raw : decoded;
|
||||
var cookies = document.cookie.split('; ');
|
||||
var result = key ? null : {};
|
||||
for (var i = 0, l = cookies.length; i < l; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var name = decode(parts.shift());
|
||||
var cookie = decode(parts.join('='));
|
||||
|
||||
if (key && key === name) {
|
||||
result = fromJSON(cookie);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
result[name] = fromJSON(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
config.defaults = {};
|
||||
|
||||
$.removeCookie = function (key, options) {
|
||||
if ($.cookie(key) !== null) {
|
||||
$.cookie(key, null, options);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
})(jQuery, document);
|
||||
@@ -0,0 +1,23 @@
|
||||
/*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */
|
||||
(function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';}
|
||||
var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;}
|
||||
if(type==='number'||type==='boolean'){return String(o);}
|
||||
if(type==='string'){return $.quoteString(o);}
|
||||
if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());}
|
||||
if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;}
|
||||
if(day<10){day='0'+day;}
|
||||
if(hours<10){hours='0'+hours;}
|
||||
if(minutes<10){minutes='0'+minutes;}
|
||||
if(seconds<10){seconds='0'+seconds;}
|
||||
if(milli<100){milli='0'+milli;}
|
||||
if(milli<10){milli='0'+milli;}
|
||||
return'"'+year+'-'+month+'-'+day+'T'+
|
||||
hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
|
||||
pairs=[];if($.isArray(o)){for(k=0;k<o.length;k++){pairs.push($.toJSON(o[k])||'null');}
|
||||
return'['+pairs.join(',')+']';}
|
||||
if(typeof o==='object'){for(k in o){if(hasOwn.call(o,k)){type=typeof k;if(type==='number'){name='"'+k+'"';}else if(type==='string'){name=$.quoteString(k);}else{continue;}
|
||||
type=typeof o[k];if(type!=='function'&&type!=='undefined'){val=$.toJSON(o[k]);pairs.push(name+':'+val);}}}
|
||||
return'{'+pairs.join(',')+'}';}};$.evalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){return eval('('+str+')');};$.secureEvalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){var filtered=str.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)){return eval('('+str+')');}
|
||||
throw new SyntaxError('Error parsing JSON, source is not valid.');};$.quoteString=function(str){if(str.match(escape)){return'"'+str.replace(escape,function(a){var c=meta[a];if(typeof c==='string'){return c;}
|
||||
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
|
||||
return'"'+str+'"';};}(jQuery));
|
||||
@@ -0,0 +1,9 @@
|
||||
/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
|
||||
!function(a,b,c){"function"==typeof define&&define.amd?define(["jquery"],function(d){return c(d,a,b),d.mobile}):c(a.jQuery,a,b)}(this,document,function(a,b,c,d){!function(a){a.mobile={}}(a),function(a,b,d){var e={};a.mobile=a.extend(a.mobile,{version:"1.3.2",ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",focusClass:"ui-focus",ajaxEnabled:!0,hashListeningEnabled:!0,linkBindingEnabled:!0,defaultPageTransition:"fade",maxTransitionWidth:!1,minScrollBack:250,touchOverflowEnabled:!1,defaultDialogTransition:"pop",pageLoadErrorMessage:"Error Loading Page",pageLoadErrorMessageTheme:"e",phonegapNavigationEnabled:!1,autoInitializePage:!0,pushStateEnabled:!0,ignoreContentEnabled:!1,orientationChangeEnabled:!0,buttonMarkup:{hoverDelay:200},window:a(b),document:a(c),keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},behaviors:{},silentScroll:function(c){"number"!==a.type(c)&&(c=a.mobile.defaultHomeScroll),a.event.special.scrollstart.enabled=!1,setTimeout(function(){b.scrollTo(0,c),a.mobile.document.trigger("silentscroll",{x:0,y:c})},20),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},nsNormalizeDict:e,nsNormalize:function(b){return b?e[b]||(e[b]=a.camelCase(a.mobile.ns+b)):void 0},getInheritedTheme:function(a,b){for(var c,d,e=a[0],f="",g=/ui-(bar|body|overlay)-([a-z])\b/;e&&(c=e.className||"",!(c&&(d=g.exec(c))&&(f=d[2])));)e=e.parentNode;return f||b||"a"},closestPageData:function(a){return a.closest(':jqmData(role="page"), :jqmData(role="dialog")').data("mobile-page")},enhanceable:function(a){return this.haveParents(a,"enhance")},hijackable:function(a){return this.haveParents(a,"ajax")},haveParents:function(b,c){if(!a.mobile.ignoreContentEnabled)return b;for(var d,e,f,g=b.length,h=a(),i=0;g>i;i++){for(e=b.eq(i),f=!1,d=b[i];d;){var j=d.getAttribute?d.getAttribute("data-"+a.mobile.ns+c):"";if("false"===j){f=!0;break}d=d.parentNode}f||(h=h.add(e))}return h},getScreenHeight:function(){return b.innerHeight||a.mobile.window.height()}},a.mobile),a.fn.jqmData=function(b,c){var e;return"undefined"!=typeof b&&(b&&(b=a.mobile.nsNormalize(b)),e=arguments.length<2||c===d?this.data(b):this.data(b,c)),e},a.jqmData=function(b,c,d){var e;return"undefined"!=typeof c&&(e=a.data(b,c?a.mobile.nsNormalize(c):c,d)),e},a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))},a.jqmRemoveData=function(b,c){return a.removeData(b,a.mobile.nsNormalize(c))},a.fn.removeWithDependents=function(){a.removeWithDependents(this)},a.removeWithDependents=function(b){var c=a(b);(c.jqmData("dependents")||a()).remove(),c.remove()},a.fn.addDependents=function(b){a.addDependents(a(this),b)},a.addDependents=function(b,c){var d=a(b).jqmData("dependents")||a();a(b).jqmData("dependents",a.merge(d,c))},a.fn.getEncodedText=function(){return a("<div/>").text(a(this).text()).html()},a.fn.jqmEnhanceable=function(){return a.mobile.enhanceable(this)},a.fn.jqmHijackable=function(){return a.mobile.hijackable(this)};var f=a.find,g=/:jqmData\(([^)]*)\)/g;a.find=function(b,c,d,e){return b=b.replace(g,"[data-"+(a.mobile.ns||"")+"$1]"),f.call(this,b,c,d,e)},a.extend(a.find,f),a.find.matches=function(b,c){return a.find(b,null,null,c)},a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}}(a,this),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c,d=0;null!=(c=b[d]);d++)try{a(c).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i=b.split(".")[0];b=b.split(".")[1],e=i+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[i]=a[i]||{},f=a[i][b],g=a[i][b]=function(a,b){return this._createWidget?(arguments.length&&this._createWidget(a,b),void 0):new g(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,e){a.isFunction(e)&&(d[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},d=function(a){return c.prototype[b].apply(this,a)};return function(){var b,c=this._super,f=this._superApply;return this._super=a,this._superApply=d,b=e.apply(this,arguments),this._super=c,this._superApply=f,b}}())}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix:b},d,{constructor:g,namespace:i,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g)},a.widget.extend=function(c){for(var e,f,g=d.call(arguments,1),h=0,i=g.length;i>h;h++)for(e in g[h])f=g[h][e],g[h].hasLine truncated
|
||||
}if(d.which&&1!==d.which)return!1;var j,k=d.target;d.originalEvent,c.bind("vmouseup",g).bind("vclick",i),f.bind("vmousecancel",h),j=setTimeout(function(){e(b,"taphold",a.Event("taphold",{target:k}))},a.event.special.tap.tapholdThreshold)})}},a.event.special.swipe={scrollSupressionThreshold:30,durationThreshold:1e3,horizontalDistanceThreshold:30,verticalDistanceThreshold:75,start:function(b){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b;return{time:(new Date).getTime(),coords:[c.pageX,c.pageY],origin:a(b.target)}},stop:function(a){var b=a.originalEvent.touches?a.originalEvent.touches[0]:a;return{time:(new Date).getTime(),coords:[b.pageX,b.pageY]}},handleSwipe:function(b,c){c.time-b.time<a.event.special.swipe.durationThreshold&&Math.abs(b.coords[0]-c.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(b.coords[1]-c.coords[1])<a.event.special.swipe.verticalDistanceThreshold&&b.origin.trigger("swipe").trigger(b.coords[0]>c.coords[0]?"swipeleft":"swiperight")},setup:function(){var b=this,c=a(b);c.bind(i,function(b){function e(b){g&&(f=a.event.special.swipe.stop(b),Math.abs(g.coords[0]-f.coords[0])>a.event.special.swipe.scrollSupressionThreshold&&b.preventDefault())}var f,g=a.event.special.swipe.start(b);c.bind(k,e).one(j,function(){c.unbind(k,e),g&&f&&a.event.special.swipe.handleSwipe(g,f),g=f=d})})}},a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})}(a,this),function(a){a.event.special.throttledresize={setup:function(){a(this).bind("resize",f)},teardown:function(){a(this).unbind("resize",f)}};var b,c,d,e=250,f=function(){c=(new Date).getTime(),d=c-g,d>=e?(g=c,a(this).trigger("throttledresize")):(b&&clearTimeout(b),b=setTimeout(f,e-d))},g=0}(a),function(a,b){function d(){var a=e();a!==f&&(f=a,i.trigger(j))}var e,f,g,h,i=a(b),j="orientationchange",k={0:!0,180:!0};if(a.support.orientation){var l=b.innerWidth||i.width(),m=b.innerHeight||i.height(),n=50;g=l>m&&l-m>n,h=k[b.orientation],(g&&h||!g&&!h)&&(k={"-90":!0,90:!0})}a.event.special.orientationchange=a.extend({},a.event.special.orientationchange,{setup:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(f=e(),i.bind("throttledresize",d),void 0)},teardown:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(i.unbind("throttledresize",d),void 0)},add:function(a){var b=a.handler;a.handler=function(a){return a.orientation=e(),b.apply(this,arguments)}}}),a.event.special.orientationchange.orientation=e=function(){var d=!0,e=c.documentElement;return d=a.support.orientation?k[b.orientation]:e&&e.clientWidth/e.clientHeight<1.1,d?"portrait":"landscape"},a.fn[j]=function(a){return a?this.bind(j,a):this.trigger(j)},a.attrFn&&(a.attrFn[j]=!0)}(a,this),function(a){a.widget("mobile.page",a.mobile.widget,{options:{theme:"c",domCache:!1,keepNativeDefault:":jqmData(role='none'), :jqmData(role='nojs')"},_create:function(){return this._trigger("beforecreate")===!1?!1:(this.element.attr("tabindex","0").addClass("ui-page ui-body-"+this.options.theme),this._on(this.element,{pagebeforehide:"removeContainerBackground",pagebeforeshow:"_handlePageBeforeShow"}),void 0)},_handlePageBeforeShow:function(){this.setContainerBackground()},removeContainerBackground:function(){a.mobile.pageContainer.removeClass("ui-overlay-"+a.mobile.getInheritedTheme(this.element.parent()))},setContainerBackground:function(b){this.options.theme&&a.mobile.pageContainer.addClass("ui-overlay-"+(b||this.options.theme))},keepNativeSelector:function(){var b=this.options,c=b.keepNative&&a.trim(b.keepNative);return c&&b.keepNative!==b.keepNativeDefault?[b.keepNative,b.keepNativeDefault].join(", "):b.keepNativeDefault}})}(a),function(a,b,c){var d=function(d){return d===c&&(d=!0),function(c,e,f,g){var h=new a.Deferred,i=e?" reverse":"",j=a.mobile.urlHistory.getActive(),k=j.lastScroll||a.mobile.defaultHomeScroll,l=a.mobile.getScreenHeight(),m=a.mobile.maxTransitionWidth!==!1&&a.mobile.window.width()>a.mobile.maxTransitionWidth,n=!a.support.cssTransitions||m||!c||"none"===c||Math.max(a.mobile.window.scrollTop(),k)>a.mobile.getMaxScrollForTransition(),o=" ui-page-pre-in",p=function(){a.mobile.pageContainer.toggleClass("ui-mobile-viewport-transitioning viewport-"+c)},q=function(){a.event.special.scrollstart.enabled=!1,b.scrollTo(0,k),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},r=function(){g.removeClass(a.mobile.activePageClass+" out in reverse "+c).height("")},s=function(){d?g.animationComplete(t):t(),g.height(l+a.mobile.window.scrollTop()).addClass(c+" out"+i)},t=function(){g&&d&&r(),u()},u=function(){f.css("z-index",-10),f.addClass(a.mobile.activePageClass+o),a.mobile.focusPage(f),f.height(l+k),q(),f.css("z-index",""),n||f.animationComplete(v),f.removeClass(o).addClass(c+" in"+i),n&&v()},v=function(){d||g&&r(),f.removeClass("out in reverse "+c).height(""),p(),a.mobile.window.scrollTop(Line truncated
|
||||
c.parent().is(":jqmData(role='collapsible-set')")&&c.siblings(".ui-collapsible").trigger("collapse")})},_init:function(){var a=this.element,b=a.children(":jqmData(role='collapsible')"),c=b.filter(":jqmData(collapsed='false')");this._refresh("true"),c.trigger("expand")},_refresh:function(b){var c=this.element.children(":jqmData(role='collapsible')");a.mobile.collapsible.prototype.enhance(c.not(".ui-collapsible")),this._addFirstLastClasses(c,this._getVisibles(c,b),b)},refresh:function(){this._refresh(!1)}},a.mobile.behaviors.addFirstLastClasses)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.collapsibleset.prototype.enhanceWithin(b.target)})}(a),function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br").contents().filter(function(){return 3===this.nodeType&&!/\S/.test(this.nodeValue)}).remove()},a(c).bind("pagecreate create",function(b){a(":jqmData(role='fieldcontain')",b.target).jqmEnhanceable().fieldcontain()})}(a),function(a){a.fn.grid=function(b){return this.each(function(){var c,d=a(this),e=a.extend({grid:null},b),f=d.children(),g={solo:1,a:2,b:3,c:4,d:5},h=e.grid;if(!h)if(f.length<=5)for(var i in g)g[i]===f.length&&(h=i);else h="a",d.addClass("ui-grid-duo");c=g[h],d.addClass("ui-grid-"+h),f.filter(":nth-child("+c+"n+1)").addClass("ui-block-a"),c>1&&f.filter(":nth-child("+c+"n+2)").addClass("ui-block-b"),c>2&&f.filter(":nth-child("+c+"n+3)").addClass("ui-block-c"),c>3&&f.filter(":nth-child("+c+"n+4)").addClass("ui-block-d"),c>4&&f.filter(":nth-child("+c+"n+5)").addClass("ui-block-e")})}}(a),function(a,b){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null,initSelector:":jqmData(role='navbar')"},_create:function(){var d=this.element,e=d.find("a"),f=e.filter(":jqmData(icon)").length?this.options.iconpos:b;d.addClass("ui-navbar ui-mini").attr("role","navigation").find("ul").jqmEnhanceable().grid({grid:this.options.grid}),e.buttonMarkup({corners:!1,shadow:!1,inline:!0,iconpos:f}),d.delegate("a","vclick",function(b){var d=a(b.target).is("a")?a(this):a(this).parent("a");if(!d.is(".ui-disabled, .ui-btn-active")){e.removeClass(a.mobile.activeBtnClass),a(this).addClass(a.mobile.activeBtnClass);var f=a(this);a(c).one("pagehide",function(){f.removeClass(a.mobile.activeBtnClass)})}}),d.closest(".ui-page").bind("pagebeforeshow",function(){e.filter(".ui-state-persist").addClass(a.mobile.activeBtnClass)})}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.navbar.prototype.enhanceWithin(b.target)})}(a),function(a){var b={};a.widget("mobile.listview",a.mobile.widget,a.extend({options:{theme:null,countTheme:"c",headerTheme:"b",dividerTheme:"b",icon:"arrow-r",splitIcon:"arrow-r",splitTheme:"b",corners:!0,shadow:!0,inset:!1,initSelector:":jqmData(role='listview')"},_create:function(){var a=this,b="";b+=a.options.inset?" ui-listview-inset":"",a.options.inset&&(b+=a.options.corners?" ui-corner-all":"",b+=a.options.shadow?" ui-shadow":""),a.element.addClass(function(a,c){return c+" ui-listview"+b}),a.refresh(!0)},_findFirstElementByTagName:function(a,b,c,d){var e={};for(e[c]=e[d]=!0;a;){if(e[a.nodeName])return a;a=a[b]}return null},_getChildrenByTagName:function(b,c,d){var e=[],f={};for(f[c]=f[d]=!0,b=b.firstChild;b;)f[b.nodeName]&&e.push(b),b=b.nextSibling;return a(e)},_addThumbClasses:function(b){var c,d,e=b.length;for(c=0;e>c;c++)d=a(this._findFirstElementByTagName(b[c].firstChild,"nextSibling","img","IMG")),d.length&&(d.addClass("ui-li-thumb"),a(this._findFirstElementByTagName(d[0].parentNode,"parentNode","li","LI")).addClass(d.is(".ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb"))},refresh:function(b){this.parentPage=this.element.closest(".ui-page"),this._createSubPages();var d,e,f,g,h,i,j,k,l,m,n,o,p=this.options,q=this.element,r=q.jqmData("dividertheme")||p.dividerTheme,s=q.jqmData("splittheme"),t=q.jqmData("spliticon"),u=q.jqmData("icon"),v=this._getChildrenByTagName(q[0],"li","LI"),w=!!a.nodeName(q[0],"ol"),x=!a.support.cssPseudoElement,y=q.attr("start"),z={};w&&x&&q.find(".ui-li-dec").remove(),w&&(y||0===y?x?j=parseInt(y,10):(k=parseInt(y,10)-1,q.css("counter-reset","listnumbering "+k)):x&&(j=1)),p.theme||(p.theme=a.mobile.getInheritedTheme(this.element,"c"));for(var A=0,B=v.length;B>A;A++){if(d=v.eq(A),e="ui-li",b||!d.hasClass("ui-li")){f=d.jqmData("theme")||p.theme,g=this._getChildrenByTagName(d[0],"a","A");var C="list-divider"===d.jqmData("role");g.length&&!C?(n=d.jqmData("icon"),d.buttonMarkup({wrapperEls:"div",shadow:!1,corners:!1,iconpos:"right",icon:g.length>1||n===!1?!1:n||u||p.icon,theme:f}),n!==!1&&1===g.length&&d.addClass("ui-li-has-arrow"),g.first().removeClass("ui-link").addClass("ui-link-inherit"),g.length>1&&(e+=" ui-li-has-alt",h=g.last(),i=s||h.jqmData("theme")||p.splitTheme,o=h.jqmData("icon"),h.appendTo(d).attr("title",a.trim(h.getEncodedText())).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:!1,corners:!1,theme:f,icon:!1,iconpos:"notext"}).find(".ui-btn-inner").append(a(c.createElement("span")).Line truncated
|
||||
},_setDisabled:function(a){return this.element.attr("disabled",a),this.button.attr("aria-disabled",a),this._setOption("disabled",a)},_focusButton:function(){var a=this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){var b="";~this.element[0].className.indexOf("ui-btn-left")&&(b=" ui-btn-left"),~this.element[0].className.indexOf("ui-btn-right")&&(b=" ui-btn-right"),this.select=this.element.removeClass("ui-btn-left ui-btn-right").wrap("<div class='ui-select"+b+"'>"),this.selectID=this.select.attr("id"),this.label=a("label[for='"+this.selectID+"']").addClass("ui-select"),this.isMultiple=this.select[0].multiple,this.options.theme||(this.options.theme=a.mobile.getInheritedTheme(this.select,"c"))},_destroy:function(){var a=this.element.parents(".ui-select");a.length>0&&(a.is(".ui-btn-left, .ui-btn-right")&&this.element.addClass(a.is(".ui-btn-left")?"ui-btn-left":"ui-btn-right"),this.element.insertAfter(a),a.remove())},_create:function(){this._preExtension(),this._trigger("beforeCreate"),this.button=this._button();var c=this,d=this.options,e=d.inline||this.select.jqmData("inline"),f=d.mini||this.select.jqmData("mini"),g=d.icon?d.iconpos||this.select.jqmData("iconpos"):!1,h=(-1===this.select[0].selectedIndex?0:this.select[0].selectedIndex,this.button.insertBefore(this.select).buttonMarkup({theme:d.theme,icon:d.icon,iconpos:g,inline:e,corners:d.corners,shadow:d.shadow,iconshadow:d.iconshadow,mini:f}));this.setButtonText(),d.nativeMenu&&b.opera&&b.opera.version&&h.addClass("ui-select-nativeonly"),this.isMultiple&&(this.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(h.addClass("ui-li-has-count"))),(d.disabled||this.element.attr("disabled"))&&this.disable(),this.select.change(function(){c.refresh(),d.nativeMenu&&this.blur()}),this._handleFormReset(),this.build()},build:function(){var b=this;this.select.appendTo(b.button).bind("vmousedown",function(){b.button.addClass(a.mobile.activeBtnClass)}).bind("focus",function(){b.button.addClass(a.mobile.focusClass)}).bind("blur",function(){b.button.removeClass(a.mobile.focusClass)}).bind("focus vmouseover",function(){b.button.trigger("vmouseover")}).bind("vmousemove",function(){b.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){b.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}).bind("change blur",function(){b.button.removeClass("ui-btn-down-"+b.options.theme)}),b.button.bind("vmousedown",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.label.bind("click focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.select.bind("focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.button.bind("mouseup",function(){b.options.preventFocusZoom&&setTimeout(function(){a.mobile.zoom.enable(!0)},0)}),b.select.bind("blur",function(){b.options.preventFocusZoom&&a.mobile.zoom.enable(!0)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var b=this,d=this.selected(),e=this.placeholder,f=a(c.createElement("span"));this.button.find(".ui-btn-text").html(function(){return e=d.length?d.map(function(){return a(this).text()}).get().join(", "):b.placeholder,f.text(e).addClass(b.select.attr("class")).addClass(d.attr("class"))})},setButtonCount:function(){var a=this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},_reset:function(){this.refresh()},refresh:function(){this.setButtonText(),this.setButtonCount()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(!0),this.button.addClass("ui-disabled")},enable:function(){this._setDisabled(!1),this.button.removeClass("ui-disabled")}},a.mobile.behaviors.formReset)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.selectmenu.prototype.enhanceWithin(b.target,!0)})}(a),function(a,d){function e(a,b,c,d){var e=d;return e=b>a?c+(a-b)/2:Math.min(Math.max(c,d-b/2),c+a-b)}function f(){var c=a.mobile.window;return{x:c.scrollLeft(),y:c.scrollTop(),cx:b.innerWidth||c.width(),cy:b.innerHeight||c.height()}}a.widget("mobile.popup",a.mobile.widget,{options:{theme:null,overlayTheme:null,shadow:!0,corners:!0,transition:"none",positionTo:"origin",tolerance:null,initSelector:":jqmData(role='popup')",closeLinkSelector:"a:jqmData(rel='back')",closeLinkEvents:"click.popup",navigateEvents:"navigate.popup",closeEvents:"navigate.popup pagebeforechange.popup",dismissible:!0,history:!a.mobile.browser.oldIE},_eatEventAndClose:function(a){return a.preventDefault(),a.stopImmediatePropagation(),this.options.dismissible&&this.close(),!1},_resizeScreen:function(){var a=this._ui.container.outerHeight(!0);this._ui.screen.removeAttr("style"),a>this._ui.screen.height()&&this._ui.screen.height(a)},_handleWindowKeyUp:function(bLine truncated
|
||||
return c||(d=Math.round(d-a.mobile.window.height()+b.outerHeight())-60),d},_bindScrollWorkaround:function(){var b=this;this._on(a.mobile.window,{scrollstop:function(){var a=b._viewportOffset();a>2&&b._visible&&b._triggerRedraw()}})},_bindListThumbWorkaround:function(){this.element.closest(".ui-page").addClass("ui-android-2x-fixed")},_triggerRedraw:function(){var b=parseFloat(a(".ui-page-active").css("padding-bottom"));a(".ui-page-active").css("padding-bottom",b+1+"px"),setTimeout(function(){a(".ui-page-active").css("padding-bottom",b+"px")},0)},destroy:function(){this._super(),this.element.closest(".ui-page-active").removeClass("ui-android-2x-fix")}})}(a),function(a,d){a.widget("mobile.panel",a.mobile.widget,{options:{classes:{panel:"ui-panel",panelOpen:"ui-panel-open",panelClosed:"ui-panel-closed",panelFixed:"ui-panel-fixed",panelInner:"ui-panel-inner",modal:"ui-panel-dismiss",modalOpen:"ui-panel-dismiss-open",pagePanel:"ui-page-panel",pagePanelOpen:"ui-page-panel-open",contentWrap:"ui-panel-content-wrap",contentWrapOpen:"ui-panel-content-wrap-open",contentWrapClosed:"ui-panel-content-wrap-closed",contentFixedToolbar:"ui-panel-content-fixed-toolbar",contentFixedToolbarOpen:"ui-panel-content-fixed-toolbar-open",contentFixedToolbarClosed:"ui-panel-content-fixed-toolbar-closed",animate:"ui-panel-animate"},animate:!0,theme:"c",position:"left",dismissible:!0,display:"reveal",initSelector:":jqmData(role='panel')",swipeClose:!0,positionFixed:!1},_panelID:null,_closeLink:null,_page:null,_modal:null,_panelInner:null,_wrapper:null,_fixedToolbar:null,_create:function(){var b=this,c=b.element,d=c.closest(":jqmData(role='page')"),e=function(){var b=a.data(d[0],"mobilePage").options.theme,c="ui-body-"+b;return c},f=function(){var a=c.find("."+b.options.classes.panelInner);return 0===a.length&&(a=c.children().wrapAll('<div class="'+b.options.classes.panelInner+'" />').parent()),a},g=function(){var c=d.find("."+b.options.classes.contentWrap);return 0===c.length&&(c=d.children(".ui-header:not(:jqmData(position='fixed')), .ui-content:not(:jqmData(role='popup')), .ui-footer:not(:jqmData(position='fixed'))").wrapAll('<div class="'+b.options.classes.contentWrap+" "+e()+'" />').parent(),a.support.cssTransform3d&&b.options.animate&&c.addClass(b.options.classes.animate)),c},h=function(){var c=d.find("."+b.options.classes.contentFixedToolbar);return 0===c.length&&(c=d.find(".ui-header:jqmData(position='fixed'), .ui-footer:jqmData(position='fixed')").addClass(b.options.classes.contentFixedToolbar),a.support.cssTransform3d&&b.options.animate&&c.addClass(b.options.classes.animate)),c};a.extend(this,{_panelID:c.attr("id"),_closeLink:c.find(":jqmData(rel='close')"),_page:c.closest(":jqmData(role='page')"),_pageTheme:e(),_panelInner:f(),_wrapper:g(),_fixedToolbar:h()}),b._addPanelClasses(),b._wrapper.addClass(this.options.classes.contentWrapClosed),b._fixedToolbar.addClass(this.options.classes.contentFixedToolbarClosed),b._page.addClass(b.options.classes.pagePanel),a.support.cssTransform3d&&b.options.animate&&this.element.addClass(b.options.classes.animate),b._bindUpdateLayout(),b._bindCloseEvents(),b._bindLinkListeners(),b._bindPageEvents(),b.options.dismissible&&b._createModal(),b._bindSwipeEvents()},_createModal:function(){var b=this;b._modal=a("<div class='"+b.options.classes.modal+"' data-panelid='"+b._panelID+"'></div>").on("mousedown",function(){b.close()}).appendTo(this._page)},_getPosDisplayClasses:function(a){return a+"-position-"+this.options.position+" "+a+"-display-"+this.options.display},_getPanelClasses:function(){var a=this.options.classes.panel+" "+this._getPosDisplayClasses(this.options.classes.panel)+" "+this.options.classes.panelClosed;return this.options.theme&&(a+=" ui-body-"+this.options.theme),this.options.positionFixed&&(a+=" "+this.options.classes.panelFixed),a},_addPanelClasses:function(){this.element.addClass(this._getPanelClasses())},_bindCloseEvents:function(){var a=this;a._closeLink.on("click.panel",function(b){return b.preventDefault(),a.close(),!1}),a.element.on("click.panel","a:jqmData(ajax='false')",function(){a.close()})},_positionPanel:function(){var b=this,c=b._panelInner.outerHeight(),d=c>a.mobile.getScreenHeight();d||!b.options.positionFixed?(d&&(b._unfixPanel(),a.mobile.resetActivePageHeight(c)),b._scrollIntoView(c)):b._fixPanel()},_scrollIntoView:function(c){c<a(b).scrollTop()&&b.scrollTo(0,0)},_bindFixListener:function(){this._on(a(b),{throttledresize:"_positionPanel"})},_unbindFixListener:function(){this._off(a(b),"throttledresize")},_unfixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.removeClass(this.options.classes.panelFixed)},_fixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.addClass(this.options.classes.panelFixed)},_bindUpdateLayout:function(){var a=this;a.element.on("updatelayout",function(){a._open&&a._positionPanel()})},_bindLinkListeners:function(){var b=this;b._page.on("click.panel","a",function(c){if(this.hrLine truncated
|
||||
/*
|
||||
//@ sourceMappingURL=jquery.mobile-1.3.2.min.map
|
||||
*/
|
||||
@@ -0,0 +1,196 @@
|
||||
|
||||
(function($){function findLine(sdpLines,prefix,substr){return findLineInRange(sdpLines,0,-1,prefix,substr);}
|
||||
function findLineInRange(sdpLines,startLine,endLine,prefix,substr){var realEndLine=(endLine!=-1)?endLine:sdpLines.length;for(var i=startLine;i<realEndLine;++i){if(sdpLines[i].indexOf(prefix)===0){if(!substr||sdpLines[i].toLowerCase().indexOf(substr.toLowerCase())!==-1){return i;}}}
|
||||
return null;}
|
||||
function getCodecPayloadType(sdpLine){var pattern=new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');var result=sdpLine.match(pattern);return(result&&result.length==2)?result[1]:null;}
|
||||
function setDefaultCodec(mLine,payload){var elements=mLine.split(' ');var newLine=[];var index=0;for(var i=0;i<elements.length;i++){if(index===3)
|
||||
newLine[index++]=payload;if(elements[i]!==payload)newLine[index++]=elements[i];}
|
||||
return newLine.join(' ');}
|
||||
$.FSRTC=function(options){this.options=$.extend({useVideo:null,useStereo:false,userData:null,videoParams:{},callbacks:{onICEComplete:function(){},onICE:function(){},onOfferSDP:function(){}}},options);this.mediaData={SDP:null,profile:{},candidateList:[]};this.constraints={optional:[{'DtlsSrtpKeyAgreement':'true'}],mandatory:{OfferToReceiveAudio:true,OfferToReceiveVideo:this.options.useVideo?true:false,}};if(self.options.useVideo){self.options.useVideo.style.display='none';}
|
||||
setCompat();checkCompat();};$.FSRTC.prototype.useVideo=function(obj){var self=this;if(obj){self.options.useVideo=obj;self.constraints.mandatory.OfferToReceiveVideo=true;}else{self.options.useVideo=null;self.constraints.mandatory.OfferToReceiveVideo=false;}
|
||||
if(self.options.useVideo){self.options.useVideo.style.display='none';}};$.FSRTC.prototype.useStereo=function(on){var self=this;self.options.useStereo=on;};$.FSRTC.prototype.stereoHack=function(sdp){var self=this;if(!self.options.useStereo){return sdp;}
|
||||
var sdpLines=sdp.split('\r\n');var opusIndex=findLine(sdpLines,'a=rtpmap','opus/48000'),opusPayload;if(opusIndex){opusPayload=getCodecPayloadType(sdpLines[opusIndex]);}
|
||||
var fmtpLineIndex=findLine(sdpLines,'a=fmtp:'+opusPayload.toString());if(fmtpLineIndex===null)return sdp;sdpLines[fmtpLineIndex]=sdpLines[fmtpLineIndex].concat('; stereo=1');sdp=sdpLines.join('\r\n');return sdp;};function setCompat(){$.FSRTC.moz=!!navigator.mozGetUserMedia;if(!navigator.getUserMedia){navigator.getUserMedia=navigator.mozGetUserMedia||navigator.webkitGetUserMedia||navigator.msGetUserMedia;}}
|
||||
function checkCompat(){if(!navigator.getUserMedia){alert('This application cannot function in this browser.');return false;}
|
||||
return true;}
|
||||
function onStreamError(self){console.log('There has been a problem retrieving the streams - did you allow access?');}
|
||||
function onStreamSuccess(self){console.log("Stream Success");}
|
||||
function onICE(self,candidate){self.mediaData.candidate=candidate;self.mediaData.candidateList.push(self.mediaData.candidate);doCallback(self,"onICE");}
|
||||
function doCallback(self,func,arg){if(func in self.options.callbacks){self.options.callbacks[func](self,arg);}}
|
||||
function onICEComplete(self,candidate){console.log("ICE Complete");doCallback(self,"onICEComplete");}
|
||||
function onChannelError(self,e){console.error("Channel Error",e);doCallback(self,"onError",e);}
|
||||
function onICESDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("ICE SDP");doCallback(self,"onICESDP");}
|
||||
function onAnswerSDP(self,sdp){self.answer.SDP=self.stereoHack(sdp.sdp);console.log("ICE ANSWER SDP");doCallback(self,"onAnswerSDP",self.answer.SDP);}
|
||||
function onMessage(self,msg){console.log("Message");doCallback(self,"onICESDP",msg);}
|
||||
function onRemoteStream(self,stream){if(self.options.useVideo){self.options.useVideo.style.display='block';}
|
||||
var element=self.options.useAudio;console.log("REMOTE STREAM",stream,element);if(typeof element.srcObject!=='undefined'){element.srcObject=stream;}else if(typeof element.mozSrcObject!=='undefined'){element.mozSrcObject=stream;}else if(typeof element.src!=='undefined'){element.src=URL.createObjectURL(stream);}else{console.error('Error attaching stream to element.');}
|
||||
self.options.useAudio.play();self.remoteStream=stream;}
|
||||
function onOfferSDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("Offer SDP");doCallback(self,"onOfferSDP");}
|
||||
$.FSRTC.prototype.answer=function(sdp,onSuccess,onError){this.peer.addAnswerSDP({type:"answer",sdp:sdp},onSuccess,onError);};$.FSRTC.prototype.stop=function(){var self=this;if(self.options.useVideo){self.options.useVideo.style.display='none';}
|
||||
if(self.localStream){self.localStream.stop();self.localStream=null;}
|
||||
if(self.peer){console.log("stopping peer");self.peer.stop();}};$.FSRTC.prototype.createAnswer=function(sdp){var self=this;self.type="answer";self.remoteSDP=sdp;console.debug("inbound sdp: ",sdp);function onSuccess(stream){self.localStream=stream;self.peer=RTCPeerConnection({type:self.type,attachStream:self.localStream,onICE:function(candidate){return onICE(self,candidate);},onICEComplete:function(){return onICEComplete(self);},onRemoteStream:function(stream){return onRemoteStream(self,stream);},onICESDP:function(sdp){return onICESDP(self,sdp);},onChannelError:function(e){return onChannelError(self,e);},constraints:self.constraints,offerSDP:{type:"offer",sdp:self.remoteSDP}});onStreamSuccess(self);}
|
||||
function onError(){onStreamError(self);}
|
||||
getUserMedia({constraints:{audio:true,video:this.options.useVideo?{mandatory:this.options.videoParams,optional:[]}:null},video:this.options.useVideo?true:false,onsuccess:onSuccess,onerror:onError});};$.FSRTC.prototype.call=function(profile){checkCompat();var self=this;self.type="offer";function onSuccess(stream){self.localStream=stream;self.peer=RTCPeerConnection({type:self.type,attachStream:self.localStream,onICE:function(candidate){return onICE(self,candidate);},onICEComplete:function(){return onICEComplete(self);},onRemoteStream:function(stream){return onRemoteStream(self,stream);},onOfferSDP:function(sdp){return onOfferSDP(self,sdp);},onICESDP:function(sdp){return onICESDP(self,sdp);},onChannelError:function(e){return onChannelError(self,e);},constraints:self.constraints});onStreamSuccess(self);}
|
||||
function onError(){onStreamError(self);}
|
||||
getUserMedia({constraints:{audio:true,video:this.options.useVideo?{mandatory:this.options.videoParams,optional:[]}:null},video:this.options.useVideo?true:false,onsuccess:onSuccess,onerror:onError});};window.moz=!!navigator.mozGetUserMedia;function RTCPeerConnection(options){var w=window,PeerConnection=w.mozRTCPeerConnection||w.webkitRTCPeerConnection,SessionDescription=w.mozRTCSessionDescription||w.RTCSessionDescription,IceCandidate=w.mozRTCIceCandidate||w.RTCIceCandidate;var STUN={url:!moz?'stun:stun.l.google.com:19302':'stun:23.21.150.121'};var TURN={url:'turn:homeo@turn.bistri.com:80',credential:'homeo'};var iceServers={iceServers:options.iceServers||[STUN]};if(!moz&&!options.iceServers){if(parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2])>=28)TURN={url:'turn:turn.bistri.com:80',credential:'homeo',username:'homeo'};iceServers.iceServers=[STUN];}
|
||||
var optional={optional:[]};if(!moz){optional.optional=[{DtlsSrtpKeyAgreement:true},{RtpDataChannels:options.onChannelMessage?true:false}];}
|
||||
var peer=new PeerConnection(iceServers,optional);openOffererChannel();var x=0;peer.onicecandidate=function(event){console.log("WTF ICE",event);if(event.candidate){options.onICE(event.candidate);}else{if(options.onICEComplete){options.onICEComplete();}
|
||||
if(options.type=="offer"){if(!moz&&!x&&options.onICESDP){options.onICESDP(peer.localDescription);}}else{if(!x&&options.onICESDP){options.onICESDP(peer.localDescription);}}}};if(options.attachStream)peer.addStream(options.attachStream);if(options.attachStreams&&options.attachStream.length){var streams=options.attachStreams;for(var i=0;i<streams.length;i++){peer.addStream(streams[i]);}}
|
||||
peer.onaddstream=function(event){var remoteMediaStream=event.stream;remoteMediaStream.onended=function(){if(options.onRemoteStreamEnded)options.onRemoteStreamEnded(remoteMediaStream);};if(options.onRemoteStream)options.onRemoteStream(remoteMediaStream);};var constraints=options.constraints||{optional:[],mandatory:{OfferToReceiveAudio:true,OfferToReceiveVideo:true}};function createOffer(){if(!options.onOfferSDP)return;peer.createOffer(function(sessionDescription){sessionDescription.sdp=serializeSdp(sessionDescription.sdp);peer.setLocalDescription(sessionDescription);options.onOfferSDP(sessionDescription);if(moz&&options.onICESDP){options.onICESDP(sessionDescription);}},onSdpError,constraints);}
|
||||
function createAnswer(){if(options.type!="answer")return;peer.setRemoteDescription(new SessionDescription(options.offerSDP),onSdpSuccess,onSdpError);peer.createAnswer(function(sessionDescription){sessionDescription.sdp=serializeSdp(sessionDescription.sdp);peer.setLocalDescription(sessionDescription);if(options.onAnswerSDP){options.onAnswerSDP(sessionDescription);}},onSdpError,constraints);}
|
||||
if((options.onChannelMessage&&!moz)||!options.onChannelMessage){createOffer();createAnswer();}
|
||||
function setBandwidth(sdp){sdp=sdp.replace(/b=AS([^\r\n]+\r\n)/g,'');sdp=sdp.replace(/a=mid:data\r\n/g,'a=mid:data\r\nb=AS:1638400\r\n');return sdp;}
|
||||
function getInteropSDP(sdp){var chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),extractedChars='';function getChars(){extractedChars+=chars[parseInt(Math.random()*40)]||'';if(extractedChars.length<40)getChars();return extractedChars;}
|
||||
if(options.onAnswerSDP)sdp=sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g,'');var inline=getChars()+'\r\n'+(extractedChars='');sdp=sdp.indexOf('a=crypto')==-1?sdp.replace(/c=IN/g,'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:'+inline+'c=IN'):sdp;return sdp;}
|
||||
function serializeSdp(sdp){return sdp;}
|
||||
var channel;function openOffererChannel(){if(!options.onChannelMessage||(moz&&!options.onOfferSDP))return;_openOffererChannel();if(!moz)return;navigator.mozGetUserMedia({audio:true,fake:true},function(stream){peer.addStream(stream);createOffer();},useless);}
|
||||
function _openOffererChannel(){channel=peer.createDataChannel(options.channel||'RTCDataChannel',moz?{}:{reliable:false});if(moz)channel.binaryType='blob';setChannelEvents();}
|
||||
function setChannelEvents(){channel.onmessage=function(event){if(options.onChannelMessage)options.onChannelMessage(event);};channel.onopen=function(){if(options.onChannelOpened)options.onChannelOpened(channel);};channel.onclose=function(event){if(options.onChannelClosed)options.onChannelClosed(event);console.warn('WebRTC DataChannel closed',event);};channel.onerror=function(event){if(options.onChannelError)options.onChannelError(event);console.error('WebRTC DataChannel error',event);};}
|
||||
if(options.onAnswerSDP&&moz&&options.onChannelMessage)openAnswererChannel();function openAnswererChannel(){peer.ondatachannel=function(event){channel=event.channel;channel.binaryType='blob';setChannelEvents();};if(!moz)return;navigator.mozGetUserMedia({audio:true,fake:true},function(stream){peer.addStream(stream);createAnswer();},useless);}
|
||||
function useless(){log('Error in fake:true');}
|
||||
function onSdpSuccess(){}
|
||||
function onSdpError(e){if(options.onChannelError){options.onChannelError(e);}
|
||||
console.error('sdp error:',e);}
|
||||
return{addAnswerSDP:function(sdp,cbSuccess,cbError){peer.setRemoteDescription(new SessionDescription(sdp),cbSuccess?cbSuccess:onSdpSuccess,cbError?cbError:onSdpError);},addICE:function(candidate){peer.addIceCandidate(new IceCandidate({sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate}));},peer:peer,channel:channel,sendData:function(message){if(channel){channel.send(message);}},stop:function(){peer.close();if(options.attachStream){options.attachStream.stop();}}};}
|
||||
var video_constraints={mandatory:{},optional:[]};function getUserMedia(options){var n=navigator,media;n.getMedia=n.webkitGetUserMedia||n.mozGetUserMedia;n.getMedia(options.constraints||{audio:true,video:video_constraints},streaming,options.onerror||function(e){console.error(e);});function streaming(stream){var video=options.video;if(video){video[moz?'mozSrcObject':'src']=moz?stream:window.webkitURL.createObjectURL(stream);}
|
||||
if(options.onsuccess){options.onsuccess(stream);}
|
||||
media=stream;}
|
||||
return media;}})(jQuery);(function($){$.JsonRpcClient=function(options){var self=this;this.options=$.extend({ajaxUrl:null,socketUrl:null,onmessage:null,login:null,passwd:null,sessid:null,getSocket:function(onmessage_cb){return self._getSocket(onmessage_cb);}},options);this.wsOnMessage=function(event){self._wsOnMessage(event);};};$.JsonRpcClient.prototype._ws_socket=null;$.JsonRpcClient.prototype._ws_callbacks={};$.JsonRpcClient.prototype._current_id=1;$.JsonRpcClient.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};}
|
||||
if(this.options.sessid){params.sessid=this.options.sessid;}
|
||||
var request={jsonrpc:'2.0',method:method,params:params,id:this._current_id++};if(!success_cb){success_cb=function(e){console.log("Success: ",e);};}
|
||||
if(!error_cb){error_cb=function(e){console.log("Error: ",e);};}
|
||||
var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this._wsCall(socket,request,success_cb,error_cb);return;}
|
||||
if(this.options.ajaxUrl===null){throw"$.JsonRpcClient.call used with no websocket and no http endpoint.";}
|
||||
$.ajax({type:'POST',url:this.options.ajaxUrl,data:$.toJSON(request),dataType:'json',cache:false,success:function(data){if('error'in data)error_cb(data.error,this);success_cb(data.result,this);},error:function(jqXHR,textStatus,errorThrown){try{var response=$.parseJSON(jqXHR.responseText);if('console'in window)console.log(response);error_cb(response.error,this);}
|
||||
catch(err){error_cb({error:jqXHR.responseText},this);}}});};$.JsonRpcClient.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;}
|
||||
var request={jsonrpc:'2.0',method:method,params:params};var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this._wsCall(socket,request);return;}
|
||||
if(this.options.ajaxUrl===null){throw"$.JsonRpcClient.notify used with no websocket and no http endpoint.";}
|
||||
$.ajax({type:'POST',url:this.options.ajaxUrl,data:$.toJSON(request),dataType:'json',cache:false});};$.JsonRpcClient.prototype.batch=function(callback,all_done_cb,error_cb){var batch=new $.JsonRpcClient._batchObject(this,all_done_cb,error_cb);callback(batch);batch._execute();};$.JsonRpcClient.prototype.socketReady=function(){if(this._ws_socket===null||this._ws_socket.readyState>1){return false;}
|
||||
return true;}
|
||||
$.JsonRpcClient.prototype.closeSocket=function(){if(self.socketReady()){this._ws_socket.onclose=function(w){console.log("Closing Socket")}
|
||||
this._ws_socket.close();}}
|
||||
$.JsonRpcClient.prototype.loginData=function(params){self.options.login=params.login;self.options.passwd=params.passwd;}
|
||||
$.JsonRpcClient.prototype.connectSocket=function(onmessage_cb){var self=this;if(!self.socketReady()){self.authing=false;this._ws_socket=new WebSocket(this.options.socketUrl);if(this._ws_socket){this._ws_socket.onmessage=onmessage_cb;this._ws_socket.onclose=function(w){if(!self.ws_sleep){self.ws_sleep=2;}
|
||||
self.ws_cnt=0;if(self.options.onWSClose){self.options.onWSClose(self);}
|
||||
console.error("Websocket Lost sleep: "+self.ws_sleep+"sec");setTimeout(function(){console.log("Attempting Reconnection....");self.connectSocket(onmessage_cb);},self.ws_sleep*1000);if(++self.ws_cnt>=150){self.ws_sleep=30;}}
|
||||
this._ws_socket.onopen=function(){this.ws_sleep=2;this.ws_cnt=0;if(self.options.onWSConnect){self.options.onWSConnect(self);}
|
||||
var req;while(req=$.JsonRpcClient.q.pop()){self._ws_socket.send(req);}}}}
|
||||
return this._ws_socket?true:false;}
|
||||
$.JsonRpcClient.prototype._getSocket=function(onmessage_cb){if(this.options.socketUrl===null||!("WebSocket"in window))return null;this.connectSocket(onmessage_cb);return this._ws_socket;};$.JsonRpcClient.q=[];$.JsonRpcClient.prototype._wsCall=function(socket,request,success_cb,error_cb){var request_json=$.toJSON(request);if(socket.readyState<1){self=this;$.JsonRpcClient.q.push(request_json);}
|
||||
else{socket.send(request_json);}
|
||||
if('id'in request&&typeof success_cb!=='undefined'){this._ws_callbacks[request.id]={request:request_json,request_obj:request,success_cb:success_cb,error_cb:error_cb};}};$.JsonRpcClient.prototype._wsOnMessage=function(event){var response;try{response=$.parseJSON(event.data);if(typeof response==='object'&&'jsonrpc'in response&&response.jsonrpc==='2.0'){if('result'in response&&this._ws_callbacks[response.id]){var success_cb=this._ws_callbacks[response.id].success_cb;delete this._ws_callbacks[response.id];success_cb(response.result,this);return;}
|
||||
else if('error'in response&&this._ws_callbacks[response.id]){var error_cb=this._ws_callbacks[response.id].error_cb;var orig_req=this._ws_callbacks[response.id].request;if(!self.authing&&response.error.code==-32000&&self.options.login&&self.options.passwd){self.authing=true;this.call("login",{login:self.options.login,passwd:self.options.passwd},this._ws_callbacks[response.id].request_obj.method=="login"?function(e){self.authing=false;console.log("logged in");delete self._ws_callbacks[response.id];if(self.options.onWSLogin){self.options.onWSLogin(true,self);}}:function(e){self.authing=false;console.log("logged in, resending request id: "+response.id);var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send(orig_req);}
|
||||
if(self.options.onWSLogin){self.options.onWSLogin(true,self);}},function(e){console.log("error logging in, request id:",response.id);delete self._ws_callbacks[response.id];error_cb(response.error,this);if(self.options.onWSLogin){self.options.onWSLogin(false,self);}});return;}
|
||||
delete this._ws_callbacks[response.id];error_cb(response.error,this);return;}}}
|
||||
catch(err){console.log("ERROR: "+err);return;}
|
||||
if(typeof this.options.onmessage==='function'){event.eventData=response;if(!event.eventData){event.eventData={};}
|
||||
var reply=this.options.onmessage(event);if(reply&&typeof reply==="object"&&event.eventData.id){var msg={jsonrpc:"2.0",id:event.eventData.id,result:reply};var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send($.toJSON(msg));}}}};$.JsonRpcClient._batchObject=function(jsonrpcclient,all_done_cb,error_cb){this._requests=[];this.jsonrpcclient=jsonrpcclient;this.all_done_cb=all_done_cb;this.error_cb=typeof error_cb==='function'?error_cb:function(){};};$.JsonRpcClient._batchObject.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};}
|
||||
if(this.options.sessid){params.sessid=this.options.sessid;}
|
||||
if(!success_cb){success_cb=function(e){console.log("Success: ",e);};}
|
||||
if(!error_cb){error_cb=function(e){console.log("Error: ",e);};}
|
||||
this._requests.push({request:{jsonrpc:'2.0',method:method,params:params,id:this.jsonrpcclient._current_id++},success_cb:success_cb,error_cb:error_cb});};$.JsonRpcClient._batchObject.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;}
|
||||
this._requests.push({request:{jsonrpc:'2.0',method:method,params:params}});};$.JsonRpcClient._batchObject.prototype._execute=function(){var self=this;if(this._requests.length===0)return;var batch_request=[];var handlers={};var socket=self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);if(socket!==null){for(var i=0;i<this._requests.length;i++){var call=this._requests[i];var success_cb=('success_cb'in call)?call.success_cb:undefined;var error_cb=('error_cb'in call)?call.error_cb:undefined;self.jsonrpcclient._wsCall(socket,call.request,success_cb,error_cb);}
|
||||
if(typeof all_done_cb==='function')all_done_cb(result);return;}
|
||||
for(var i=0;i<this._requests.length;i++){var call=this._requests[i];batch_request.push(call.request);if('id'in call.request){handlers[call.request.id]={success_cb:call.success_cb,error_cb:call.error_cb};}}
|
||||
var success_cb=function(data){self._batchCb(data,handlers,self.all_done_cb);};if(self.jsonrpcclient.options.ajaxUrl===null){throw"$.JsonRpcClient.batch used with no websocket and no http endpoint.";}
|
||||
$.ajax({url:self.jsonrpcclient.options.ajaxUrl,data:$.toJSON(batch_request),dataType:'json',cache:false,type:'POST',error:function(jqXHR,textStatus,errorThrown){self.error_cb(jqXHR,textStatus,errorThrown);},success:success_cb});};$.JsonRpcClient._batchObject.prototype._batchCb=function(result,handlers,all_done_cb){for(var i=0;i<result.length;i++){var response=result[i];if('error'in response){if(response.id===null||!(response.id in handlers)){if('console'in window)console.log(response);}
|
||||
else handlers[response.id].error_cb(response.error,this);}
|
||||
else{if(!(response.id in handlers)&&'console'in window)console.log(response);else handlers[response.id].success_cb(response.result,this);}}
|
||||
if(typeof all_done_cb==='function')all_done_cb(result);};})(jQuery);(function($){var generateGUID=(typeof(window.crypto)!=='undefined'&&typeof(window.crypto.getRandomValues)!=='undefined')?function(){var buf=new Uint16Array(8);window.crypto.getRandomValues(buf);var S4=function(num){var ret=num.toString(16);while(ret.length<4){ret="0"+ret;}
|
||||
return ret;};return(S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));}:function(){return'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);return v.toString(16);});};$.verto=function(options,callbacks){var verto=this;$.verto.saved.push(verto);verto.options=$.extend({login:null,passwd:null,socketUrl:null,tag:null,videoParams:{},ringSleep:6000},options);verto.sessid=$.cookie('verto_session_uuid')||generateGUID();$.cookie('verto_session_uuid',verto.sessid,{expires:1});verto.dialogs={};verto.callbacks=callbacks||{};verto.eventSUBS={};verto.rpcClient=new $.JsonRpcClient({login:verto.options.login,passwd:verto.options.passwd,socketUrl:verto.options.socketUrl,sessid:verto.sessid,onmessage:function(e){return verto.handleMessage(e.eventData);},onWSConnect:function(o){o.call('login',{});},onWSLogin:function(success){if(verto.callbacks.onWSLogin){verto.callbacks.onWSLogin(verto,success);}},onWSClose:function(success){if(verto.callbacks.onWSClose){verto.callbacks.onWSClose(verto,success);}
|
||||
verto.purge();}});if(verto.options.ringFile&&verto.options.tag){verto.ringer=$("#"+verto.options.tag);}
|
||||
verto.rpcClient.call('login',{});};$.verto.prototype.loginData=function(params){verto.options.login=params.login;verto.options.passwd=params.passwd;verto.rpcClient.loginData(params);};$.verto.prototype.logout=function(msg){var verto=this;verto.rpcClient.closeSocket();verto.purge();};$.verto.prototype.login=function(msg){var verto=this;verto.logout();verto.rpcClient.call('login',{});};$.verto.prototype.message=function(msg){var verto=this;var err=0;if(!msg.to){console.error("Missing To");err++;}
|
||||
if(!msg.body){console.error("Missing Body");err++;}
|
||||
if(err){return false;}
|
||||
verto.sendMethod("verto.info",{msg:msg});return true;};$.verto.prototype.processReply=function(method,success,e){var verto=this;var i;console.log("Response: "+method,success,e);switch(method){case"verto.subscribe":for(i in e.unauthorizedChannels){drop_bad(verto,e.unauthorizedChannels[i]);}
|
||||
for(i in e.subscribedChannels){mark_ready(verto,e.subscribedChannels[i]);}
|
||||
break;case"verto.unsubscribe":break;}};$.verto.prototype.sendMethod=function(method,params){var verto=this;verto.rpcClient.call(method,params,function(e){verto.processReply(method,true,e);},function(e){verto.processReply(method,false,e);});};function do_sub(verto,channel,obj){}
|
||||
function drop_bad(verto,channel){console.error("drop unauthorized channel: "+channel);delete verto.eventSUBS[channel];}
|
||||
function mark_ready(verto,channel){for(var j in verto.eventSUBS[channel]){verto.eventSUBS[channel][j].ready=true;console.log("subscribed to channel: "+channel);if(verto.eventSUBS[channel][j].readyHandler){verto.eventSUBS[channel][j].readyHandler(verto,channel);}}}
|
||||
var SERNO=1;function do_subscribe(verto,channel,subChannels,sparams){var params=sparams||{};var local=params.local;var obj={eventChannel:channel,userData:params.userData,handler:params.handler,ready:false,readyHandler:params.readyHandler,serno:SERNO++};var isnew=false;if(!verto.eventSUBS[channel]){verto.eventSUBS[channel]=[];subChannels.push(channel);isnew=true;}
|
||||
verto.eventSUBS[channel].push(obj);if(local){obj.ready=true;obj.local=true;}
|
||||
if(!isnew&&verto.eventSUBS[channel][0].ready){obj.ready=true;if(obj.readyHandler){obj.readyHandler(verto,channel);}}
|
||||
return{serno:obj.serno,eventChannel:channel};}
|
||||
$.verto.prototype.subscribe=function(channel,sparams){var verto=this;var r=[];var subChannels=[];var params=sparams||{};if(typeof(channel)==="string"){r.push(do_subscribe(verto,channel,subChannels,params));}else{for(var i in channel){r.push(do_subscribe(verto,channel,subChannels,params));}}
|
||||
if(subChannels.length){verto.sendMethod("verto.subscribe",{eventChannel:subChannels.length==1?subChannels[0]:subChannels,subParams:params.subParams});}
|
||||
return r;};$.verto.prototype.unsubscribe=function(handle){var verto=this;var i;if(!handle){for(i in verto.eventSUBS){if(verto.eventSUBS[i]){verto.unsubscribe(verto.eventSUBS[i]);}}}else{var unsubChannels={};var sendChannels=[];var channel;if(typeof(handle)=="string"){delete verto.eventSUBS[handle];unsubChannels[handle]++;}else{for(i in handle){if(typeof(handle[i])=="string"){channel=handle[i];delete verto.eventSUBS[channel];unsubChannels[channel]++;}else{var repl=[];channel=handle[i].eventChannel;for(var j in verto.eventSUBS[channel]){if(verto.eventSUBS[channel][j].serno==handle[i].serno){}else{repl.push(verto.eventSUBS[channel][j]);}}
|
||||
verto.eventSUBS[channel]=repl;if(verto.eventSUBS[channel].length===0){delete verto.eventSUBS[channel];unsubChannels[channel]++;}}}}
|
||||
for(var u in unsubChannels){console.log("Sending Unsubscribe for: ",u);sendChannels.push(u);}
|
||||
if(sendChannels.length){verto.sendMethod("verto.unsubscribe",{eventChannel:sendChannels.length==1?sendChannels[0]:sendChannels});}}};$.verto.prototype.broadcast=function(channel,params){var verto=this;var msg={eventChannel:channel,data:{}};for(var i in params){msg.data[i]=params[i];}
|
||||
verto.sendMethod("verto.broadcast",msg);};$.verto.prototype.purge=function(callID){var verto=this;var x=0;var i;for(i in verto.dialogs){if(!x){console.log("purging dialogs");}
|
||||
x++;verto.dialogs[i].setState($.verto.enum.state.purge);}
|
||||
for(i in verto.eventSUBS){if(verto.eventSUBS[i]){console.log("purging subscription: "+i);delete verto.eventSUBS[i];}}};$.verto.prototype.hangup=function(callID){var verto=this;if(callID){var dialog=verto.dialogs[callID];if(dialog){dialog.hangup();}}else{for(var i in verto.dialogs){verto.dialogs[i].hangup();}}};$.verto.prototype.newCall=function(args,callbacks){var verto=this;if(!verto.rpcClient.socketReady()){console.error("Not Connected...");return;}
|
||||
var dialog=new $.verto.dialog($.verto.enum.direction.outbound,this,args);dialog.invite();if(callbacks){dialog.callbacks=callbacks;}
|
||||
return dialog;};$.verto.prototype.handleMessage=function(data){var verto=this;if(data.params.callID){var dialog=verto.dialogs[data.params.callID];if(dialog){switch(data.method){case'verto.bye':dialog.hangup();break;case'verto.answer':dialog.handleAnswer(data.params.sdp);break;case'verto.media':dialog.handleMedia(data.params.sdp);break;case'verto.display':dialog.handleDisplay(data.params);break;case'verto.info':dialog.handleInfo(data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}else{switch(data.method){case'verto.attach':data.params.attach=true;if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.useVideo=true;}
|
||||
if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;}
|
||||
dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;case'verto.invite':if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.wantVideo=true;}
|
||||
if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;}
|
||||
dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");break;}}
|
||||
return{method:data.method};}else{switch(data.method){case'verto.event':var list=null;var key=null;if(data.params){key=data.params.eventChannel;}
|
||||
if(key){list=verto.eventSUBS[key];if(!list){list=verto.eventSUBS[key.split(".")[0]];}}
|
||||
if(!list&&key&&verto.dialogs[key]){verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent,data.params);}else if(!list){if(!key){key="UNDEFINED";}
|
||||
console.error("UNSUBBED or invalid EVENT "+key+" IGNORED");}else{for(var i in list){var sub=list[i];if(!sub||!sub.ready){console.error("invalid EVENT for "+key+" IGNORED");}else if(sub.handler){sub.handler(verto,data.params,sub.userData);}else if(verto.callbacks.onEvent){verto.callbacks.onEvent(verto,data.params,sub.userData);}else{console.log("EVENT:",data.params);}}}
|
||||
break;case"verto.info":if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.info,data.params.msg);}
|
||||
console.error(data);console.debug("MESSAGE from: "+data.params.msg.from,data.params.msg.body);break;default:console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}};var del_array=function(array,name){var r=[];var len=array.length;for(var i=0;i<len;i++){if(array[i]!=name){r.push(array[i]);}}
|
||||
return r;};var hashArray=function(){var vha=this;var hash={};var array=[];vha.reorder=function(a){array=a;var h=hash;hash={};var len=array.length;for(var i=0;i<len;i++){var key=array[i];if(h[key]){hash[key]=h[key];delete h[key];}}
|
||||
h=undefined;};vha.clear=function(){hash=undefined;array=undefined;hash={};array=[];};vha.add=function(name,val,insertAt){var redraw=false;if(!hash[name]){if(insertAt===undefined||insertAt<0||insertAt>=array.length){array.push(name);}else{var x=0;var n=[];var len=array.length;for(var i=0;i<len;i++){if(x++==insertAt){n.push(name);}
|
||||
n.push(array[i]);}
|
||||
array=undefined;array=n;n=undefined;redraw=true;}}
|
||||
hash[name]=val;return redraw;};vha.del=function(name){var r=false;if(hash[name]){array=del_array(array,name);delete hash[name];r=true;}else{console.error("can't del nonexistant key "+name);}
|
||||
return r;};vha.get=function(name){return hash[name];};vha.order=function(){return array;};vha.hash=function(){return hash;};vha.indexOf=function(name){var len=array.length;for(var i=0;i<len;i++){if(array[i]==name){return i;}}};vha.arrayLen=function(){return array.length;};vha.asArray=function(){var r=[];var len=array.length;for(var i=0;i<len;i++){var key=array[i];r.push(hash[key]);}
|
||||
return r;};vha.each=function(cb){var len=array.length;for(var i=0;i<len;i++){cb(array[i],hash[array[i]]);}};vha.dump=function(html){var str="";vha.each(function(name,val){str+="name: "+name+" val: "+JSON.stringify(val)+(html?"<br>":"\n");});return str;};};$.verto.liveArray=function(verto,context,name,config){var la=this;var lastSerno=0;var binding=null;var user_obj=config.userObj;var local=false;hashArray.call(la);la._add=la.add;la._del=la.del;la._reorder=la.reorder;la._clear=la.clear;la.context=context;la.name=name;la.user_obj=user_obj;la.verto=verto;la.broadcast=function(channel,obj){verto.broadcast(channel,obj);};la.errs=0;la.clear=function(){la._clear();lastSerno=0;if(la.onChange){la.onChange(la,{action:"clear"});}};la.checkSerno=function(serno){if(serno<0){return true;}
|
||||
if(lastSerno>0&&serno!=(lastSerno+1)){if(la.onErr){la.onErr(la,{lastSerno:lastSerno,serno:serno});}
|
||||
la.errs++;console.debug(la.errs);if(la.errs<3){la.bootstrap(la.user_obj);}
|
||||
return false;}else{lastSerno=serno;return true;}};la.reorder=function(serno,a){if(la.checkSerno(serno)){la._reorder(a);if(la.onChange){la.onChange(la,{serno:serno,action:"reorder"});}}};la.init=function(serno,val,key,index){if(key===null||key===undefined){key=serno;}
|
||||
if(la.checkSerno(serno)){if(la.onChange){la.onChange(la,{serno:serno,action:"init",index:index,key:key,data:val});}}};la.bootObj=function(serno,val){if(la.checkSerno(serno)){for(var i in val){la._add(val[i][0],val[i][1]);}
|
||||
if(la.onChange){la.onChange(la,{serno:serno,action:"bootObj",data:val,redraw:true});}}};la.add=function(serno,val,key,index){if(key===null||key===undefined){key=serno;}
|
||||
if(la.checkSerno(serno)){var redraw=la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"add",index:index,key:key,data:val,redraw:redraw});}}};la.modify=function(serno,val,key,index){if(key===null||key===undefined){key=serno;}
|
||||
if(la.checkSerno(serno)){la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"modify",key:key,data:val,index:index});}}};la.del=function(serno,key,index){if(key===null||key===undefined){key=serno;}
|
||||
if(la.checkSerno(serno)){if(index===null||index<0||index===undefined){index=la.indexOf(key);}
|
||||
var ok=la._del(key);if(ok&&la.onChange){la.onChange(la,{serno:serno,action:"del",key:key,index:index});}}};var eventHandler=function(v,e,la){var packet=e.data;if(packet.name!=la.name){return;}
|
||||
console.error("READ:",packet);switch(packet.action){case"init":la.init(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"bootObj":la.bootObj(packet.wireSerno,packet.data);break;case"add":la.add(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"modify":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.modify(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);}
|
||||
break;case"del":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.del(packet.wireSerno,packet.hashKey,packet.arrIndex);}
|
||||
break;case"clear":la.clear();break;case"reorder":la.reorder(packet.wireSerno,packet.order);break;default:if(la.checkSerno(packet.wireSerno)){if(la.onChange){la.onChange(la,{serno:packet.wireSerno,action:packet.action,data:packet.data});}}
|
||||
break;}};if(la.context){binding=la.verto.subscribe(la.context,{handler:eventHandler,userData:la,subParams:config.subParams});}
|
||||
la.destroy=function(){la._clear();la.verto.unsubscribe(binding);};la.bootstrap=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"bootstrap",context:self.context,name:self.name,obj:obj}});};la.changepage=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"changepage",context:la.context,name:la.name,obj:obj}});};la.heartbeat=function(obj){var self=la;var callback=function(){self.heartbeat.call(self,obj);};self.broadcast(self.context,{liveArray:{command:"heartbeat",context:self.context,name:self.name,obj:obj}});self.hb_pid=setTimeout(callback,30000);};la.bootstrap(la.user_obj);};$.verto.liveTable=function(verto,context,name,jq,config){var dt;var la=new $.verto.liveArray(verto,context,name,{subParams:config.subParams});var lt=this;lt.liveArray=la;lt.dataTable=dt;lt.verto=verto;lt.destroy=function(){if(dt){dt.fnDestroy();}
|
||||
if(la){la.destroy();}
|
||||
dt=null;la=null;};la.onErr=function(obj,args){console.error("Error: ",obj,args);};la.onChange=function(obj,args){var index=0;var iserr=0;if(!dt){if(!config.aoColumns){if(args.action!="init"){return;}
|
||||
config.aoColumns=[];for(var i in args.data){config.aoColumns.push({"sTitle":args.data[i]});}}
|
||||
dt=jq.dataTable(config);}
|
||||
if(dt&&(args.action=="del"||args.action=="modify")){index=args.index;if(index===undefined&&args.key){index=la.indexOf(args.key);}
|
||||
if(index===undefined){console.error("INVALID PACKET Missing INDEX\n",args);return;}}
|
||||
try{switch(args.action){case"bootObj":if(!args.data){console.error("missing data");return;}
|
||||
dt.fnClearTable();dt.fnAddData(obj.asArray());dt.fnAdjustColumnSizing();break;case"add":if(!args.data){console.error("missing data");return;}
|
||||
if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(obj.asArray());}else{dt.fnAddData(args.data);}
|
||||
dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;}
|
||||
console.debug(args,index);dt.fnUpdate(args.data,index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(obj.asArray());break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;}
|
||||
if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}
|
||||
if(config.onChange){config.onChange(obj,args);}};la.onChange(la,{action:"init"});};$.verto.dialog=function(direction,verto,params){var dialog=this;dialog.params=$.extend({useVideo:verto.options.useVideo,useStereo:verto.options.useStereo,tag:verto.options.tag},params);dialog.verto=verto;dialog.direction=direction;dialog.lastState=null;dialog.state=dialog.lastState=$.verto.enum.state.new;dialog.callbacks=verto.callbacks;dialog.answered=false;dialog.attach=params.attach||false;if(dialog.params.callID){dialog.callID=dialog.params.callID;}else{dialog.callID=dialog.params.callID=generateGUID();}
|
||||
if(dialog.params.tag){dialog.audioStream=document.getElementById(dialog.params.tag);if(dialog.params.useVideo){dialog.videoStream=dialog.audioStream;}}
|
||||
dialog.verto.dialogs[dialog.callID]=dialog;var RTCcallbacks={};if(dialog.direction==$.verto.enum.direction.inbound){dialog.params.remote_caller_id_name=dialog.params.caller_id_name;dialog.params.remote_caller_id_number=dialog.params.caller_id_number;if(!dialog.params.remote_caller_id_name){dialog.params.remote_caller_id_name="Nobody";}
|
||||
if(!dialog.params.remote_caller_id_number){dialog.params.remote_caller_id_number="UNKNOWN";}
|
||||
RTCcallbacks.onMessage=function(rtc,msg){console.debug(msg);};RTCcallbacks.onAnswerSDP=function(rtc,sdp){console.error("answer sdp",sdp);};}else{dialog.params.remote_caller_id_name="Outbound Call";dialog.params.remote_caller_id_number=dialog.params.destination_number;}
|
||||
RTCcallbacks.onICESDP=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.SDP);dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.invite",{sdp:rtc.mediaData.SDP});}else{dialog.setState($.verto.enum.state.answering);dialog.sendMethod(dialog.attach?"verto.attach":"verto.answer",{sdp:dialog.rtc.mediaData.SDP});}};RTCcallbacks.onICE=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.candidate);return;}};RTCcallbacks.onError=function(e){console.error("ERROR:",e);dialog.hangup();};dialog.rtc=new $.FSRTC({callbacks:RTCcallbacks,useVideo:dialog.videoStream,useAudio:dialog.audioStream,useStereo:dialog.params.useStereo,videoParams:verto.options.videoParams,});dialog.rtc.verto=dialog.verto;if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.attach){dialog.answer();}else{dialog.ring();}}};$.verto.dialog.prototype.invite=function(){var dialog=this;dialog.rtc.call();};$.verto.dialog.prototype.sendMethod=function(method,obj){var dialog=this;obj.dialogParams={};for(var i in dialog.params){if(i=="sdp"&&method!="verto.invite"&&method!="verto.attach"){continue;}
|
||||
obj.dialogParams[i]=dialog.params[i];}
|
||||
dialog.verto.rpcClient.call(method,obj,function(e){dialog.processReply(method,true,e);},function(e){dialog.processReply(method,false,e);});};function checkStateChange(oldS,newS){if(newS==$.verto.enum.state.purge||$.verto.enum.states[oldS.name][newS.name]){return true;}
|
||||
return false;}
|
||||
$.verto.dialog.prototype.setState=function(state){var dialog=this;if(dialog.state==$.verto.enum.state.ringing){dialog.stopRinging();}
|
||||
if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Dialog "+dialog.callID+": INVALID state change from "+dialog.state.name+" to "+state.name);dialog.hangup();return false;}
|
||||
console.error("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(dialog.callbacks.onDialogState){dialog.callbacks.onDialogState(this);}
|
||||
switch(dialog.state){case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});}
|
||||
dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:delete verto.dialogs[dialog.callID];dialog.rtc.stop();break;}
|
||||
return true;};$.verto.dialog.prototype.processReply=function(method,success,e){var dialog=this;console.log("Response: "+method+" State:"+dialog.state.name,success,e);switch(method){case"verto.answer":case"verto.attach":if(success){dialog.setState($.verto.enum.state.active);}else{dialog.hangup();}
|
||||
break;case"verto.invite":if(success){dialog.setState($.verto.enum.state.trying);}else{dialog.setState($.verto.enum.state.destroy);}
|
||||
break;case"verto.bye":dialog.hangup();break;case"verto.modify":if(e.holdState){if(e.holdState=="held"){if(dialog.state!=$.verto.enum.state.held){dialog.setState($.verto.enum.state.held);}}else if(e.holdState=="active"){if(dialog.state!=$.verto.enum.state.active){dialog.setState($.verto.enum.state.active);}}}
|
||||
if(success){}
|
||||
break;default:break;}};$.verto.dialog.prototype.hangup=function(sdp){var dialog=this;if(dialog.state.val>$.verto.enum.state.new.val&&dialog.state.val<$.verto.enum.state.hangup.val){dialog.setState($.verto.enum.state.hangup);}else if(dialog.state.val<$.verto.enum.state.destroy){dialog.setState($.verto.enum.state.destroy);}};$.verto.dialog.prototype.stopRinging=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.stop();}};$.verto.dialog.prototype.indicateRing=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.attr("src",dialog.verto.options.ringFile)[0].play();setTimeout(function(){dialog.stopRinging();if(dialog.state==$.verto.enum.state.ringing){dialog.indicateRing();}},dialog.verto.options.ringSleep);}};$.verto.dialog.prototype.ring=function(){var dialog=this;dialog.setState($.verto.enum.state.ringing);dialog.indicateRing();};$.verto.dialog.prototype.useVideo=function(on){var dialog=this;dialog.params.useVideo=on;if(on){dialog.videoStream=dialog.audioStream;}else{dialog.videoStream=null;}
|
||||
dialog.rtc.useVideo(dialog.videoStream);};$.verto.dialog.prototype.useStereo=function(on){var dialog=this;dialog.params.useStereo=on;dialog.rtc.useStereo(on);};$.verto.dialog.prototype.dtmf=function(digits){var dialog=this;if(digits){dialog.sendMethod("verto.info",{dtmf:digits});}};$.verto.dialog.prototype.transfer=function(dest,params){var dialog=this;if(dest){cur_call.sendMethod("verto.modify",{action:"transfer",destination:dest,params:params});}};$.verto.dialog.prototype.hold=function(params){var dialog=this;cur_call.sendMethod("verto.modify",{action:"hold",params:params});};$.verto.dialog.prototype.unhold=function(params){var dialog=this;cur_call.sendMethod("verto.modify",{action:"unhold",params:params});};$.verto.dialog.prototype.toggleHold=function(params){var dialog=this;cur_call.sendMethod("verto.modify",{action:"toggleHold",params:params});};$.verto.dialog.prototype.message=function(msg){var dialog=this;var err=0;if(!msg.to){console.error("Missing To");err++;}
|
||||
if(!msg.body){console.error("Missing Body");err++;}
|
||||
if(err){return false;}
|
||||
dialog.sendMethod("verto.info",{msg:msg});return true;};$.verto.dialog.prototype.answer=function(params){var dialog=this;if(!dialog.answered){if(params){if(params.useVideo){dialog.useVideo(true);}}
|
||||
dialog.rtc.createAnswer(dialog.params.sdp);dialog.answered=true;}};$.verto.dialog.prototype.handleAnswer=function(sdp){var dialog=this;if(dialog.state.val>=$.verto.enum.state.active.val){return;}
|
||||
if(dialog.state.val>=$.verto.enum.state.early.val){dialog.setState($.verto.enum.state.active);}else{dialog.rtc.answer(sdp,function(){dialog.setState($.verto.enum.state.active);},function(e){console.error(e);dialog.hangup();});console.log("ANSWER SDP",sdp);}};$.verto.dialog.prototype.cidString=function(enc){var dialog=this;var party=dialog.params.remote_caller_id_name+(enc?" <":" <")+dialog.params.remote_caller_id_number+(enc?">":">");return party;};$.verto.dialog.prototype.sendMessage=function(msg,params){var dialog=this;if(dialog.callbacks.onMessage){dialog.callbacks.onMessage(dialog.verto,dialog,msg,params);}};$.verto.dialog.prototype.handleInfo=function(params){var dialog=this;dialog.sendMessage($.verto.enum.message.info,params.msg);};$.verto.dialog.prototype.handleDisplay=function(params){var dialog=this;if(params.display_name){dialog.params.remote_caller_id_name=params.display_name;}
|
||||
if(params.display_number){dialog.params.remote_caller_id_number=params.display_number;}
|
||||
dialog.sendMessage($.verto.enum.message.display,{});};$.verto.dialog.prototype.handleMedia=function(sdp){var dialog=this;if(dialog.state.val>=$.verto.enum.state.early.val){return;}
|
||||
dialog.rtc.answer(sdp,function(){dialog.setState($.verto.enum.state.early);},function(e){console.error(e);dialog.hangup();});console.log("EARLY SDP",sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,ringing:1,destroy:1,answering:1},requesting:{trying:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$(window).bind('beforeunload',function(){for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.logout();verto.purge();}}
|
||||
return $.verto.warnOnUnload;});})(jQuery);
|
||||
@@ -0,0 +1,261 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/jquery.mobile-1.3.2.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/jsontable.css" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<meta charset="utf-8" />
|
||||
<title>FreeSWITCH Verto Demo</title>
|
||||
|
||||
<style type="text/css">
|
||||
.pageheader {
|
||||
font-size: 22px;
|
||||
font-weight: normal;
|
||||
height: 27px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div data-role="page" id="page-login" align="center">
|
||||
<div data-role="header" class="page-header">
|
||||
FreeSWITCH Verto Demo
|
||||
</div>
|
||||
<br>
|
||||
<a target="_CC2104" href="https://www.cluecon.com"><img border="0" width="300" src="img/cc_banner2014.gif"></a>
|
||||
|
||||
<div data-role="fieldcontain">
|
||||
<label for="name">Login</label>
|
||||
<input type="text" size="20" id="login"/>
|
||||
</div>
|
||||
|
||||
<div data-role="fieldcontain">
|
||||
<label for="name">Password</label>
|
||||
<input type="password" size="20" id="passwd"/>
|
||||
</div>
|
||||
|
||||
<div data-role="fieldcontain">
|
||||
<label for="name">CID Name</label>
|
||||
<input type="text" size="30" id="name"/>
|
||||
</div>
|
||||
|
||||
<div data-role="fieldcontain">
|
||||
<label for="name">CID Number</label>
|
||||
<input type="text" size="20" id="cid"/>
|
||||
</div>
|
||||
|
||||
<div data-role="fieldcontain">
|
||||
<label for="name">Hostname</label>
|
||||
<input type="text" size="20" id="hostName"/>
|
||||
</div>
|
||||
|
||||
<div data-role="fieldcontain">
|
||||
<label for="name">Websocket URL</label>
|
||||
<input type="text" size="20" id="wsURL"/>
|
||||
</div>
|
||||
|
||||
<br><br>
|
||||
<button data-inline="true" id="loginbtn">Log In</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div data-role="page" id="page-incall" align="center">
|
||||
<div data-role="header" id="calltitle" class="pageheader">
|
||||
Verto IN CALL
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<a target="_CC2104" href="https://www.cluecon.com"><img border="0" width="300" src="img/cc_banner2014.gif"></a>
|
||||
<br><br>
|
||||
|
||||
<div id="conf">
|
||||
<div style="color:black;font-family: verdana" align="center" id="mcount"></div>
|
||||
<table cellspacing="0" cellpadding="0" border="0" align="center" id="example" class="jsDataTable">
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="display" style="font-weight:bold;font-size:18px"></div>
|
||||
<br>
|
||||
<div data-role="fieldcontain" id="xferdiv">
|
||||
<input data-mini="true" type="text" id="xferto"><br>
|
||||
<button data-inline="true" id="cancelxferbtn">Cancel Transfer</button>
|
||||
<button data-inline="true" class="startxferbtn">Complete Transfer</button>
|
||||
</div>
|
||||
|
||||
<div id=keypad>
|
||||
<button class="dtmf" data-inline="true">1</button>
|
||||
<button class="dtmf" data-inline="true">2</button>
|
||||
<button class="dtmf" data-inline="true">3</button>
|
||||
<br>
|
||||
<button class="dtmf" data-inline="true">4</button>
|
||||
<button class="dtmf" data-inline="true">5</button>
|
||||
<button class="dtmf" data-inline="true">6</button>
|
||||
<br>
|
||||
<button class="dtmf" data-inline="true">7</button>
|
||||
<button class="dtmf" data-inline="true">8</button>
|
||||
<button class="dtmf" data-inline="true">9</button>
|
||||
<br>
|
||||
<button class="dtmf" data-inline="true">*</button>
|
||||
<button class="dtmf" data-inline="true">0</button>
|
||||
<button class="dtmf" data-inline="true">#</button>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<button data-inline="true" id="hold">HOLD</button>
|
||||
<button data-inline="true" id="hupbtn">End Call</button>
|
||||
<button data-inline="true" class="startxferbtn">Transfer</button>
|
||||
|
||||
<div id="media">
|
||||
<video width=800 id="webcam" autoplay="autoplay" hidden="true"></video>
|
||||
</div>
|
||||
<br><br>
|
||||
</div>
|
||||
|
||||
<div data-role="page" id="page-main" align="center">
|
||||
<div data-role="header" class="pageheader">
|
||||
FreeSWITCH Verto Demo
|
||||
</div>
|
||||
<br>
|
||||
<a target="_CC2104" href="https://www.cluecon.com"><img border="0" width="300" src="img/cc_banner2014.gif"></a>
|
||||
|
||||
<div id="offline">
|
||||
<h2>LOGGING IN</h2>
|
||||
<img src="images/login.gif"></img>
|
||||
<div id="errordisplay" style="font-weight:bold;font-size:18px;color:#ae0000"></div>
|
||||
</div>
|
||||
|
||||
<div id="online" align="center">
|
||||
<div id="text"></div>
|
||||
<div data-role="fieldcontain">
|
||||
<input type="text" id="ext"/><br>
|
||||
<div id="dialpad">
|
||||
<button class="dialbtn" data-inline="true">1</button>
|
||||
<button class="dialbtn" data-inline="true">2</button>
|
||||
<button class="dialbtn" data-inline="true">3</button>
|
||||
<br>
|
||||
<button class="dialbtn" data-inline="true">4</button>
|
||||
<button class="dialbtn" data-inline="true">5</button>
|
||||
<button class="dialbtn" data-inline="true">6</button>
|
||||
<br>
|
||||
<button class="dialbtn" data-inline="true">7</button>
|
||||
<button class="dialbtn" data-inline="true">8</button>
|
||||
<button class="dialbtn" data-inline="true">9</button>
|
||||
<br>
|
||||
<button class="dialbtn" data-inline="true">*</button>
|
||||
<button class="dialbtn" data-inline="true">0</button>
|
||||
<button class="dialbtn" data-inline="true">#</button>
|
||||
</div>
|
||||
|
||||
<button data-inline="true" id="clearbtn">Clear</button>
|
||||
<button data-inline="true" id="callbtn">Call</button>
|
||||
<br><br>
|
||||
<button data-inline="true"id="logoutbtn">Log Out</button>
|
||||
</div>
|
||||
<br>
|
||||
<label><input id="use_vid" type="checkbox" value="foo" > Use Video</label>
|
||||
<label><input id="use_stereo" type="checkbox" value="foo" > Stereo Audio</label>
|
||||
<br>
|
||||
<!--
|
||||
<b>TEXT</b><br>To: <input type="text" size="20" id="textto"/> MSG: <input type="text" size="40" id="textmsg"/>
|
||||
<button id="vtxtbtn">Send</button>
|
||||
-->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<table width=500 style="font-size:11pt;font-face:arial">
|
||||
<tr><td align=center colspan=2><b>FreeSWITCH VERTO WebRTC Demo Directory<Br><br></td></tr>
|
||||
<tr><td width=100><b>Dial</b></td><td><b>Desc</b></td></tr>
|
||||
<tr><td align=left colspan=2><hr></td></tr>
|
||||
|
||||
<tr><td>3d1</td><td> 3D sound demo #1</td></tr>
|
||||
<tr><td>3d2</td><td> 3D sound demo #2</td></tr>
|
||||
|
||||
<tr><td>stereo1</td><td> Stereo sound demo #1</td></tr>
|
||||
<tr><td>stereo2</td><td> Stereo sound demo #2</td></tr>
|
||||
<tr><td>stereo3</td><td> Stereo sound demo #3</td></tr>
|
||||
<tr><td>3500</td><td>Local 48k Stereo Conference</td></tr>
|
||||
<tr><td> </td></tr>
|
||||
<tr><td>cluecon</td><td> ClueCon Hotline</td></tr>
|
||||
<tr><td><number></td><td>Call a US/Canda Number</td></tr>
|
||||
|
||||
<tr><td>vuc</td><td>VoIP Users Conference</td></tr>
|
||||
<tr><td>888</td><td>FreeSWITCH Community Conference</td></tr>
|
||||
|
||||
<tr><td>3300</td><td>Local 48k Conference</td></tr>
|
||||
<tr><td>5000</td><td>Try the Demo IVR</td></tr>
|
||||
<tr><td>9664</td><td>Listen to Hold Music</td></tr>
|
||||
<tr><td>9386</td><td>Funny Prompts</td></tr>
|
||||
<tr><td>9198</td><td>Tetris (tone generator)</td></tr>
|
||||
<tr><td colspan=2><Br>
|
||||
<center>
|
||||
<br><br><br>
|
||||
</td></tr>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- /page -->
|
||||
|
||||
<div data-role="page" id="dialog-logout" data-close-btn="none">
|
||||
<div data-role="header">
|
||||
<h2>Logged Out</h2>
|
||||
</div>
|
||||
<div data-role="content">
|
||||
<p>You have been logged out or disconnected from the server.</p>
|
||||
|
||||
<button onclick="$('#dialog-logout').dialog('close')">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-role="page" id="dialog-login-error" data-close-btn="none">
|
||||
<div data-role="header">
|
||||
<h2>Login Error</h2>
|
||||
</div>
|
||||
<div data-role="content">
|
||||
<p>Error logging in</p>
|
||||
|
||||
<button onclick="$('#dialog-login-error').dialog('close')">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-role="page" id="dialog-hold" data-close-btn="none">
|
||||
<div data-role="header">
|
||||
<h2>Call On hold</h2>
|
||||
</div>
|
||||
<div data-role="content">
|
||||
<p>The call is on hold</p>
|
||||
|
||||
<button onclick="$('#dialog-hold').dialog('close');cur_call.toggleHold();">Resume Call</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-role="page" id="dialog-incoming-call" data-close-btn="none">
|
||||
<div data-role="header">
|
||||
<h2>Incoming Call</h2>
|
||||
</div>
|
||||
<div data-role="content">
|
||||
<div id="dialog-incoming-call-txt"><p>Incoming Call</p></div>
|
||||
<button id="ansbtn">Answer</button>
|
||||
<div id="vansdiv"><button id="vansbtn">Answer Video</button></div>
|
||||
<button id="declinebtn">Decline</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript" src="js/jquery-2.0.3.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.mobile-1.3.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.json-2.4.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.cookie.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.dataTables.js"></script>
|
||||
<script type="text/javascript" src="js/verto-min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="verto.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
'use strict';
|
||||
var cur_call = null;
|
||||
var la = null;
|
||||
var $display = $("#display");
|
||||
var verto;
|
||||
var ringing = false;
|
||||
|
||||
function display(msg) {
|
||||
$("#calltitle").html(msg);
|
||||
}
|
||||
|
||||
function clearLa() {
|
||||
if (la) {
|
||||
la.destroy();
|
||||
la = null;
|
||||
}
|
||||
|
||||
$("#conf").hide();
|
||||
}
|
||||
|
||||
function goto_dialog(where) {
|
||||
$.mobile.changePage("#dialog-" + where, {
|
||||
role: "dialog"
|
||||
});
|
||||
}
|
||||
|
||||
function goto_page(where) {
|
||||
$.mobile.changePage("#page-" + where);
|
||||
}
|
||||
|
||||
var first_login = false;
|
||||
var online_visible = false;
|
||||
function online(on) {
|
||||
if (on) {
|
||||
$("#online").show();
|
||||
$("#offline").hide();
|
||||
first_login = true;
|
||||
} else {
|
||||
if (first_login && online_visible) {
|
||||
goto_dialog("logout");
|
||||
}
|
||||
|
||||
$("#online").hide();
|
||||
$("#offline").show();
|
||||
}
|
||||
|
||||
online_visible = on;
|
||||
}
|
||||
|
||||
function check_vid() {
|
||||
var use_vid = $("#use_vid").is(':checked');
|
||||
return use_vid;
|
||||
}
|
||||
|
||||
var callbacks = {
|
||||
|
||||
onMessage: function(verto, dialog, msg, data) {
|
||||
|
||||
switch (msg) {
|
||||
case $.verto.enum.message.pvtEvent:
|
||||
console.error("pvtEvent", data.pvtData.action);
|
||||
if (data.pvtData) {
|
||||
switch (data.pvtData.action) {
|
||||
case "conference-liveArray-part":
|
||||
clearLa();
|
||||
break;
|
||||
case "conference-liveArray-join":
|
||||
|
||||
$(".jsDataTable").width(check_vid() ? "650px" : "550px");
|
||||
|
||||
la = new $.verto.liveTable(verto, data.pvtData.laChannel, data.pvtData.laName, $('#example'), {
|
||||
subParams: {
|
||||
callID: dialog.callID
|
||||
},
|
||||
|
||||
"onChange": function(obj, args) {
|
||||
//var len = obj.asArray().length;
|
||||
$("#mcount").text("Conference Members: " + " (" + obj.arrayLen() + " Total)");
|
||||
},
|
||||
|
||||
"aaData": [],
|
||||
"aoColumns": [{
|
||||
"sTitle": "ID"
|
||||
},
|
||||
{
|
||||
"sTitle": "Number"
|
||||
},
|
||||
{
|
||||
"sTitle": "Name"
|
||||
},
|
||||
{
|
||||
"sTitle": "Codec"
|
||||
},
|
||||
{
|
||||
"sTitle": "Status",
|
||||
"sWidth": check_vid() ? "300px" : "150px"
|
||||
}],
|
||||
"bAutoWidth": true,
|
||||
"bDestroy": true,
|
||||
"bSort": false,
|
||||
"bInfo": false,
|
||||
"bFilter": false,
|
||||
"bLengthChange": false,
|
||||
"bPaginate": false,
|
||||
"iDisplayLength": 1000,
|
||||
|
||||
"oLanguage": {
|
||||
"sEmptyTable": "The Conference is Empty....."
|
||||
}
|
||||
});
|
||||
|
||||
$("#conf").show();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case $.verto.enum.message.info:
|
||||
$("#text").html("Message from: <b>" + data.from + "</b>:<br>" + "<pre>" + data.body + "</pre>");
|
||||
break;
|
||||
case $.verto.enum.message.display:
|
||||
var party = dialog.params.remote_caller_id_name + "<" + dialog.params.remote_caller_id_number + ">";
|
||||
display("Talking to: " + dialog.cidString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onDialogState: function(d) {
|
||||
cur_call = d;
|
||||
|
||||
switch (d.state) {
|
||||
case $.verto.enum.state.ringing:
|
||||
display("Call From: " + d.cidString());
|
||||
|
||||
$("#ansbtn").click(function() {
|
||||
ringing = false;
|
||||
cur_call.answer({
|
||||
useStereo: $("#use_stereo").is(':checked')
|
||||
});
|
||||
$('#dialog-incoming-call').dialog('close');
|
||||
});
|
||||
|
||||
$("#declinebtn").click(function() {
|
||||
ringing = false;
|
||||
cur_call.hangup();
|
||||
$('#dialog-incoming-call').dialog('close');
|
||||
});
|
||||
|
||||
ringing = true;
|
||||
|
||||
goto_dialog("incoming-call");
|
||||
$("#dialog-incoming-call-txt").text("Incoming call from: " + d.cidString());
|
||||
|
||||
if (d.params.wantVideo) {
|
||||
$("#vansbtn").click(function() {
|
||||
ringing = false;
|
||||
$("#use_vid").prop("checked", true);
|
||||
cur_call.answer({
|
||||
useVideo: true,
|
||||
useStereo: $("#use_stereo").is(':checked')
|
||||
});
|
||||
});
|
||||
// the buttons in this jquery mobile wont hide .. gotta wrap them in a div as a workaround
|
||||
$("#vansdiv").show();
|
||||
} else {
|
||||
$("#vansdiv").hide();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case $.verto.enum.state.active:
|
||||
display("Talking to: " + d.cidString());
|
||||
goto_page("incall");
|
||||
break;
|
||||
case $.verto.enum.state.hangup:
|
||||
case $.verto.enum.state.destroy:
|
||||
clearLa();
|
||||
goto_page("main");
|
||||
cur_call = null;
|
||||
break;
|
||||
case $.verto.enum.state.held:
|
||||
break;
|
||||
default:
|
||||
display("");
|
||||
break;
|
||||
}
|
||||
},
|
||||
onWSLogin: function(v, success) {
|
||||
display("");
|
||||
|
||||
if (success) {
|
||||
online(true);
|
||||
|
||||
verto.subscribe("presence", {
|
||||
handler: function(v, e) {
|
||||
console.error("PRESENCE:", e);
|
||||
}
|
||||
});
|
||||
if (!window.location.hash) {
|
||||
goto_page("main");
|
||||
}
|
||||
} else {
|
||||
goto_page("login");
|
||||
goto_dialog("login-error");
|
||||
}
|
||||
|
||||
},
|
||||
onWSClose: function(v, success) {
|
||||
if ($('#online').is(':visible')) {
|
||||
display("");
|
||||
online(false);
|
||||
}
|
||||
var today = new Date();
|
||||
$("#errordisplay").html("Connection Error.<br>Last Attempt: " + today);
|
||||
goto_page("main");
|
||||
},
|
||||
|
||||
onEvent: function(v, e) {
|
||||
console.debug("w00t", e);
|
||||
},
|
||||
};
|
||||
|
||||
$("#hold").click(function(e) {
|
||||
cur_call.toggleHold();
|
||||
goto_dialog("hold");
|
||||
});
|
||||
|
||||
$("#cancelxferbtn").click(function(e) {
|
||||
$("#xferto").val("");
|
||||
$("#xferdiv").hide();
|
||||
});
|
||||
|
||||
$(".startxferbtn").click(function(e) {
|
||||
if ($('#xferdiv').is(':visible')) {
|
||||
var xfer = $("#xferto").val();
|
||||
if (xfer) {
|
||||
cur_call.transfer(xfer);
|
||||
}
|
||||
$("#xferto").val("");
|
||||
$("#xferdiv").hide();
|
||||
} else {
|
||||
$("#xferdiv").show();
|
||||
}
|
||||
});
|
||||
|
||||
$("#clearbtn").click(function(e) {
|
||||
$("#ext").val("");
|
||||
});
|
||||
|
||||
$(".dialbtn").click(function(e) {
|
||||
$("#ext").val($("#ext").val() + e.currentTarget.textContent);
|
||||
});
|
||||
|
||||
$(".dtmf").click(function(e) {
|
||||
if ($('#xferdiv').is(':visible')) {
|
||||
$("#xferto").val($("#xferto").val() + e.currentTarget.textContent);
|
||||
} else {
|
||||
cur_call.dtmf(e.currentTarget.textContent);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$("#hupbtn").click(function() {
|
||||
verto.hangup();
|
||||
cur_call = null;
|
||||
});
|
||||
|
||||
$("#webcam").click(function() {
|
||||
check_vid();
|
||||
});
|
||||
|
||||
$("#callbtn").click(function() {
|
||||
$('#ext').trigger('change');
|
||||
|
||||
if (cur_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
cur_call = verto.newCall({
|
||||
destination_number: $("#ext").val(),
|
||||
caller_id_name: $("#name").val(),
|
||||
caller_id_number: $("#cid").val(),
|
||||
useVideo: check_vid(),
|
||||
useStereo: $("#use_stereo").is(':checked')
|
||||
});
|
||||
});
|
||||
|
||||
function pop(id, cname, dft) {
|
||||
var tmp = $.cookie(cname) || dft;
|
||||
$.cookie(cname, tmp, {
|
||||
expires: 365
|
||||
});
|
||||
$(id).val(tmp).change(function() {
|
||||
$.cookie(cname, $(id).val(), {
|
||||
expires: 365
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function init() {
|
||||
pop("#ext", "verto_demo_ext", "3500");
|
||||
pop("#name", "verto_demo_name", "FreeSWITCH User");
|
||||
pop("#cid", "verto_demo_cid", "1008");
|
||||
pop("#textto", "verto_demo_textto", "1000");
|
||||
|
||||
pop("#login", "verto_demo_login", "1008");
|
||||
pop("#passwd", "verto_demo_passwd", "1234");
|
||||
|
||||
pop("#hostName", "verto_demo_hostname", window.location.hostname);
|
||||
pop("#wsURL", "verto_demo_wsurl", "wss://" + window.location.hostname + ":8082");
|
||||
|
||||
var tmp = $.cookie("verto_demo_vid_checked") || "false";
|
||||
$.cookie("verto_demo_vid_checked", tmp, {
|
||||
expires: 365
|
||||
});
|
||||
|
||||
$("#use_vid").prop("checked", tmp === "true").change(function(e) {
|
||||
tmp = $("#use_vid").is(':checked');
|
||||
$.cookie("verto_demo_vid_checked", tmp ? "true" : "false", {
|
||||
expires: 365
|
||||
});
|
||||
});
|
||||
|
||||
tmp = $.cookie("verto_demo_stereo_checked") || "false";
|
||||
$.cookie("verto_demo_stereo_checked", tmp, {
|
||||
expires: 365
|
||||
});
|
||||
|
||||
$("#use_stereo").prop("checked", tmp === "true").change(function(e) {
|
||||
tmp = $("#use_stereo").is(':checked');
|
||||
$.cookie("verto_demo_stereo_checked", tmp ? "true" : "false", {
|
||||
expires: 365
|
||||
});
|
||||
});
|
||||
|
||||
verto = new $.verto({
|
||||
login: $("#login").val() + "@" + $("#hostName").val(),
|
||||
passwd: $("#passwd").val(),
|
||||
socketUrl: $("#wsURL").val(),
|
||||
tag: "webcam",
|
||||
ringFile: "sounds/bell_ring2.wav",
|
||||
videoParams: {
|
||||
"minWidth": "1280",
|
||||
"minHeight": "720"
|
||||
}
|
||||
},
|
||||
callbacks);
|
||||
|
||||
$("#login").change(function(e) {
|
||||
$("#cid").val(e.currentTarget.value);
|
||||
$.cookie("verto_demo_cid", e.currentTarget.value, {
|
||||
expires: 365
|
||||
});
|
||||
});
|
||||
|
||||
$("#vtxtbtn").click(function() {
|
||||
verto.message({
|
||||
to: $("#textto").val(),
|
||||
body: $("#textmsg").val()
|
||||
});
|
||||
$("#textmsg").val("");
|
||||
});
|
||||
|
||||
$("#logoutbtn").click(function() {
|
||||
verto.logout();
|
||||
goto_page("login");
|
||||
online(false);
|
||||
});
|
||||
|
||||
$("#loginbtn").click(function() {
|
||||
online(false);
|
||||
verto.loginData({
|
||||
login: $("#login").val() + "@" + $("#hostName").val(),
|
||||
passwd: $("#passwd").val()
|
||||
});
|
||||
verto.login();
|
||||
goto_page("main");
|
||||
});
|
||||
|
||||
$("#xferdiv").hide();
|
||||
$("#webcam").hide();
|
||||
|
||||
online(false);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
init();
|
||||
$("#page-incall").on("pagebeforechange", function(event) {});
|
||||
});
|
||||
|
||||
$(document).bind("pagebeforechange", function(e, data) {
|
||||
if (typeof(data.toPage) !== "string") {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (window.location.hash) {
|
||||
|
||||
case "#page-incall":
|
||||
|
||||
console.error(e, data);
|
||||
setTimeout(function() {
|
||||
if (!cur_call) {
|
||||
goto_page("main");
|
||||
}
|
||||
},
|
||||
10000);
|
||||
break;
|
||||
|
||||
case "#page-main":
|
||||
|
||||
console.error(e, data);
|
||||
setTimeout(function() {
|
||||
if (cur_call && !ringing) {
|
||||
goto_page("incall");
|
||||
}
|
||||
},
|
||||
2000);
|
||||
break;
|
||||
|
||||
case "#page-login":
|
||||
|
||||
setTimeout(function() {
|
||||
if (online_visible) {
|
||||
goto_page("main");
|
||||
}
|
||||
},
|
||||
1000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
JSFILES=src/jquery.FSRTC.js src/jquery.jsonrpcclient.js src/jquery.verto.js
|
||||
|
||||
all: jsmin verto-min.js
|
||||
|
||||
jsmin: jsmin.c
|
||||
$(CC) $< -o $@
|
||||
|
||||
verto-min.js: jsmin $(JSFILES)
|
||||
cat $(JSFILES) | ./jsmin > $@
|
||||
|
||||
clean:
|
||||
rm -f verto-min.js jsmin *~
|
||||
|
||||
install-demo: all
|
||||
cp verto-min.js ../demo/js
|
||||
@@ -0,0 +1,10 @@
|
||||
This file needs to say more.
|
||||
Documentation for the api needs to be developed with jsdoc-toolkit http://pulkitgoyal.in/documenting-jquery-plugins-jsdoc-toolkit/
|
||||
|
||||
Dependancies for DEMO
|
||||
jquery-2.0.3.min.js
|
||||
jquery-2.0.3.min.map
|
||||
jquery.cookie.js
|
||||
jquery.dataTables.js
|
||||
jquery.json-2.4.min.js
|
||||
jquery.mobile-1.3.2.min.js
|
||||
@@ -0,0 +1,306 @@
|
||||
/* jsmin.c
|
||||
2013-03-29
|
||||
|
||||
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
|
||||
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 shall be used for Good, not Evil.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int theA;
|
||||
static int theB;
|
||||
static int theLookahead = EOF;
|
||||
static int theX = EOF;
|
||||
static int theY = EOF;
|
||||
|
||||
|
||||
static void
|
||||
error(char* s)
|
||||
{
|
||||
fputs("JSMIN Error: ", stderr);
|
||||
fputs(s, stderr);
|
||||
fputc('\n', stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* isAlphanum -- return true if the character is a letter, digit, underscore,
|
||||
dollar sign, or non-ASCII character.
|
||||
*/
|
||||
|
||||
static int
|
||||
isAlphanum(int c)
|
||||
{
|
||||
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
|
||||
c > 126);
|
||||
}
|
||||
|
||||
|
||||
/* get -- return the next character from stdin. Watch out for lookahead. If
|
||||
the character is a control character, translate it to a space or
|
||||
linefeed.
|
||||
*/
|
||||
|
||||
static int
|
||||
get()
|
||||
{
|
||||
int c = theLookahead;
|
||||
theLookahead = EOF;
|
||||
if (c == EOF) {
|
||||
c = getc(stdin);
|
||||
}
|
||||
if (c >= ' ' || c == '\n' || c == EOF) {
|
||||
return c;
|
||||
}
|
||||
if (c == '\r') {
|
||||
return '\n';
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
||||
|
||||
/* peek -- get the next character without getting it.
|
||||
*/
|
||||
|
||||
static int
|
||||
peek()
|
||||
{
|
||||
theLookahead = get();
|
||||
return theLookahead;
|
||||
}
|
||||
|
||||
|
||||
/* next -- get the next character, excluding comments. peek() is used to see
|
||||
if a '/' is followed by a '/' or '*'.
|
||||
*/
|
||||
|
||||
static int
|
||||
next()
|
||||
{
|
||||
int c = get();
|
||||
if (c == '/') {
|
||||
switch (peek()) {
|
||||
case '/':
|
||||
for (;;) {
|
||||
c = get();
|
||||
if (c <= '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
get();
|
||||
while (c != ' ') {
|
||||
switch (get()) {
|
||||
case '*':
|
||||
if (peek() == '/') {
|
||||
get();
|
||||
c = ' ';
|
||||
}
|
||||
break;
|
||||
case EOF:
|
||||
error("Unterminated comment.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
theY = theX;
|
||||
theX = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* action -- do something! What you do is determined by the argument:
|
||||
1 Output A. Copy B to A. Get the next B.
|
||||
2 Copy B to A. Get the next B. (Delete A).
|
||||
3 Get the next B. (Delete B).
|
||||
action treats a string as a single character. Wow!
|
||||
action recognizes a regular expression if it is preceded by ( or , or =.
|
||||
*/
|
||||
|
||||
static void
|
||||
action(int d)
|
||||
{
|
||||
switch (d) {
|
||||
case 1:
|
||||
putc(theA, stdout);
|
||||
if (
|
||||
(theY == '\n' || theY == ' ') &&
|
||||
(theA == '+' || theA == '-' || theA == '*' || theA == '/') &&
|
||||
(theB == '+' || theB == '-' || theB == '*' || theB == '/')
|
||||
) {
|
||||
putc(theY, stdout);
|
||||
}
|
||||
case 2:
|
||||
theA = theB;
|
||||
if (theA == '\'' || theA == '"' || theA == '`') {
|
||||
for (;;) {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
if (theA == theB) {
|
||||
break;
|
||||
}
|
||||
if (theA == '\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
error("Unterminated string literal.");
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
theB = next();
|
||||
if (theB == '/' && (
|
||||
theA == '(' || theA == ',' || theA == '=' || theA == ':' ||
|
||||
theA == '[' || theA == '!' || theA == '&' || theA == '|' ||
|
||||
theA == '?' || theA == '+' || theA == '-' || theA == '~' ||
|
||||
theA == '*' || theA == '/' || theA == '{' || theA == '\n'
|
||||
)) {
|
||||
putc(theA, stdout);
|
||||
if (theA == '/' || theA == '*') {
|
||||
putc(' ', stdout);
|
||||
}
|
||||
putc(theB, stdout);
|
||||
for (;;) {
|
||||
theA = get();
|
||||
if (theA == '[') {
|
||||
for (;;) {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
if (theA == ']') {
|
||||
break;
|
||||
}
|
||||
if (theA == '\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
error("Unterminated set in Regular Expression literal.");
|
||||
}
|
||||
}
|
||||
} else if (theA == '/') {
|
||||
switch (peek()) {
|
||||
case '/':
|
||||
case '*':
|
||||
error("Unterminated set in Regular Expression literal.");
|
||||
}
|
||||
break;
|
||||
} else if (theA =='\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
error("Unterminated Regular Expression literal.");
|
||||
}
|
||||
putc(theA, stdout);
|
||||
}
|
||||
theB = next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* jsmin -- Copy the input to the output, deleting the characters which are
|
||||
insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
Most spaces and linefeeds will be removed.
|
||||
*/
|
||||
|
||||
static void
|
||||
jsmin()
|
||||
{
|
||||
if (peek() == 0xEF) {
|
||||
get();
|
||||
get();
|
||||
get();
|
||||
}
|
||||
theA = '\n';
|
||||
action(3);
|
||||
while (theA != EOF) {
|
||||
switch (theA) {
|
||||
case ' ':
|
||||
action(isAlphanum(theB) ? 1 : 2);
|
||||
break;
|
||||
case '\n':
|
||||
switch (theB) {
|
||||
case '{':
|
||||
case '[':
|
||||
case '(':
|
||||
case '+':
|
||||
case '-':
|
||||
case '!':
|
||||
case '~':
|
||||
action(1);
|
||||
break;
|
||||
case ' ':
|
||||
action(3);
|
||||
break;
|
||||
default:
|
||||
action(isAlphanum(theB) ? 1 : 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (theB) {
|
||||
case ' ':
|
||||
action(isAlphanum(theA) ? 1 : 3);
|
||||
break;
|
||||
case '\n':
|
||||
switch (theA) {
|
||||
case '}':
|
||||
case ']':
|
||||
case ')':
|
||||
case '+':
|
||||
case '-':
|
||||
case '"':
|
||||
case '\'':
|
||||
case '`':
|
||||
action(1);
|
||||
break;
|
||||
default:
|
||||
action(isAlphanum(theA) ? 1 : 3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
action(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* main -- Output any command line arguments as comments
|
||||
and then minify the input.
|
||||
*/
|
||||
extern int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; i += 1) {
|
||||
fprintf(stdout, "// %s\n", argv[i]);
|
||||
}
|
||||
jsmin();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
|
||||
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* jquery.FSRTC.js - WebRTC Glue code
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
// Find the line in sdpLines that starts with |prefix|, and, if specified,
|
||||
// contains |substr| (case-insensitive search).
|
||||
function findLine(sdpLines, prefix, substr) {
|
||||
return findLineInRange(sdpLines, 0, -1, prefix, substr);
|
||||
}
|
||||
|
||||
// Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix|
|
||||
// and, if specified, contains |substr| (case-insensitive search).
|
||||
function findLineInRange(sdpLines, startLine, endLine, prefix, substr) {
|
||||
var realEndLine = (endLine != -1) ? endLine : sdpLines.length;
|
||||
for (var i = startLine; i < realEndLine; ++i) {
|
||||
if (sdpLines[i].indexOf(prefix) === 0) {
|
||||
if (!substr || sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Gets the codec payload type from an a=rtpmap:X line.
|
||||
function getCodecPayloadType(sdpLine) {
|
||||
var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
|
||||
var result = sdpLine.match(pattern);
|
||||
return (result && result.length == 2) ? result[1] : null;
|
||||
}
|
||||
|
||||
// Returns a new m= line with the specified codec as the first one.
|
||||
function setDefaultCodec(mLine, payload) {
|
||||
var elements = mLine.split(' ');
|
||||
var newLine = [];
|
||||
var index = 0;
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (index === 3) // Format of media starts from the fourth.
|
||||
newLine[index++] = payload; // Put target payload to the first.
|
||||
if (elements[i] !== payload) newLine[index++] = elements[i];
|
||||
}
|
||||
return newLine.join(' ');
|
||||
}
|
||||
|
||||
$.FSRTC = function(options) {
|
||||
this.options = $.extend({
|
||||
useVideo: null,
|
||||
useStereo: false,
|
||||
userData: null,
|
||||
videoParams: {},
|
||||
callbacks: {
|
||||
onICEComplete: function() {},
|
||||
onICE: function() {},
|
||||
onOfferSDP: function() {}
|
||||
}
|
||||
},
|
||||
options);
|
||||
|
||||
this.mediaData = {
|
||||
SDP: null,
|
||||
profile: {},
|
||||
candidateList: []
|
||||
};
|
||||
|
||||
this.constraints = {
|
||||
optional: [{
|
||||
'DtlsSrtpKeyAgreement': 'true'
|
||||
}],
|
||||
mandatory: {
|
||||
OfferToReceiveAudio: true,
|
||||
OfferToReceiveVideo: this.options.useVideo ? true : false,
|
||||
}
|
||||
};
|
||||
|
||||
if (self.options.useVideo) {
|
||||
self.options.useVideo.style.display = 'none';
|
||||
}
|
||||
|
||||
setCompat();
|
||||
checkCompat();
|
||||
};
|
||||
|
||||
$.FSRTC.prototype.useVideo = function(obj) {
|
||||
var self = this;
|
||||
|
||||
if (obj) {
|
||||
self.options.useVideo = obj;
|
||||
self.constraints.mandatory.OfferToReceiveVideo = true;
|
||||
} else {
|
||||
self.options.useVideo = null;
|
||||
self.constraints.mandatory.OfferToReceiveVideo = false;
|
||||
}
|
||||
|
||||
if (self.options.useVideo) {
|
||||
self.options.useVideo.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
$.FSRTC.prototype.useStereo = function(on) {
|
||||
var self = this;
|
||||
self.options.useStereo = on;
|
||||
};
|
||||
|
||||
// Sets Opus in stereo if stereo is enabled, by adding the stereo=1 fmtp param.
|
||||
$.FSRTC.prototype.stereoHack = function(sdp) {
|
||||
var self = this;
|
||||
|
||||
if (!self.options.useStereo) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
var sdpLines = sdp.split('\r\n');
|
||||
|
||||
// Find opus payload.
|
||||
var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000'),
|
||||
opusPayload;
|
||||
if (opusIndex) {
|
||||
opusPayload = getCodecPayloadType(sdpLines[opusIndex]);
|
||||
}
|
||||
|
||||
// Find the payload in fmtp line.
|
||||
var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString());
|
||||
if (fmtpLineIndex === null) return sdp;
|
||||
|
||||
// Append stereo=1 to fmtp line.
|
||||
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1');
|
||||
|
||||
sdp = sdpLines.join('\r\n');
|
||||
return sdp;
|
||||
};
|
||||
|
||||
function setCompat() {
|
||||
$.FSRTC.moz = !!navigator.mozGetUserMedia;
|
||||
//navigator.getUserMedia || (navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia);
|
||||
if (!navigator.getUserMedia) {
|
||||
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia;
|
||||
}
|
||||
}
|
||||
|
||||
function checkCompat() {
|
||||
if (!navigator.getUserMedia) {
|
||||
alert('This application cannot function in this browser.');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStreamError(self) {
|
||||
console.log('There has been a problem retrieving the streams - did you allow access?');
|
||||
|
||||
}
|
||||
|
||||
function onStreamSuccess(self) {
|
||||
console.log("Stream Success");
|
||||
}
|
||||
|
||||
function onICE(self, candidate) {
|
||||
self.mediaData.candidate = candidate;
|
||||
self.mediaData.candidateList.push(self.mediaData.candidate);
|
||||
|
||||
doCallback(self, "onICE");
|
||||
}
|
||||
|
||||
function doCallback(self, func, arg) {
|
||||
if (func in self.options.callbacks) {
|
||||
self.options.callbacks[func](self, arg);
|
||||
}
|
||||
}
|
||||
|
||||
function onICEComplete(self, candidate) {
|
||||
console.log("ICE Complete");
|
||||
doCallback(self, "onICEComplete");
|
||||
}
|
||||
|
||||
function onChannelError(self, e) {
|
||||
console.error("Channel Error", e);
|
||||
doCallback(self, "onError", e);
|
||||
}
|
||||
|
||||
function onICESDP(self, sdp) {
|
||||
self.mediaData.SDP = self.stereoHack(sdp.sdp);
|
||||
console.log("ICE SDP");
|
||||
doCallback(self, "onICESDP");
|
||||
}
|
||||
|
||||
function onAnswerSDP(self, sdp) {
|
||||
self.answer.SDP = self.stereoHack(sdp.sdp);
|
||||
console.log("ICE ANSWER SDP");
|
||||
doCallback(self, "onAnswerSDP", self.answer.SDP);
|
||||
}
|
||||
|
||||
function onMessage(self, msg) {
|
||||
console.log("Message");
|
||||
doCallback(self, "onICESDP", msg);
|
||||
}
|
||||
|
||||
function onRemoteStream(self, stream) {
|
||||
if (self.options.useVideo) {
|
||||
self.options.useVideo.style.display = 'block';
|
||||
}
|
||||
|
||||
var element = self.options.useAudio;
|
||||
console.log("REMOTE STREAM", stream, element);
|
||||
|
||||
if (typeof element.srcObject !== 'undefined') {
|
||||
element.srcObject = stream;
|
||||
} else if (typeof element.mozSrcObject !== 'undefined') {
|
||||
element.mozSrcObject = stream;
|
||||
} else if (typeof element.src !== 'undefined') {
|
||||
element.src = URL.createObjectURL(stream);
|
||||
} else {
|
||||
console.error('Error attaching stream to element.');
|
||||
}
|
||||
|
||||
self.options.useAudio.play();
|
||||
self.remoteStream = stream;
|
||||
}
|
||||
|
||||
function onOfferSDP(self, sdp) {
|
||||
self.mediaData.SDP = self.stereoHack(sdp.sdp);
|
||||
console.log("Offer SDP");
|
||||
doCallback(self, "onOfferSDP");
|
||||
}
|
||||
|
||||
$.FSRTC.prototype.answer = function(sdp, onSuccess, onError) {
|
||||
this.peer.addAnswerSDP({
|
||||
type: "answer",
|
||||
sdp: sdp
|
||||
},
|
||||
onSuccess, onError);
|
||||
};
|
||||
|
||||
$.FSRTC.prototype.stop = function() {
|
||||
var self = this;
|
||||
|
||||
if (self.options.useVideo) {
|
||||
self.options.useVideo.style.display = 'none';
|
||||
}
|
||||
|
||||
if (self.localStream) {
|
||||
self.localStream.stop();
|
||||
self.localStream = null;
|
||||
}
|
||||
|
||||
if (self.peer) {
|
||||
console.log("stopping peer");
|
||||
self.peer.stop();
|
||||
}
|
||||
};
|
||||
|
||||
$.FSRTC.prototype.createAnswer = function(sdp) {
|
||||
var self = this;
|
||||
self.type = "answer";
|
||||
self.remoteSDP = sdp;
|
||||
console.debug("inbound sdp: ", sdp);
|
||||
|
||||
function onSuccess(stream) {
|
||||
self.localStream = stream;
|
||||
|
||||
self.peer = RTCPeerConnection({
|
||||
type: self.type,
|
||||
attachStream: self.localStream,
|
||||
onICE: function(candidate) {
|
||||
return onICE(self, candidate);
|
||||
},
|
||||
onICEComplete: function() {
|
||||
return onICEComplete(self);
|
||||
},
|
||||
onRemoteStream: function(stream) {
|
||||
return onRemoteStream(self, stream);
|
||||
},
|
||||
onICESDP: function(sdp) {
|
||||
return onICESDP(self, sdp);
|
||||
},
|
||||
onChannelError: function(e) {
|
||||
return onChannelError(self, e);
|
||||
},
|
||||
constraints: self.constraints,
|
||||
offerSDP: {
|
||||
type: "offer",
|
||||
sdp: self.remoteSDP
|
||||
}
|
||||
});
|
||||
|
||||
onStreamSuccess(self);
|
||||
}
|
||||
|
||||
function onError() {
|
||||
onStreamError(self);
|
||||
}
|
||||
|
||||
getUserMedia({
|
||||
constraints: {
|
||||
audio: true,
|
||||
video: this.options.useVideo ? {
|
||||
mandatory: this.options.videoParams,
|
||||
optional: []
|
||||
} : null
|
||||
},
|
||||
video: this.options.useVideo ? true : false,
|
||||
onsuccess: onSuccess,
|
||||
onerror: onError
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$.FSRTC.prototype.call = function(profile) {
|
||||
checkCompat();
|
||||
|
||||
var self = this;
|
||||
|
||||
self.type = "offer";
|
||||
|
||||
function onSuccess(stream) {
|
||||
self.localStream = stream;
|
||||
|
||||
self.peer = RTCPeerConnection({
|
||||
type: self.type,
|
||||
attachStream: self.localStream,
|
||||
onICE: function(candidate) {
|
||||
return onICE(self, candidate);
|
||||
},
|
||||
onICEComplete: function() {
|
||||
return onICEComplete(self);
|
||||
},
|
||||
onRemoteStream: function(stream) {
|
||||
return onRemoteStream(self, stream);
|
||||
},
|
||||
onOfferSDP: function(sdp) {
|
||||
return onOfferSDP(self, sdp);
|
||||
},
|
||||
onICESDP: function(sdp) {
|
||||
return onICESDP(self, sdp);
|
||||
},
|
||||
onChannelError: function(e) {
|
||||
return onChannelError(self, e);
|
||||
},
|
||||
constraints: self.constraints
|
||||
});
|
||||
|
||||
onStreamSuccess(self);
|
||||
}
|
||||
|
||||
function onError() {
|
||||
onStreamError(self);
|
||||
}
|
||||
|
||||
getUserMedia({
|
||||
constraints: {
|
||||
audio: true,
|
||||
video: this.options.useVideo ? {
|
||||
mandatory: this.options.videoParams,
|
||||
optional: []
|
||||
} : null
|
||||
},
|
||||
video: this.options.useVideo ? true : false,
|
||||
onsuccess: onSuccess,
|
||||
onerror: onError
|
||||
});
|
||||
|
||||
/*
|
||||
navigator.getUserMedia({
|
||||
video: this.options.useVideo,
|
||||
audio: true
|
||||
}, onSuccess, onError);
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
// DERIVED from RTCPeerConnection-v1.5
|
||||
// 2013, @muazkh - github.com/muaz-khan
|
||||
// MIT License - https://www.webrtc-experiment.com/licence/
|
||||
// Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RTCPeerConnection
|
||||
window.moz = !!navigator.mozGetUserMedia;
|
||||
|
||||
function RTCPeerConnection(options) {
|
||||
|
||||
var w = window,
|
||||
PeerConnection = w.mozRTCPeerConnection || w.webkitRTCPeerConnection,
|
||||
SessionDescription = w.mozRTCSessionDescription || w.RTCSessionDescription,
|
||||
IceCandidate = w.mozRTCIceCandidate || w.RTCIceCandidate;
|
||||
|
||||
var STUN = {
|
||||
url: !moz ? 'stun:stun.l.google.com:19302' : 'stun:23.21.150.121'
|
||||
};
|
||||
|
||||
var TURN = {
|
||||
url: 'turn:homeo@turn.bistri.com:80',
|
||||
credential: 'homeo'
|
||||
};
|
||||
|
||||
var iceServers = {
|
||||
iceServers: options.iceServers || [STUN]
|
||||
};
|
||||
|
||||
if (!moz && !options.iceServers) {
|
||||
if (parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 28) TURN = {
|
||||
url: 'turn:turn.bistri.com:80',
|
||||
credential: 'homeo',
|
||||
username: 'homeo'
|
||||
};
|
||||
|
||||
iceServers.iceServers = [STUN];
|
||||
}
|
||||
|
||||
var optional = {
|
||||
optional: []
|
||||
};
|
||||
|
||||
if (!moz) {
|
||||
optional.optional = [{
|
||||
DtlsSrtpKeyAgreement: true
|
||||
},
|
||||
{
|
||||
RtpDataChannels: options.onChannelMessage ? true : false
|
||||
}];
|
||||
}
|
||||
|
||||
var peer = new PeerConnection(iceServers, optional);
|
||||
|
||||
openOffererChannel();
|
||||
var x = 0;
|
||||
|
||||
peer.onicecandidate = function(event) {
|
||||
console.log("WTF ICE", event);
|
||||
|
||||
if (event.candidate) {
|
||||
options.onICE(event.candidate);
|
||||
} else {
|
||||
if (options.onICEComplete) {
|
||||
options.onICEComplete();
|
||||
}
|
||||
|
||||
if (options.type == "offer") {
|
||||
if (!moz && !x && options.onICESDP) {
|
||||
options.onICESDP(peer.localDescription);
|
||||
//x = 1;
|
||||
/*
|
||||
x = 1;
|
||||
peer.createOffer(function(sessionDescription) {
|
||||
sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
|
||||
peer.setLocalDescription(sessionDescription);
|
||||
if (options.onICESDP) {
|
||||
options.onICESDP(sessionDescription);
|
||||
}
|
||||
}, onSdpError, constraints);
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
if (!x && options.onICESDP) {
|
||||
options.onICESDP(peer.localDescription);
|
||||
//x = 1;
|
||||
/*
|
||||
x = 1;
|
||||
peer.createAnswer(function(sessionDescription) {
|
||||
sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
|
||||
peer.setLocalDescription(sessionDescription);
|
||||
if (options.onICESDP) {
|
||||
options.onICESDP(sessionDescription);
|
||||
}
|
||||
}, onSdpError, constraints);
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// attachStream = MediaStream;
|
||||
if (options.attachStream) peer.addStream(options.attachStream);
|
||||
|
||||
// attachStreams[0] = audio-stream;
|
||||
// attachStreams[1] = video-stream;
|
||||
// attachStreams[2] = screen-capturing-stream;
|
||||
if (options.attachStreams && options.attachStream.length) {
|
||||
var streams = options.attachStreams;
|
||||
for (var i = 0; i < streams.length; i++) {
|
||||
peer.addStream(streams[i]);
|
||||
}
|
||||
}
|
||||
|
||||
peer.onaddstream = function(event) {
|
||||
var remoteMediaStream = event.stream;
|
||||
|
||||
// onRemoteStreamEnded(MediaStream)
|
||||
remoteMediaStream.onended = function() {
|
||||
if (options.onRemoteStreamEnded) options.onRemoteStreamEnded(remoteMediaStream);
|
||||
};
|
||||
|
||||
// onRemoteStream(MediaStream)
|
||||
if (options.onRemoteStream) options.onRemoteStream(remoteMediaStream);
|
||||
|
||||
//console.debug('on:add:stream', remoteMediaStream);
|
||||
};
|
||||
|
||||
var constraints = options.constraints || {
|
||||
optional: [],
|
||||
mandatory: {
|
||||
OfferToReceiveAudio: true,
|
||||
OfferToReceiveVideo: true
|
||||
}
|
||||
};
|
||||
|
||||
// onOfferSDP(RTCSessionDescription)
|
||||
function createOffer() {
|
||||
if (!options.onOfferSDP) return;
|
||||
|
||||
peer.createOffer(function(sessionDescription) {
|
||||
sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
|
||||
peer.setLocalDescription(sessionDescription);
|
||||
options.onOfferSDP(sessionDescription);
|
||||
if (moz && options.onICESDP) {
|
||||
options.onICESDP(sessionDescription);
|
||||
}
|
||||
},
|
||||
onSdpError, constraints);
|
||||
}
|
||||
|
||||
// onAnswerSDP(RTCSessionDescription)
|
||||
function createAnswer() {
|
||||
if (options.type != "answer") return;
|
||||
|
||||
//options.offerSDP.sdp = addStereo(options.offerSDP.sdp);
|
||||
peer.setRemoteDescription(new SessionDescription(options.offerSDP), onSdpSuccess, onSdpError);
|
||||
peer.createAnswer(function(sessionDescription) {
|
||||
sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
|
||||
peer.setLocalDescription(sessionDescription);
|
||||
if (options.onAnswerSDP) {
|
||||
options.onAnswerSDP(sessionDescription);
|
||||
}
|
||||
},
|
||||
onSdpError, constraints);
|
||||
}
|
||||
|
||||
// if Mozilla Firefox & DataChannel; offer/answer will be created later
|
||||
if ((options.onChannelMessage && !moz) || !options.onChannelMessage) {
|
||||
createOffer();
|
||||
createAnswer();
|
||||
}
|
||||
|
||||
// DataChannel Bandwidth
|
||||
function setBandwidth(sdp) {
|
||||
// remove existing bandwidth lines
|
||||
sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, '');
|
||||
sdp = sdp.replace(/a=mid:data\r\n/g, 'a=mid:data\r\nb=AS:1638400\r\n');
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
// old: FF<>Chrome interoperability management
|
||||
function getInteropSDP(sdp) {
|
||||
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
|
||||
extractedChars = '';
|
||||
|
||||
function getChars() {
|
||||
extractedChars += chars[parseInt(Math.random() * 40)] || '';
|
||||
if (extractedChars.length < 40) getChars();
|
||||
|
||||
return extractedChars;
|
||||
}
|
||||
|
||||
// usually audio-only streaming failure occurs out of audio-specific crypto line
|
||||
// a=crypto:1 AES_CM_128_HMAC_SHA1_32 --------- kAttributeCryptoVoice
|
||||
if (options.onAnswerSDP) sdp = sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g, '');
|
||||
|
||||
// video-specific crypto line i.e. SHA1_80
|
||||
// a=crypto:1 AES_CM_128_HMAC_SHA1_80 --------- kAttributeCryptoVideo
|
||||
var inline = getChars() + '\r\n' + (extractedChars = '');
|
||||
sdp = sdp.indexOf('a=crypto') == -1 ? sdp.replace(/c=IN/g, 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:' + inline + 'c=IN') : sdp;
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
function serializeSdp(sdp) {
|
||||
//if (!moz) sdp = setBandwidth(sdp);
|
||||
//sdp = getInteropSDP(sdp);
|
||||
//console.debug(sdp);
|
||||
return sdp;
|
||||
}
|
||||
|
||||
// DataChannel management
|
||||
var channel;
|
||||
|
||||
function openOffererChannel() {
|
||||
if (!options.onChannelMessage || (moz && !options.onOfferSDP)) return;
|
||||
|
||||
_openOffererChannel();
|
||||
|
||||
if (!moz) return;
|
||||
navigator.mozGetUserMedia({
|
||||
audio: true,
|
||||
fake: true
|
||||
},
|
||||
function(stream) {
|
||||
peer.addStream(stream);
|
||||
createOffer();
|
||||
},
|
||||
useless);
|
||||
}
|
||||
|
||||
function _openOffererChannel() {
|
||||
channel = peer.createDataChannel(options.channel || 'RTCDataChannel', moz ? {} : {
|
||||
reliable: false
|
||||
});
|
||||
|
||||
if (moz) channel.binaryType = 'blob';
|
||||
|
||||
setChannelEvents();
|
||||
}
|
||||
|
||||
function setChannelEvents() {
|
||||
channel.onmessage = function(event) {
|
||||
if (options.onChannelMessage) options.onChannelMessage(event);
|
||||
};
|
||||
|
||||
channel.onopen = function() {
|
||||
if (options.onChannelOpened) options.onChannelOpened(channel);
|
||||
};
|
||||
channel.onclose = function(event) {
|
||||
if (options.onChannelClosed) options.onChannelClosed(event);
|
||||
|
||||
console.warn('WebRTC DataChannel closed', event);
|
||||
};
|
||||
channel.onerror = function(event) {
|
||||
if (options.onChannelError) options.onChannelError(event);
|
||||
|
||||
console.error('WebRTC DataChannel error', event);
|
||||
};
|
||||
}
|
||||
|
||||
if (options.onAnswerSDP && moz && options.onChannelMessage) openAnswererChannel();
|
||||
|
||||
function openAnswererChannel() {
|
||||
peer.ondatachannel = function(event) {
|
||||
channel = event.channel;
|
||||
channel.binaryType = 'blob';
|
||||
setChannelEvents();
|
||||
};
|
||||
|
||||
if (!moz) return;
|
||||
navigator.mozGetUserMedia({
|
||||
audio: true,
|
||||
fake: true
|
||||
},
|
||||
function(stream) {
|
||||
peer.addStream(stream);
|
||||
createAnswer();
|
||||
},
|
||||
useless);
|
||||
}
|
||||
|
||||
// fake:true is also available on chrome under a flag!
|
||||
function useless() {
|
||||
log('Error in fake:true');
|
||||
}
|
||||
|
||||
function onSdpSuccess() {}
|
||||
|
||||
function onSdpError(e) {
|
||||
if (options.onChannelError) {
|
||||
options.onChannelError(e);
|
||||
}
|
||||
console.error('sdp error:', e);
|
||||
}
|
||||
|
||||
return {
|
||||
addAnswerSDP: function(sdp, cbSuccess, cbError) {
|
||||
|
||||
peer.setRemoteDescription(new SessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError);
|
||||
},
|
||||
addICE: function(candidate) {
|
||||
peer.addIceCandidate(new IceCandidate({
|
||||
sdpMLineIndex: candidate.sdpMLineIndex,
|
||||
candidate: candidate.candidate
|
||||
}));
|
||||
},
|
||||
|
||||
peer: peer,
|
||||
channel: channel,
|
||||
sendData: function(message) {
|
||||
if (channel) {
|
||||
channel.send(message);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
peer.close();
|
||||
if (options.attachStream) {
|
||||
options.attachStream.stop();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// getUserMedia
|
||||
var video_constraints = {
|
||||
mandatory: {},
|
||||
optional: []
|
||||
};
|
||||
|
||||
function getUserMedia(options) {
|
||||
var n = navigator,
|
||||
media;
|
||||
n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia;
|
||||
n.getMedia(options.constraints || {
|
||||
audio: true,
|
||||
video: video_constraints
|
||||
},
|
||||
streaming, options.onerror ||
|
||||
function(e) {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
function streaming(stream) {
|
||||
var video = options.video;
|
||||
if (video) {
|
||||
video[moz ? 'mozSrcObject' : 'src'] = moz ? stream : window.webkitURL.createObjectURL(stream);
|
||||
//video.play();
|
||||
}
|
||||
if (options.onsuccess) {
|
||||
options.onsuccess(stream);
|
||||
}
|
||||
media = stream;
|
||||
}
|
||||
|
||||
return media;
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,653 @@
|
||||
/*
|
||||
* Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
|
||||
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is jquery.jsonrpclient.js modified for Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Textalk AB http://textalk.se/
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* jquery.jsonrpclient.js - JSON RPC client code
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* This plugin requires jquery.json.js to be available, or at least the methods $.toJSON and
|
||||
* $.parseJSON.
|
||||
*
|
||||
* The plan is to make use of websockets if they are available, but work just as well with only
|
||||
* http if not.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' });
|
||||
* foo.call(
|
||||
* 'bar', [ 'A parameter', 'B parameter' ],
|
||||
* function(result) { alert('Foo bar answered: ' + result.my_answer); },
|
||||
* function(error) { console.log('There was an error', error); }
|
||||
* );
|
||||
*
|
||||
* More examples are available in README.md
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* @fn new
|
||||
* @memberof $.JsonRpcClient
|
||||
*
|
||||
* @param options An object stating the backends:
|
||||
* ajaxUrl A url (relative or absolute) to a http(s) backend.
|
||||
* socketUrl A url (relative of absolute) to a ws(s) backend.
|
||||
* onmessage A socket message handler for other messages (non-responses).
|
||||
* getSocket A function returning a WebSocket or null.
|
||||
* It must take an onmessage_cb and bind it to the onmessage event
|
||||
* (or chain it before/after some other onmessage handler).
|
||||
* Or, it could return null if no socket is available.
|
||||
* The returned instance must have readyState <= 1, and if less than 1,
|
||||
* react to onopen binding.
|
||||
*/
|
||||
$.JsonRpcClient = function(options) {
|
||||
var self = this;
|
||||
this.options = $.extend({
|
||||
ajaxUrl : null,
|
||||
socketUrl : null, ///< The ws-url for default getSocket.
|
||||
onmessage : null, ///< Other onmessage-handler.
|
||||
login : null, /// auth login
|
||||
passwd : null, /// auth passwd
|
||||
sessid : null,
|
||||
getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); }
|
||||
}, options);
|
||||
|
||||
// Declare an instance version of the onmessage callback to wrap 'this'.
|
||||
this.wsOnMessage = function(event) { self._wsOnMessage(event); };
|
||||
};
|
||||
|
||||
/// Holding the WebSocket on default getsocket.
|
||||
$.JsonRpcClient.prototype._ws_socket = null;
|
||||
|
||||
/// Object <id>: { success_cb: cb, error_cb: cb }
|
||||
$.JsonRpcClient.prototype._ws_callbacks = {};
|
||||
|
||||
/// The next JSON-RPC request id.
|
||||
$.JsonRpcClient.prototype._current_id = 1;
|
||||
|
||||
/**
|
||||
* @fn call
|
||||
* @memberof $.JsonRpcClient
|
||||
*
|
||||
* @param method The method to run on JSON-RPC server.
|
||||
* @param params The params; an array or object.
|
||||
* @param success_cb A callback for successful request.
|
||||
* @param error_cb A callback for error.
|
||||
*/
|
||||
$.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) {
|
||||
// Construct the JSON-RPC 2.0 request.
|
||||
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
|
||||
if (this.options.sessid) {
|
||||
params.sessid = this.options.sessid;
|
||||
}
|
||||
|
||||
var request = {
|
||||
jsonrpc : '2.0',
|
||||
method : method,
|
||||
params : params,
|
||||
id : this._current_id++ // Increase the id counter to match request/response
|
||||
};
|
||||
|
||||
if (!success_cb) {
|
||||
success_cb = function(e){console.log("Success: ", e);};
|
||||
}
|
||||
|
||||
if (!error_cb) {
|
||||
error_cb = function(e){console.log("Error: ", e);};
|
||||
}
|
||||
|
||||
// Try making a WebSocket call.
|
||||
var socket = this.options.getSocket(this.wsOnMessage);
|
||||
if (socket !== null) {
|
||||
this._wsCall(socket, request, success_cb, error_cb);
|
||||
return;
|
||||
}
|
||||
|
||||
// No WebSocket, and no HTTP backend? This won't work.
|
||||
if (this.options.ajaxUrl === null) {
|
||||
throw "$.JsonRpcClient.call used with no websocket and no http endpoint.";
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : this.options.ajaxUrl,
|
||||
data : $.toJSON(request),
|
||||
dataType : 'json',
|
||||
cache : false,
|
||||
|
||||
success : function(data) {
|
||||
if ('error' in data) error_cb(data.error, this);
|
||||
success_cb(data.result, this);
|
||||
},
|
||||
|
||||
// JSON-RPC Server could return non-200 on error
|
||||
error : function(jqXHR, textStatus, errorThrown) {
|
||||
try {
|
||||
var response = $.parseJSON(jqXHR.responseText);
|
||||
if ('console' in window) console.log(response);
|
||||
error_cb(response.error, this);
|
||||
}
|
||||
catch (err) {
|
||||
// Perhaps the responseText wasn't really a jsonrpc-error.
|
||||
error_cb({ error: jqXHR.responseText }, this);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify sends a command to the server that won't need a response. In http, there is probably
|
||||
* an empty response - that will be dropped, but in ws there should be no response at all.
|
||||
*
|
||||
* This is very similar to call, but has no id and no handling of callbacks.
|
||||
*
|
||||
* @fn notify
|
||||
* @memberof $.JsonRpcClient
|
||||
*
|
||||
* @param method The method to run on JSON-RPC server.
|
||||
* @param params The params; an array or object.
|
||||
*/
|
||||
$.JsonRpcClient.prototype.notify = function(method, params) {
|
||||
// Construct the JSON-RPC 2.0 request.
|
||||
|
||||
if (this.options.sessid) {
|
||||
params.sessid = this.options.sessid;
|
||||
}
|
||||
|
||||
var request = {
|
||||
jsonrpc: '2.0',
|
||||
method: method,
|
||||
params: params
|
||||
};
|
||||
|
||||
// Try making a WebSocket call.
|
||||
var socket = this.options.getSocket(this.wsOnMessage);
|
||||
if (socket !== null) {
|
||||
this._wsCall(socket, request);
|
||||
return;
|
||||
}
|
||||
|
||||
// No WebSocket, and no HTTP backend? This won't work.
|
||||
if (this.options.ajaxUrl === null) {
|
||||
throw "$.JsonRpcClient.notify used with no websocket and no http endpoint.";
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : this.options.ajaxUrl,
|
||||
data : $.toJSON(request),
|
||||
dataType : 'json',
|
||||
cache : false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a batch-call by using a callback.
|
||||
*
|
||||
* The callback will get an object "batch" as only argument. On batch, you can call the methods
|
||||
* "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be
|
||||
* sent as a batch call then the callback is done.
|
||||
*
|
||||
* @fn batch
|
||||
* @memberof $.JsonRpcClient
|
||||
*
|
||||
* @param callback The main function which will get a batch handler to run call and notify on.
|
||||
* @param all_done_cb A callback function to call after all results have been handled.
|
||||
* @param error_cb A callback function to call if there is an error from the server.
|
||||
* Note, that batch calls should always get an overall success, and the
|
||||
* only error
|
||||
*/
|
||||
$.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) {
|
||||
var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb);
|
||||
callback(batch);
|
||||
batch._execute();
|
||||
};
|
||||
|
||||
/**
|
||||
* The default getSocket handler.
|
||||
*
|
||||
* @param onmessage_cb The callback to be bound to onmessage events on the socket.
|
||||
*
|
||||
* @fn _getSocket
|
||||
* @memberof $.JsonRpcClient
|
||||
*/
|
||||
|
||||
$.JsonRpcClient.prototype.socketReady = function() {
|
||||
if (this._ws_socket === null || this._ws_socket.readyState > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$.JsonRpcClient.prototype.closeSocket = function() {
|
||||
if (self.socketReady()) {
|
||||
this._ws_socket.onclose = function (w) {console.log("Closing Socket")}
|
||||
this._ws_socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
$.JsonRpcClient.prototype.loginData = function(params) {
|
||||
self.options.login = params.login;
|
||||
self.options.passwd = params.passwd;
|
||||
}
|
||||
|
||||
$.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) {
|
||||
var self = this;
|
||||
|
||||
if (!self.socketReady()) {
|
||||
self.authing = false;
|
||||
// No socket, or dying socket, let's get a new one.
|
||||
this._ws_socket = new WebSocket(this.options.socketUrl);
|
||||
|
||||
if (this._ws_socket) {
|
||||
// Set up onmessage handler.
|
||||
this._ws_socket.onmessage = onmessage_cb;
|
||||
this._ws_socket.onclose = function (w) {
|
||||
if (!self.ws_sleep) {
|
||||
self.ws_sleep = 2;
|
||||
}
|
||||
|
||||
self.ws_cnt = 0;
|
||||
|
||||
if (self.options.onWSClose) {
|
||||
self.options.onWSClose(self);
|
||||
}
|
||||
|
||||
console.error("Websocket Lost sleep: " + self.ws_sleep + "sec");
|
||||
|
||||
setTimeout(function() {
|
||||
console.log("Attempting Reconnection....");
|
||||
self.connectSocket(onmessage_cb);
|
||||
}, self.ws_sleep * 1000);
|
||||
|
||||
|
||||
if (++self.ws_cnt >= 150) {
|
||||
self.ws_sleep = 30;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up sending of message for when the socket is open.
|
||||
this._ws_socket.onopen = function() {
|
||||
this.ws_sleep = 2;
|
||||
this.ws_cnt = 0;
|
||||
if (self.options.onWSConnect) {
|
||||
self.options.onWSConnect(self);
|
||||
}
|
||||
|
||||
var req;
|
||||
// Send the requests.
|
||||
while (req = $.JsonRpcClient.q.pop()) {
|
||||
self._ws_socket.send(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._ws_socket ? true : false;
|
||||
}
|
||||
|
||||
$.JsonRpcClient.prototype._getSocket = function(onmessage_cb) {
|
||||
// If there is no ws url set, we don't have a socket.
|
||||
// Likewise, if there is no window.WebSocket.
|
||||
if (this.options.socketUrl === null || !("WebSocket" in window)) return null;
|
||||
|
||||
this.connectSocket(onmessage_cb);
|
||||
|
||||
return this._ws_socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queue to save messages delivered when websocket is not ready
|
||||
*/
|
||||
$.JsonRpcClient.q = [];
|
||||
|
||||
/**
|
||||
* Internal handler to dispatch a JRON-RPC request through a websocket.
|
||||
*
|
||||
* @fn _wsCall
|
||||
* @memberof $.JsonRpcClient
|
||||
*/
|
||||
$.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) {
|
||||
var request_json = $.toJSON(request);
|
||||
|
||||
if (socket.readyState < 1) {
|
||||
// The websocket is not open yet; we have to set sending of the message in onopen.
|
||||
self = this; // In closure below, this is set to the WebSocket. Use self instead.
|
||||
|
||||
$.JsonRpcClient.q.push(request_json);
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
// We have a socket and it should be ready to send on.
|
||||
socket.send(request_json);
|
||||
}
|
||||
|
||||
// Setup callbacks. If there is an id, this is a call and not a notify.
|
||||
if ('id' in request && typeof success_cb !== 'undefined') {
|
||||
this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal handler for the websocket messages. It determines if the message is a JSON-RPC
|
||||
* response, and if so, tries to couple it with a given callback. Otherwise, it falls back to
|
||||
* given external onmessage-handler, if any.
|
||||
*
|
||||
* @param event The websocket onmessage-event.
|
||||
*/
|
||||
$.JsonRpcClient.prototype._wsOnMessage = function(event) {
|
||||
// Check if this could be a JSON RPC message.
|
||||
var response;
|
||||
try {
|
||||
response = $.parseJSON(event.data);
|
||||
|
||||
/// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends.
|
||||
|
||||
if (typeof response === 'object'
|
||||
&& 'jsonrpc' in response
|
||||
&& response.jsonrpc === '2.0') {
|
||||
|
||||
/// @todo Handle bad response (without id).
|
||||
|
||||
// If this is an object with result, it is a response.
|
||||
if ('result' in response && this._ws_callbacks[response.id]) {
|
||||
// Get the success callback.
|
||||
var success_cb = this._ws_callbacks[response.id].success_cb;
|
||||
|
||||
/*
|
||||
// set the sessid if present
|
||||
if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) {
|
||||
this.options.sessid = response.result.sessid;
|
||||
if (this.options.sessid) {
|
||||
console.log("setting session UUID to: " + this.options.sessid);
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Delete the callback from the storage.
|
||||
delete this._ws_callbacks[response.id];
|
||||
|
||||
// Run callback with result as parameter.
|
||||
success_cb(response.result, this);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an object with error, it is an error response.
|
||||
else if ('error' in response && this._ws_callbacks[response.id]) {
|
||||
|
||||
// Get the error callback.
|
||||
var error_cb = this._ws_callbacks[response.id].error_cb;
|
||||
var orig_req = this._ws_callbacks[response.id].request;
|
||||
|
||||
// if this is an auth request, send the credentials and resend the failed request
|
||||
if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) {
|
||||
self.authing = true;
|
||||
|
||||
this.call("login", { login: self.options.login, passwd: self.options.passwd},
|
||||
this._ws_callbacks[response.id].request_obj.method == "login"
|
||||
?
|
||||
function(e) {
|
||||
self.authing = false;
|
||||
console.log("logged in");
|
||||
delete self._ws_callbacks[response.id];
|
||||
|
||||
if (self.options.onWSLogin) {
|
||||
self.options.onWSLogin(true, self);
|
||||
}
|
||||
}
|
||||
|
||||
:
|
||||
|
||||
function(e) {
|
||||
self.authing = false;
|
||||
console.log("logged in, resending request id: " + response.id);
|
||||
var socket = self.options.getSocket(self.wsOnMessage);
|
||||
if (socket !== null) {
|
||||
socket.send(orig_req);
|
||||
}
|
||||
if (self.options.onWSLogin) {
|
||||
self.options.onWSLogin(true, self);
|
||||
}
|
||||
},
|
||||
|
||||
function(e) {
|
||||
console.log("error logging in, request id:", response.id);
|
||||
delete self._ws_callbacks[response.id];
|
||||
error_cb(response.error, this);
|
||||
if (self.options.onWSLogin) {
|
||||
self.options.onWSLogin(false, self);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the callback from the storage.
|
||||
delete this._ws_callbacks[response.id];
|
||||
|
||||
// Run callback with the error object as parameter.
|
||||
error_cb(response.error, this);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// Probably an error while parsing a non json-string as json. All real JSON-RPC cases are
|
||||
// handled above, and the fallback method is called below.
|
||||
console.log("ERROR: "+ err);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is not a JSON-RPC response. Call the fallback message handler, if given.
|
||||
if (typeof this.options.onmessage === 'function') {
|
||||
event.eventData = response;
|
||||
if (!event.eventData) {
|
||||
event.eventData = {};
|
||||
}
|
||||
|
||||
var reply = this.options.onmessage(event);
|
||||
|
||||
if (reply && typeof reply === "object" && event.eventData.id) {
|
||||
var msg = {
|
||||
jsonrpc: "2.0",
|
||||
id: event.eventData.id,
|
||||
result: reply
|
||||
};
|
||||
|
||||
var socket = self.options.getSocket(self.wsOnMessage);
|
||||
if (socket !== null) {
|
||||
socket.send($.toJSON(msg));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* Batch object with methods
|
||||
************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Handling object for batch calls.
|
||||
*/
|
||||
$.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) {
|
||||
// Array of objects to hold the call and notify requests. Each objects will have the request
|
||||
// object, and unless it is a notify, success_cb and error_cb.
|
||||
this._requests = [];
|
||||
|
||||
this.jsonrpcclient = jsonrpcclient;
|
||||
this.all_done_cb = all_done_cb;
|
||||
this.error_cb = typeof error_cb === 'function' ? error_cb : function() {};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @sa $.JsonRpcClient.prototype.call
|
||||
*/
|
||||
$.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) {
|
||||
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
|
||||
if (this.options.sessid) {
|
||||
params.sessid = this.options.sessid;
|
||||
}
|
||||
|
||||
if (!success_cb) {
|
||||
success_cb = function(e){console.log("Success: ", e);};
|
||||
}
|
||||
|
||||
if (!error_cb) {
|
||||
error_cb = function(e){console.log("Error: ", e);};
|
||||
}
|
||||
|
||||
this._requests.push({
|
||||
request : {
|
||||
jsonrpc : '2.0',
|
||||
method : method,
|
||||
params : params,
|
||||
id : this.jsonrpcclient._current_id++ // Use the client's id series.
|
||||
},
|
||||
success_cb : success_cb,
|
||||
error_cb : error_cb
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @sa $.JsonRpcClient.prototype.notify
|
||||
*/
|
||||
$.JsonRpcClient._batchObject.prototype.notify = function(method, params) {
|
||||
if (this.options.sessid) {
|
||||
params.sessid = this.options.sessid;
|
||||
}
|
||||
|
||||
this._requests.push({
|
||||
request : {
|
||||
jsonrpc : '2.0',
|
||||
method : method,
|
||||
params : params
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes the batched up calls.
|
||||
*/
|
||||
$.JsonRpcClient._batchObject.prototype._execute = function() {
|
||||
var self = this;
|
||||
|
||||
if (this._requests.length === 0) return; // All done :P
|
||||
|
||||
// Collect all request data and sort handlers by request id.
|
||||
var batch_request = [];
|
||||
var handlers = {};
|
||||
|
||||
// If we have a WebSocket, just send the requests individually like normal calls.
|
||||
var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);
|
||||
if (socket !== null) {
|
||||
for (var i = 0; i < this._requests.length; i++) {
|
||||
var call = this._requests[i];
|
||||
var success_cb = ('success_cb' in call) ? call.success_cb : undefined;
|
||||
var error_cb = ('error_cb' in call) ? call.error_cb : undefined;
|
||||
self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb);
|
||||
}
|
||||
if (typeof all_done_cb === 'function') all_done_cb(result);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this._requests.length; i++) {
|
||||
var call = this._requests[i];
|
||||
batch_request.push(call.request);
|
||||
|
||||
// If the request has an id, it should handle returns (otherwise it's a notify).
|
||||
if ('id' in call.request) {
|
||||
handlers[call.request.id] = {
|
||||
success_cb : call.success_cb,
|
||||
error_cb : call.error_cb
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); };
|
||||
|
||||
// No WebSocket, and no HTTP backend? This won't work.
|
||||
if (self.jsonrpcclient.options.ajaxUrl === null) {
|
||||
throw "$.JsonRpcClient.batch used with no websocket and no http endpoint.";
|
||||
}
|
||||
|
||||
// Send request
|
||||
$.ajax({
|
||||
url : self.jsonrpcclient.options.ajaxUrl,
|
||||
data : $.toJSON(batch_request),
|
||||
dataType : 'json',
|
||||
cache : false,
|
||||
type : 'POST',
|
||||
|
||||
// Batch-requests should always return 200
|
||||
error : function(jqXHR, textStatus, errorThrown) {
|
||||
self.error_cb(jqXHR, textStatus, errorThrown);
|
||||
},
|
||||
success : success_cb
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper to match the result array from a batch call to their respective callbacks.
|
||||
*
|
||||
* @fn _batchCb
|
||||
* @memberof $.JsonRpcClient
|
||||
*/
|
||||
$.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) {
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var response = result[i];
|
||||
|
||||
// Handle error
|
||||
if ('error' in response) {
|
||||
if (response.id === null || !(response.id in handlers)) {
|
||||
// An error on a notify? Just log it to the console.
|
||||
if ('console' in window) console.log(response);
|
||||
}
|
||||
else handlers[response.id].error_cb(response.error, this);
|
||||
}
|
||||
else {
|
||||
// Here we should always have a correct id and no error.
|
||||
if (!(response.id in handlers) && 'console' in window) console.log(response);
|
||||
else handlers[response.id].success_cb(response.result, this);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof all_done_cb === 'function') all_done_cb(result);
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||