").attr("id",b).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(b){a.isArray(b)&&(b.length?b.length===this.anchors.length&&(b=!0):b=!1);for(var c,d=0;c=this.tabs[d];d++)b===!0||-1!==a.inArray(d,b)?a(c).addClass("ui-state-disabled").attr("aria-disabled","true"):a(c).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=b},_setupEvents:function(b){var c={click:function(a){a.preventDefault()}};b&&a.each(b.split(" "),function(a,b){c[b]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,c),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(b){var c,d=this.element.parent();"fill"===b?(c=d.height(),c-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var b=a(this),d=b.css("position");"absolute"!==d&&"fixed"!==d&&(c-=b.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){c-=a(this).outerHeight(!0)}),this.panels.each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")):"auto"===b&&(c=0,this.panels.each(function(){c=Math.max(c,a(this).height("").height())}).height(c))},_eventHandler:function(b){var c=this.options,d=this.active,e=a(b.currentTarget),f=e.closest("li"),g=f[0]===d[0],h=g&&c.collapsible,i=h?a():this._getPanelForTab(f),j=d.length?this._getPanelForTab(d):a(),k={oldTab:d,oldPanel:j,newTab:h?a():f,newPanel:i};b.preventDefault(),f.hasClass("ui-state-disabled")||f.hasClass("ui-tabs-loading")||this.running||g&&!c.collapsible||this._trigger("beforeActivate",b,k)===!1||(c.active=h?!1:this.tabs.index(f),this.active=g?a():f,this.xhr&&this.xhr.abort(),j.length||i.length||a.error("jQuery UI Tabs: Mismatching fragment identifier."),i.length&&this.load(this.tabs.index(f),b),this._toggle(b,k))},_toggle:function(b,c){function d(){f.running=!1,f._trigger("activate",b,c)}function e(){c.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),g.length&&f.options.show?f._show(g,f.options.show,d):(g.show(),d())}var f=this,g=c.newPanel,h=c.oldPanel;this.running=!0,h.length&&this.options.hide?this._hide(h,this.options.hide,function(){c.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),e()}):(c.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),h.hide(),e()),h.attr({"aria-expanded":"false","aria-hidden":"true"}),c.oldTab.attr("aria-selected","false"),g.length&&h.length?c.oldTab.attr("tabIndex",-1):g.length&&this.tabs.filter(function(){return 0===a(this).attr("tabIndex")}).attr("tabIndex",-1),g.attr({"aria-expanded":"true","aria-hidden":"false"}),c.newTab.attr({"aria-selected":"true",tabIndex:0})
+},_activate:function(b){var c,d=this._findActive(b);d[0]!==this.active[0]&&(d.length||(d=this.active),c=d.find(".ui-tabs-anchor")[0],this._eventHandler({target:c,currentTarget:c,preventDefault:a.noop}))},_findActive:function(b){return b===!1?a():this.tabs.eq(b)},_getIndex:function(a){return"string"==typeof a&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){a.data(this,"ui-tabs-destroy")?a(this).remove():a(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var b=a(this),c=b.data("ui-tabs-aria-controls");c?b.attr("aria-controls",c).removeData("ui-tabs-aria-controls"):b.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(c){var d=this.options.disabled;d!==!1&&(c===b?d=!1:(c=this._getIndex(c),d=a.isArray(d)?a.map(d,function(a){return a!==c?a:null}):a.map(this.tabs,function(a,b){return b!==c?b:null})),this._setupDisabled(d))},disable:function(c){var d=this.options.disabled;if(d!==!0){if(c===b)d=!0;else{if(c=this._getIndex(c),-1!==a.inArray(c,d))return;d=a.isArray(d)?a.merge([c],d).sort():[c]}this._setupDisabled(d)}},load:function(b,c){b=this._getIndex(b);var e=this,f=this.tabs.eq(b),g=f.find(".ui-tabs-anchor"),h=this._getPanelForTab(f),i={tab:f,panel:h};d(g[0])||(this.xhr=a.ajax(this._ajaxSettings(g,c,i)),this.xhr&&"canceled"!==this.xhr.statusText&&(f.addClass("ui-tabs-loading"),h.attr("aria-busy","true"),this.xhr.success(function(a){setTimeout(function(){h.html(a),e._trigger("load",c,i)},1)}).complete(function(a,b){setTimeout(function(){"abort"===b&&e.panels.stop(!1,!0),f.removeClass("ui-tabs-loading"),h.removeAttr("aria-busy"),a===e.xhr&&delete e.xhr},1)})))},_ajaxSettings:function(b,c,d){var e=this;return{url:b.attr("href"),beforeSend:function(b,f){return e._trigger("beforeLoad",c,a.extend({jqXHR:b,ajaxSettings:f},d))}}},_getPanelForTab:function(b){var c=a(b).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+c))}})}(a),function(){}(a),function(a,b){function c(a){e=a.originalEvent,i=e.accelerationIncludingGravity,f=Math.abs(i.x),g=Math.abs(i.y),h=Math.abs(i.z),!b.orientation&&(f>7||(h>6&&8>g||8>h&&g>6)&&f>5)?d.enabled&&d.disable():d.enabled||d.enable()}a.mobile.iosorientationfixEnabled=!0;var d,e,f,g,h,i,j=navigator.userAgent;return/iPhone|iPad|iPod/.test(navigator.platform)&&/OS [1-5]_[0-9_]* like Mac OS X/i.test(j)&&j.indexOf("AppleWebKit")>-1?(d=a.mobile.zoom,void a.mobile.document.on("mobileinit",function(){a.mobile.iosorientationfixEnabled&&a.mobile.window.bind("orientationchange.iosorientationfix",d.enable).bind("devicemotion.iosorientationfix",c)})):void(a.mobile.iosorientationfixEnabled=!1)}(a,this),function(a,b){function d(){e.removeClass("ui-mobile-rendering")}var e=a("html"),f=a.mobile.window;a(b.document).trigger("mobileinit"),a.mobile.gradeA()&&(a.mobile.ajaxBlacklist&&(a.mobile.ajaxEnabled=!1),e.addClass("ui-mobile ui-mobile-rendering"),setTimeout(d,5e3),a.extend(a.mobile,{initializePage:function(){var b=a.mobile.path,e=a(":jqmData(role='page'), :jqmData(role='dialog')"),g=b.stripHash(b.stripQueryParams(b.parseLocation().hash)),h=a.mobile.path.parseLocation(),i=c.getElementById(g);e.length||(e=a("body").wrapInner("
").children(0)),e.each(function(){var b=a(this);b[0].getAttribute("data-"+a.mobile.ns+"url")||b.attr("data-"+a.mobile.ns+"url",b.attr("id")||h.pathname+h.search)}),a.mobile.firstPage=e.first(),a.mobile.pageContainer=a.mobile.firstPage.parent().addClass("ui-mobile-viewport").pagecontainer(),a.mobile.navreadyDeferred.resolve(),f.trigger("pagecontainercreate"),a.mobile.loading("show"),d(),a.mobile.hashListeningEnabled&&a.mobile.path.isHashValid(location.hash)&&(a(i).is(":jqmData(role='page')")||a.mobile.path.isPath(g)||g===a.mobile.dialogHashKey)?a.event.special.navigate.isPushStateEnabled()?(a.mobile.navigate.history.stack=[],a.mobile.navigate(a.mobile.path.isPath(location.hash)?location.hash:location.href)):f.trigger("hashchange",[!0]):(a.mobile.path.isHashValid(location.hash)&&(a.mobile.navigate.history.initialDst=g.replace("#","")),a.event.special.navigate.isPushStateEnabled()&&a.mobile.navigate.navigator.squash(b.parseLocation().href),a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:!0,changeHash:!1,fromHashChange:!0}))}}),a(function(){a.support.inlineSVG(),a.mobile.hideUrlBar&&b.scrollTo(0,1),a.mobile.defaultHomeScroll=a.support.scrollTop&&1!==a.mobile.window.scrollTop()?1:0,a.mobile.autoInitializePage&&a.mobile.initializePage(),a.mobile.hideUrlBar&&f.load(a.mobile.silentScroll),a.support.cssPointerEvents||a.mobile.document.delegate(".ui-state-disabled,.ui-disabled","vclick",function(a){a.preventDefault(),a.stopImmediatePropagation()})}))}(a,this)});
+//# sourceMappingURL=jquery.mobile.min.map
\ No newline at end of file
diff --git a/html5/verto/verto_communicator/js/material-design/material.js b/html5/verto/verto_communicator/js/material-design/material.js
new file mode 100755
index 0000000000..a315edeb09
--- /dev/null
+++ b/html5/verto/verto_communicator/js/material-design/material.js
@@ -0,0 +1,232 @@
+/* globals jQuery */
+
+(function($) {
+ // Selector to select only not already processed elements
+ $.expr[":"].notmdproc = function(obj){
+ if ($(obj).data("mdproc")) {
+ return false;
+ } else {
+ return true;
+ }
+ };
+
+ function _isChar(evt) {
+ if (typeof evt.which == "undefined") {
+ return true;
+ } else if (typeof evt.which == "number" && evt.which > 0) {
+ return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8 && evt.which != 9;
+ }
+ return false;
+ }
+
+ $.material = {
+ "options": {
+ // These options set what will be started by $.material.init()
+ "input": true,
+ "ripples": true,
+ "checkbox": true,
+ "togglebutton": true,
+ "radio": true,
+ "arrive": true,
+ "autofill": false,
+
+ "withRipples": [
+ ".btn:not(.btn-link)",
+ ".card-image",
+ ".navbar a:not(.withoutripple)",
+ ".dropdown-menu a",
+ ".nav-tabs a:not(.withoutripple)",
+ ".withripple"
+ ].join(","),
+ "inputElements": "input.form-control, textarea.form-control, select.form-control",
+ "checkboxElements": ".checkbox > label > input[type=checkbox]",
+ "togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
+ "radioElements": ".radio > label > input[type=radio]"
+ },
+ "checkbox": function(selector) {
+ // Add fake-checkbox to material checkboxes
+ $((selector) ? selector : this.options.checkboxElements)
+ .filter(":notmdproc")
+ .data("mdproc", true)
+ .after("
");
+ },
+ "togglebutton": function(selector) {
+ // Add fake-checkbox to material checkboxes
+ $((selector) ? selector : this.options.togglebuttonElements)
+ .filter(":notmdproc")
+ .data("mdproc", true)
+ .after("
");
+ },
+ "radio": function(selector) {
+ // Add fake-radio to material radios
+ $((selector) ? selector : this.options.radioElements)
+ .filter(":notmdproc")
+ .data("mdproc", true)
+ .after("
");
+ },
+ "input": function(selector) {
+ $((selector) ? selector : this.options.inputElements)
+ .filter(":notmdproc")
+ .data("mdproc", true)
+ .each( function() {
+ var $this = $(this);
+
+ if (!$(this).attr("data-hint") && !$this.hasClass("floating-label")) {
+ return;
+ }
+ $this.wrap("
");
+ $this.after("
");
+
+ // Add floating label if required
+ if ($this.hasClass("floating-label")) {
+ var placeholder = $this.attr("placeholder");
+ $this.attr("placeholder", null).removeClass("floating-label");
+ $this.after("
" + placeholder + "
");
+ }
+
+ // Add hint label if required
+ if ($this.attr("data-hint")) {
+ $this.after("
" + $this.attr("data-hint") + "
");
+ }
+
+ // Set as empty if is empty (damn I must improve this...)
+ if ($this.val() === null || $this.val() == "undefined" || $this.val() === "") {
+ $this.addClass("empty");
+ }
+
+ // Support for file input
+ if ($this.parent().next().is("[type=file]")) {
+ $this.parent().addClass("fileinput");
+ var $input = $this.parent().next().detach();
+ $this.after($input);
+ }
+ });
+
+ $(document)
+ .on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); })
+ .on("keydown paste", ".form-control", function(e) {
+ if(_isChar(e)) {
+ $(this).removeClass("empty");
+ }
+ })
+ .on("keyup change", ".form-control", function() {
+ var $this = $(this);
+ if ($this.val() === "" && (typeof $this[0].checkValidity != "undefined" && $this[0].checkValidity())) {
+ $this.addClass("empty");
+ } else {
+ $this.removeClass("empty");
+ }
+ })
+ .on("focus", ".form-control-wrapper.fileinput", function() {
+ $(this).find("input").addClass("focus");
+ })
+ .on("blur", ".form-control-wrapper.fileinput", function() {
+ $(this).find("input").removeClass("focus");
+ })
+ .on("change", ".form-control-wrapper.fileinput [type=file]", function() {
+ var value = "";
+ $.each($(this)[0].files, function(i, file) {
+ value += file.name + ", ";
+ });
+ value = value.substring(0, value.length - 2);
+ if (value) {
+ $(this).prev().removeClass("empty");
+ } else {
+ $(this).prev().addClass("empty");
+ }
+ $(this).prev().val(value);
+ });
+ },
+ "ripples": function(selector) {
+ $((selector) ? selector : this.options.withRipples).ripples();
+ },
+ "autofill": function() {
+
+ // This part of code will detect autofill when the page is loading (username and password inputs for example)
+ var loading = setInterval(function() {
+ $("input[type!=checkbox]").each(function() {
+ if ($(this).val() && $(this).val() !== $(this).attr("value")) {
+ $(this).trigger("change");
+ }
+ });
+ }, 100);
+
+ // After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
+ setTimeout(function() {
+ clearInterval(loading);
+ }, 10000);
+ // Now we just listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
+ var focused;
+ $(document)
+ .on("focus", "input", function() {
+ var $inputs = $(this).parents("form").find("input").not("[type=file]");
+ focused = setInterval(function() {
+ $inputs.each(function() {
+ if ($(this).val() !== $(this).attr("value")) {
+ $(this).trigger("change");
+ }
+ });
+ }, 100);
+ })
+ .on("blur", "input", function() {
+ clearInterval(focused);
+ });
+ },
+ "init": function() {
+ if ($.fn.ripples && this.options.ripples) {
+ console.log('ripples');
+ this.ripples();
+ }
+ if (this.options.input) {
+ console.log('input');
+ this.input();
+ }
+ if (this.options.checkbox) {
+ console.log('checkbox');
+ this.checkbox();
+ }
+ if (this.options.togglebutton) {
+ console.log('togglebutton');
+ this.togglebutton();
+ }
+ if (this.options.radio) {
+ console.log('radio');
+ this.radio();
+ }
+ if (this.options.autofill) {
+ console.log('autofill');
+ this.autofill();
+ }
+
+ if (document.arrive && this.options.arrive) {
+ if ($.fn.ripples && this.options.ripples) {
+ $(document).arrive(this.options.withRipples, function() {
+ $.material.ripples($(this));
+ });
+ }
+ if (this.options.input) {
+ $(document).arrive(this.options.inputElements, function() {
+ $.material.input($(this));
+ });
+ }
+ if (this.options.checkbox) {
+ $(document).arrive(this.options.checkboxElements, function() {
+ $.material.checkbox($(this));
+ });
+ }
+ if (this.options.radio) {
+ $(document).arrive(this.options.radioElements, function() {
+ $.material.radio($(this));
+ });
+ }
+ if (this.options.togglebutton) {
+ $(document).arrive(this.options.togglebuttonElements, function() {
+ $.material.togglebutton($(this));
+ });
+ }
+
+ }
+ }
+ };
+
+})(jQuery);
diff --git a/html5/verto/verto_communicator/js/material-design/material.min.js b/html5/verto/verto_communicator/js/material-design/material.min.js
new file mode 100755
index 0000000000..dc4958a9b7
--- /dev/null
+++ b/html5/verto/verto_communicator/js/material-design/material.min.js
@@ -0,0 +1,2 @@
+!function(a){function b(a){return"undefined"==typeof a.which?!0:"number"==typeof a.which&&a.which>0?!a.ctrlKey&&!a.metaKey&&!a.altKey&&8!=a.which&&9!=a.which:!1}a.expr[":"].notmdproc=function(b){return a(b).data("mdproc")?!1:!0},a.material={options:{input:!0,ripples:!0,checkbox:!0,togglebutton:!0,radio:!0,arrive:!0,autofill:!1,withRipples:[".btn:not(.btn-link)",".card-image",".navbar a:not(.withoutripple)",".dropdown-menu a",".nav-tabs a:not(.withoutripple)",".withripple"].join(","),inputElements:"input.form-control, textarea.form-control, select.form-control",checkboxElements:".checkbox > label > input[type=checkbox]",togglebuttonElements:".togglebutton > label > input[type=checkbox]",radioElements:".radio > label > input[type=radio]"},checkbox:function(b){a(b?b:this.options.checkboxElements).filter(":notmdproc").data("mdproc",!0).after("
")},togglebutton:function(b){a(b?b:this.options.togglebuttonElements).filter(":notmdproc").data("mdproc",!0).after("
")},radio:function(b){a(b?b:this.options.radioElements).filter(":notmdproc").data("mdproc",!0).after("
")},input:function(c){a(c?c:this.options.inputElements).filter(":notmdproc").data("mdproc",!0).each(function(){var b=a(this);if(a(this).attr("data-hint")||b.hasClass("floating-label")){if(b.wrap("
"),b.after("
"),b.hasClass("floating-label")){var c=b.attr("placeholder");b.attr("placeholder",null).removeClass("floating-label"),b.after("
"+c+"
")}if(b.attr("data-hint")&&b.after("
"+b.attr("data-hint")+"
"),(null===b.val()||"undefined"==b.val()||""===b.val())&&b.addClass("empty"),b.parent().next().is("[type=file]")){b.parent().addClass("fileinput");var d=b.parent().next().detach();b.after(d)}}}),a(document).on("change",".checkbox input[type=checkbox]",function(){a(this).blur()}).on("keydown paste",".form-control",function(c){b(c)&&a(this).removeClass("empty")}).on("keyup change",".form-control",function(){var b=a(this);""===b.val()&&"undefined"!=typeof b[0].checkValidity&&b[0].checkValidity()?b.addClass("empty"):b.removeClass("empty")}).on("focus",".form-control-wrapper.fileinput",function(){a(this).find("input").addClass("focus")}).on("blur",".form-control-wrapper.fileinput",function(){a(this).find("input").removeClass("focus")}).on("change",".form-control-wrapper.fileinput [type=file]",function(){var b="";a.each(a(this)[0].files,function(a,c){b+=c.name+", "}),b=b.substring(0,b.length-2),b?a(this).prev().removeClass("empty"):a(this).prev().addClass("empty"),a(this).prev().val(b)})},ripples:function(b){a(b?b:this.options.withRipples).ripples()},autofill:function(){var b=setInterval(function(){a("input[type!=checkbox]").each(function(){a(this).val()&&a(this).val()!==a(this).attr("value")&&a(this).trigger("change")})},100);setTimeout(function(){clearInterval(b)},1e4);var c;a(document).on("focus","input",function(){var b=a(this).parents("form").find("input").not("[type=file]");c=setInterval(function(){b.each(function(){a(this).val()!==a(this).attr("value")&&a(this).trigger("change")})},100)}).on("blur","input",function(){clearInterval(c)})},init:function(){a.fn.ripples&&this.options.ripples&&this.ripples(),this.options.input&&this.input(),this.options.checkbox&&this.checkbox(),this.options.togglebutton&&this.togglebutton(),this.options.radio&&this.radio(),this.options.autofill&&this.autofill(),document.arrive&&this.options.arrive&&(a.fn.ripples&&this.options.ripples&&a(document).arrive(this.options.withRipples,function(){a.material.ripples(a(this))}),this.options.input&&a(document).arrive(this.options.inputElements,function(){a.material.input(a(this))}),this.options.checkbox&&a(document).arrive(this.options.checkboxElements,function(){a.material.checkbox(a(this))}),this.options.radio&&a(document).arrive(this.options.radioElements,function(){a.material.radio(a(this))}),this.options.togglebutton&&a(document).arrive(this.options.togglebuttonElements,function(){a.material.togglebutton(a(this))}))}}}(jQuery);
+//# sourceMappingURL=material.min.js.map
\ No newline at end of file
diff --git a/html5/verto/verto_communicator/js/material-design/ripples.js b/html5/verto/verto_communicator/js/material-design/ripples.js
new file mode 100755
index 0000000000..634dfdf35e
--- /dev/null
+++ b/html5/verto/verto_communicator/js/material-design/ripples.js
@@ -0,0 +1,324 @@
+/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
+/* globals jQuery, navigator */
+
+(function($, window, document, undefined) {
+
+ "use strict";
+
+ /**
+ * Define the name of the plugin
+ */
+ var ripples = "ripples";
+
+
+ /**
+ * Get an instance of the plugin
+ */
+ var self = null;
+
+
+ /**
+ * Define the defaults of the plugin
+ */
+ var defaults = {};
+
+
+ /**
+ * Create the main plugin function
+ */
+ function Ripples(element, options) {
+ self = this;
+
+ this.element = $(element);
+
+ this.options = $.extend({}, defaults, options);
+
+ this._defaults = defaults;
+ this._name = ripples;
+
+ this.init();
+ }
+
+
+ /**
+ * Initialize the plugin
+ */
+ Ripples.prototype.init = function() {
+ var $element = this.element;
+
+ $element.on("mousedown touchstart", function(event) {
+ /**
+ * Verify if the user is just touching on a device and return if so
+ */
+ if(self.isTouch() && event.type === "mousedown") {
+ return;
+ }
+
+
+ /**
+ * Verify if the current element already has a ripple wrapper element and
+ * creates if it doesn't
+ */
+ if(!($element.find(".ripple-wrapper").length)) {
+ $element.append("
");
+ }
+
+
+ /**
+ * Find the ripple wrapper
+ */
+ var $wrapper = $element.children(".ripple-wrapper");
+
+
+ /**
+ * Get relY and relX positions
+ */
+ var relY = self.getRelY($wrapper, event);
+ var relX = self.getRelX($wrapper, event);
+
+
+ /**
+ * If relY and/or relX are false, return the event
+ */
+ if(!relY && !relX) {
+ return;
+ }
+
+
+ /**
+ * Get the ripple color
+ */
+ var rippleColor = self.getRipplesColor($element);
+
+
+ /**
+ * Create the ripple element
+ */
+ var $ripple = $("
");
+
+ $ripple
+ .addClass("ripple")
+ .css({
+ "left": relX,
+ "top": relY,
+ "background-color": rippleColor
+ });
+
+
+ /**
+ * Append the ripple to the wrapper
+ */
+ $wrapper.append($ripple);
+
+
+ /**
+ * Make sure the ripple has the styles applied (ugly hack but it works)
+ */
+ (function() { return window.getComputedStyle($ripple[0]).opacity; })();
+
+
+ /**
+ * Turn on the ripple animation
+ */
+ self.rippleOn($element, $ripple);
+
+
+ /**
+ * Call the rippleEnd function when the transition "on" ends
+ */
+ setTimeout(function() {
+ self.rippleEnd($ripple);
+ }, 500);
+
+
+ /**
+ * Detect when the user leaves the element
+ */
+ $element.on("mouseup mouseleave touchend", function() {
+ $ripple.data("mousedown", "off");
+
+ if($ripple.data("animating") === "off") {
+ self.rippleOut($ripple);
+ }
+ });
+
+ });
+ };
+
+
+ /**
+ * Get the new size based on the element height/width and the ripple width
+ */
+ Ripples.prototype.getNewSize = function($element, $ripple) {
+
+ return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
+ };
+
+
+ /**
+ * Get the relX
+ */
+ Ripples.prototype.getRelX = function($wrapper, event) {
+ var wrapperOffset = $wrapper.offset();
+
+ if(!self.isTouch()) {
+ /**
+ * Get the mouse position relative to the ripple wrapper
+ */
+ return event.pageX - wrapperOffset.left;
+ } else {
+ /**
+ * Make sure the user is using only one finger and then get the touch
+ * position relative to the ripple wrapper
+ */
+ event = event.originalEvent;
+
+ if(event.touches.length === 1) {
+ return event.touches[0].pageX - wrapperOffset.left;
+ }
+
+ return false;
+ }
+ };
+
+
+ /**
+ * Get the relY
+ */
+ Ripples.prototype.getRelY = function($wrapper, event) {
+ var wrapperOffset = $wrapper.offset();
+
+ if(!self.isTouch()) {
+ /**
+ * Get the mouse position relative to the ripple wrapper
+ */
+ return event.pageY - wrapperOffset.top;
+ } else {
+ /**
+ * Make sure the user is using only one finger and then get the touch
+ * position relative to the ripple wrapper
+ */
+ event = event.originalEvent;
+
+ if(event.touches.length === 1) {
+ return event.touches[0].pageY - wrapperOffset.top;
+ }
+
+ return false;
+ }
+ };
+
+
+ /**
+ * Get the ripple color
+ */
+ Ripples.prototype.getRipplesColor = function($element) {
+
+ var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
+
+ return color;
+ };
+
+
+ /**
+ * Verify if the client browser has transistion support
+ */
+ Ripples.prototype.hasTransitionSupport = function() {
+ var thisBody = document.body || document.documentElement;
+ var thisStyle = thisBody.style;
+
+ var support = (
+ thisStyle.transition !== undefined ||
+ thisStyle.WebkitTransition !== undefined ||
+ thisStyle.MozTransition !== undefined ||
+ thisStyle.MsTransition !== undefined ||
+ thisStyle.OTransition !== undefined
+ );
+
+ return support;
+ };
+
+
+ /**
+ * Verify if the client is using a mobile device
+ */
+ Ripples.prototype.isTouch = function() {
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+ };
+
+
+ /**
+ * End the animation of the ripple
+ */
+ Ripples.prototype.rippleEnd = function($ripple) {
+ $ripple.data("animating", "off");
+
+ if($ripple.data("mousedown") === "off") {
+ self.rippleOut($ripple);
+ }
+ };
+
+
+ /**
+ * Turn off the ripple effect
+ */
+ Ripples.prototype.rippleOut = function($ripple) {
+ $ripple.off();
+
+ if(self.hasTransitionSupport()) {
+ $ripple.addClass("ripple-out");
+ } else {
+ $ripple.animate({"opacity": 0}, 100, function() {
+ $ripple.trigger("transitionend");
+ });
+ }
+
+ $ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
+ $ripple.remove();
+ });
+ };
+
+
+ /**
+ * Turn on the ripple effect
+ */
+ Ripples.prototype.rippleOn = function($element, $ripple) {
+ var size = self.getNewSize($element, $ripple);
+
+ if(self.hasTransitionSupport()) {
+ $ripple
+ .css({
+ "-ms-transform": "scale(" + size + ")",
+ "-moz-transform": "scale(" + size + ")",
+ "-webkit-transform": "scale(" + size + ")",
+ "transform": "scale(" + size + ")"
+ })
+ .addClass("ripple-on")
+ .data("animating", "on")
+ .data("mousedown", "on");
+ } else {
+ $ripple.animate({
+ "width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
+ "height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
+ "margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
+ "margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
+ "opacity": 0.2
+ }, 500, function() {
+ $ripple.trigger("transitionend");
+ });
+ }
+ };
+
+
+ /**
+ * Create the jquery plugin function
+ */
+ $.fn.ripples = function(options) {
+ return this.each(function() {
+ if(!$.data(this, "plugin_" + ripples)) {
+ $.data(this, "plugin_" + ripples, new Ripples(this, options));
+ }
+ });
+ };
+
+})(jQuery, window, document);
diff --git a/html5/verto/verto_communicator/js/material-design/ripples.min.js b/html5/verto/verto_communicator/js/material-design/ripples.min.js
new file mode 100755
index 0000000000..a1b233b5d3
--- /dev/null
+++ b/html5/verto/verto_communicator/js/material-design/ripples.min.js
@@ -0,0 +1,2 @@
+!function(a,b,c,d){"use strict";function e(b,c){g=this,this.element=a(b),this.options=a.extend({},h,c),this._defaults=h,this._name=f,this.init()}var f="ripples",g=null,h={};e.prototype.init=function(){var c=this.element;c.on("mousedown touchstart",function(d){if(!g.isTouch()||"mousedown"!==d.type){c.find(".ripple-wrapper").length||c.append('
');var e=c.children(".ripple-wrapper"),f=g.getRelY(e,d),h=g.getRelX(e,d);if(f||h){var i=g.getRipplesColor(c),j=a("
");j.addClass("ripple").css({left:h,top:f,"background-color":i}),e.append(j),function(){return b.getComputedStyle(j[0]).opacity}(),g.rippleOn(c,j),setTimeout(function(){g.rippleEnd(j)},500),c.on("mouseup mouseleave touchend",function(){j.data("mousedown","off"),"off"===j.data("animating")&&g.rippleOut(j)})}}})},e.prototype.getNewSize=function(a,b){return Math.max(a.outerWidth(),a.outerHeight())/b.outerWidth()*2.5},e.prototype.getRelX=function(a,b){var c=a.offset();return g.isTouch()?(b=b.originalEvent,1!==b.touches.length?b.touches[0].pageX-c.left:!1):b.pageX-c.left},e.prototype.getRelY=function(a,b){var c=a.offset();return g.isTouch()?(b=b.originalEvent,1!==b.touches.length?b.touches[0].pageY-c.top:!1):b.pageY-c.top},e.prototype.getRipplesColor=function(a){var c=a.data("ripple-color")?a.data("ripple-color"):b.getComputedStyle(a[0]).color;return c},e.prototype.hasTransitionSupport=function(){var a=c.body||c.documentElement,b=a.style,e=b.transition!==d||b.WebkitTransition!==d||b.MozTransition!==d||b.MsTransition!==d||b.OTransition!==d;return e},e.prototype.isTouch=function(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},e.prototype.rippleEnd=function(a){a.data("animating","off"),"off"===a.data("mousedown")&&g.rippleOut(a)},e.prototype.rippleOut=function(a){a.off(),g.hasTransitionSupport()?a.addClass("ripple-out"):a.animate({opacity:0},100,function(){a.trigger("transitionend")}),a.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",function(){a.remove()})},e.prototype.rippleOn=function(a,b){var c=g.getNewSize(a,b);g.hasTransitionSupport()?b.css({"-ms-transform":"scale("+c+")","-moz-transform":"scale("+c+")","-webkit-transform":"scale("+c+")",transform:"scale("+c+")"}).addClass("ripple-on").data("animating","on").data("mousedown","on"):b.animate({width:2*Math.max(a.outerWidth(),a.outerHeight()),height:2*Math.max(a.outerWidth(),a.outerHeight()),"margin-left":-1*Math.max(a.outerWidth(),a.outerHeight()),"margin-top":-1*Math.max(a.outerWidth(),a.outerHeight()),opacity:.2},500,function(){b.trigger("transitionend")})},a.fn.ripples=function(b){return this.each(function(){a.data(this,"plugin_"+f)||a.data(this,"plugin_"+f,new e(this,b))})}}(jQuery,window,document);
+//# sourceMappingURL=ripples.min.js.map
\ No newline at end of file
diff --git a/html5/verto/verto_communicator/js/storage-service.js b/html5/verto/verto_communicator/js/storage-service.js
new file mode 100644
index 0000000000..8b153fcc45
--- /dev/null
+++ b/html5/verto/verto_communicator/js/storage-service.js
@@ -0,0 +1,35 @@
+'use strict';
+
+var storageService = angular.module('storageService', ['ngStorage']);
+
+storageService.service('storage', ['$rootScope', '$localStorage', 'verto', function($rootScope, $localStorage, verto) {
+ var data = $localStorage;
+
+ data.$default({
+ ui_connected: false,
+ ws_connected: false,
+ cur_call: 0,
+ called_number: '',
+ useVideo: true,
+ call_history: [],
+ call_start: false,
+ name: '',
+ email: '',
+ login: '',
+ password: '',
+ userStatus: 'disconnected',
+ mutedVideo: false,
+ mutedMic: false,
+ verto: verto
+ });
+
+ return {
+ data: data,
+ reset: function() {
+ data.ui_connected = false;
+ data.ws_connected = false;
+ data.cur_call = 0;
+ data.userStatus = 'disconnected';
+ },
+ };
+}]);
diff --git a/html5/verto/verto_communicator/js/verto-service.js b/html5/verto/verto_communicator/js/verto-service.js
new file mode 100644
index 0000000000..16194c1864
--- /dev/null
+++ b/html5/verto/verto_communicator/js/verto-service.js
@@ -0,0 +1,651 @@
+'use strict';
+
+/* Controllers */
+
+var videoQuality = [
+ {id: 'qvga', label: 'QVGA 320x240'},
+ {id: 'vga', label: 'VGA 640x480'},
+ {id: 'qvga_wide', label: 'QVGA WIDE 320x180'},
+ {id: 'vga_wide', label: 'VGA WIDE 640x360'},
+ {id: 'hd', label: 'HD 1280x720'},
+ {id: 'hhd', label: 'HHD 1920x1080'},
+];
+
+var videoResolution = {
+ qvga: {width: 320, height: 240},
+ vga: {width: 640, height: 480},
+ qvga_wide: {width: 320, height: 180},
+ vga_wide: {width: 640, height: 360},
+ hd: {width: 1280, height: 720},
+ hhd: {width: 1920, height: 1080},
+};
+
+var bandwidth = [
+ {id: '250', label: '250kb'},
+ {id: '500', label: '500kb'},
+ {id: '1024', label: '1mb'},
+ {id: '1536', label: '1.5mb'},
+ {id: '2048', label: '2mb'},
+ {id: '5120', label: '5mb'},
+ {id: '0', label: 'No Limit'},
+ {id: 'default', label: 'Server Default'},
+];
+
+var vertoService = angular.module('vertoService', ['ngCookies']);
+
+vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', function($rootScope, $cookieStore, $location) {
+ var data = {
+ // Connection data.
+ instance: null,
+ connected: false,
+
+ // Call data.
+ call: null,
+ shareCall: null,
+ callState: null,
+ conf: null,
+ confLayouts: [],
+ confRole: null,
+ chattingWith: null,
+ liveArray: null,
+
+ // Settings data.
+ videoDevices: [],
+ audioDevices: [],
+ shareDevices: [],
+ extension: $cookieStore.get('verto_demo_ext'),
+ name: $cookieStore.get('verto_demo_name'),
+ email: $cookieStore.get('verto_demo_email'),
+ cid: $cookieStore.get('verto_demo_cid'),
+ textTo: $cookieStore.get('verto_demo_textto') || "1000",
+ login: $cookieStore.get('verto_demo_login') || "1008",
+ password: $cookieStore.get('verto_demo_passwd') || "1234",
+ hostname: $cookieStore.get('verto_demo_hostname') || window.location.hostname,
+ wsURL: $cookieStore.get('verto_demo_wsurl') || ("wss://" + window.location.hostname + ":8082"),
+ useVideo: $cookieStore.get('verto_demo_vid_checked') || true,
+ useCamera: $cookieStore.get('verto_demo_camera_checked') || true,
+ useStereo: $cookieStore.get('verto_demo_stereo_checked') || true,
+ useSTUN: $cookieStore.get('verto_demo_stun_checked') || true,
+ useDedenc: $cookieStore.get('verto_demo_dedenc_checked') || false,
+ mirrorInput: $cookieStore.get('verto_demo_mirror_input_checked') || false,
+ outgoingBandwidth: $cookieStore.get('verto_demo_outgoingBandwidth') || 'default',
+ incomingBandwidth: $cookieStore.get('verto_demo_incomingBandwidth') || 'default',
+ vidQual: $cookieStore.get('verto_demo_vqual') || 'qvga',
+ localVideo: $cookieStore.get('verto_demo_local_video_checked') || false,
+ selectedVideo: null,
+ selectedAudio: null,
+ selectedShare: null
+ };
+
+ function cleanShareCall(that) {
+ that.refreshVideoResolution();
+ data.shareCall = null;
+ data.callState = 'active';
+ that.refreshDevices();
+ }
+
+ function cleanCall() {
+ data.call = null;
+ data.callState = null;
+ data.conf = null;
+ data.confLayouts = [];
+ data.confRole = null;
+ data.chattingWith = null;
+
+ $rootScope.$emit('call.hangup', 'hangup');
+ }
+
+ function inCall() {
+ $rootScope.$emit('page.incall', 'call');
+ }
+
+ function callActive(last_state) {
+ $rootScope.$emit('call.active', last_state);
+ }
+
+ function calling() {
+ $rootScope.$emit('call.calling', 'calling');
+ }
+
+ function incomingCall(number) {
+ $rootScope.$emit('call.incoming', number);
+ }
+
+ function getVideoParams() {
+ return {
+ minWidth: videoResolution[data.vidQual].width,
+ minHeight: videoResolution[data.vidQual].height,
+ maxWidth: videoResolution[data.vidQual].width,
+ maxHeight: videoResolution[data.vidQual].height
+ };
+ }
+
+ function changeData(verto_data) {
+ $cookieStore.put('verto_demo_vid_checked', verto_data.data.useVideo);
+ $cookieStore.put('verto_demo_camera_checked', verto_data.data.useCamera);
+ $cookieStore.put('verto_demo_stereo_checked', verto_data.data.useStereo);
+ $cookieStore.put('verto_demo_stun_checked', verto_data.data.useSTUN);
+ $cookieStore.put('verto_demo_dedenc_checked', verto_data.data.useDedenc);
+ $cookieStore.put('verto_demo_mirror_input_checked', verto_data.data.mirrorInput);
+ $cookieStore.put('verto_demo_outgoingBandwidth', verto_data.data.outgoingBandwidth);
+ $cookieStore.put('verto_demo_incomingBandwidth', verto_data.data.incomingBandwidth);
+ $cookieStore.put('verto_demo_vqual', verto_data.data.vidQual);
+
+ data.useVideo = verto_data.data.useVideo;
+ data.useCamera = verto_data.data.useCamera;
+ data.useStereo = verto_data.data.useStereo;
+ data.useDedenc = verto_data.data.useDedenc;
+ data.useSTUN = verto_data.data.useSTUN;
+ data.vidQual = verto_data.data.vidQual;
+ data.mirrorInput = verto_data.data.mirrorInput;
+ data.outgoingBandwidth = verto_data.data.outgoingBandwidth;
+ data.incomingBandwidth = verto_data.data.incomingBandwidth;
+ }
+
+ var callState = {
+ muteMic: false,
+ muteVideo: false
+ };
+
+ return {
+ data: data,
+ callState: callState,
+ changeData: changeData,
+
+ // Options to compose the interface.
+ videoQuality: videoQuality,
+ videoResolution: videoResolution,
+ bandwidth: bandwidth,
+
+ refreshDevices: function(callback) {
+ console.debug('Attempting to refresh the devices.');
+
+
+ data.videoDevices = [{id: 'none', label: 'No camera'}];
+ data.shareDevices = [{id: 'screen', label: 'Screen'}];
+ data.audioDevices = [];
+
+ data.selectedVideo = 'none';
+ data.selectedShare = 'screen';
+ data.selectedAudio = null;
+
+ for (var i in jQuery.verto.videoDevices) {
+ var device = jQuery.verto.videoDevices[i];
+ if(!device.label) {
+ data.videoDevices.push({id: 'Camera ' + i, label: 'Camera ' + i});
+ } else {
+ data.videoDevices.push({id: device.id, label: device.label || device.id});
+ }
+
+ // Selecting the first source.
+ if (i == 0) {
+ data.selectedVideo = device.id;
+ }
+
+ if(!device.label) {
+ data.shareDevices.push({id: 'Share Device ' + i, label: 'Share Device ' + i});
+ continue;
+ }
+
+ data.shareDevices.push({id: device.id, label: device.label || device.id});
+ }
+
+ data.audioDevices = [];
+ for (var i in jQuery.verto.audioDevices) {
+ var device = jQuery.verto.audioDevices[i];
+ // Selecting the first source.
+ if (i == 0) {
+ data.selectedAudio = device.id;
+ }
+
+ if(!device.label) {
+ data.audioDevices.push({id: 'Microphone ' + i, label: 'Microphone ' + i});
+ continue;
+ }
+ data.audioDevices.push({id: device.id, label: device.label || device.id});
+ }
+
+ console.debug('Devices were refreshed.');
+
+ if (angular.isFunction(callback)) {
+ var devices = {
+ audio: data.audioDevices,
+ video: data.videoDevices,
+ share: data.shareDevices
+ };
+ callback(data.instance, devices);
+ }
+ },
+
+ /**
+ * Updates the video resolutions based on settings.
+ */
+ refreshVideoResolution: function() {
+ console.debug('Attempting to refresh video resolutions.');
+
+ if (data.instance) {
+ data.instance.videoParams(getVideoParams());
+ } else {
+ console.debug('There is no instance of verto.');
+ }
+ },
+
+ /**
+ * Connects to the verto server. Automatically calls `onWSLogin`
+ * callback set in the verto object.
+ *
+ * @param callback
+ */
+ connect: function(callback) {
+ console.debug('Attempting to connect to verto.');
+ var that = this;
+
+ function startConference(v, dialog, pvtData) {
+ $rootScope.$emit('call.video', 'video');
+ data.chattingWith = pvtData.chatID;
+ data.confRole = pvtData.role;
+
+ var conf = new $.verto.conf(v, {
+ dialog: dialog,
+ hasVid: data.useVideo,
+ laData: pvtData,
+ onBroadcast: function(v, conf, message) {
+ console.log('>>> conf.onBroadcast:', arguments);
+ if (message.action == 'response') {
+ // This is a response with the video layouts list.
+ if (message['conf-command'] == 'list-videoLayouts') {
+ data.confLayouts = message.responseData.sort();
+ } else {
+ $rootScope.$emit('conference.broadcast', message);
+ }
+ }
+ }
+ });
+
+ console.log('>>> conf.listVideoLayouts();');
+ conf.listVideoLayouts();
+ data.conf = conf;
+
+ data.liveArray = new $.verto.liveArray(
+ data.instance, pvtData.laChannel,
+ pvtData.laName,
+ {subParams: {callID: dialog ? dialog.callID : null}});
+
+ data.liveArray.onErr = function(obj, args) {
+ console.log('liveArray.onErr', obj, args);
+ };
+
+ data.liveArray.onChange = function(obj, args) {
+ console.log('liveArray.onChange', obj, args);
+
+ switch(args.action) {
+ case 'bootObj':
+ $rootScope.$emit('members.boot', args.data);
+ break;
+ case 'add':
+ var member = [args.key, args.data];
+ $rootScope.$emit('members.add', member);
+ break;
+ case 'del':
+ var uuid = args.key;
+ $rootScope.$emit('members.del', uuid);
+ break;
+ case 'clear':
+ $rootScope.$emit('members.clear');
+ break;
+ case 'modify':
+ var member = [args.key, args.data];
+ $rootScope.$emit('members.update', member);
+ break;
+ default:
+ console.log('NotImplemented', args.action);
+ }
+ };
+ }
+
+ function stopConference() {
+ console.log('stopConference()');
+ if (data.liveArray) {
+ console.log('Has data.liveArray.');
+ $rootScope.$emit('members.clear');
+ data.liveArray.destroy();
+ data.liveArray = null;
+ } else {
+ console.log('Doesn\'t found data.liveArray.');
+ }
+ }
+
+ var callbacks = {
+ onWSLogin: function(v, success) {
+ data.connected = success;
+ console.debug('Connected to verto server:', success);
+
+ if (angular.isFunction(callback)) {
+ callback(v, success);
+ }
+ },
+
+ onMessage: function(v, dialog, msg, params) {
+ console.debug('onMessage:', v, dialog, msg, params);
+
+ switch (msg) {
+ case $.verto.enum.message.pvtEvent:
+ if (params.pvtData) {
+ switch (params.pvtData.action) {
+ case "conference-liveArray-join":
+ console.log("conference-liveArray-join");
+ startConference(v, dialog, params.pvtData);
+ break;
+ case "conference-liveArray-part":
+ console.log("conference-liveArray-part");
+ stopConference();
+ break;
+ }
+ }
+ break;
+ case $.verto.enum.message.info:
+ var body = params.body;
+ var from = params.from_msg_name || params.from;
+ $rootScope.$emit('chat.newMessage', {from: from, body: body});
+ break;
+ default:
+ break;
+ }
+ },
+
+ onDialogState: function(d) {
+ if(!data.call) {
+ data.call = d;
+ if(d.state.name !== 'ringing') {
+ inCall();
+ }
+ }
+
+ console.debug('onDialogState:', d);
+ switch (d.state.name) {
+ case "ringing":
+ incomingCall(d.params.caller_id_number);
+ break;
+ case "trying":
+ console.debug('Calling:', d.cidString());
+ data.callState = 'trying';
+ break;
+ case "early":
+ console.debug('Talking to:', d.cidString());
+ data.callState = 'active';
+ calling();
+ break;
+ case "active":
+ console.debug('Talking to:', d.cidString());
+ data.callState = 'active';
+ callActive(d.lastState.name);
+ break;
+ case "hangup":
+ console.debug('Call ended with cause: ' + d.cause);
+ data.callState = 'hangup';
+ break;
+ case "destroy":
+ console.debug('Destroying: ' + d.cause);
+ if(d.params.screenShare) {
+ cleanShareCall(that);
+ } else {
+ cleanCall();
+ }
+ break;
+ }
+ },
+
+ onWSClose: function(v, success) {
+ console.debug('onWSClose:', success);
+ },
+
+ onEvent: function(v, e) {
+ console.debug('onEvent:', e);
+ }
+ };
+
+ var init = function() {
+
+ that.refreshVideoResolution();
+
+ data.instance = new jQuery.verto({
+ login: data.login + '@' + data.hostname,
+ passwd: data.password,
+ socketUrl: data.wsURL,
+ tag: "webcam",
+ ringFile: "sounds/bell_ring2.wav",
+ loginParams: {
+ foo: true,
+ bar: "yes"
+ },
+ videoParams: getVideoParams(),
+ iceServers: data.useSTUN
+ }, callbacks);
+
+ that.refreshDevices();
+ };
+
+ jQuery.verto.init({}, init);
+ },
+
+ /**
+ * Login the client.
+ *
+ * @param callback
+ */
+ login: function(callback) {
+ data.instance.loginData({
+ login: data.login + '@' + data.hostname,
+ passwd: data.password
+ });
+ data.instance.login();
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, true);
+ }
+ },
+
+ /**
+ * Disconnects from the verto server. Automatically calls `onWSClose`
+ * callback set in the verto object.
+ *
+ * @param callback
+ */
+ disconnect: function(callback) {
+ console.debug('Attempting to disconnect to verto.');
+
+ data.instance.logout();
+ data.connected = false;
+
+ console.debug('Disconnected from verto server.');
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, data.connected);
+ }
+ },
+
+ /**
+ * Make a call.
+ *
+ * @param callback
+ */
+ call: function(destination, callback) {
+ console.debug('Attempting to call destination ' + destination + '.');
+
+ this.refreshVideoResolution();
+
+ var call = data.instance.newCall({
+ destination_number: destination,
+ caller_id_name: data.name,
+ caller_id_number: data.login,
+ outgoingBandwidth: data.outgoingBandwidth,
+ incomingBandwidth: data.incomingBandwidth,
+ useVideo: data.useVideo,
+ useStereo: data.useStereo,
+ useCamera: data.selectedVideo,
+ useMic: data.selectedAudio,
+ dedEnc: data.useDedenc,
+ mirrorInput: data.mirrorInput
+ });
+
+ data.call = call;
+
+ data.mutedMic = false;
+ data.mutedVideo = false;
+
+ this.refreshDevices();
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, call);
+ }
+ },
+
+ screenshare: function(destination, callback) {
+ console.log('share screen video');
+
+ this.refreshVideoResolution();
+
+ var that = this;
+
+ getScreenId(function(error, sourceId, screen_constraints) {
+ var call = data.instance.newCall({
+ destination_number: destination + '-screen',
+ caller_id_name: data.name + ' (Screen)',
+ caller_id_number: data.login + ' (Screen)',
+ outgoingBandwidth: data.outgoingBandwidth,
+ incomingBandwidth: data.incomingBandwidth,
+ videoParams: screen_constraints.video.mandatory,
+ useVideo: data.useVideo,
+ screenShare: true,
+ dedEnc: data.useDedenc,
+ mirrorInput: data.mirrorInput
+ });
+
+ data.shareCall = call;
+
+ console.log('shareCall', data);
+
+ data.mutedMic = false;
+ data.mutedVideo = false;
+
+ that.refreshDevices();
+
+ });
+
+ },
+
+ screenshareHangup: function() {
+ if(!data.shareCall) {
+ console.debug('There is no call to hangup.');
+ return false;
+ }
+
+ console.log('shareCall End', data.shareCall);
+ data.shareCall.hangup();
+
+ console.debug('The screencall was hangup.');
+
+ },
+
+ /**
+ * Hangup the current call.
+ *
+ * @param callback
+ */
+ hangup: function(callback) {
+ console.debug('Attempting to hangup the current call.');
+
+ if (!data.call) {
+ console.debug('There is no call to hangup.');
+ return false;
+ }
+
+ data.call.hangup();
+
+ console.debug('The call was hangup.');
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, true);
+ }
+ },
+
+ /**
+ * Send a DTMF to the current call.
+ *
+ * @param {string|integer} number
+ * @param callback
+ */
+ dtmf: function(number, callback) {
+ console.debug('Attempting to send DTMF "' + number + '".');
+
+ if (!data.call) {
+ console.debug('There is no call to send DTMF.');
+ return false;
+ }
+
+ data.call.dtmf(number);
+ console.debug('The DTMF was sent for the call.');
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, true);
+ }
+ },
+
+ /**
+ * Mute the microphone for the current call.
+ *
+ * @param callback
+ */
+ muteMic: function(callback) {
+ console.debug('Attempting to mute mic for the current call.');
+
+ if (!data.call) {
+ console.debug('There is no call to mute.');
+ return false;
+ }
+
+ data.call.dtmf('0');
+ data.mutedMic = !data.mutedMic;
+ console.debug('The mic was muted for the call.');
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, true);
+ }
+ },
+
+ /**
+ * Mute the video for the current call.
+ *
+ * @param callback
+ */
+ muteVideo: function(callback) {
+ console.debug('Attempting to mute video for the current call.');
+
+ if (!data.call) {
+ console.debug('There is no call to mute.');
+ return false;
+ }
+
+ data.call.dtmf('*0');
+ data.mutedVideo = !data.mutedVideo;
+ console.debug('The video was muted for the call.');
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, true);
+ }
+ },
+
+ sendMessage: function(body, callback) {
+ data.call.message({
+ to: data.chattingWith,
+ body: body,
+ from_msg_name: data.name,
+ from_msg_number: data.cid
+ });
+
+ if (angular.isFunction(callback)) {
+ callback(data.instance, true);
+ }
+ }
+ };
+ }]);
diff --git a/html5/verto/verto_communicator/partials/angular-prompt.html b/html5/verto/verto_communicator/partials/angular-prompt.html
new file mode 100644
index 0000000000..d8a26b9bf4
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/angular-prompt.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+ {{options.message}}
+
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/browser_upgrade.html b/html5/verto/verto_communicator/partials/browser_upgrade.html
new file mode 100644
index 0000000000..fd2800b5b8
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/browser_upgrade.html
@@ -0,0 +1,27 @@
+
+
+
+
+
Sorry, your browser is not supported.
+
Use one of the following supported browsers.
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/chat.html b/html5/verto/verto_communicator/partials/chat.html
new file mode 100644
index 0000000000..928b690fbe
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/chat.html
@@ -0,0 +1,120 @@
+
diff --git a/html5/verto/verto_communicator/partials/contributors.html b/html5/verto/verto_communicator/partials/contributors.html
new file mode 100644
index 0000000000..45e129b20a
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/contributors.html
@@ -0,0 +1,23 @@
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/dialpad.html b/html5/verto/verto_communicator/partials/dialpad.html
new file mode 100644
index 0000000000..0f21203976
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/dialpad.html
@@ -0,0 +1,143 @@
+
+
+
+
+
+ Call History
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/dialpad_widget.html b/html5/verto/verto_communicator/partials/dialpad_widget.html
new file mode 100644
index 0000000000..583b023c74
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/dialpad_widget.html
@@ -0,0 +1,111 @@
+
diff --git a/html5/verto/verto_communicator/partials/incall.html b/html5/verto/verto_communicator/partials/incall.html
new file mode 100644
index 0000000000..702c943994
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/incall.html
@@ -0,0 +1,5 @@
+
diff --git a/html5/verto/verto_communicator/partials/login.html b/html5/verto/verto_communicator/partials/login.html
new file mode 100644
index 0000000000..47cfae4791
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/login.html
@@ -0,0 +1,56 @@
+
+
+
+
+
Login
+
+
+
Verify the fields bellow and try again.
+
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/menu.html b/html5/verto/verto_communicator/partials/menu.html
new file mode 100644
index 0000000000..ea846ddc1e
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/menu.html
@@ -0,0 +1,69 @@
+
diff --git a/html5/verto/verto_communicator/partials/modal_logininfo.html b/html5/verto/verto_communicator/partials/modal_logininfo.html
new file mode 100644
index 0000000000..e41eef4de1
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/modal_logininfo.html
@@ -0,0 +1,31 @@
+
+
+
diff --git a/html5/verto/verto_communicator/partials/modal_settings.html b/html5/verto/verto_communicator/partials/modal_settings.html
new file mode 100644
index 0000000000..5c07e74679
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/modal_settings.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/phone_call.html b/html5/verto/verto_communicator/partials/phone_call.html
new file mode 100644
index 0000000000..966d5398cc
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/phone_call.html
@@ -0,0 +1,58 @@
+
+
+
+
+
![]()
+
+
+
{{ storage.data.called_number }}
+
+ {{hhours}}:{{mminutes}}:{{sseconds}}
+
+
+
Calling
+
+
+
+
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/partials/video_call.html b/html5/verto/verto_communicator/partials/video_call.html
new file mode 100644
index 0000000000..314ad5a709
--- /dev/null
+++ b/html5/verto/verto_communicator/partials/video_call.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{hhours}}:{{mminutes}}:{{sseconds}}
+
+
+
+
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/sounds/bell_ring2.mp3 b/html5/verto/verto_communicator/sounds/bell_ring2.mp3
new file mode 100644
index 0000000000..d0a423b609
Binary files /dev/null and b/html5/verto/verto_communicator/sounds/bell_ring2.mp3 differ
diff --git a/html5/verto/verto_communicator/sounds/bell_ring2.wav b/html5/verto/verto_communicator/sounds/bell_ring2.wav
new file mode 100644
index 0000000000..e5501435f9
Binary files /dev/null and b/html5/verto/verto_communicator/sounds/bell_ring2.wav differ