pull/6539/head
Guilherme Gazzo 8 years ago
parent 7a2e9f7786
commit a8ad6397ef
  1. 91
      packages/rocketchat-ui/client/lib/accountBox.coffee
  2. 106
      packages/rocketchat-ui/client/lib/accountBox.js
  3. 6
      packages/rocketchat-ui/client/lib/accounts.coffee
  4. 9
      packages/rocketchat-ui/client/lib/accounts.js
  5. 26
      packages/rocketchat-ui/client/lib/avatar.coffee
  6. 31
      packages/rocketchat-ui/client/lib/avatar.js
  7. 29
      packages/rocketchat-ui/client/lib/cordova/facebook-login.coffee
  8. 31
      packages/rocketchat-ui/client/lib/cordova/facebook-login.js
  9. 25
      packages/rocketchat-ui/client/lib/cordova/keyboard-fix.coffee
  10. 32
      packages/rocketchat-ui/client/lib/cordova/keyboard-fix.js
  11. 53
      packages/rocketchat-ui/client/lib/menu.coffee
  12. 55
      packages/rocketchat-ui/client/lib/menu.js
  13. 145
      packages/rocketchat-ui/client/lib/sideNav.coffee
  14. 176
      packages/rocketchat-ui/client/lib/sideNav.js
  15. 15
      packages/rocketchat-ui/client/lib/tapi18n.coffee
  16. 23
      packages/rocketchat-ui/client/lib/tapi18n.js
  17. 52
      packages/rocketchat-ui/client/views/app/privateHistory.coffee
  18. 97
      packages/rocketchat-ui/client/views/app/privateHistory.js
  19. 23
      packages/rocketchat-ui/client/views/app/videoCall/videoButtons.coffee
  20. 39
      packages/rocketchat-ui/client/views/app/videoCall/videoButtons.js
  21. 121
      packages/rocketchat-ui/client/views/app/videoCall/videoCall.coffee
  22. 129
      packages/rocketchat-ui/client/views/app/videoCall/videoCall.js
  23. 22
      packages/rocketchat-ui/package.js

@ -1,91 +0,0 @@
@AccountBox = (->
status = 0
self = {}
items = new ReactiveVar []
setStatus = (status) ->
Meteor.call('UserPresence:setDefaultStatus', status)
toggle = ->
if status then close() else open()
open = ->
if SideNav.flexStatus()
SideNav.closeFlex()
return;
status = 1
self.options.removeClass("animated-hidden")
self.box.addClass("active")
SideNav.toggleArrow 1
close = ->
status = 0
self.options.addClass("animated-hidden")
self.box.removeClass("active")
SideNav.toggleArrow -1
openFlex = ->
status = 0
self.options.addClass("animated-hidden")
self.box.removeClass("active")
init = ->
self.box = $(".account-box")
self.options = self.box.find(".options")
###
# @param newOption:
# name: Button label
# icon: Button icon
# class: Class of the item
# permissions: Which permissions a user should have (all of them) to see this item
###
addItem = (newItem) ->
Tracker.nonreactive ->
actual = items.get()
actual.push newItem
items.set actual
checkCondition = (item) ->
return not item.condition? or item.condition()
getItems = ->
return _.filter items.get(), (item) ->
if checkCondition(item)
return true
addRoute = (newRoute, router = FlowRouter) ->
# @TODO check for mandatory fields
routeConfig =
center: 'pageContainer'
pageTemplate: newRoute.pageTemplate
if newRoute.i18nPageTitle?
routeConfig.i18nPageTitle = newRoute.i18nPageTitle
if newRoute.pageTitle?
routeConfig.pageTitle = newRoute.pageTitle
router.route newRoute.path,
name: newRoute.name
action: ->
Session.set 'openedRoom'
BlazeLayout.render 'main', routeConfig
triggersEnter: [ ->
if newRoute.sideNav?
SideNav.setFlex newRoute.sideNav
SideNav.openFlex()
]
setStatus: setStatus
toggle: toggle
open: open
close: close
openFlex: openFlex
init: init
addRoute: addRoute
addItem: addItem
getItems: getItems
)()

