Merge remote-tracking branch 'origin/master'

This commit is contained in:
damencho 2015-10-06 11:20:11 -05:00
commit a49505f25d
40 changed files with 207 additions and 26337 deletions

View File

@ -3,7 +3,7 @@ BROWSERIFY = ./node_modules/.bin/browserify
UGLIFYJS = ./node_modules/.bin/uglifyjs UGLIFYJS = ./node_modules/.bin/uglifyjs
EXORCIST = ./node_modules/.bin/exorcist EXORCIST = ./node_modules/.bin/exorcist
DEPLOY_DIR = libs DEPLOY_DIR = libs
BROWSERIFY_FLAGS = -d -x jquery BROWSERIFY_FLAGS = -d
OUTPUT_DIR = . OUTPUT_DIR = .
all: compile uglify deploy clean all: compile uglify deploy clean

11
app.js
View File

@ -1,6 +1,17 @@
/* jshint -W117 */ /* jshint -W117 */
/* application specific logic */ /* application specific logic */
require("jquery");
require("jquery-ui");
require("strophe");
require("strophe-disco");
require("strophe-caps");
require("tooltip");
require("popover");
window.toastr = require("toastr");
require("jQuery-Impromptu");
require("autosize");
var APP = var APP =
{ {
init: function () { init: function () {

View File

@ -10,15 +10,15 @@
<meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/> <meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
<meta itemprop="image" content="/images/jitsilogo.png"/> <meta itemprop="image" content="/images/jitsilogo.png"/>
<script src="https://api.callstats.io/static/callstats.min.js"></script> <script src="https://api.callstats.io/static/callstats.min.js"></script>
<script src="libs/jquery-2.1.1.min.js"></script> <!--<script src="libs/jquery-2.1.1.min.js"></script>-->
<script src="config.js?v=14"></script><!-- adapt to your needs, i.e. set hosts and bosh path --> <script src="config.js?v=14"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="libs/strophe/strophe.min.js?v=2"></script> <!--<script src="libs/strophe/strophe.min.js?v=2"></script>-->
<script src="libs/strophe/strophe.disco.min.js?v=1"></script> <!--<script src="libs/strophe/strophe.disco.min.js?v=1"></script>-->
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script> <!--<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>-->
<script src="libs/jquery-ui.min.js"></script> <!--<script src="libs/jquery-ui.min.js"></script>-->
<script src="libs/tooltip.min.js?v=1"></script><!-- bootstrap tooltip lib --> <!--<script src="libs/tooltip.min.js?v=1"></script>&lt;!&ndash; bootstrap tooltip lib &ndash;&gt;-->
<script src="libs/popover.min.js?v=1"></script><!-- bootstrap tooltip lib --> <!--<script src="libs/popover.min.js?v=1"></script>&lt;!&ndash; bootstrap tooltip lib &ndash;&gt;-->
<script src="libs/toastr.min.js?v=1"></script><!-- notifications lib --> <!--<script src="libs/toastr.min.js?v=1"></script>&lt;!&ndash; notifications lib &ndash;&gt;-->
<script src="interface_config.js?v=6"></script> <script src="interface_config.js?v=6"></script>
<script src="libs/app.bundle.min.js?v=138"></script> <script src="libs/app.bundle.min.js?v=138"></script>
<script src="analytics.js?v=1"></script><!-- google analytics plugin --> <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
@ -42,8 +42,8 @@
Link used for inline installation of chrome desktop streaming extension, Link used for inline installation of chrome desktop streaming extension,
is updated automatically from the code with the value defined in config.js --> is updated automatically from the code with the value defined in config.js -->
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/diibjkoicjeejcmhdnailmkgecihlobk"> <link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/diibjkoicjeejcmhdnailmkgecihlobk">
<script src="libs/jquery-impromptu.min.js?v=2"></script> <!--<script src="libs/jquery-impromptu.min.js?v=2"></script>-->
<script src="libs/jquery.autosize.min.js"></script> <!--<script src="libs/jquery.autosize.min.js"></script>-->
<!--#include virtual="plugin.head.html" --> <!--#include virtual="plugin.head.html" -->
</head> </head>
<body> <body>

9190
libs/jquery-2.1.1.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,863 +0,0 @@
/*! jQuery-Impromptu - v6.0.0 - 2014-12-27
* http://trentrichardson.com/Impromptu
* Copyright (c) 2014 Trent Richardson; Licensed MIT */
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(root.jQuery);
}
}(this, function($) {
'use strict';
// ########################################################################
// Base object
// ########################################################################
/**
* Imp - Impromptu object - passing no params will not open, only return the instance
* @param message String/Object - String of html or Object of states
* @param options Object - Options to set the prompt
* @return Imp - the instance of this Impromptu object
*/
var Imp = function(message, options){
var t = this;
t.id = Imp.count++;
Imp.lifo.push(t);
if(message){
t.open(message, options);
}
return t;
};
// ########################################################################
// static properties and methods
// ########################################################################
/**
* defaults - the default options
*/
Imp.defaults = {
prefix:'jqi',
classes: {
box: '',
fade: '',
prompt: '',
form: '',
close: '',
title: '',
message: '',
buttons: '',
button: '',
defaultButton: ''
},
title: '',
closeText: '&times;',
buttons: {
Ok: true
},
loaded: function(e){},
submit: function(e,v,m,f){},
close: function(e,v,m,f){},
statechanging: function(e, from, to){},
statechanged: function(e, to){},
opacity: 0.6,
zIndex: 999,
overlayspeed: 'slow',
promptspeed: 'fast',
show: 'fadeIn',
hide: 'fadeOut',
focus: 0,
defaultButton: 0,
useiframe: false,
top: '15%',
position: {
container: null,
x: null,
y: null,
arrow: null,
width: null
},
persistent: true,
timeout: 0,
states: {},
state: {
name: null,
title: '',
html: '',
buttons: {
Ok: true
},
focus: 0,
defaultButton: 0,
position: {
container: null,
x: null,
y: null,
arrow: null,
width: null
},
submit: function(e,v,m,f){
return true;
}
}
};
/**
* setDefaults - Sets the default options
* @param o Object - Options to set as defaults
* @return void
*/
Imp.setDefaults = function(o) {
Imp.defaults = $.extend({}, Imp.defaults, o);
};
/**
* setStateDefaults - Sets the default options for a state
* @param o Object - Options to set as defaults
* @return void
*/
Imp.setStateDefaults = function(o) {
Imp.defaults.state = $.extend({}, Imp.defaults.state, o);
};
/**
* @var Int - A counter used to provide a unique ID for new prompts
*/
Imp.count = 0;
/**
* @var Array - An array of Impromptu intances in a LIFO queue (last in first out)
*/
Imp.lifo = [];
/**
* getLast - get the last element from the queue (doesn't pop, just returns)
* @return Imp - the instance of this Impromptu object or false if queue is empty
*/
Imp.getLast = function(){
var l = Imp.lifo.length;
return (l > 0)? Imp.lifo[l-1] : false;
};
/**
* removeFromStack - remove an element from the lifo stack by its id
* @param id int - id of the instance to remove
* @return api - The api of the element removed from the stack or void
*/
Imp.removeFromStack = function(id){
for(var i=Imp.lifo.length-1; i>=0; i--){
if(Imp.lifo[i].id === id){
return Imp.lifo.splice(i,1)[0];
}
}
};
// ########################################################################
// extend our object instance properties and methods
// ########################################################################
Imp.prototype = {
/**
* @var Int - A unique id, simply an autoincremented number
*/
id: null,
/**
* open - Opens the prompt
* @param message String/Object - String of html or Object of states
* @param options Object - Options to set the prompt
* @return Imp - the instance of this Impromptu object
*/
open: function(message, options) {
var t = this;
t.options = $.extend({},Imp.defaults,options);
// Be sure any previous timeouts are destroyed
if(t.timeout){
clearTimeout(t.timeout);
}
t.timeout = false;
var opts = t.options,
$body = $(document.body),
$window = $(window);
//build the box and fade
var msgbox = '<div class="'+ opts.prefix +'box '+ opts.classes.box +'">';
if(opts.useiframe && ($('object, applet').length > 0)) {
msgbox += '<iframe src="javascript:false;" style="display:block;position:absolute;z-index:-1;" class="'+ opts.prefix +'fade '+ opts.classes.fade +'"></iframe>';
} else {
msgbox += '<div class="'+ opts.prefix +'fade '+ opts.classes.fade +'"></div>';
}
msgbox += '<div class="'+ opts.prefix +' '+ opts.classes.prompt +'">'+
'<form action="javascript:false;" onsubmit="return false;" class="'+ opts.prefix +'form '+ opts.classes.form +'">'+
'<div class="'+ opts.prefix +'close '+ opts.classes.close +'">'+ opts.closeText +'</div>'+
'<div class="'+ opts.prefix +'states"></div>'+
'</form>'+
'</div>'+
'</div>';
t.jqib = $(msgbox).appendTo($body);
t.jqi = t.jqib.children('.'+ opts.prefix);
t.jqif = t.jqib.children('.'+ opts.prefix +'fade');
//if a string was passed, convert to a single state
if(message.constructor === String){
message = {
state0: {
title: opts.title,
html: message,
buttons: opts.buttons,
position: opts.position,
focus: opts.focus,
defaultButton: opts.defaultButton,
submit: opts.submit
}
};
}
//build the states
t.options.states = {};
var k,v;
for(k in message){
v = $.extend({},Imp.defaults.state,{name:k},message[k]);
t.addState(v.name, v);
if(t.currentStateName === ''){
t.currentStateName = v.name;
}
}
//Events
t.jqi.on('click', '.'+ opts.prefix +'buttons button', function(e){
var $t = $(this),
$state = $t.parents('.'+ opts.prefix +'state'),
stateobj = t.options.states[$state.data('jqi-name')],
msg = $state.children('.'+ opts.prefix +'message'),
clicked = stateobj.buttons[$t.text()] || stateobj.buttons[$t.html()],
forminputs = {};
// if for some reason we couldn't get the value
if(clicked === undefined){
for(var i in stateobj.buttons){
if(stateobj.buttons[i].title === $t.text() || stateobj.buttons[i].title === $t.html()){
clicked = stateobj.buttons[i].value;
}
}
}
//collect all form element values from all states.
$.each(t.jqi.children('form').serializeArray(),function(i,obj){
if (forminputs[obj.name] === undefined) {
forminputs[obj.name] = obj.value;
} else if (typeof forminputs[obj.name] === Array || typeof forminputs[obj.name] === 'object') {
forminputs[obj.name].push(obj.value);
} else {
forminputs[obj.name] = [forminputs[obj.name],obj.value];
}
});
// trigger an event
var promptsubmite = new $.Event('impromptu:submit');
promptsubmite.stateName = stateobj.name;
promptsubmite.state = $state;
$state.trigger(promptsubmite, [clicked, msg, forminputs]);
if(!promptsubmite.isDefaultPrevented()){
t.close(true, clicked,msg,forminputs);
}
});
// if the fade is clicked blink the prompt
var fadeClicked = function(){
if(opts.persistent){
var offset = (opts.top.toString().indexOf('%') >= 0? ($window.height()*(parseInt(opts.top,10)/100)) : parseInt(opts.top,10)),
top = parseInt(t.jqi.css('top').replace('px',''),10) - offset;
//$window.scrollTop(top);
$('html,body').animate({ scrollTop: top }, 'fast', function(){
var i = 0;
t.jqib.addClass(opts.prefix +'warning');
var intervalid = setInterval(function(){
t.jqib.toggleClass(opts.prefix +'warning');
if(i++ > 1){
clearInterval(intervalid);
t.jqib.removeClass(opts.prefix +'warning');
}
}, 100);
});
}
else {
t.close(true);
}
};
// listen for esc or tab keys
var keyDownEventHandler = function(e){
var key = (window.event) ? event.keyCode : e.keyCode;
//escape key closes
if(key === 27) {
fadeClicked();
}
//enter key pressed trigger the default button if its not on it, ignore if it is a textarea
if(key === 13){
var $defBtn = t.getCurrentState().find('.'+ opts.prefix +'defaultbutton');
var $tgt = $(e.target);
if($tgt.is('textarea,.'+opts.prefix+'button') === false && $defBtn.length > 0){
e.preventDefault();
$defBtn.click();
}
}
//constrain tabs, tabs should iterate through the state and not leave
if (key === 9){
var $inputels = $('input,select,textarea,button',t.getCurrentState());
var fwd = !e.shiftKey && e.target === $inputels[$inputels.length-1];
var back = e.shiftKey && e.target === $inputels[0];
if (fwd || back) {
setTimeout(function(){
if (!$inputels){
return;
}
var el = $inputels[back===true ? $inputels.length-1 : 0];
if (el){
el.focus();
}
},10);
return false;
}
}
};
t.position();
t.style();
// store copy of the window resize function for interal use only
t._windowResize = function(e){
t.position(e);
};
$window.resize({ animate: false }, t._windowResize);
t.jqif.click(fadeClicked);
t.jqi.find('.'+ opts.prefix +'close').click(function(){ t.close(); });
t.jqib.on("keydown",keyDownEventHandler)
.on('impromptu:loaded', opts.loaded)
.on('impromptu:close', opts.close)
.on('impromptu:statechanging', opts.statechanging)
.on('impromptu:statechanged', opts.statechanged);
// Show it
t.jqif[opts.show](opts.overlayspeed);
t.jqi[opts.show](opts.promptspeed, function(){
var $firstState = t.jqi.find('.'+ opts.prefix +'states .'+ opts.prefix +'state').eq(0);
t.goToState($firstState.data('jqi-name'));
t.jqib.trigger('impromptu:loaded');
});
// Timeout
if(opts.timeout > 0){
t.timeout = setTimeout(function(){ t.close(true); },opts.timeout);
}
return t;
},
/**
* close - Closes the prompt
* @param callback Function - called when the transition is complete
* @param clicked String - value of the button clicked (only used internally)
* @param msg jQuery - The state message body (only used internally)
* @param forvals Object - key/value pairs of all form field names and values (only used internally)
* @return Imp - the instance of this Impromptu object
*/
close: function(callCallback, clicked, msg, formvals){
var t = this;
Imp.removeFromStack(t.id);
if(t.timeout){
clearTimeout(t.timeout);
t.timeout = false;
}
if(t.jqib){
t.jqib[t.options.hide]('fast',function(){
t.jqib.trigger('impromptu:close', [clicked,msg,formvals]);
t.jqib.remove();
$(window).off('resize', t._windowResize);
if(typeof callCallback === 'function'){
callCallback();
}
});
}
t.currentStateName = "";
return t;
},
/**
* addState - Injects a state into the prompt
* @param statename String - Name of the state
* @param stateobj Object - options for the state
* @param afterState String - selector of the state to insert after
* @return jQuery - the newly created state
*/
addState: function(statename, stateobj, afterState) {
var t = this,
state = '',
$state = null,
arrow = '',
title = '',
opts = t.options,
$jqistates = $('.'+ opts.prefix +'states'),
buttons = [],
showHtml,defbtn,k,v,l,i=0;
stateobj = $.extend({},Imp.defaults.state, {name:statename}, stateobj);
if(stateobj.position.arrow !== null){
arrow = '<div class="'+ opts.prefix + 'arrow '+ opts.prefix + 'arrow'+ stateobj.position.arrow +'"></div>';
}
if(stateobj.title && stateobj.title !== ''){
title = '<div class="lead '+ opts.prefix + 'title '+ opts.classes.title +'">'+ stateobj.title +'</div>';
}
showHtml = stateobj.html;
if (typeof stateobj.html === 'function') {
showHtml = 'Error: html function must return text';
}
state += '<div class="'+ opts.prefix + 'state" data-jqi-name="'+ statename +'" style="display:none;">'+
arrow + title +
'<div class="'+ opts.prefix +'message '+ opts.classes.message +'">' + showHtml +'</div>'+
'<div class="'+ opts.prefix +'buttons '+ opts.classes.buttons +'"'+ ($.isEmptyObject(stateobj.buttons)? 'style="display:none;"':'') +'>';
// state buttons may be in object or array, lets convert objects to arrays
if($.isArray(stateobj.buttons)){
buttons = stateobj.buttons;
}
else if($.isPlainObject(stateobj.buttons)){
for(k in stateobj.buttons){
if(stateobj.buttons.hasOwnProperty(k)){
buttons.push({ title: k, value: stateobj.buttons[k] });
}
}
}
// iterate over each button and create them
for(i=0, l=buttons.length; i<l; i++){
v = buttons[i],
defbtn = stateobj.focus === i || (isNaN(stateobj.focus) && stateobj.defaultButton === i) ? (opts.prefix + 'defaultbutton ' + opts.classes.defaultButton) : '';
state += '<button class="'+ opts.classes.button +' '+ opts.prefix + 'button '+ defbtn;
if(typeof v.classes !== "undefined"){
state += ' '+ ($.isArray(v.classes)? v.classes.join(' ') : v.classes) + ' ';
}
state += '" name="' + opts.prefix + '_' + statename + '_button' + v.title.replace(/[^a-z0-9]+/gi,'') + '" value="' + v.value + '">' + v.title + '</button>';
}
state += '</div></div>';
$state = $(state);
$state.on('impromptu:submit', stateobj.submit);
if(afterState !== undefined){
$jqistates.find('[data-jqi-name="'+afterState+'"]').after($state);
}
else{
$jqistates.append($state);
}
t.options.states[statename] = stateobj;
return $state;
},
/**
* removeState - Removes a state from the prompt
* @param state String - Name of the state
* @param newState String - Name of the state to transition to
* @return Boolean - returns true on success, false on failure
*/
removeState: function(state, newState) {
var t = this,
$state = t.getState(state),
rm = function(){ $state.remove(); };
if($state.length === 0){
return false;
}
// transition away from it before deleting
if($state.css('display') !== 'none'){
if(newState !== undefined && t.getState(newState).length > 0){
t.goToState(newState, false, rm);
}
else if($state.next().length > 0){
t.nextState(rm);
}
else if($state.prev().length > 0){
t.prevState(rm);
}
else{
t.close();
}
}
else{
$state.slideUp('slow', rm);
}
return true;
},
/**
* getApi - Get the api, so you can extract it from $.prompt stack
* @return jQuery - the prompt
*/
getApi: function() {
return this;
},
/**
* getBox - Get the box containing fade and prompt
* @return jQuery - the prompt
*/
getBox: function() {
return this.jqib;
},
/**
* getPrompt - Get the prompt
* @return jQuery - the prompt
*/
getPrompt: function() {
return this.jqi;
},
/**
* getState - Get the state by its name
* @param statename String - Name of the state
* @return jQuery - the state
*/
getState: function(statename) {
return this.jqi.find('[data-jqi-name="'+ statename +'"]');
},
/**
* getCurrentState - Get the current visible state
* @return jQuery - the current visible state
*/
getCurrentState: function() {
return this.getState(this.getCurrentStateName());
},
/**
* getCurrentStateName - Get the name of the current visible state/substate
* @return String - the current visible state's name
*/
getCurrentStateName: function() {
return this.currentStateName;
},
/**
* position - Repositions the prompt (Used internally)
* @return void
*/
position: function(e){
var t = this,
restoreFx = $.fx.off,
$state = t.getCurrentState(),
stateObj = t.options.states[$state.data('jqi-name')],
pos = stateObj? stateObj.position : undefined,
$window = $(window),
bodyHeight = document.body.scrollHeight, //$(document.body).outerHeight(true),
windowHeight = $(window).height(),
documentHeight = $(document).height(),
height = bodyHeight > windowHeight ? bodyHeight : windowHeight,
top = parseInt($window.scrollTop(),10) + (t.options.top.toString().indexOf('%') >= 0?
(windowHeight*(parseInt(t.options.top,10)/100)) : parseInt(t.options.top,10));
// when resizing the window turn off animation
if(e !== undefined && e.data.animate === false){
$.fx.off = true;
}
t.jqib.css({
position: "absolute",
height: height,
width: "100%",
top: 0,
left: 0,
right: 0,
bottom: 0
});
t.jqif.css({
position: "fixed",
height: height,
width: "100%",
top: 0,
left: 0,
right: 0,
bottom: 0
});
// tour positioning
if(pos && pos.container){
var offset = $(pos.container).offset();
if($.isPlainObject(offset) && offset.top !== undefined){
t.jqi.css({
position: "absolute"
});
t.jqi.animate({
top: offset.top + pos.y,
left: offset.left + pos.x,
marginLeft: 0,
width: (pos.width !== undefined)? pos.width : null
});
top = (offset.top + pos.y) - (t.options.top.toString().indexOf('%') >= 0? (windowHeight*(parseInt(t.options.top,10)/100)) : parseInt(t.options.top,10));
$('html,body').animate({ scrollTop: top }, 'slow', 'swing', function(){});
}
}
// custom state width animation
else if(pos && pos.width){
t.jqi.css({
position: "absolute",
left: '50%'
});
t.jqi.animate({
top: pos.y || top,
left: pos.x || '50%',
marginLeft: ((pos.width/2)*-1),
width: pos.width
});
}
// standard prompt positioning
else{
t.jqi.css({
position: "absolute",
top: top,
left: '50%',//$window.width()/2,
marginLeft: ((t.jqi.outerWidth(false)/2)*-1)
});
}
// restore fx settings
if(e !== undefined && e.data.animate === false){
$.fx.off = restoreFx;
}
},
/**
* style - Restyles the prompt (Used internally)
* @return void
*/
style: function(){
var t = this;
t.jqif.css({
zIndex: t.options.zIndex,
display: "none",
opacity: t.options.opacity
});
t.jqi.css({
zIndex: t.options.zIndex+1,
display: "none"
});
t.jqib.css({
zIndex: t.options.zIndex
});
},
/**
* goToState - Goto the specified state
* @param state String - name of the state to transition to
* @param subState Boolean - true to be a sub state within the currently open state
* @param callback Function - called when the transition is complete
* @return jQuery - the newly active state
*/
goToState: function(state, subState, callback) {
var t = this,
$jqi = t.jqi,
jqiopts = t.options,
$state = t.getState(state),
stateobj = jqiopts.states[$state.data('jqi-name')],
promptstatechanginge = new $.Event('impromptu:statechanging'),
opts = t.options;
if(stateobj !== undefined){
if (typeof stateobj.html === 'function') {
var contentLaterFunc = stateobj.html;
$state.find('.' + opts.prefix +'message ').html(contentLaterFunc());
}
// subState can be ommitted
if(typeof subState === 'function'){
callback = subState;
subState = false;
}
t.jqib.trigger(promptstatechanginge, [t.getCurrentStateName(), state]);
if(!promptstatechanginge.isDefaultPrevented() && $state.length > 0){
t.jqi.find('.'+ opts.prefix +'parentstate').removeClass(opts.prefix +'parentstate');
if(subState){ // hide any open substates
// get rid of any substates
t.jqi.find('.'+ opts.prefix +'substate').not($state)
.slideUp(jqiopts.promptspeed)
.removeClass('.'+ opts.prefix +'substate')
.find('.'+ opts.prefix +'arrow').hide();
// add parent state class so it can be visible, but blocked
t.jqi.find('.'+ opts.prefix +'state:visible').addClass(opts.prefix +'parentstate');
// add substate class so we know it will be smaller
$state.addClass(opts.prefix +'substate');
}
else{ // hide any open states
t.jqi.find('.'+ opts.prefix +'state').not($state)
.slideUp(jqiopts.promptspeed)
.find('.'+ opts.prefix +'arrow').hide();
}
t.currentStateName = stateobj.name;
$state.slideDown(jqiopts.promptspeed,function(){
var $t = $(this);
// if focus is a selector, find it, else its button index
if(typeof(stateobj.focus) === 'string'){
$t.find(stateobj.focus).eq(0).focus();
}
else{
$t.find('.'+ opts.prefix +'defaultbutton').focus();
}
$t.find('.'+ opts.prefix +'arrow').show(jqiopts.promptspeed);
if (typeof callback === 'function'){
t.jqib.on('impromptu:statechanged', callback);
}
t.jqib.trigger('impromptu:statechanged', [state]);
if (typeof callback === 'function'){
t.jqib.off('impromptu:statechanged', callback);
}
});
if(!subState){
t.position();
}
} // end isDefaultPrevented()
}// end stateobj !== undefined
return $state;
},
/**
* nextState - Transition to the next state
* @param callback Function - called when the transition is complete
* @return jQuery - the newly active state
*/
nextState: function(callback) {
var t = this,
$next = t.getCurrentState().next();
if($next.length > 0){
t.goToState( $next.data('jqi-name'), callback );
}
return $next;
},
/**
* prevState - Transition to the previous state
* @param callback Function - called when the transition is complete
* @return jQuery - the newly active state
*/
prevState: function(callback) {
var t = this,
$prev = t.getCurrentState().prev();
if($prev.length > 0){
t.goToState( $prev.data('jqi-name'), callback );
}
return $prev;
}
};
// ########################################################################
// $.prompt will manage a queue of Impromptu instances
// ########################################################################
/**
* $.prompt create a new Impromptu instance and push it on the stack of instances
* @param message String/Object - String of html or Object of states
* @param options Object - Options to set the prompt
* @return jQuery - the jQuery object of the prompt within the modal
*/
$.prompt = function(message, options){
var api = new Imp(message, options);
return api.jqi;
};
/**
* Copy over static methods
*/
$.each(Imp, function(k,v){
$.prompt[k] = v;
});
/**
* Create a proxy for accessing all instance methods. The close method pops from queue.
*/
$.each(Imp.prototype, function(k,v){
$.prompt[k] = function(){
var api = Imp.getLast(); // always use the last instance on the stack
if(api && typeof api[k] === "function"){
return api[k].apply(api, arguments);
}
};
});
// ########################################################################
// jQuery Plugin and public access
// ########################################################################
/**
* Enable using $('.selector').prompt({});
* This will grab the html within the prompt as the prompt message
*/
$.fn.prompt = function(options){
if(options === undefined){
options = {};
}
if(options.withDataAndEvents === undefined){
options.withDataAndEvents = false;
}
$.prompt($(this).clone(options.withDataAndEvents).html(),options);
};
/**
* Export it as Impromptu and $.prompt
* Can be used from here forth as new Impromptu(states, opts)
*/
window.Impromptu = Imp;
}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

15008
libs/jquery-ui.js vendored

File diff suppressed because it is too large Load Diff

10
libs/jquery-ui.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,250 +0,0 @@
/*!
Autosize v1.18.1 - 2013-11-05
Automatically adjust textarea height based on user input.
(c) 2013 Jack Moore - http://www.jacklmoore.com/autosize
license: http://www.opensource.org/licenses/mit-license.php
*/
(function ($) {
var
defaults = {
className: 'autosizejs',
append: '',
callback: false,
resizeDelay: 10
},
// border:0 is unnecessary, but avoids a bug in Firefox on OSX
copy = '<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; padding: 0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>',
// line-height is conditionally included because IE7/IE8/old Opera do not return the correct value.
typographyStyles = [
'fontFamily',
'fontSize',
'fontWeight',
'fontStyle',
'letterSpacing',
'textTransform',
'wordSpacing',
'textIndent'
],
// to keep track which textarea is being mirrored when adjust() is called.
mirrored,
// the mirror element, which is used to calculate what size the mirrored element should be.
mirror = $(copy).data('autosize', true)[0];
// test that line-height can be accurately copied.
mirror.style.lineHeight = '99px';
if ($(mirror).css('lineHeight') === '99px') {
typographyStyles.push('lineHeight');
}
mirror.style.lineHeight = '';
$.fn.autosize = function (options) {
if (!this.length) {
return this;
}
options = $.extend({}, defaults, options || {});
if (mirror.parentNode !== document.body) {
$(document.body).append(mirror);
}
return this.each(function () {
var
ta = this,
$ta = $(ta),
maxHeight,
minHeight,
boxOffset = 0,
callback = $.isFunction(options.callback),
originalStyles = {
height: ta.style.height,
overflow: ta.style.overflow,
overflowY: ta.style.overflowY,
wordWrap: ta.style.wordWrap,
resize: ta.style.resize
},
timeout,
width = $ta.width();
if ($ta.data('autosize')) {
// exit if autosize has already been applied, or if the textarea is the mirror element.
return;
}
$ta.data('autosize', true);
if ($ta.css('box-sizing') === 'border-box' || $ta.css('-moz-box-sizing') === 'border-box' || $ta.css('-webkit-box-sizing') === 'border-box'){
boxOffset = $ta.outerHeight() - $ta.height();
}
// IE8 and lower return 'auto', which parses to NaN, if no min-height is set.
minHeight = Math.max(parseInt($ta.css('minHeight'), 10) - boxOffset || 0, $ta.height());
$ta.css({
overflow: 'hidden',
overflowY: 'hidden',
wordWrap: 'break-word', // horizontal overflow is hidden, so break-word is necessary for handling words longer than the textarea width
resize: ($ta.css('resize') === 'none' || $ta.css('resize') === 'vertical') ? 'none' : 'horizontal'
});
// The mirror width must exactly match the textarea width, so using getBoundingClientRect because it doesn't round the sub-pixel value.
function setWidth() {
var style, width;
if ('getComputedStyle' in window) {
style = window.getComputedStyle(ta, null);
width = ta.getBoundingClientRect().width;
$.each(['paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'], function(i,val){
width -= parseInt(style[val],10);
});
mirror.style.width = width + 'px';
}
else {
// window.getComputedStyle, getBoundingClientRect returning a width are unsupported and unneeded in IE8 and lower.
mirror.style.width = Math.max($ta.width(), 0) + 'px';
}
}
function initMirror() {
var styles = {};
mirrored = ta;
mirror.className = options.className;
maxHeight = parseInt($ta.css('maxHeight'), 10);
// mirror is a duplicate textarea located off-screen that
// is automatically updated to contain the same text as the
// original textarea. mirror always has a height of 0.
// This gives a cross-browser supported way getting the actual
// height of the text, through the scrollTop property.
$.each(typographyStyles, function(i,val){
styles[val] = $ta.css(val);
});
$(mirror).css(styles);
setWidth();
// Chrome-specific fix:
// When the textarea y-overflow is hidden, Chrome doesn't reflow the text to account for the space
// made available by removing the scrollbar. This workaround triggers the reflow for Chrome.
if (window.chrome) {
var width = ta.style.width;
ta.style.width = '0px';
var ignore = ta.offsetWidth;
ta.style.width = width;
}
}
// Using mainly bare JS in this function because it is going
// to fire very often while typing, and needs to very efficient.
function adjust() {
var height, original;
if (mirrored !== ta) {
initMirror();
} else {
setWidth();
}
mirror.value = ta.value + options.append;
mirror.style.overflowY = ta.style.overflowY;
original = parseInt(ta.style.height,10);
// Setting scrollTop to zero is needed in IE8 and lower for the next step to be accurately applied
mirror.scrollTop = 0;
mirror.scrollTop = 9e4;
// Using scrollTop rather than scrollHeight because scrollHeight is non-standard and includes padding.
height = mirror.scrollTop;
if (maxHeight && height > maxHeight) {
ta.style.overflowY = 'scroll';
height = maxHeight;
} else {
ta.style.overflowY = 'hidden';
if (height < minHeight) {
height = minHeight;
}
}
height += boxOffset;
if (original !== height) {
ta.style.height = height + 'px';
if (callback) {
options.callback.call(ta,ta);
}
}
}
function resize () {
clearTimeout(timeout);
timeout = setTimeout(function(){
var newWidth = $ta.width();
if (newWidth !== width) {
width = newWidth;
adjust();
}
}, parseInt(options.resizeDelay,10));
}
if ('onpropertychange' in ta) {
if ('oninput' in ta) {
// Detects IE9. IE9 does not fire onpropertychange or oninput for deletions,
// so binding to onkeyup to catch most of those occasions. There is no way that I
// know of to detect something like 'cut' in IE9.
$ta.on('input.autosize keyup.autosize', adjust);
} else {
// IE7 / IE8
$ta.on('propertychange.autosize', function(){
if(event.propertyName === 'value'){
adjust();
}
});
}
} else {
// Modern Browsers
$ta.on('input.autosize', adjust);
}
// Set options.resizeDelay to false if using fixed-width textarea elements.
// Uses a timeout and width check to reduce the amount of times adjust needs to be called after window resize.
if (options.resizeDelay !== false) {
$(window).on('resize.autosize', resize);
}
// Event for manual triggering if needed.
// Should only be needed when the value of the textarea is changed through JavaScript rather than user input.
$ta.on('autosize.resize', adjust);
// Event for manual triggering that also forces the styles to update as well.
// Should only be needed if one of typography styles of the textarea change, and the textarea is already the target of the adjust method.
$ta.on('autosize.resizeIncludeStyle', function() {
mirrored = null;
adjust();
});
$ta.on('autosize.destroy', function(){
mirrored = null;
clearTimeout(timeout);
$(window).off('resize', resize);
$ta
.off('autosize')
.off('.autosize')
.css(originalStyles)
.removeData('autosize');
});
// Call adjust in case the textarea already contains text.
adjust();
});
};
}(window.jQuery || window.$)); // jQuery or jQuery-like library, such as Zepto

View File

@ -1,2 +0,0 @@
(function($){var defaults={className:"autosizejs",append:"",callback:false,resizeDelay:10},copy='<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; padding: 0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>',typographyStyles=["fontFamily","fontSize","fontWeight","fontStyle","letterSpacing","textTransform","wordSpacing","textIndent"],mirrored,mirror=$(copy).data("autosize",true)[0];mirror.style.lineHeight="99px";if($(mirror).css("lineHeight")==="99px"){typographyStyles.push("lineHeight")}mirror.style.lineHeight="";$.fn.autosize=function(options){if(!this.length){return this}options=$.extend({},defaults,options||{});if(mirror.parentNode!==document.body){$(document.body).append(mirror)}return this.each(function(){var ta=this,$ta=$(ta),maxHeight,minHeight,boxOffset=0,callback=$.isFunction(options.callback),originalStyles={height:ta.style.height,overflow:ta.style.overflow,overflowY:ta.style.overflowY,wordWrap:ta.style.wordWrap,resize:ta.style.resize},timeout,width=$ta.width();if($ta.data("autosize")){return}$ta.data("autosize",true);if($ta.css("box-sizing")==="border-box"||$ta.css("-moz-box-sizing")==="border-box"||$ta.css("-webkit-box-sizing")==="border-box"){boxOffset=$ta.outerHeight()-$ta.height()}minHeight=Math.max(parseInt($ta.css("minHeight"),10)-boxOffset||0,$ta.height());$ta.css({overflow:"hidden",overflowY:"hidden",wordWrap:"break-word",resize:$ta.css("resize")==="none"||$ta.css("resize")==="vertical"?"none":"horizontal"});function setWidth(){var style,width;if("getComputedStyle"in window){style=window.getComputedStyle(ta,null);width=ta.getBoundingClientRect().width;$.each(["paddingLeft","paddingRight","borderLeftWidth","borderRightWidth"],function(i,val){width-=parseInt(style[val],10)});mirror.style.width=width+"px"}else{mirror.style.width=Math.max($ta.width(),0)+"px"}}function initMirror(){var styles={};mirrored=ta;mirror.className=options.className;maxHeight=parseInt($ta.css("maxHeight"),10);$.each(typographyStyles,function(i,val){styles[val]=$ta.css(val)});$(mirror).css(styles);setWidth();if(window.chrome){var width=ta.style.width;ta.style.width="0px";var ignore=ta.offsetWidth;ta.style.width=width}}function adjust(){var height,original;if(mirrored!==ta){initMirror()}else{setWidth()}mirror.value=ta.value+options.append;mirror.style.overflowY=ta.style.overflowY;original=parseInt(ta.style.height,10);mirror.scrollTop=0;mirror.scrollTop=9e4;height=mirror.scrollTop;if(maxHeight&&height>maxHeight){ta.style.overflowY="scroll";height=maxHeight}else{ta.style.overflowY="hidden";if(height<minHeight){height=minHeight}}height+=boxOffset;if(original!==height){ta.style.height=height+"px";if(callback){options.callback.call(ta,ta)}}}function resize(){clearTimeout(timeout);timeout=setTimeout(function(){var newWidth=$ta.width();if(newWidth!==width){width=newWidth;adjust()}},parseInt(options.resizeDelay,10))}if("onpropertychange"in ta){if("oninput"in ta){$ta.on("input.autosize keyup.autosize",adjust)}else{$ta.on("propertychange.autosize",function(){if(event.propertyName==="value"){adjust()}})}}else{$ta.on("input.autosize",adjust)}if(options.resizeDelay!==false){$(window).on("resize.autosize",resize)}$ta.on("autosize.resize",adjust);$ta.on("autosize.resizeIncludeStyle",function(){mirrored=null;adjust()});$ta.on("autosize.destroy",function(){mirrored=null;clearTimeout(timeout);$(window).off("resize",resize);$ta.off("autosize").off(".autosize").css(originalStyles).removeData("autosize")});adjust()})}})(window.jQuery||window.$);
//# sourceMappingURL=jquery.autosize.min.map

View File

@ -1 +0,0 @@
{"version":3,"file":"jquery.autosize.min.js","sources":["jquery.autosize.js"],"names":["$","defaults","className","append","callback","resizeDelay","copy","typographyStyles","mirrored","mirror","data","style","lineHeight","css","push","fn","autosize","options","this","length","extend","parentNode","document","body","each","ta","$ta","maxHeight","minHeight","boxOffset","isFunction","originalStyles","height","overflow","overflowY","wordWrap","resize","timeout","width","outerHeight","Math","max","parseInt","setWidth","window","getComputedStyle","getBoundingClientRect","i","val","initMirror","styles","chrome","ignore","offsetWidth","adjust","original","value","scrollTop","call","clearTimeout","setTimeout","newWidth","on","event","propertyName","off","removeData","jQuery"],"mappings":"CAMC,SAAUA,GACV,GACAC,WACCC,UAAW,aACXC,OAAQ,GACRC,SAAU,MACVC,YAAa,IAIdC,KAAO,oWAGPC,kBACC,aACA,WACA,aACA,YACA,gBACA,gBACA,cACA,cAIDC,SAGAC,OAAST,EAAEM,MAAMI,KAAK,WAAY,MAAM,EAGxCD,QAAOE,MAAMC,WAAa,MAC1B,IAAIZ,EAAES,QAAQI,IAAI,gBAAkB,OAAQ,CAC3CN,iBAAiBO,KAAK,cAEvBL,OAAOE,MAAMC,WAAa,EAE1BZ,GAAEe,GAAGC,SAAW,SAAUC,SACzB,IAAKC,KAAKC,OAAQ,CACjB,MAAOD,MAGRD,QAAUjB,EAAEoB,UAAWnB,SAAUgB,YAEjC,IAAIR,OAAOY,aAAeC,SAASC,KAAM,CACxCvB,EAAEsB,SAASC,MAAMpB,OAAOM,QAGzB,MAAOS,MAAKM,KAAK,WAChB,GACAC,IAAKP,KACLQ,IAAM1B,EAAEyB,IACRE,UACAC,UACAC,UAAY,EACZzB,SAAWJ,EAAE8B,WAAWb,QAAQb,UAChC2B,gBACCC,OAAQP,GAAGd,MAAMqB,OACjBC,SAAUR,GAAGd,MAAMsB,SACnBC,UAAWT,GAAGd,MAAMuB,UACpBC,SAAUV,GAAGd,MAAMwB,SACnBC,OAAQX,GAAGd,MAAMyB,QAElBC,QACAC,MAAQZ,IAAIY,OAEZ,IAAIZ,IAAIhB,KAAK,YAAa,CAEzB,OAEDgB,IAAIhB,KAAK,WAAY,KAErB,IAAIgB,IAAIb,IAAI,gBAAkB,cAAgBa,IAAIb,IAAI,qBAAuB,cAAgBa,IAAIb,IAAI,wBAA0B,aAAa,CAC3IgB,UAAYH,IAAIa,cAAgBb,IAAIM,SAIrCJ,UAAYY,KAAKC,IAAIC,SAAShB,IAAIb,IAAI,aAAc,IAAMgB,WAAa,EAAGH,IAAIM,SAE9EN,KAAIb,KACHoB,SAAU,SACVC,UAAW,SACXC,SAAU,aACVC,OAASV,IAAIb,IAAI,YAAc,QAAUa,IAAIb,IAAI,YAAc,WAAc,OAAS,cAIvF,SAAS8B,YACR,GAAIhC,OAAO2B,KAEX,IAAI,oBAAsBM,QAAQ,CACjCjC,MAAQiC,OAAOC,iBAAiBpB,GAAI,KACpCa,OAAQb,GAAGqB,wBAAwBR,KAEnCtC,GAAEwB,MAAM,cAAe,eAAgB,kBAAmB,oBAAqB,SAASuB,EAAEC,KACzFV,OAASI,SAAS/B,MAAMqC,KAAK,KAG9BvC,QAAOE,MAAM2B,MAAQA,MAAQ,SAEzB,CAEJ7B,OAAOE,MAAM2B,MAAQE,KAAKC,IAAIf,IAAIY,QAAS,GAAK,MAIlD,QAASW,cACR,GAAIC,UAEJ1C,UAAWiB,EACXhB,QAAOP,UAAYe,QAAQf,SAC3ByB,WAAYe,SAAShB,IAAIb,IAAI,aAAc,GAO3Cb,GAAEwB,KAAKjB,iBAAkB,SAASwC,EAAEC,KACnCE,OAAOF,KAAOtB,IAAIb,IAAImC,MAEvBhD,GAAES,QAAQI,IAAIqC,OAEdP,WAKA,IAAIC,OAAOO,OAAQ,CAClB,GAAIb,OAAQb,GAAGd,MAAM2B,KACrBb,IAAGd,MAAM2B,MAAQ,KACjB,IAAIc,QAAS3B,GAAG4B,WAChB5B,IAAGd,MAAM2B,MAAQA,OAMnB,QAASgB,UACR,GAAItB,QAAQuB,QAEZ,IAAI/C,WAAaiB,GAAI,CACpBwB,iBACM,CACNN,WAGDlC,OAAO+C,MAAQ/B,GAAG+B,MAAQvC,QAAQd,MAClCM,QAAOE,MAAMuB,UAAYT,GAAGd,MAAMuB,SAClCqB,UAAWb,SAASjB,GAAGd,MAAMqB,OAAO,GAGpCvB,QAAOgD,UAAY,CAEnBhD,QAAOgD,UAAY,GAGnBzB,QAASvB,OAAOgD,SAEhB,IAAI9B,WAAaK,OAASL,UAAW,CACpCF,GAAGd,MAAMuB,UAAY,QACrBF,QAASL,cACH,CACNF,GAAGd,MAAMuB,UAAY,QACrB,IAAIF,OAASJ,UAAW,CACvBI,OAASJ,WAIXI,QAAUH,SAEV,IAAI0B,WAAavB,OAAQ,CACxBP,GAAGd,MAAMqB,OAASA,OAAS,IAC3B,IAAI5B,SAAU,CACba,QAAQb,SAASsD,KAAKjC,GAAGA,MAK5B,QAASW,UACRuB,aAAatB,QACbA,SAAUuB,WAAW,WACpB,GAAIC,UAAWnC,IAAIY,OAEnB,IAAIuB,WAAavB,MAAO,CACvBA,MAAQuB,QACRP,YAECZ,SAASzB,QAAQZ,YAAY,KAGjC,GAAI,oBAAsBoB,IAAI,CAC7B,GAAI,WAAaA,IAAI,CAIpBC,IAAIoC,GAAG,gCAAiCR,YAClC,CAEN5B,IAAIoC,GAAG,0BAA2B,WACjC,GAAGC,MAAMC,eAAiB,QAAQ,CACjCV,iBAIG,CAEN5B,IAAIoC,GAAG,iBAAkBR,QAM1B,GAAIrC,QAAQZ,cAAgB,MAAO,CAClCL,EAAE4C,QAAQkB,GAAG,kBAAmB1B,QAKjCV,IAAIoC,GAAG,kBAAmBR,OAI1B5B,KAAIoC,GAAG,8BAA+B,WACrCtD,SAAW,IACX8C,WAGD5B,KAAIoC,GAAG,mBAAoB,WAC1BtD,SAAW,IACXmD,cAAatB,QACbrC,GAAE4C,QAAQqB,IAAI,SAAU7B,OACxBV,KACEuC,IAAI,YACJA,IAAI,aACJpD,IAAIkB,gBACJmC,WAAW,aAIdZ,eAGDV,OAAOuB,QAAUvB,OAAO5C"}

View File

@ -1,110 +0,0 @@
/* ========================================================================
* Bootstrap: popover.js v3.1.1
* http://getbootstrap.com/javascript/#popovers
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// POPOVER PUBLIC CLASS DEFINITION
// ===============================
var Popover = function (element, options) {
this.init('popover', element, options)
}
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right',
trigger: 'click',
content: '',
template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
})
// NOTE: POPOVER EXTENDS tooltip.js
// ================================
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
Popover.prototype.constructor = Popover
Popover.prototype.getDefaults = function () {
return Popover.DEFAULTS
}
Popover.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
var content = this.getContent()
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
$tip.find('.popover-content')[ // we use append for html objects to maintain js events
this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
](content)
$tip.removeClass('fade top bottom left right in')
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
// this manually by checking the contents.
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
}
Popover.prototype.hasContent = function () {
return this.getTitle() || this.getContent()
}
Popover.prototype.getContent = function () {
var $e = this.$element
var o = this.options
return $e.attr('data-content')
|| (typeof o.content == 'function' ?
o.content.call($e[0]) :
o.content)
}
Popover.prototype.arrow = function () {
return this.$arrow = this.$arrow || this.tip().find('.arrow')
}
Popover.prototype.tip = function () {
if (!this.$tip) this.$tip = $(this.options.template)
return this.$tip
}
// POPOVER PLUGIN DEFINITION
// =========================
var old = $.fn.popover
$.fn.popover = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.popover')
var options = typeof option == 'object' && option
if (!data && option == 'destroy') return
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.popover.Constructor = Popover
// POPOVER NO CONFLICT
// ===================
$.fn.popover.noConflict = function () {
$.fn.popover = old
return this
}
}(jQuery);

2
libs/popover.min.js vendored
View File

@ -1,2 +0,0 @@
+function($){"use strict";var Popover=function(element,options){this.init("popover",element,options)};if(!$.fn.tooltip)throw new Error("Popover requires tooltip.js");Popover.DEFAULTS=$.extend({},$.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'});Popover.prototype=$.extend({},$.fn.tooltip.Constructor.prototype);Popover.prototype.constructor=Popover;Popover.prototype.getDefaults=function(){return Popover.DEFAULTS};Popover.prototype.setContent=function(){var $tip=this.tip();var title=this.getTitle();var content=this.getContent();$tip.find(".popover-title")[this.options.html?"html":"text"](title);$tip.find(".popover-content")[this.options.html?typeof content=="string"?"html":"append":"text"](content);$tip.removeClass("fade top bottom left right in");if(!$tip.find(".popover-title").html())$tip.find(".popover-title").hide()};Popover.prototype.hasContent=function(){return this.getTitle()||this.getContent()};Popover.prototype.getContent=function(){var $e=this.$element;var o=this.options;return $e.attr("data-content")||(typeof o.content=="function"?o.content.call($e[0]):o.content)};Popover.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};Popover.prototype.tip=function(){if(!this.$tip)this.$tip=$(this.options.template);return this.$tip};var old=$.fn.popover;$.fn.popover=function(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.popover");var options=typeof option=="object"&&option;if(!data&&option=="destroy")return;if(!data)$this.data("bs.popover",data=new Popover(this,options));if(typeof option=="string")data[option]()})};$.fn.popover.Constructor=Popover;$.fn.popover.noConflict=function(){$.fn.popover=old;return this}}(jQuery);
//# sourceMappingURL=popover.min.map

View File

@ -1 +0,0 @@
{"version":3,"file":"popover.min.js","sources":["popover.js"],"names":["$","Popover","element","options","this","init","fn","tooltip","Error","DEFAULTS","extend","Constructor","placement","trigger","content","template","prototype","constructor","getDefaults","setContent","$tip","tip","title","getTitle","getContent","find","html","removeClass","hide","hasContent","$e","$element","o","attr","call","arrow","$arrow","old","popover","option","each","$this","data","noConflict","jQuery"],"mappings":"CASC,SAAUA,GACT,YAKA,IAAIC,SAAU,SAAUC,QAASC,SAC/BC,KAAKC,KAAK,UAAWH,QAASC,SAGhC,KAAKH,EAAEM,GAAGC,QAAS,KAAM,IAAIC,OAAM,8BAEnCP,SAAQQ,SAAWT,EAAEU,UAAWV,EAAEM,GAAGC,QAAQI,YAAYF,UACvDG,UAAW,QACXC,QAAS,QACTC,QAAS,GACTC,SAAU,0HAOZd,SAAQe,UAAYhB,EAAEU,UAAWV,EAAEM,GAAGC,QAAQI,YAAYK,UAE1Df,SAAQe,UAAUC,YAAchB,OAEhCA,SAAQe,UAAUE,YAAc,WAC9B,MAAOjB,SAAQQ,SAGjBR,SAAQe,UAAUG,WAAa,WAC7B,GAAIC,MAAUhB,KAAKiB,KACnB,IAAIC,OAAUlB,KAAKmB,UACnB,IAAIT,SAAUV,KAAKoB,YAEnBJ,MAAKK,KAAK,kBAAkBrB,KAAKD,QAAQuB,KAAO,OAAS,QAAQJ,MACjEF,MAAKK,KAAK,oBACRrB,KAAKD,QAAQuB,WAAeZ,UAAW,SAAW,OAAS,SAAY,QACvEA,QAEFM,MAAKO,YAAY,gCAIjB,KAAKP,KAAKK,KAAK,kBAAkBC,OAAQN,KAAKK,KAAK,kBAAkBG,OAGvE3B,SAAQe,UAAUa,WAAa,WAC7B,MAAOzB,MAAKmB,YAAcnB,KAAKoB,aAGjCvB,SAAQe,UAAUQ,WAAa,WAC7B,GAAIM,IAAK1B,KAAK2B,QACd,IAAIC,GAAK5B,KAAKD,OAEd,OAAO2B,IAAGG,KAAK,wBACFD,GAAElB,SAAW,WAClBkB,EAAElB,QAAQoB,KAAKJ,GAAG,IAClBE,EAAElB,SAGZb,SAAQe,UAAUmB,MAAQ,WACxB,MAAO/B,MAAKgC,OAAShC,KAAKgC,QAAUhC,KAAKiB,MAAMI,KAAK,UAGtDxB,SAAQe,UAAUK,IAAM,WACtB,IAAKjB,KAAKgB,KAAMhB,KAAKgB,KAAOpB,EAAEI,KAAKD,QAAQY,SAC3C,OAAOX,MAAKgB,KAOd,IAAIiB,KAAMrC,EAAEM,GAAGgC,OAEftC,GAAEM,GAAGgC,QAAU,SAAUC,QACvB,MAAOnC,MAAKoC,KAAK,WACf,GAAIC,OAAUzC,EAAEI,KAChB,IAAIsC,MAAUD,MAAMC,KAAK,aACzB,IAAIvC,eAAiBoC,SAAU,UAAYA,MAE3C,KAAKG,MAAQH,QAAU,UAAW,MAClC,KAAKG,KAAMD,MAAMC,KAAK,aAAeA,KAAO,GAAIzC,SAAQG,KAAMD,SAC9D,UAAWoC,SAAU,SAAUG,KAAKH,YAIxCvC,GAAEM,GAAGgC,QAAQ3B,YAAcV,OAM3BD,GAAEM,GAAGgC,QAAQK,WAAa,WACxB3C,EAAEM,GAAGgC,QAAUD,GACf,OAAOjC,QAGTwC"}

View File

@ -1 +0,0 @@
Strophe.addConnectionPlugin("caps",{HASH:"sha-1",node:"http://strophe.im/strophejs/",_ver:"",_connection:null,_knownCapabilities:{},_jidVerIndex:{},init:function(conn){this._connection=conn;Strophe.addNamespace("CAPS","http://jabber.org/protocol/caps");if(!this._connection.disco){throw"Caps plugin requires the disco plugin to be installed."}this._connection.disco.addFeature(Strophe.NS.CAPS);this._connection.addHandler(this._delegateCapabilities.bind(this),Strophe.NS.CAPS)},generateCapsAttrs:function(){return{xmlns:Strophe.NS.CAPS,hash:this.HASH,node:this.node,ver:this.generateVer()}},generateVer:function(){if(this._ver!==""){return this._ver}var ver="",identities=this._connection.disco._identities.sort(this._sortIdentities),identitiesLen=identities.length,features=this._connection.disco._features.sort(),featuresLen=features.length;for(var i=0;i<identitiesLen;i++){var curIdent=identities[i];ver+=curIdent.category+"/"+curIdent.type+"/"+curIdent.lang+"/"+curIdent.name+"<"}for(var i=0;i<featuresLen;i++){ver+=features[i]+"<"}this._ver=b64_sha1(ver);return this._ver},getCapabilitiesByJid:function(jid){if(this._jidVerIndex[jid]){return this._knownCapabilities[this._jidVerIndex[jid]]}return null},_delegateCapabilities:function(stanza){var from=stanza.getAttribute("from"),c=stanza.querySelector("c"),ver=c.getAttribute("ver"),node=c.getAttribute("node");if(!this._knownCapabilities[ver]){return this._requestCapabilities(from,node,ver)}else{this._jidVerIndex[from]=ver}if(!this._jidVerIndex[from]||!this._jidVerIndex[from]!==ver){this._jidVerIndex[from]=ver}return true},_requestCapabilities:function(to,node,ver){if(to!==this._connection.jid){var id=this._connection.disco.info(to,node+"#"+ver);this._connection.addHandler(this._handleDiscoInfoReply.bind(this),Strophe.NS.DISCO_INFO,"iq","result",id,to)}return true},_handleDiscoInfoReply:function(stanza){var query=stanza.querySelector("query"),node=query.getAttribute("node").split("#"),ver=node[1],from=stanza.getAttribute("from");if(!this._knownCapabilities[ver]){var childNodes=query.childNodes,childNodesLen=childNodes.length;this._knownCapabilities[ver]=[];for(var i=0;i<childNodesLen;i++){var node=childNodes[i];this._knownCapabilities[ver].push({name:node.nodeName,attributes:node.attributes})}this._jidVerIndex[from]=ver}else{if(!this._jidVerIndex[from]||!this._jidVerIndex[from]!==ver){this._jidVerIndex[from]=ver}}return false},_sortIdentities:function(a,b){if(a.category>b.category){return 1}if(a.category<b.category){return -1}if(a.type>b.type){return 1}if(a.type<b.type){return -1}if(a.lang>b.lang){return 1}if(a.lang<b.lang){return -1}return 0}});

View File

@ -1 +0,0 @@
Strophe.addConnectionPlugin("disco",{_connection:null,_identities:[],_features:[],_items:[],init:function(conn){this._connection=conn;this._identities=[];this._features=[];this._items=[];conn.addHandler(this._onDiscoInfo.bind(this),Strophe.NS.DISCO_INFO,"iq","get",null,null);conn.addHandler(this._onDiscoItems.bind(this),Strophe.NS.DISCO_ITEMS,"iq","get",null,null)},addIdentity:function(category,type,name,lang){for(var i=0;i<this._identities.length;i++){if(this._identities[i].category==category&&this._identities[i].type==type&&this._identities[i].name==name&&this._identities[i].lang==lang){return false}}this._identities.push({category:category,type:type,name:name,lang:lang});return true},addFeature:function(var_name){for(var i=0;i<this._features.length;i++){if(this._features[i]==var_name){return false}}this._features.push(var_name);return true},removeFeature:function(var_name){for(var i=0;i<this._features.length;i++){if(this._features[i]===var_name){this._features.splice(i,1);return true}}return false},addItem:function(jid,name,node,call_back){if(node&&!call_back){return false}this._items.push({jid:jid,name:name,node:node,call_back:call_back});return true},info:function(jid,node,success,error,timeout){var attrs={xmlns:Strophe.NS.DISCO_INFO};if(node){attrs.node=node}var info=$iq({from:this._connection.jid,to:jid,type:"get"}).c("query",attrs);this._connection.sendIQ(info,success,error,timeout)},items:function(jid,node,success,error,timeout){var attrs={xmlns:Strophe.NS.DISCO_ITEMS};if(node){attrs.node=node}var items=$iq({from:this._connection.jid,to:jid,type:"get"}).c("query",attrs);this._connection.sendIQ(items,success,error,timeout)},_buildIQResult:function(stanza,query_attrs){var id=stanza.getAttribute("id");var from=stanza.getAttribute("from");var iqresult=$iq({type:"result",id:id});if(from!==null){iqresult.attrs({to:from})}return iqresult.c("query",query_attrs)},_onDiscoInfo:function(stanza){var node=stanza.getElementsByTagName("query")[0].getAttribute("node");var attrs={xmlns:Strophe.NS.DISCO_INFO};if(node){attrs.node=node}var iqresult=this._buildIQResult(stanza,attrs);for(var i=0;i<this._identities.length;i++){var attrs={category:this._identities[i].category,type:this._identities[i].type};if(this._identities[i].name){attrs.name=this._identities[i].name}if(this._identities[i].lang){attrs["xml:lang"]=this._identities[i].lang}iqresult.c("identity",attrs).up()}for(var i=0;i<this._features.length;i++){iqresult.c("feature",{"var":this._features[i]}).up()}this._connection.send(iqresult.tree());return true},_onDiscoItems:function(stanza){var query_attrs={xmlns:Strophe.NS.DISCO_ITEMS};var node=stanza.getElementsByTagName("query")[0].getAttribute("node");if(node){query_attrs.node=node;var items=[];for(var i=0;i<this._items.length;i++){if(this._items[i].node==node){items=this._items[i].call_back(stanza);break}}}else{var items=this._items}var iqresult=this._buildIQResult(stanza,query_attrs);for(var i=0;i<items.length;i++){var attrs={jid:items[i].jid};if(items[i].name){attrs.name=items[i].name}if(items[i].node){attrs.node=items[i].node}iqresult.c("item",attrs).up()}this._connection.send(iqresult.tree());return true}});

File diff suppressed because one or more lines are too long

View File

@ -1,342 +0,0 @@
/*
* Toastr
* Copyright 2012-2014 John Papa and Hans Fjällemark.
* All Rights Reserved.
* Use, reproduction, distribution, and modification of this code is subject to the terms and
* conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
*
* Author: John Papa and Hans Fjällemark
* ARIA Support: Greta Krafsig
* Project: https://github.com/CodeSeven/toastr
*/
; (function (define) {
define(['jquery'], function ($) {
return (function () {
var $container;
var listener;
var toastId = 0;
var toastType = {
error: 'error',
info: 'info',
success: 'success',
warning: 'warning'
};
var toastr = {
clear: clear,
remove: remove,
error: error,
getContainer: getContainer,
info: info,
options: {},
subscribe: subscribe,
success: success,
version: '2.0.3',
warning: warning
};
return toastr;
//#region Accessible Methods
function error(message, title, optionsOverride) {
return notify({
type: toastType.error,
iconClass: getOptions().iconClasses.error,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function getContainer(options, create) {
if (!options) { options = getOptions(); }
$container = $('#' + options.containerId);
if ($container.length) {
return $container;
}
if(create) {
$container = createContainer(options);
}
return $container;
}
function info(message, title, optionsOverride) {
return notify({
type: toastType.info,
iconClass: getOptions().iconClasses.info,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function subscribe(callback) {
listener = callback;
}
function success(message, title, optionsOverride) {
return notify({
type: toastType.success,
iconClass: getOptions().iconClasses.success,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function warning(message, title, optionsOverride) {
return notify({
type: toastType.warning,
iconClass: getOptions().iconClasses.warning,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function clear($toastElement) {
var options = getOptions();
if (!$container) { getContainer(options); }
if (!clearToast($toastElement, options)) {
clearContainer(options);
}
}
function remove($toastElement) {
var options = getOptions();
if (!$container) { getContainer(options); }
if ($toastElement && $(':focus', $toastElement).length === 0) {
removeToast($toastElement);
return;
}
if ($container.children().length) {
$container.remove();
}
}
//#endregion
//#region Internal Methods
function clearContainer(options){
var toastsToClear = $container.children();
for (var i = toastsToClear.length - 1; i >= 0; i--) {
clearToast($(toastsToClear[i]), options);
};
}
function clearToast($toastElement, options){
if ($toastElement && $(':focus', $toastElement).length === 0) {
$toastElement[options.hideMethod]({
duration: options.hideDuration,
easing: options.hideEasing,
complete: function () { removeToast($toastElement); }
});
return true;
}
return false;
}
function createContainer(options) {
$container = $('<div/>')
.attr('id', options.containerId)
.addClass(options.positionClass)
.attr('aria-live', 'polite')
.attr('role', 'alert');
$container.appendTo($(options.target));
return $container;
}
function getDefaults() {
return {
tapToDismiss: true,
toastClass: 'toast',
containerId: 'toast-container',
debug: false,
showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
showDuration: 300,
showEasing: 'swing', //swing and linear are built into jQuery
onShown: undefined,
hideMethod: 'fadeOut',
hideDuration: 1000,
hideEasing: 'swing',
onHidden: undefined,
extendedTimeOut: 1000,
iconClasses: {
error: 'toast-error',
info: 'toast-info',
success: 'toast-success',
warning: 'toast-warning'
},
iconClass: 'toast-info',
positionClass: 'toast-top-right',
timeOut: 5000, // Set timeOut and extendedTimeout to 0 to make it sticky
titleClass: 'toast-title',
messageClass: 'toast-message',
target: 'body',
closeHtml: '<button>&times;</button>',
newestOnTop: true
};
}
function publish(args) {
if (!listener) { return; }
listener(args);
}
function notify(map) {
var options = getOptions(),
iconClass = map.iconClass || options.iconClass;
if (typeof (map.optionsOverride) !== 'undefined') {
options = $.extend(options, map.optionsOverride);
iconClass = map.optionsOverride.iconClass || iconClass;
}
toastId++;
$container = getContainer(options, true);
var intervalId = null,
$toastElement = $('<div/>'),
$titleElement = $('<div/>'),
$messageElement = $('<div/>'),
$closeElement = $(options.closeHtml),
response = {
toastId: toastId,
state: 'visible',
startTime: new Date(),
options: options,
map: map
};
if (map.iconClass) {
$toastElement.addClass(options.toastClass).addClass(iconClass);
}
if (map.title) {
$titleElement.append(map.title).addClass(options.titleClass);
$toastElement.append($titleElement);
}
if (map.message) {
$messageElement.append(map.message).addClass(options.messageClass);
$toastElement.append($messageElement);
}
if (options.closeButton) {
$closeElement.addClass('toast-close-button').attr("role", "button");
$toastElement.prepend($closeElement);
}
if (options.reposition) {
options.reposition();
}
$toastElement.hide();
if (options.newestOnTop) {
$container.prepend($toastElement);
} else {
$container.append($toastElement);
}
$toastElement[options.showMethod](
{ duration: options.showDuration, easing: options.showEasing, complete: options.onShown }
);
if (options.timeOut > 0) {
intervalId = setTimeout(hideToast, options.timeOut);
}
$toastElement.hover(stickAround, delayedHideToast);
if (!options.onclick && options.tapToDismiss) {
$toastElement.click(hideToast);
}
if (options.closeButton && $closeElement) {
$closeElement.click(function (event) {
if( event.stopPropagation ) {
event.stopPropagation();
} else if( event.cancelBubble !== undefined && event.cancelBubble !== true ) {
event.cancelBubble = true;
}
hideToast(true);
});
}
if (options.onclick) {
$toastElement.click(function () {
options.onclick();
hideToast();
});
}
publish(response);
if (options.debug && console) {
console.log(response);
}
return $toastElement;
function hideToast(override) {
if ($(':focus', $toastElement).length && !override) {
return;
}
return $toastElement[options.hideMethod]({
duration: options.hideDuration,
easing: options.hideEasing,
complete: function () {
removeToast($toastElement);
if (options.onHidden && response.state !== 'hidden') {
options.onHidden();
}
response.state = 'hidden';
response.endTime = new Date();
publish(response);
}
});
}
function delayedHideToast() {
if (options.timeOut > 0 || options.extendedTimeOut > 0) {
intervalId = setTimeout(hideToast, options.extendedTimeOut);
}
}
function stickAround() {
clearTimeout(intervalId);
$toastElement.stop(true, true)[options.showMethod](
{ duration: options.showDuration, easing: options.showEasing }
);
}
}
function getOptions() {
return $.extend({}, getDefaults(), toastr.options);
}
function removeToast($toastElement) {
if (!$container) { $container = getContainer(); }
if ($toastElement.is(':visible')) {
return;
}
$toastElement.remove();
$toastElement = null;
if ($container.children().length === 0) {
$container.remove();
}
}
//#endregion
})();
});
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
if (typeof module !== 'undefined' && module.exports) { //Node
module.exports = factory(require('jquery'));
} else {
window['toastr'] = factory(window['jQuery']);
}
}));

2
libs/toastr.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,422 +0,0 @@
/* ========================================================================
* Bootstrap: tooltip.js v3.1.1
* http://getbootstrap.com/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// TOOLTIP PUBLIC CLASS DEFINITION
// ===============================
var Tooltip = function (element, options) {
this.type =
this.options =
this.enabled =
this.timeout =
this.hoverState =
this.$element = null
this.init('tooltip', element, options)
}
Tooltip.DEFAULTS = {
animation: true,
placement: 'top',
selector: false,
template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
trigger: 'hover focus',
title: '',
delay: 0,
html: false,
container: false
}
Tooltip.prototype.init = function (type, element, options) {
this.enabled = true
this.type = type
this.$element = $(element)
this.options = this.getOptions(options)
var triggers = this.options.trigger.split(' ')
for (var i = triggers.length; i--;) {
var trigger = triggers[i]
if (trigger == 'click') {
this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
} else if (trigger != 'manual') {
var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
}
}
this.options.selector ?
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()
}
Tooltip.prototype.getDefaults = function () {
return Tooltip.DEFAULTS
}
Tooltip.prototype.getOptions = function (options) {
options = $.extend({}, this.getDefaults(), this.$element.data(), options)
if (options.delay && typeof options.delay == 'number') {
options.delay = {
show: options.delay,
hide: options.delay
}
}
return options
}
Tooltip.prototype.getDelegateOptions = function () {
var options = {}
var defaults = this.getDefaults()
this._options && $.each(this._options, function (key, value) {
if (defaults[key] != value) options[key] = value
})
return options
}
Tooltip.prototype.enter = function (obj) {
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
clearTimeout(self.timeout)
self.hoverState = 'in'
if (!self.options.delay || !self.options.delay.show) return self.show()
self.timeout = setTimeout(function () {
if (self.hoverState == 'in') self.show()
}, self.options.delay.show)
}
Tooltip.prototype.leave = function (obj) {
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
clearTimeout(self.timeout)
self.hoverState = 'out'
if (!self.options.delay || !self.options.delay.hide) return self.hide()
self.timeout = setTimeout(function () {
if (self.hoverState == 'out') self.hide()
}, self.options.delay.hide)
}
Tooltip.prototype.show = function () {
var e = $.Event('show.bs.' + this.type)
if (this.hasContent() && this.enabled) {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
var that = this;
var $tip = this.tip()
this.setContent()
if (this.options.animation) $tip.addClass('fade')
var placement = typeof this.options.placement == 'function' ?
this.options.placement.call(this, $tip[0], this.$element[0]) :
this.options.placement
var autoToken = /\s?auto?\s?/i
var autoPlace = autoToken.test(placement)
if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
$tip
.detach()
.css({ top: 0, left: 0, display: 'block' })
.addClass(placement)
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
var pos = this.getPosition()
var actualWidth = $tip[0].offsetWidth
var actualHeight = $tip[0].offsetHeight
if (autoPlace) {
var $parent = this.$element.parent()
var orgPlacement = placement
var docScroll = document.documentElement.scrollTop || document.body.scrollTop
var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
placement
$tip
.removeClass(orgPlacement)
.addClass(placement)
}
var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
this.applyPlacement(calculatedOffset, placement)
this.hoverState = null
var complete = function() {
that.$element.trigger('shown.bs.' + that.type)
}
var deltas = {
"bottom": $tip[0].getBoundingClientRect().bottom - window.innerHeight,
"right": $tip[0].getBoundingClientRect().right - window.innerWidth,
"left": -$tip[0].getBoundingClientRect().left,
"top": -$tip[0].getBoundingClientRect().top
};
for(var direction in deltas) {
if (deltas[direction] > 0) {
var delta = deltas[direction];
if(direction === "right" || direction === "bottom") {
delta = -delta;
}
direction = direction === "top" || direction === "bottom" ? "top" : "left";
var currentPosition = parseInt($tip.css(direction), 10);
$tip.css(direction, currentPosition + delta);
if(direction === "left") {
$tip.children(".arrow").css(direction, parseInt($tip.children(".arrow").css(direction), 10) - delta);
} else {
$tip.children(".arrow").css(direction, 50 - $tip[0].getBoundingClientRect().height / delta + "%");
}
}
}
$.support.transition && this.$tip.hasClass('fade') ?
$tip
.one($.support.transition.end, complete)
.emulateTransitionEnd(150) :
complete()
}
}
Tooltip.prototype.applyPlacement = function (offset, placement) {
var replace
var $tip = this.tip()
var width = $tip[0].offsetWidth
var height = $tip[0].offsetHeight
// manually read margins because getBoundingClientRect includes difference
var marginTop = parseInt($tip.css('margin-top'), 10)
var marginLeft = parseInt($tip.css('margin-left'), 10)
// we must check for NaN for ie 8/9
if (isNaN(marginTop)) marginTop = 0
if (isNaN(marginLeft)) marginLeft = 0
offset.top = offset.top + marginTop
offset.left = offset.left + marginLeft
// $.fn.offset doesn't round pixel values
// so we use setOffset directly with our own function B-0
$.offset.setOffset($tip[0], $.extend({
using: function (props) {
$tip.css({
top: Math.round(props.top),
left: Math.round(props.left)
})
}
}, offset), 0)
$tip.addClass('in')
// check to see if placing tip in new offset caused the tip to resize itself
var actualWidth = $tip[0].offsetWidth
var actualHeight = $tip[0].offsetHeight
if (placement == 'top' && actualHeight != height) {
replace = true
offset.top = offset.top + height - actualHeight
}
if (/bottom|top/.test(placement)) {
var delta = 0
if (offset.left < 0) {
delta = offset.left * -2
offset.left = 0
$tip.offset(offset)
actualWidth = $tip[0].offsetWidth
actualHeight = $tip[0].offsetHeight
}
this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
} else {
this.replaceArrow(actualHeight - height, actualHeight, 'top')
}
if (replace) $tip.offset(offset)
}
Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
}
Tooltip.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
$tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
$tip.removeClass('fade in top bottom left right')
}
Tooltip.prototype.hide = function () {
var that = this
var $tip = this.tip()
var e = $.Event('hide.bs.' + this.type)
function complete() {
if (that.hoverState != 'in') $tip.detach()
that.$element.trigger('hidden.bs.' + that.type)
}
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$tip.removeClass('in')
$.support.transition && this.$tip.hasClass('fade') ?
$tip
.one($.support.transition.end, complete)
.emulateTransitionEnd(150) :
complete()
this.hoverState = null
return this
}
Tooltip.prototype.fixTitle = function () {
var $e = this.$element
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
}
}
Tooltip.prototype.hasContent = function () {
return this.getTitle()
}
Tooltip.prototype.getPosition = function () {
var el = this.$element[0]
return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
width: el.offsetWidth,
height: el.offsetHeight
}, this.$element.offset())
}
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
/* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
}
Tooltip.prototype.getTitle = function () {
var title
var $e = this.$element
var o = this.options
title = $e.attr('data-original-title')
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
return title
}
Tooltip.prototype.tip = function () {
return this.$tip = this.$tip || $(this.options.template)
}
Tooltip.prototype.arrow = function () {
return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
}
Tooltip.prototype.validate = function () {
if (!this.$element[0].parentNode) {
this.hide()
this.$element = null
this.options = null
}
}
Tooltip.prototype.enable = function () {
this.enabled = true
}
Tooltip.prototype.disable = function () {
this.enabled = false
}
Tooltip.prototype.toggleEnabled = function () {
this.enabled = !this.enabled
}
Tooltip.prototype.toggle = function (e) {
var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
}
Tooltip.prototype.destroy = function () {
clearTimeout(this.timeout)
this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
}
// TOOLTIP PLUGIN DEFINITION
// =========================
var old = $.fn.tooltip
$.fn.tooltip = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tooltip')
var options = typeof option == 'object' && option
if (!data && option == 'destroy') return
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tooltip.Constructor = Tooltip
// TOOLTIP NO CONFLICT
// ===================
$.fn.tooltip.noConflict = function () {
$.fn.tooltip = old
return this
}
}(jQuery);

2
libs/tooltip.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,13 +6,12 @@ var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
* *
* @param data the data object from which we obtain the stream, * @param data the data object from which we obtain the stream,
* the peerjid, etc. * the peerjid, etc.
* @param sid the session id
* @param ssrc the ssrc corresponding to this MediaStream * @param ssrc the ssrc corresponding to this MediaStream
* @param mute the whether this MediaStream is muted * @param mute the whether this MediaStream is muted
* *
* @constructor * @constructor
*/ */
function MediaStream(data, sid, ssrc, browser, eventEmitter, mute) { function MediaStream(data, ssrc, browser, eventEmitter, muted) {
// XXX(gp) to minimize headaches in the future, we should build our // XXX(gp) to minimize headaches in the future, we should build our
// abstractions around tracks and not streams. ORTC is track based API. // abstractions around tracks and not streams. ORTC is track based API.
@ -24,14 +23,13 @@ function MediaStream(data, sid, ssrc, browser, eventEmitter, mute) {
// Also, we should be able to associate multiple SSRCs with a MediaTrack as // Also, we should be able to associate multiple SSRCs with a MediaTrack as
// a track might have an associated RTX and FEC sources. // a track might have an associated RTX and FEC sources.
this.sid = sid;
this.stream = data.stream; this.stream = data.stream;
this.peerjid = data.peerjid; this.peerjid = data.peerjid;
this.videoType = data.videoType; this.videoType = data.videoType;
this.ssrc = ssrc; this.ssrc = ssrc;
this.type = (this.stream.getVideoTracks().length > 0)? this.type = (this.stream.getVideoTracks().length > 0)?
MediaStreamType.VIDEO_TYPE : MediaStreamType.AUDIO_TYPE; MediaStreamType.VIDEO_TYPE : MediaStreamType.AUDIO_TYPE;
this.muted = mute; this.muted = muted;
this.eventEmitter = eventEmitter; this.eventEmitter = eventEmitter;
} }

View File

@ -101,7 +101,7 @@ var RTC = {
} }
} }
}, },
createRemoteStream: function (data, sid, thessrc) { createRemoteStream: function (data, ssrc) {
var jid = data.peerjid || APP.xmpp.myJid(); var jid = data.peerjid || APP.xmpp.myJid();
// check the video muted state from last stored presence if any // check the video muted state from last stored presence if any
@ -111,7 +111,7 @@ var RTC = {
muted = pres.videoMuted; muted = pres.videoMuted;
} }
var remoteStream = new MediaStream(data, sid, thessrc, var remoteStream = new MediaStream(data, ssrc,
RTCBrowserType.getBrowserType(), eventEmitter, muted); RTCBrowserType.getBrowserType(), eventEmitter, muted);
if(!this.remoteStreams[jid]) { if(!this.remoteStreams[jid]) {

View File

@ -259,8 +259,7 @@ function RTCUtils(RTCService, onTemasysPluginReady)
attachMediaStream(elSel[0], stream); attachMediaStream(elSel[0], stream);
}; };
self.getStreamID = function (stream) { self.getStreamID = function (stream) {
var id = APP.xmpp.filter_special_chars(stream.label); return APP.xmpp.filter_special_chars(stream.label);
return id;
}; };
self.getVideoSrc = function (element) { self.getVideoSrc = function (element) {
if (!element) { if (!element) {

View File

@ -129,7 +129,7 @@ var defaultToolbarButtons = {
'invite': '#toolbar_button_link', 'invite': '#toolbar_button_link',
'chat': '#toolbar_button_chat', 'chat': '#toolbar_button_chat',
'prezi': '#toolbar_button_prezi', 'prezi': '#toolbar_button_prezi',
'ethherpad': '#toolbar_button_etherpad', 'etherpad': '#toolbar_button_etherpad',
'fullscreen': '#toolbar_button_fullScreen', 'fullscreen': '#toolbar_button_fullScreen',
'settings': '#toolbar_button_settings', 'settings': '#toolbar_button_settings',
'hangup': '#toolbar_button_hangup' 'hangup': '#toolbar_button_hangup'

View File

@ -168,6 +168,9 @@ RemoteVideo.prototype.removeRemoteStreamElement =
RemoteVideo.prototype.remove = function () { RemoteVideo.prototype.remove = function () {
console.log("Remove thumbnail", this.peerJid); console.log("Remove thumbnail", this.peerJid);
this.removeConnectionIndicator(); this.removeConnectionIndicator();
// Make sure that the large video is updated if are removing its
// corresponding small video.
this.VideoLayout.updateRemovedVideo(this.getResourceJid());
// Remove whole container // Remove whole container
if (this.container.parentNode) if (this.container.parentNode)
this.container.parentNode.removeChild(this.container); this.container.parentNode.removeChild(this.container);
@ -204,13 +207,13 @@ RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
sel[0].onplaying = onPlayingHandler; sel[0].onplaying = onPlayingHandler;
}; };
RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) { RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
if (!this.container) if (!this.container)
return; return;
var self = this; var self = this;
var isVideo = stream.getVideoTracks().length > 0; var isVideo = stream.getVideoTracks().length > 0;
var streamElement = SmallVideo.createStreamElement(sid, stream); var streamElement = SmallVideo.createStreamElement(stream);
var newElementId = streamElement.id; var newElementId = streamElement.id;
// Put new stream element always in front // Put new stream element always in front
@ -233,19 +236,6 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
}; };
/**
* FF is missing onended event for remote streams. The problem we are fixing
* here is when the last participant leaves the room the video element is
* not updated. So the avatar or last video frame will stay, the fix updates
* the video elem and switches to local video the same as behavior in other
* browsers.
*/
if (RTCBrowserType.isFirefox()) {
APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, function (jid) {
self.removeRemoteStreamElement(stream, isVideo, newElementId);
});
}
// Add click handler. // Add click handler.
var onClickHandler = function (event) { var onClickHandler = function (event) {

View File

@ -102,20 +102,21 @@ SmallVideo.prototype.setPresenceStatus = function (statusMsg) {
}; };
/** /**
* Creates an audio or video stream element. * Creates an audio or video element for a particular MediaStream.
*/ */
SmallVideo.createStreamElement = function (sid, stream) { SmallVideo.createStreamElement = function (stream) {
var isVideo = stream.getVideoTracks().length > 0; var isVideo = stream.getVideoTracks().length > 0;
var element = isVideo ? document.createElement('video') var element = isVideo ? document.createElement('video')
: document.createElement('audio'); : document.createElement('audio');
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') + sid + '_' +
APP.RTC.getStreamID(stream);
element.id = id;
if (!RTCBrowserType.isIExplorer()) { if (!RTCBrowserType.isIExplorer()) {
element.autoplay = true; element.autoplay = true;
} }
element.id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') +
APP.RTC.getStreamID(stream);
element.oncontextmenu = function () { return false; }; element.oncontextmenu = function () { return false; };
return element; return element;

View File

@ -126,12 +126,11 @@ var VideoLayout = (function (my) {
/** /**
* Checks if removed video is currently displayed and tries to display * Checks if removed video is currently displayed and tries to display
* another one instead. * another one instead.
* @param removedVideoSrc src stream identifier of the video.
*/ */
my.updateRemovedVideo = function(resourceJid) { my.updateRemovedVideo = function(resourceJid) {
var newResourceJid;
if (resourceJid === LargeVideo.getResourceJid()) { if (resourceJid === LargeVideo.getResourceJid()) {
var newResourceJid;
// We'll show user's avatar if he is the dominant speaker or if // We'll show user's avatar if he is the dominant speaker or if
// his video thumbnail is pinned // his video thumbnail is pinned
if (remoteVideos[resourceJid] && if (remoteVideos[resourceJid] &&
@ -153,18 +152,32 @@ var VideoLayout = (function (my) {
var pick = $('#remoteVideos>span[id!="mixedstream"]:visible:last'); var pick = $('#remoteVideos>span[id!="mixedstream"]:visible:last');
if (pick.length) { if (pick.length) {
jid = VideoLayout.getPeerContainerResourceJid(pick[0]); jid = VideoLayout.getPeerContainerResourceJid(pick[0]);
} else { if (!remoteVideos[jid]) {
// The RemoteVideo was removed (but the DOM elements may still
// exist).
jid = null;
}
}
if (!jid) {
console.info("Last visible video no longer exists"); console.info("Last visible video no longer exists");
pick = $('#remoteVideos>span[id!="mixedstream"]'); pick = $('#remoteVideos>span[id!="mixedstream"]');
if (pick.length) { if (pick.length) {
jid = VideoLayout.getPeerContainerResourceJid(pick[0]); jid = VideoLayout.getPeerContainerResourceJid(pick[0]);
if (!remoteVideos[jid]) {
// The RemoteVideo was removed (but the DOM elements may
// still exist).
jid = null;
} }
}
}
if (!jid) { if (!jid) {
// Go with local video // Go with local video
console.info("Fallback to local video..."); console.info("Fallback to local video...");
jid = APP.xmpp.myResource(); jid = APP.xmpp.myResource();
} }
}
console.info("electLastVisibleVideo: " + jid); console.info("electLastVisibleVideo: " + jid);
return jid; return jid;
}; };
@ -175,9 +188,7 @@ var VideoLayout = (function (my) {
var resourceJid = Strophe.getResourceFromJid(stream.peerjid); var resourceJid = Strophe.getResourceFromJid(stream.peerjid);
remoteVideos[resourceJid].addRemoteStreamElement( remoteVideos[resourceJid].addRemoteStreamElement(
stream.sid, stream.getOriginalStream());
stream.getOriginalStream(),
stream.ssrc);
} }
}; };
@ -832,8 +843,7 @@ var VideoLayout = (function (my) {
focusedVideoResourceJid = null; focusedVideoResourceJid = null;
} }
if (currentDominantSpeaker === resourceJid) if (currentDominantSpeaker === resourceJid) {
{
console.info("Dominant speaker has left the conference"); console.info("Dominant speaker has left the conference");
currentDominantSpeaker = null; currentDominantSpeaker = null;
} }
@ -842,8 +852,8 @@ var VideoLayout = (function (my) {
if (remoteVideo) { if (remoteVideo) {
// Remove remote video // Remove remote video
console.info("Removing remote video: " + resourceJid); console.info("Removing remote video: " + resourceJid);
remoteVideo.remove();
delete remoteVideos[resourceJid]; delete remoteVideos[resourceJid];
remoteVideo.remove();
} else { } else {
console.warn("No remote video for " + resourceJid); console.warn("No remote video for " + resourceJid);
} }

View File

@ -135,7 +135,8 @@ module.exports = {
isUsingScreenStream = false; isUsingScreenStream = false;
newStreamCreated(stream); newStreamCreated(stream);
}, },
getVideoStreamFailed, config.resolution || '360' getVideoStreamFailed,
config.resolution || '360'
); );
} }
}, },

View File

@ -36,16 +36,33 @@ if (supportsLocalStorage()) {
} }
var Settings = { var Settings = {
/**
* Sets the local user display name and saves it to local storage
*
* @param newDisplayName the new display name for the local user
* @returns {string} the display name we just set
*/
setDisplayName: function (newDisplayName) { setDisplayName: function (newDisplayName) {
displayName = newDisplayName; displayName = newDisplayName;
window.localStorage.displayname = displayName; window.localStorage.displayname = displayName;
return displayName; return displayName;
}, },
/**
* Returns the currently used by the user
* @returns {string} currently valid user display name.
*/
getDisplayName: function () {
return displayName;
},
setEmail: function (newEmail) { setEmail: function (newEmail) {
email = newEmail; email = newEmail;
window.localStorage.email = newEmail; window.localStorage.email = newEmail;
return email; return email;
}, },
getSettings: function () { getSettings: function () {
return { return {
email: email, email: email,

View File

@ -1,4 +1,6 @@
/* global config, $, APP, Strophe, callstats */ /* global config, $, APP, Strophe, callstats */
var Settings = require('../settings/Settings');
var jsSHA = require('jssha'); var jsSHA = require('jssha');
var io = require('socket.io-client'); var io = require('socket.io-client');
var callStats = null; var callStats = null;
@ -20,6 +22,10 @@ var CallStats = {
this.userID = APP.xmpp.myResource(); this.userID = APP.xmpp.myResource();
//use whatever the user said to facilitate debugging
if(Settings.getDisplayName())
this.userID = Settings.getDisplayName();
var location = window.location; var location = window.location;
this.confID = location.hostname + location.pathname; this.confID = location.hostname + location.pathname;

View File

@ -108,21 +108,22 @@ JingleSessionPC.prototype.doInitialize = function () {
self.sendIceCandidate(event.candidate); self.sendIceCandidate(event.candidate);
}; };
this.peerconnection.onaddstream = function (event) { this.peerconnection.onaddstream = function (event) {
if (event.stream.id !== 'default') { if (event.stream.id === 'default') {
console.log("REMOTE STREAM ADDED: ", event.stream , event.stream.id);
self.remoteStreamAdded(event);
} else {
// This is a recvonly stream. Clients that implement Unified Plan, // This is a recvonly stream. Clients that implement Unified Plan,
// such as Firefox use recvonly "streams/channels/tracks" for // such as Firefox use recvonly "streams/channels/tracks" for
// receiving remote stream/tracks, as opposed to Plan B where there // receiving remote stream/tracks, as opposed to Plan B where there
// are only 3 channels: audio, video and data. // are only 3 channels: audio, video and data.
console.log("RECVONLY REMOTE STREAM IGNORED: " + event.stream + " - " + event.stream.id); console.log("RECVONLY REMOTE STREAM IGNORED: " + event.stream +
" - " + event.stream.id);
return;
} }
console.log("REMOTE STREAM ADDED: ", event.stream, event.stream.id);
self.remoteStreamAdded(event);
}; };
this.peerconnection.onremovestream = function (event) { this.peerconnection.onremovestream = function (event) {
// Remove the stream from remoteStreams // Remove the stream from remoteStreams?
// FIXME: remotestreamremoved.jingle not defined anywhere(unused) console.log("We are ignoring a removestream event: " + event);
$(document).trigger('remotestreamremoved.jingle', [event, self.sid]);
}; };
this.peerconnection.onsignalingstatechange = function (event) { this.peerconnection.onsignalingstatechange = function (event) {
if (!(self && self.peerconnection)) return; if (!(self && self.peerconnection)) return;
@ -857,7 +858,11 @@ JingleSessionPC.prototype.sendTerminate = function (reason, text) {
} }
}; };
JingleSessionPC.prototype.addSource = function (elem, fromJid) { /**
* Handles a Jingle source-add message for this Jingle session.
* @param elem An array of Jingle "content" elements.
*/
JingleSessionPC.prototype.addSource = function (elem) {
var self = this; var self = this;
// FIXME: dirty waiting // FIXME: dirty waiting
@ -865,7 +870,7 @@ JingleSessionPC.prototype.addSource = function (elem, fromJid) {
console.warn("addSource - localDescription not ready yet"); console.warn("addSource - localDescription not ready yet");
setTimeout(function() setTimeout(function()
{ {
self.addSource(elem, fromJid); self.addSource(elem);
}, },
200 200
); );
@ -938,14 +943,18 @@ JingleSessionPC.prototype.addSource = function (elem, fromJid) {
}); });
}; };
JingleSessionPC.prototype.removeSource = function (elem, fromJid) { /**
* Handles a Jingle source-remove message for this Jingle session.
* @param elem An array of Jingle "content" elements.
*/
JingleSessionPC.prototype.removeSource = function (elem) {
var self = this; var self = this;
// FIXME: dirty waiting // FIXME: dirty waiting
if (!this.peerconnection.localDescription) { if (!this.peerconnection.localDescription) {
console.warn("removeSource - localDescription not ready yet"); console.warn("removeSource - localDescription not ready yet");
setTimeout(function() { setTimeout(function() {
self.removeSource(elem, fromJid); self.removeSource(elem);
}, },
200 200
); );
@ -1440,24 +1449,29 @@ function sendKeyframe(pc) {
); );
} }
/**
JingleSessionPC.prototype.remoteStreamAdded = function (data, times) { * Handles 'onaddstream' events from the RTCPeerConnection.
* @param event the 'onaddstream' event.
*/
JingleSessionPC.prototype.remoteStreamAdded = function (event) {
var self = this; var self = this;
var thessrc; var ssrc;
var streamId = APP.RTC.getStreamID(data.stream); var ssrclines;
var streamId = APP.RTC.getStreamID(event.stream);
// look up an associated JID for a stream id // look up an associated JID for a stream id
if (!streamId) { if (!streamId) {
console.error("No stream ID for", data.stream); console.error("No stream ID for", event.stream);
} else if (streamId && streamId.indexOf('mixedmslabel') === -1) { } else if (streamId.indexOf('mixedmslabel') === -1) {
// look only at a=ssrc: and _not_ at a=ssrc-group: lines // look only at a=ssrc: and _not_ at a=ssrc-group: lines
var ssrclines ssrclines = SDPUtil.find_lines(
= SDPUtil.find_lines(this.peerconnection.remoteDescription.sdp, 'a=ssrc:'); this.peerconnection.remoteDescription.sdp,
'a=ssrc:');
ssrclines = ssrclines.filter(function (line) { ssrclines = ssrclines.filter(function (line) {
// NOTE(gp) previously we filtered on the mslabel, but that property // NOTE(gp) previously we filtered on the mslabel, but that property
// is not always present. // is not always present.
// return line.indexOf('mslabel:' + data.stream.label) !== -1; // return line.indexOf('mslabel:' + event.stream.label) !== -1;
if (RTCBrowserType.isTemasysPluginUsed()) { if (RTCBrowserType.isTemasysPluginUsed()) {
return ((line.indexOf('mslabel:' + streamId) !== -1)); return ((line.indexOf('mslabel:' + streamId) !== -1));
@ -1466,33 +1480,21 @@ JingleSessionPC.prototype.remoteStreamAdded = function (data, times) {
} }
}); });
if (ssrclines.length) { if (ssrclines.length) {
thessrc = ssrclines[0].substring(7).split(' ')[0]; ssrc = ssrclines[0].substring(7).split(' ')[0];
if (!self.ssrcOwners[thessrc]) { if (!self.ssrcOwners[ssrc]) {
console.error("No SSRC owner known for: " + thessrc); console.error("No SSRC owner known for: " + ssrc);
return; return;
} }
data.peerjid = self.ssrcOwners[thessrc]; event.peerjid = self.ssrcOwners[ssrc];
console.log('associated jid', self.ssrcOwners[thessrc]); console.log('Adding remote stream, SSRC ' + ssrc +
', associated jid ' + event.peerjid);
} else { } else {
console.error("No SSRC lines for ", streamId); console.error("No SSRC lines for ", streamId);
} }
} }
APP.RTC.createRemoteStream(data, this.sid, thessrc); APP.RTC.createRemoteStream(event, ssrc);
var isVideo = data.stream.getVideoTracks().length > 0;
// an attempt to work around https://github.com/jitsi/jitmeet/issues/32
// TODO: is this hack still needed now that we announce an SSRC for
// receive-only streams?
if (isVideo &&
data.peerjid && this.peerjid === data.peerjid &&
data.stream.getVideoTracks().length === 0 &&
APP.RTC.localVideo.getTracks().length > 0) {
window.setTimeout(function () {
sendKeyframe(self.peerconnection);
}, 3000);
}
}; };
module.exports = JingleSessionPC; module.exports = JingleSessionPC;

View File

@ -174,11 +174,11 @@ module.exports = function(XMPP, eventEmitter) {
break; break;
case 'addsource': // FIXME: proprietary, un-jingleish case 'addsource': // FIXME: proprietary, un-jingleish
case 'source-add': // FIXME: proprietary case 'source-add': // FIXME: proprietary
sess.addSource($(iq).find('>jingle>content'), fromJid); sess.addSource($(iq).find('>jingle>content'));
break; break;
case 'removesource': // FIXME: proprietary, un-jingleish case 'removesource': // FIXME: proprietary, un-jingleish
case 'source-remove': // FIXME: proprietary case 'source-remove': // FIXME: proprietary
sess.removeSource($(iq).find('>jingle>content'), fromJid); sess.removeSource($(iq).find('>jingle>content'));
break; break;
default: default:
console.warn('jingle action not implemented', action); console.warn('jingle action not implemented', action);

View File

@ -16,27 +16,84 @@
"readmeFilename": "README.md", "readmeFilename": "README.md",
"//": "Callstats.io does not work with recent versions of jsSHA (2.0.1 in particular)", "//": "Callstats.io does not work with recent versions of jsSHA (2.0.1 in particular)",
"dependencies": { "dependencies": {
"events": "*",
"pako": "*",
"i18next-client": "1.7.7",
"sdp-interop": "0.1.10",
"sdp-transform": "1.4.1",
"sdp-simulcast": "0.1.0",
"async": "0.9.0", "async": "0.9.0",
"retry": "0.6.1", "autosize": "^1.18.13",
"bootstrap": "^3.1.1",
"events": "*",
"i18next-client": "1.7.7",
"jquery": "^2.1.1",
"jQuery-Impromptu": "git+https://github.com/trentrichardson/jQuery-Impromptu.git#v6.0.0",
"jquery-ui": "^1.10.5",
"jssha": "1.5.0", "jssha": "1.5.0",
"socket.io-client": "1.3.6" "pako": "*",
"retry": "0.6.1",
"sdp-interop": "0.1.10",
"sdp-simulcast": "0.1.0",
"sdp-transform": "1.4.1",
"socket.io-client": "1.3.6",
"strophe": "^1.2.2",
"strophejs-plugins": "^0.0.6",
"toastr": "^2.0.3"
}, },
"devDependencies": { "devDependencies": {
"precommit-hook": "3.0.0",
"jshint": "2.8.0",
"uglify-js": "2.4.24",
"browserify": "11.1.x", "browserify": "11.1.x",
"exorcist": "*" "browserify-shim": "^3.8.10",
"exorcist": "*",
"jshint": "2.8.0",
"precommit-hook": "3.0.0",
"uglify-js": "2.4.24"
}, },
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {
"lint": "./node_modules/.bin/jshint ." "lint": "./node_modules/.bin/jshint .",
"validate": "npm ls"
}, },
"pre-commit": ["lint"] "pre-commit": [
"lint"
],
"browserify": {
"transform": [
"browserify-shim"
]
},
"browser": {
"jquery": "./node_modules/jquery/dist/jquery.js",
"jquery-ui": "./node_modules/jquery-ui/jquery-ui.js",
"strophe": "./node_modules/strophe/strophe.js",
"strophe-disco": "./node_modules/strophejs-plugins/disco/strophe.disco.js",
"strophe-caps": "./node_modules/strophejs-plugins/caps/strophe.caps.jsonly.js",
"toastr": "./node_modules/toastr/toastr.js",
"tooltip": "./node_modules/bootstrap/js/tooltip.js",
"popover": "./node_modules/bootstrap/js/popover.js",
"jQuery-Impromptu": "./node_modules/jQuery-Impromptu/dist/jquery-impromptu.js",
"autosize": "./node_modules/autosize/build/jquery.autosize.js"
},
"browserify-shim": {
"jquery": [
"$"
],
"strophe": {
"exports": "Strophe",
"depends": [
"jquery:$"
]
},
"strophe-disco": {
"depends": [
"strophe:Strophe"
]
},
"tooltip": {
"depends": "jquery:jQuery"
},
"popover": {
"depends": "jquery:jQuery"
},
"jQuery-Impromptu": {
"depends": "jquery:jQuery"
},
"autosize": {
"depends": "jquery:jQuery"
}
}
} }