@ -0,0 +1,106 @@
this.AccountBox = (function() {
let status = 0;
const self = {};
const items = new ReactiveVar([]);
function setStatus(status) {
return Meteor.call('UserPresence:setDefaultStatus', status);
}
function open() {
if (SideNav.flexStatus()) {
SideNav.closeFlex();
return;
}
status = 1;
self.options.removeClass('animated-hidden');
self.box.addClass('active');
return SideNav.toggleArrow(1);
}
function close() {
status = 0;
self.options.addClass('animated-hidden');
self.box.removeClass('active');
return SideNav.toggleArrow(-1);
}
function toggle() {
if (status) {
return close();
} else {
return open();
}
}
function openFlex() {
status = 0;
self.options.addClass('animated-hidden');
return self.box.removeClass('active');
}
function init() {
self.box = $('.account-box');
return self.options = self.box.find('.options');
}
/*
* @param newOption:
* name: Button label
* icon: Button icon
* class: Class of the item
* permissions: Which permissions a user should have (all of them) to see this item
*/
function addItem(newItem) {
return Tracker.nonreactive(function() {
const actual = items.get();
actual.push(newItem);
return items.set(actual);
});
}
function checkCondition(item) {
return (item.condition == null) || item.condition();
}
function getItems() {
return _.filter(items.get(), function(item) {
if (checkCondition(item)) {
return true;
}
});
}
function addRoute(newRoute, router) {
if (router == null) {
router = FlowRouter;
}
const routeConfig = {
center: 'pageContainer',
pageTemplate: newRoute.pageTemplate
};
if (newRoute.i18nPageTitle != null) {
routeConfig.i18nPageTitle = newRoute.i18nPageTitle;
}
if (newRoute.pageTitle != null) {
routeConfig.pageTitle = newRoute.pageTitle;
}
return router.route(newRoute.path, {
name: newRoute.name,
action() {
Session.set('openedRoom');
return BlazeLayout.render('main', routeConfig);
},
triggersEnter: [
function() {
if (newRoute.sideNav != null) {
SideNav.setFlex(newRoute.sideNav);
return SideNav.openFlex();
}
}
]
});
}
return {
setStatus,
toggle,
open,
close,
openFlex,
init,
addRoute,
addItem,
getItems
};
}());

@ -1,6 +0,0 @@
import toastr from 'toastr'
Accounts.onEmailVerificationLink (token, done) ->
Accounts.verifyEmail token, (error) ->
if not error?
toastr.success t('Email_verified')
done()

@ -0,0 +1,9 @@
import toastr from 'toastr';
Accounts.onEmailVerificationLink(function(token, done) {
Accounts.verifyEmail(token, function(error) {
if (error == null) {
toastr.success(t('Email_verified'));
}
return done();
});
});

@ -1,26 +0,0 @@
Blaze.registerHelper 'avatarUrlFromUsername', getAvatarUrlFromUsername
@getAvatarAsPng = (username, cb) ->
image = new Image
image.src = getAvatarUrlFromUsername(username)
image.onload = ->
canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
context = canvas.getContext('2d')
context.drawImage(image, 0, 0)
cb canvas.toDataURL('image/png')
image.onerror = ->
cb ''
@updateAvatarOfUsername = (username) ->
key = "avatar_random_#{username}"
Session.set key, Math.round(Math.random() * 1000)
for key, room of RoomManager.openedRooms
url = getAvatarUrlFromUsername username
$(room.dom).find(".message[data-username='#{username}'] .avatar-image").css('background-image', "url(#{url})");
return true

@ -0,0 +1,31 @@
Blaze.registerHelper('avatarUrlFromUsername', getAvatarUrlFromUsername);
this.getAvatarAsPng = function(username, cb) {
const image = new Image;
image.src = getAvatarUrlFromUsername(username);
image.onload = function() {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
return cb(canvas.toDataURL('image/png'));
};
return image.onerror = function() {
return cb('');
};
};
this.updateAvatarOfUsername = function(username) {
const key = `avatar_random_${ username }`;
Session.set(key, Math.round(Math.random() * 1000));
Object.keys(RoomManager.openedRooms).forEach((key) => {
const room = RoomManager.openedRooms[key];
const url = getAvatarUrlFromUsername(username);
$(room.dom).find(`.message[data-username='${ username }'] .avatar-image`).css('background-image', `url(${ url })`);
});
return true;
};

@ -1,29 +0,0 @@
Meteor.loginWithFacebookCordova = (options, callback) ->
if not callback and typeof options is "function"
callback = options
options = null
credentialRequestCompleteCallback = Accounts.oauth.credentialRequestCompleteHandler(callback)
fbLoginSuccess = (data) ->
data.cordova = true
Accounts.callLoginMethod
methodArguments: [data]
userCallback: callback
if typeof facebookConnectPlugin isnt "undefined"
facebookConnectPlugin.getLoginStatus (response) ->
if response.status isnt "connected"
facebookConnectPlugin.login ["public_profile", "email"], fbLoginSuccess, (error) ->
console.log('login', JSON.stringify(error), error)
callback(error)
else
fbLoginSuccess(response)
, (error) ->
console.log('getLoginStatus', JSON.stringify(error), error)
callback(error)
else
Facebook.requestCredential(options, credentialRequestCompleteCallback)

@ -0,0 +1,31 @@
/* globals facebookConnectPlugin Facebook*/
Meteor.loginWithFacebookCordova = function(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = null;
}
const credentialRequestCompleteCallback = Accounts.oauth.credentialRequestCompleteHandler(callback);
const fbLoginSuccess = function(data) {
data.cordova = true;
return Accounts.callLoginMethod({
methodArguments: [data],
userCallback: callback
});
};
if (typeof facebookConnectPlugin !== 'undefined') {
return facebookConnectPlugin.getLoginStatus(function(response) {
if (response.status !== 'connected') {
return facebookConnectPlugin.login(['public_profile', 'email'], fbLoginSuccess, function(error) {
console.log('login', JSON.stringify(error), error);
return callback(error);
});
} else {
return fbLoginSuccess(response);
}
}, function(error) {
console.log('getLoginStatus', JSON.stringify(error), error);
return callback(error);
});
}
return Facebook.requestCredential(options, credentialRequestCompleteCallback);
};

@ -1,25 +0,0 @@
if Meteor.isCordova
document.addEventListener 'deviceready', ->
if device?.platform.toLowerCase() isnt 'android'
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
window.addEventListener 'native.keyboardshow', ->
if device?.platform.toLowerCase() isnt 'android'
if Meteor.userId()?
$('.main-content').css 'height', window.innerHeight
$('.sweet-alert').css 'transform', "translateY(-#{(document.height - window.innerHeight) / 2}px)"
$('.sweet-alert').css '-webkit-transform', "translateY(-#{(document.height - window.innerHeight) / 2}px)"
else
$(document.body).css 'height', window.innerHeight
$(document.body).css 'overflow', 'scroll'
window.addEventListener 'native.keyboardhide', ->
if device?.platform.toLowerCase() isnt 'android'
if Meteor.userId()?
$('.main-content').css 'height', window.innerHeight
$('.sweet-alert').css 'transform', ''
$('.sweet-alert').css '-webkit-transform', ''
else
$(document.body).css 'height', window.innerHeight
$(document.body).css 'overflow', 'visible'

@ -0,0 +1,32 @@
/* globals device cordova*/
if (Meteor.isCordova) {
const body = $(document.body);
document.addEventListener('deviceready', function() {
if (typeof device !== 'undefined' && device !== null && device.platform.toLowerCase() !== 'android') {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
return cordova.plugins.Keyboard.disableScroll(true);
}
});
window.addEventListener('native.keyboardshow', function() {
if (typeof device !== 'undefined' && device !== null && device.platform.toLowerCase() !== 'android') {
if (Meteor.userId() != null) {
$('.main-content').css('height', window.innerHeight);
$('.sweet-alert').css('transform', `translateY(-${ (document.height - window.innerHeight) / 2 }px)`).css('-webkit-transform', `translateY(-${ (document.height - window.innerHeight) / 2 }px)`);
} else {
body.css('height', window.innerHeight);
body.css('overflow', 'scroll');
}
}
});
window.addEventListener('native.keyboardhide', function() {
if (typeof device !== 'undefined' && device !== null && device.platform.toLowerCase() !== 'android') {
if (Meteor.userId() != null) {
$('.main-content').css('height', window.innerHeight);
$('.sweet-alert').css('transform', '').css('-webkit-transform', '');
} else {
body.css('height', window.innerHeight);
body.css('overflow', 'visible');
}
}
});
}

@ -1,53 +0,0 @@
@menu = new class
init: ->
@mainContent = $('.main-content')
@list = $('.rooms-list')
Session.set("isMenuOpen", false)
isOpen: ->
return Session.get("isMenuOpen")
open: ->
Session.set("isMenuOpen", true)
if isRtl localStorage.getItem "userLanguage"
@mainContent?.css('transform', 'translateX(-260px)')
else
@mainContent?.css('transform', 'translateX(260px)')
close: ->
Session.set("isMenuOpen", false)
@mainContent?.css('transform', 'translateX(0)')
toggle: ->
if @isOpen()
@close()
else
@open()
updateUnreadBars: _.throttle ->
if not @list?
return
listOffset = @list.offset()
listHeight = @list.height()
showTop = false
showBottom = false
$('li.has-alert').each ->
if $(this).offset().top < listOffset.top - $(this).height()
showTop = true
if $(this).offset().top > listOffset.top + listHeight
showBottom = true
if showTop is true
$('.top-unread-rooms').removeClass('hidden')
else
$('.top-unread-rooms').addClass('hidden')
if showBottom is true
$('.bottom-unread-rooms').removeClass('hidden')
else
$('.bottom-unread-rooms').addClass('hidden')
, 200

@ -0,0 +1,55 @@
/* globals isRtl */
this.menu = new class {
constructor() {
this.updateUnreadBars = _.throttle(() => {
if (this.list == null) {
return;
}
const listOffset = this.list.offset();
const listHeight = this.list.height();
let showTop = false;
let showBottom = false;
$('li.has-alert').each(function() {
if ($(this).offset().top < listOffset.top - $(this).height()) {
showTop = true;
}
if ($(this).offset().top > listOffset.top + listHeight) {
return showBottom = true;
}
});
if (showTop === true) {
$('.top-unread-rooms').removeClass('hidden');
} else {
$('.top-unread-rooms').addClass('hidden');
}
if (showBottom === true) {
return $('.bottom-unread-rooms').removeClass('hidden');
} else {
return $('.bottom-unread-rooms').addClass('hidden');
}
}, 200);
}
init() {
this.mainContent = $('.main-content');
this.list = $('.rooms-list');
Session.set('isMenuOpen', false);
}
isOpen() {
return Session.get('isMenuOpen');
}
open() {
Session.set('isMenuOpen', true);
this.mainContent && this.mainContent.css('transform', `translateX(${ isRtl(localStorage.getItem('userLanguage'))?'-':'' }260px)`);
}
close() {
Session.set('isMenuOpen', false);
this.mainContent && this.mainContent .css('transform', 'translateX(0)');
}
toggle() {
return this.isOpen() ? this.close() : this.open();
}
};

@ -1,145 +0,0 @@
@SideNav = (->
initiated = false
sideNav = {}
flexNav = {}
arrow = {}
animating = false
openQueue = []
toggleArrow = (status = null) ->
if status is 0
arrow.addClass "close"
arrow.removeClass "top"
arrow.removeClass "bottom"
else if status is -1 or (status isnt 1 and arrow.hasClass "top")
arrow.removeClass "close"
arrow.removeClass "top"
arrow.addClass "bottom"
else
arrow.removeClass "close"
arrow.addClass "top"
arrow.removeClass "bottom"
toggleCurrent = ->
if flexNav.opened then closeFlex() else AccountBox.toggle()
overArrow = ->
arrow.addClass "hover"
leaveArrow = ->
arrow.removeClass "hover"
arrowBindHover = ->
arrow.on "mouseenter", ->
sideNav.find("header").addClass "hover"
arrow.on "mouseout", ->
sideNav.find("header").removeClass "hover"
focusInput = ->
sideNavDivs = _.filter document.querySelectorAll('aside.side-nav')[0].children, (ele) ->
ele.tagName == 'DIV' and !ele.classList.contains('hidden')
highestZidx = 0
highestZidxElem = undefined
_.each sideNavDivs, (ele) ->
zIndex = Number(window.getComputedStyle(ele).zIndex)
if Number(zIndex) > highestZidx
highestZidx = Number(zIndex)
highestZidxElem = ele
return
setTimeout ->
highestZidxElem.querySelector('input')?.focus()
, 200
return
validate = ->
invalid = []
sideNav.find("input.required").each ->
if not this.value.length
invalid.push $(this).prev("label").html()
if invalid.length
return invalid
return false;
toggleFlex = (status = null, callback = null) ->
return if animating == true
animating = true
if status is -1 or (status isnt 1 and flexNav.opened)
flexNav.opened = false
flexNav.addClass "animated-hidden"
else
flexNav.opened = true
# added a delay to make sure the template is already rendered before animating it
setTimeout ->
flexNav.removeClass "animated-hidden"
, 50
setTimeout ->
animating = false
callback?()
, 500
openFlex = (callback = null) ->
if not initiated
return openQueue.push { config: getFlex(), callback: callback }
return if animating == true
AccountBox.close()
toggleArrow 0
toggleFlex 1, callback
focusInput()
closeFlex = (callback = null) ->
if not RocketChat.roomTypes.getTypes().filter((i) -> i.route).map((i) -> i.route.name).includes(FlowRouter.current().route.name)
subscription = RocketChat.models.Subscriptions.findOne({rid: Session.get('openedRoom')})
if subscription?
RocketChat.roomTypes.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams);
else
FlowRouter.go('home')
return if animating == true
toggleArrow -1
toggleFlex -1, callback
flexStatus = ->
return flexNav.opened
setFlex = (template, data={}) ->
Session.set "flex-nav-template", template
Session.set "flex-nav-data", data
getFlex = ->
return {
template: Session.get "flex-nav-template"
data: Session.get "flex-nav-data"
}
init = ->
sideNav = $(".side-nav")
flexNav = sideNav.find ".flex-nav"
arrow = sideNav.children ".arrow"
setFlex ""
arrowBindHover()
initiated = true
if openQueue.length > 0
openQueue.forEach (item) ->
setFlex item.config.template, item.config.data
openFlex item.callback
openQueue = []
getSideNav = ->
return sideNav
init: init
setFlex: setFlex
getFlex: getFlex
openFlex: openFlex
closeFlex: closeFlex
validate: validate
flexStatus: flexStatus
toggleArrow: toggleArrow
toggleCurrent: toggleCurrent
overArrow: overArrow
leaveArrow: leaveArrow
getSideNav: getSideNav
)()

@ -0,0 +1,176 @@
this.SideNav = new class {
constructor() {
this.initiated = false;
this.sideNav = {};
this.flexNav = {};
this.arrow = {};
this.animating = false;
this.openQueue = [];
}
toggleArrow(status) {
if (status == null) {
status = null;
}
if (status === 0) {
this.arrow.addClass('close');
this.arrow.removeClass('top');
return this.arrow.removeClass('bottom');
} else if (status === -1 || (status !== 1 && this.arrow.hasClass('top'))) {
this.arrow.removeClass('close');
this.arrow.removeClass('top');
return this.arrow.addClass('bottom');
} else {
this.arrow.removeClass('close');
this.arrow.addClass('top');
return this.arrow.removeClass('bottom');
}
}
toggleFlex(status, callback) {
if (this.animating === true) {
return;
}
this.animating = true;
if (status === -1 || (status !== 1 && this.flexNav.opened)) {
this.flexNav.opened = false;
this.flexNav.addClass('animated-hidden');
} else {
this.flexNav.opened = true;
setTimeout(() => {
return this.flexNav.removeClass('animated-hidden');
}, 50);
}
return setTimeout(() => {
this.animating = false;
return typeof callback === 'function' && callback();
}, 500);
}
closeFlex(callback) {
let subscription;
if (callback == null) {
callback = null;
}
if (!RocketChat.roomTypes.getTypes().filter(function(i) {
return i.route;
}).map(function(i) {
return i.route.name;
}).includes(FlowRouter.current().route.name)) {
subscription = RocketChat.models.Subscriptions.findOne({
rid: Session.get('openedRoom')
});
if (subscription != null) {
RocketChat.roomTypes.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams);
} else {
FlowRouter.go('home');
}
}
if (this.animating === true) {
return;
}
this.toggleArrow(-1);
return this.toggleFlex(-1, callback);
}
flexStatus() {
return this.flexNav.opened;
}
setFlex(template, data) {
if (data == null) {
data = {};
}
Session.set('flex-nav-template', template);
return Session.set('flex-nav-data', data);
}
getFlex() {
return {
template: Session.get('flex-nav-template'),
data: Session.get('flex-nav-data')
};
}
toggleCurrent() {
if (this.flexNav && this.flexNav.opened) {
return this.closeFlex();
} else {
return AccountBox.toggle();
}
}
overArrow() {
return this.arrow.addClass('hover');
}
leaveArrow() {
return this.arrow.removeClass('hover');
}
arrowBindHover() {
this.arrow.on('mouseenter', () => {
return this.sideNav.find('header').addClass('hover');
});
return this.arrow.on('mouseout', () => {
return this.sideNav.find('header').removeClass('hover');
});
}
focusInput() {
const sideNavDivs = _.filter(document.querySelectorAll('aside.side-nav')[0].children, function(ele) {
return ele.tagName === 'DIV' && !ele.classList.contains('hidden');
});
let highestZidx = 0;
let highestZidxElem;
_.each(sideNavDivs, (ele) => {
const zIndex = Number(window.getComputedStyle(ele).zIndex);
if (Number(zIndex) > highestZidx) {
highestZidx = Number(zIndex);
highestZidxElem = ele;
}
});
setTimeout(() => {
const ref = highestZidxElem.querySelector('input');
return ref && ref.focus();
}, 200);
}
validate() {
const invalid = [];
this.sideNav.find('input.required').each(function() {
if (!this.value.length) {
return invalid.push($(this).prev('label').html());
}
});
if (invalid.length) {
return invalid;
}
return false;
}
openFlex(callback) {
if (!this.initiated) {
return this.openQueue.push({
config: this.getFlex(),
callback
});
}
if (this.animating === true) {
return;
}
AccountBox.close();
this.toggleArrow(0);
this.toggleFlex(1, callback);
return this.focusInput();
}
init() {
this.sideNav = $('.side-nav');
this.flexNav = this.sideNav.find('.flex-nav');
this.arrow = this.sideNav.children('.arrow');
this.setFlex('');
this.arrowBindHover();
this.initiated = true;
if (this.openQueue.length > 0) {
this.openQueue.forEach((item) => {
this.setFlex(item.config.template, item.config.data);
return this.openFlex(item.callback);
});
return this.openQueue = [];
}
}
getSideNav() {
return this.sideNav;
}
};

@ -1,15 +0,0 @@
@t = (key, replaces...) ->
if _.isObject replaces[0]
return TAPi18n.__ key, replaces
else
return TAPi18n.__ key, { postProcess: 'sprintf', sprintf: replaces }
@tr = (key, options, replaces...) ->
if _.isObject replaces[0]
return TAPi18n.__ key, options, replaces
else
return TAPi18n.__ key, options, { postProcess: 'sprintf', sprintf: replaces }
@isRtl = (language) ->
# https://en.wikipedia.org/wiki/Right-to-left#cite_note-2
return language?.split('-').shift().toLowerCase() in ['ar', 'dv', 'fa', 'he', 'ku', 'ps', 'sd', 'ug', 'ur', 'yi']

@ -0,0 +1,23 @@
this.t = function(key, ...replaces) {
if (_.isObject(replaces[0])) {
return TAPi18n.__(key, replaces);
} else {
return TAPi18n.__(key, {
postProcess: 'sprintf',
sprintf: replaces
});
}
};
this.tr = function(key, options, ...replaces) {
if (_.isObject(replaces[0])) {
return TAPi18n.__(key, options, replaces);
} else {
return TAPi18n.__(key, options, {
postProcess: 'sprintf',
sprintf: replaces
});
}
};
this.isRtl = (language) => language != null && ['ar', 'dv', 'fa', 'he', 'ku', 'ps', 'sd', 'ug', 'ur', 'yi'].includes(language.split('-').shift().toLowerCase());

@ -1,52 +0,0 @@
import moment from 'moment'
Template.privateHistory.helpers
history: ->
items = ChatSubscription.find { name: { $regex: Session.get('historyFilter'), $options: 'i' }, t: { $in: ['d', 'c', 'p'] }, archived: { $ne: true } }, {'sort': { 'ts': -1 } }
return {
items: items
length: items.count()
}
archivedHistory: ->
items = ChatSubscription.find { name: { $regex: Session.get('historyFilter'), $options: 'i' }, t: { $in: ['d', 'c', 'p'] }, archived: true }, {'sort': { 'ts': -1 } }
return {
items: items
length: items.count()
}
roomOf: (rid) ->
return ChatRoom.findOne rid
type: ->
switch this.t
when 'd' then 'icon-at'
when 'c' then 'icon-hash'
when 'p' then 'icon-lock'
creation: ->
return moment(this.ts).format('LLL')
lastMessage: ->
return moment(this.lm).format('LLL') if this.lm
path: ->
switch this.t
when 'c'
return FlowRouter.path 'channel', { name: this.name }
when 'p'
return FlowRouter.path 'group', { name: this.name }
when 'd'
return FlowRouter.path 'direct', { username: this.name }
Template.privateHistory.events
'keydown #history-filter': (event) ->
if event.which is 13
event.stopPropagation()
event.preventDefault()
'keyup #history-filter': (event) ->
event.stopPropagation()
event.preventDefault()
Session.set('historyFilter', event.currentTarget.value)

@ -0,0 +1,97 @@
import moment from 'moment';
Template.privateHistory.helpers({
history() {
const items = ChatSubscription.find({
name: {
$regex: Session.get('historyFilter'),
$options: 'i'
},
t: {
$in: ['d', 'c', 'p']
},
archived: {
$ne: true
}
}, {
'sort': {
'ts': -1
}
});
return {
items,
length: items.count()
};
},
archivedHistory() {
const items = ChatSubscription.find({
name: {
$regex: Session.get('historyFilter'),
$options: 'i'
},
t: {
$in: ['d', 'c', 'p']
},
archived: true
}, {
'sort': {
'ts': -1
}
});
return {
items,
length: items.count()
};
},
roomOf(rid) {
return ChatRoom.findOne(rid);
},
type() {
switch (this.t) {
case 'd':
return 'icon-at';
case 'c':
return 'icon-hash';
case 'p':
return 'icon-lock';
}
},
creation() {
return moment(this.ts).format('LLL');
},
lastMessage() {
if (this.lm) {
return moment(this.lm).format('LLL');
}
},
path() {
switch (this.t) {
case 'c':
return FlowRouter.path('channel', {
name: this.name
});
case 'p':
return FlowRouter.path('group', {
name: this.name
});
case 'd':
return FlowRouter.path('direct', {
username: this.name
});
}
}
});
Template.privateHistory.events({
'keydown #history-filter'(event) {
if (event.which === 13) {
event.stopPropagation();
return event.preventDefault();
}
},
'keyup #history-filter'(event) {
event.stopPropagation();
event.preventDefault();
return Session.set('historyFilter', event.currentTarget.value);
}
});

@ -1,23 +0,0 @@
Template.videoButtons.helpers
videoAvaliable: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom'))?
videoActive: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).localUrl.get()? or WebRTC.getInstanceByRoomId(Session.get('openedRoom')).remoteItems.get()?.length > 0
callInProgress: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).callInProgress.get()
Template.videoButtons.events
'click .start-video-call': ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).startCall({audio: true, video: true})
'click .start-audio-call': ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).startCall({audio: true})
'click .join-video-call': ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).joinCall({audio: true, video: true})
'click .join-audio-call': ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).joinCall({audio: true})

@ -0,0 +1,39 @@
/* globals WebRTC */
Template.videoButtons.helpers({
videoAvaliable() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')) != null;
},
videoActive() {
const {localUrl, remoteItems} = WebRTC.getInstanceByRoomId(Session.get('openedRoom'));
const r = remoteItems.get() || [];
return localUrl.get() != null || r.length > 0;
},
callInProgress() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).callInProgress.get();
}
});
Template.videoButtons.events({
'click .start-video-call'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).startCall({
audio: true,
video: true
});
},
'click .start-audio-call'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).startCall({
audio: true
});
},
'click .join-video-call'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).joinCall({
audio: true,
video: true
});
},
'click .join-audio-call'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).joinCall({
audio: true
});
}
});

@ -1,121 +0,0 @@
Template.videoCall.onCreated ->
@mainVideo = new ReactiveVar '$auto'
Template.videoCall.helpers
videoAvaliable: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom'))?
videoActive: ->
webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'))
overlay = @overlay?
if overlay isnt webrtc?.overlayEnabled.get()
return false
return webrtc.localUrl.get()? or webrtc.remoteItems.get()?.length > 0
callInProgress: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).callInProgress.get()
overlayEnabled: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).overlayEnabled.get()
audioEnabled: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).audioEnabled.get()
videoEnabled: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).videoEnabled.get()
audioAndVideoEnabled: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).audioEnabled.get() and WebRTC.getInstanceByRoomId(Session.get('openedRoom')).videoEnabled.get()
screenShareAvailable: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareAvailable
screenShareEnabled: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareEnabled.get()
remoteVideoItems: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).remoteItems.get()
selfVideoUrl: ->
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).localUrl.get()
mainVideoUrl: ->
template = Template.instance()
webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'))
if template.mainVideo.get() is '$self'
return webrtc.localUrl.get()
if template.mainVideo.get() is '$auto'
remoteItems = webrtc.remoteItems.get()
if remoteItems?.length > 0
return remoteItems[0].url
return webrtc.localUrl.get()
if webrtc.remoteItemsById.get()[template.mainVideo.get()]?
return webrtc.remoteItemsById.get()[template.mainVideo.get()].url
else
template.mainVideo.set '$auto'
return
mainVideoUsername: ->
template = Template.instance()
webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'))
if template.mainVideo.get() is '$self'
return t 'you'
if template.mainVideo.get() is '$auto'
remoteItems = webrtc.remoteItems.get()
if remoteItems?.length > 0
return Meteor.users.findOne(remoteItems[0].id)?.username
return t 'you'
if webrtc.remoteItemsById.get()[template.mainVideo.get()]?
return Meteor.users.findOne(webrtc.remoteItemsById.get()[template.mainVideo.get()].id)?.username
else
template.mainVideo.set '$auto'
return
usernameByUserId: (userId) ->
return Meteor.users.findOne(userId)?.username
Template.videoCall.events
'click .stop-call': ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).stop()
'click .video-item': (e, t) ->
t.mainVideo.set $(e.currentTarget).data('username')
'click .disable-audio': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).disableAudio()
'click .enable-audio': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).enableAudio()
'click .disable-video': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).disableVideo()
'click .enable-video': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).enableVideo()
'click .disable-screen-share': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).disableScreenShare()
'click .enable-screen-share': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).enableScreenShare()
'click .disable-overlay': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).overlayEnabled.set(false)
'click .enable-overlay': (e, t) ->
WebRTC.getInstanceByRoomId(Session.get('openedRoom')).overlayEnabled.set(true)
'loadstart video[muted]': (e) ->
e.currentTarget.muted = true
e.currentTarget.volume = 0

@ -0,0 +1,129 @@
/* globals WebRTC */
Template.videoCall.onCreated(function() {
return this.mainVideo = new ReactiveVar('$auto');
});
Template.videoCall.helpers({
videoAvaliable() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')) != null;
},
videoActive() {
const webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'));
const overlay = this.overlay != null;
if (overlay !== (webrtc != null ? webrtc.overlayEnabled.get() : null)) {
return false;
}
let { remoteItems } = webrtc;
const { localUrl } = webrtc;
remoteItems = remoteItems.get() || [];
return (localUrl.get() != null) || remoteItems.length > 0;
},
callInProgress() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).callInProgress.get();
},
overlayEnabled() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).overlayEnabled.get();
},
audioEnabled() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).audioEnabled.get();
},
videoEnabled() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).videoEnabled.get();
},
audioAndVideoEnabled() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).audioEnabled.get() && WebRTC.getInstanceByRoomId(Session.get('openedRoom')).videoEnabled.get();
},
screenShareAvailable() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareAvailable;
},
screenShareEnabled() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareEnabled.get();
},
remoteVideoItems() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).remoteItems.get();
},
selfVideoUrl() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).localUrl.get();
},
mainVideoUrl() {
const template = Template.instance();
const webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'));
if (template.mainVideo.get() === '$self') {
return webrtc.localUrl.get();
}
if (template.mainVideo.get() === '$auto') {
const remoteItems = webrtc.remoteItems.get() | [];
if (remoteItems.length > 0) {
return remoteItems[0].url;
}
return webrtc.localUrl.get();
}
if (webrtc.remoteItemsById.get()[template.mainVideo.get()] != null) {
return webrtc.remoteItemsById.get()[template.mainVideo.get()].url;
} else {
template.mainVideo.set('$auto');
}
},
mainVideoUsername() {
const template = Template.instance();
const webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'));
if (template.mainVideo.get() === '$self') {
return t('you');
}
if (template.mainVideo.get() === '$auto') {
const remoteItems = webrtc.remoteItems.get() || [];
if (remoteItems.length > 0) {
const user = Meteor.users.findOne(remoteItems[0].id);
return user != null ? user.username : undefined;
}
return t('you');
}
if (webrtc.remoteItemsById.get()[template.mainVideo.get()] != null) {
const user = Meteor.users.findOne(webrtc.remoteItemsById.get()[template.mainVideo.get()].id);
return user != null ? user.username : undefined;
} else {
template.mainVideo.set('$auto');
}
},
usernameByUserId(userId) {
const user = Meteor.users.findOne(userId);
return user != null ? user.username : undefined;
}
});
Template.videoCall.events({
'click .stop-call'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).stop();
},
'click .video-item'(e, t) {
return t.mainVideo.set($(e.currentTarget).data('username'));
},
'click .disable-audio'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).disableAudio();
},
'click .enable-audio'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).enableAudio();
},
'click .disable-video'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).disableVideo();
},
'click .enable-video'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).enableVideo();
},
'click .disable-screen-share'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).disableScreenShare();
},
'click .enable-screen-share'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).enableScreenShare();
},
'click .disable-overlay'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).overlayEnabled.set(false);
},
'click .enable-overlay'() {
return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).overlayEnabled.set(true);
},
'loadstart video[muted]'(e) {
e.currentTarget.muted = true;
return e.currentTarget.volume = 0;
}
});

@ -32,16 +32,16 @@ Package.onUse(function(api) {
api.addFiles('getAvatarUrlFromUsername.js');
// LIB FILES
api.addFiles('client/lib/accountBox.coffee', 'client');
api.addFiles('client/lib/accounts.coffee', 'client');
api.addFiles('client/lib/avatar.coffee', 'client');
api.addFiles('client/lib/accountBox.js', 'client');
api.addFiles('client/lib/accounts.js', 'client');
api.addFiles('client/lib/avatar.js', 'client');
api.addFiles('client/lib/chatMessages.coffee', 'client');
api.addFiles('client/lib/collections.js', 'client');
api.addFiles('client/lib/customEventPolyfill.js', 'client');
api.addFiles('client/lib/fileUpload.coffee', 'client');
api.addFiles('client/lib/fireEvent.js', 'client');
api.addFiles('client/lib/iframeCommands.js', 'client');
api.addFiles('client/lib/menu.coffee', 'client');
api.addFiles('client/lib/menu.js', 'client');
api.addFiles('client/lib/modal.coffee', 'client');
api.addFiles('client/lib/Modernizr.js', 'client');
api.addFiles('client/lib/msgTyping.coffee', 'client');
@ -51,15 +51,15 @@ Package.onUse(function(api) {
api.addFiles('client/lib/rocket.coffee', 'client');
api.addFiles('client/lib/RoomHistoryManager.coffee', 'client');
api.addFiles('client/lib/RoomManager.coffee', 'client');
api.addFiles('client/lib/sideNav.coffee', 'client');
api.addFiles('client/lib/tapi18n.coffee', 'client');
api.addFiles('client/lib/sideNav.js', 'client');
api.addFiles('client/lib/tapi18n.js', 'client');
api.addFiles('client/lib/textarea-autogrow.js', 'client');
api.addFiles('client/lib/codeMirror/codeMirror.js', 'client');
// LIB CORDOVA
api.addFiles('client/lib/cordova/facebook-login.coffee', 'client');
api.addFiles('client/lib/cordova/keyboard-fix.coffee', 'client');
api.addFiles('client/lib/cordova/facebook-login.js', 'client');
api.addFiles('client/lib/cordova/keyboard-fix.js', 'client');
api.addFiles('client/lib/cordova/push.coffee', 'client');
api.addFiles('client/lib/cordova/urls.coffee', 'client');
api.addFiles('client/lib/cordova/user-state.js', 'client');
@ -101,11 +101,11 @@ Package.onUse(function(api) {
api.addFiles('client/views/app/burger.js', 'client');
api.addFiles('client/views/app/home.js', 'client');
api.addFiles('client/views/app/mobileMessageMenu.js', 'client');
api.addFiles('client/views/app/privateHistory.coffee', 'client');
api.addFiles('client/views/app/privateHistory.js', 'client');
api.addFiles('client/views/app/room.coffee', 'client');
api.addFiles('client/views/app/roomSearch.js', 'client');
api.addFiles('client/views/app/secretURL.js', 'client');
api.addFiles('client/views/app/videoCall/videoButtons.coffee', 'client');
api.addFiles('client/views/app/videoCall/videoCall.coffee', 'client');
api.addFiles('client/views/app/videoCall/videoButtons.js', 'client');
api.addFiles('client/views/app/videoCall/videoCall.js', 'client');
api.addFiles('client/views/app/photoswipe.js', 'client');
});

Loading…
Cancel
Save