Merge branch 'testing-version-008' of github.com:antobinary/bigbluebutton into testing-version-008

This commit is contained in:
Anton Georgiev 2015-01-07 19:16:34 +00:00
commit d40e7250b7
26 changed files with 465 additions and 769 deletions

View File

@ -1 +1 @@
METEOR@1.0
METEOR@1.0.2

View File

@ -1,77 +1,84 @@
agnito:raphael@0.1.0
alanning:package-stubber@0.0.9
amplify@1.0.0
application-configuration@1.0.3
application-configuration@1.0.4
arunoda:npm@0.2.6
autoupdate@1.1.3
base64@1.0.1
binary-heap@1.0.1
blaze-tools@1.0.1
blaze@2.0.3
boilerplate-generator@1.0.1
autoupdate@1.1.4
base64@1.0.2
binary-heap@1.0.2
blaze@2.0.4
blaze-tools@1.0.2
boilerplate-generator@1.0.2
brentjanderson:winston-client@0.2.0
callback-hook@1.0.1
check@1.0.2
coffeescript@1.0.4
ctl-helper@1.0.4
ctl@1.0.2
ddp@1.0.11
deps@1.0.5
callback-hook@1.0.2
check@1.0.3
coffeescript@1.0.5
ddp@1.0.13
deps@1.0.6
duongthienduc:meteor-winston@1.0.0
ejson@1.0.4
fastclick@1.0.1
follower-livedata@1.0.2
ejson@1.0.5
fastclick@1.0.2
follower-livedata@1.0.3
francocatena:status@1.0.3
geojson-utils@1.0.1
html-tools@1.0.2
htmljs@1.0.2
http@1.0.8
id-map@1.0.1
geojson-utils@1.0.2
html-tools@1.0.3
htmljs@1.0.3
http@1.0.9
id-map@1.0.2
infinitedg:winston@0.7.3
iron:controller@1.0.0
iron:core@1.0.0
iron:dynamic-template@1.0.0
iron:layout@1.0.0
iron:location@1.0.1
iron:middleware-stack@1.0.0
iron:router@1.0.1
iron:url@1.0.0
jquery@1.0.1
json@1.0.1
launch-screen@1.0.0
less@1.0.11
livedata@1.0.11
logging@1.0.5
meteor-platform@1.2.0
meteor@1.1.3
minifiers@1.1.2
minimongo@1.0.5
mizzao:bootstrap-3@3.3.0
iron:controller@1.0.6
iron:core@1.0.6
iron:dynamic-template@1.0.6
iron:layout@1.0.6
iron:location@1.0.6
iron:middleware-stack@1.0.6
iron:router@1.0.6
iron:url@1.0.6
jquery@1.0.2
json@1.0.2
launch-screen@1.0.1
less@1.0.12
livedata@1.0.12
logging@1.0.6
meteor@1.1.4
meteor-platform@1.2.1
minifiers@1.1.3
minimongo@1.0.6
mizzao:bootstrap-3@3.3.1_1
mizzao:build-fetcher@0.2.0
mizzao:jquery-ui@1.11.2
mizzao:timesync@0.2.2
mobile-status-bar@1.0.1
mongo@1.0.8
mobile-status-bar@1.0.2
mongo@1.0.10
mrt:external-file-loader@0.1.4
mrt:redis@0.1.3
observe-sequence@1.0.3
ordered-dict@1.0.1
random@1.0.1
reactive-dict@1.0.4
reactive-var@1.0.3
reload@1.1.1
retry@1.0.1
routepolicy@1.0.2
sanjo:jasmine@0.1.0
session@1.0.4
spacebars-compiler@1.0.3
spacebars@1.0.3
standard-app-packages@1.0.3
observe-sequence@1.0.4
ordered-dict@1.0.2
practicalmeteor:chai@1.9.2_3
practicalmeteor:loglevel@1.1.0_3
random@1.0.2
reactive-dict@1.0.5
reactive-var@1.0.4
reload@1.1.2
retry@1.0.2
routepolicy@1.0.3
sanjo:jasmine@0.9.0
sanjo:karma@1.1.1
session@1.0.5
spacebars@1.0.4
spacebars-compiler@1.0.4
standard-app-packages@1.0.4
tap:http-methods@0.0.23
tap:i18n@1.0.7
templating@1.0.9
tracker@1.0.3
ui@1.0.4
underscore@1.0.1
url@1.0.2
webapp-hashing@1.0.1
webapp@1.1.4
templating@1.0.10
tracker@1.0.4
ui@1.0.5
underscore@1.0.2
url@1.0.3
velocity:core@0.4.3
velocity:meteor-stubs@1.0.0_2
velocity:node-soft-mirror@0.1.0
velocity:shim@0.1.0
velocity:test-proxy@0.0.4
webapp@1.1.5
webapp-hashing@1.0.2

View File

@ -243,6 +243,19 @@ Handlebars.registerHelper "visibility", (section) ->
setInSession "display_whiteboard", !getInSession "display_whiteboard"
setTimeout(redrawWhiteboard, 0)
@toggleSlidingMenu = ->
if $('#sliding-menu').hasClass('sliding-menu-opened')
setInSession 'display_slidingMenu', false
$('#sliding-menu').removeClass('sliding-menu-opened')
$('#darkened-screen').css('display', 'none')
$(document).unbind('scroll')
else
setInSession 'display_slidingMenu', true
$('#sliding-menu').addClass('sliding-menu-opened')
$('#darkened-screen').css('display', 'block')
$(document).bind 'scroll', () ->
window.scrollTo(0, 0)
# Starts the entire logout procedure.
# meeting: the meeting the user is in
# the user's userId
@ -257,7 +270,6 @@ Handlebars.registerHelper "visibility", (section) ->
delete SessionAmplify.keys['bbbServerVersion']
delete SessionAmplify.keys['chatTabs']
delete SessionAmplify.keys['dateOfBuild']
delete SessionAmplify.keys['displayChatNotifications']
delete SessionAmplify.keys['display_chatPane']
delete SessionAmplify.keys['display_chatbar']
delete SessionAmplify.keys['display_navbar']
@ -270,7 +282,6 @@ Handlebars.registerHelper "visibility", (section) ->
delete SessionAmplify.keys['tabsRenderedTime']
delete SessionAmplify.keys['userId']
delete SessionAmplify.keys['userName']
console.log "clearSessionVar"
callback()
# assign the default values for the Session vars
@ -284,7 +295,7 @@ Handlebars.registerHelper "visibility", (section) ->
setInSession "joinedAt", getTime()
setInSession "inChatWith", 'PUBLIC_CHAT'
setInSession "messageFontSize", 12
setInSession "displayChatNotifications", true
setInSession 'display_slidingMenu', false
@onLoadComplete = ->

View File

@ -8,46 +8,6 @@ loadLib = (libname) ->
Meteor.Loader.loadJs("http://#{window.location.hostname}/client/lib/#{libname}", successCallback, 10000).fail(retryMessageCallback)
recalculateLayout = ->
usersDisplayed = getInSession "display_usersList"
whiteboardDisplayed = getInSession "display_whiteboard"
chatDisplayed = getInSession "display_chatbar"
# If only one module is selected (presentation), it should take up
# the entire width of the screen. If it's two modules, each module
# should take up 50% of the screen. If it's 3 modules (25%, 50%, 25%)
console.log "recalculateLayout #{usersDisplayed} #{whiteboardDisplayed} #{chatDisplayed}"
# clear the default width
# $("#users").removeAttr('style')#.css("width","")
# $("#whiteboard").removeAttr('style')#.css("width","")
# $("#chat").removeAttr('style')#.css("width","")
if whiteboardDisplayed
if chatDisplayed and usersDisplayed
$("#users").removeClass("halfScreen").addClass("quarterScreen")
$("#whiteboard").removeClass("fullScreenPresentation").addClass("halfScreen")
$("#chat").removeClass("halfScreen").addClass("quarterScreen")
displaySlide @whiteboardPaperModel
else
if chatDisplayed or usersDisplayed
if chatDisplayed
$("#whiteboard").removeClass("fullScreenPresentation").addClass("halfScreen")
$("#chat").removeClass("quarterScreen").addClass("halfScreen")
if usersDisplayed
$("#whiteboard").removeClass("fullScreenPresentation").addClass("halfScreen")
$("#users").removeClass("quarterScreen").addClass("halfScreen")
else
console.log "fullscreen"
$("#whiteboard").removeClass("halfScreen").addClass("fullScreenPresentation")
else
if chatDisplayed
$("#chat").removeClass("quarterScreen").addClass("halfScreen")
return
if usersDisplayed
$("#users").removeClass("quarterScreen").addClass("halfScreen")
return
# These settings can just be stored locally in session, created at start up
Meteor.startup ->
@ -76,25 +36,19 @@ Template.footer.helpers
Template.header.events
"click .audioFeedIcon": (event) ->
$('.audioFeedIcon').blur()
toggleSlidingMenu()
toggleVoiceCall @
"click .chatBarIcon": (event) ->
$(".tooltip").hide()
toggleSlidingMenu()
toggleChatbar()
#recalculateLayout()
"click .collapseButton": (event) ->
toggleSlidingMenu()
$(".tooltip").hide()
if $('.collapseSection').css('display') is 'block'
$('.collapseSection').css({'display': 'none'})
$('.navbarTitle').css({ 'margin-left': 'auto', 'margin-right': 'auto', 'width': '80%' })
$('.collapseButton > i').removeClass('glyphicon-chevron-left')
$('.collapseButton > i').addClass('glyphicon-chevron-right')
else
$('.collapseSection').css({'display': 'block'})
$('.navbarTitle').css({ 'width': '30%' })
$('.collapseButton > i').removeClass('glyphicon-chevron-right')
$('.collapseButton > i').addClass('glyphicon-chevron-left')
$('.collapseButton').blur()
$('.myNavbar').css('z-index', 1032)
"click .hideNavbarIcon": (event) ->
$(".tooltip").hide()
@ -102,6 +56,7 @@ Template.header.events
"click .lowerHand": (event) ->
$(".tooltip").hide()
toggleSlidingMenu()
Meteor.call('userLowerHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken"))
"click .muteIcon": (event) ->
@ -112,11 +67,21 @@ Template.header.events
#Meteor.log.info "navbar raise own hand from client"
console.log "navbar raise own hand from client"
$(".tooltip").hide()
toggleSlidingMenu()
Meteor.call('userRaiseHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken"))
# "click .settingsIcon": (event) ->
# alert "settings"
"click .signOutIcon": (event) ->
$('.signOutIcon').blur()
if window.matchMedia('(orientation: portrait)').matches
if $('#dialog').dialog('option', 'height') isnt 450
$('#dialog').dialog('option', 'width', '100%')
$('#dialog').dialog('option', 'height', 450)
else
if $('#dialog').dialog('option', 'height') isnt 115
$('#dialog').dialog('option', 'width', 270)
$('#dialog').dialog('option', 'height', 115)
$("#dialog").dialog("open")
"click .hideNavbarIcon": (event) ->
$(".tooltip").hide()
@ -126,8 +91,8 @@ Template.header.events
"click .usersListIcon": (event) ->
$(".tooltip").hide()
toggleSlidingMenu
toggleUsersList()
#recalculateLayout()
"click .videoFeedIcon": (event) ->
$(".tooltip").hide()
@ -135,8 +100,8 @@ Template.header.events
"click .whiteboardIcon": (event) ->
$(".tooltip").hide()
toggleSlidingMenu
toggleWhiteBoard()
#recalculateLayout()
"mouseout #navbarMinimizedButton": (event) ->
$("#navbarMinimizedButton").removeClass("navbarMinimizedButtonLarge")
@ -146,6 +111,47 @@ Template.header.events
$("#navbarMinimizedButton").removeClass("navbarMinimizedButtonSmall")
$("#navbarMinimizedButton").addClass("navbarMinimizedButtonLarge")
Template.slidingMenu.events
'click .audioFeedIcon': (event) ->
$('.audioFeedIcon').blur()
toggleSlidingMenu()
toggleVoiceCall @
if BBB.amISharingAudio()
$('.navbarTitle').css('width', '70%')
else
$('.navbarTitle').css('width', '55%')
'click .chatBarIcon': (event) ->
$('.tooltip').hide()
toggleSlidingMenu()
toggleChatbar()
'click .lowerHand': (event) ->
$('.tooltip').hide()
toggleSlidingMenu()
Meteor.call('userLowerHand', getInSession('meetingId'), getInSession('userId'), getInSession('userId'), getInSession('authToken'))
'click .raiseHand': (event) ->
console.log 'navbar raise own hand from client'
$('.tooltip').hide()
toggleSlidingMenu()
Meteor.call('userRaiseHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken"))
'click .usersListIcon': (event) ->
$('.tooltip').hide()
toggleSlidingMenu()
toggleUsersList()
'click .whiteboardIcon': (event) ->
$('.tooltip').hide()
toggleSlidingMenu()
toggleWhiteBoard()
'click .collapseButton': (event) ->
$('.tooltip').hide()
toggleSlidingMenu()
$('.collapseButton').blur()
Template.main.helpers
setTitle: ->
document.title = "BigBlueButton #{window.getMeetingName() ? 'HTML5'}"
@ -156,8 +162,6 @@ Template.main.rendered = ->
draggable: false
resizable: false
autoOpen: false
height: 115
width: 270
dialogClass: 'no-close logout-dialog'
buttons: [
{
@ -181,6 +185,13 @@ Template.main.rendered = ->
of: '.signOutIcon'
)
$(window).resize( ->
$('#dialog').dialog('close')
)
$('#darkened-screen').click () ->
toggleSlidingMenu()
Template.makeButton.rendered = ->
$('button[rel=tooltip]').tooltip()

View File

@ -9,29 +9,32 @@
<div id="navbar" class="myNavbar gradientBar navbar navbar-default navbar-fixed-top" role="navigation">
<div class="navbarUserButtons navbarSection">
<div id="collapseButtonSection">
{{> makeButton btn_class="navbarButton collapseButton" i_class="chevron-right" rel="tooltip" data_placement="bottom" title="Expand"}}
{{#if getInSession "display_slidingMenu"}}
{{> makeButton btn_class="navbarButton collapseButton" i_class="chevron-left" rel="tooltip" data_placement="bottom" title="Collapse"}}
{{else}}
{{> makeButton btn_class="navbarButton collapseButton" i_class="chevron-right" rel="tooltip" data_placement="bottom" title="Expand"}}
{{/if}}
</div>
<div id='collapse-container' class='collapseSection'>
<div class='collapseSection'>
<!-- display/hide users list toggle -->
{{#if getInSession "display_usersList"}}
{{> makeButton btn_class="navbarIconToggleActive usersListIcon navbarButton" i_class="user" rel="tooltip" data_placement="bottom" title="Hide List of Users"}}
{{> makeButton btn_class="navbarIconToggleActive usersListIcon navbarButton collapseSectionButton" i_class="user" rel="tooltip" data_placement="bottom" title="Hide List of Users"}}
{{else}}
{{> makeButton btn_class="usersListIcon navbarButton" i_class="user" rel="tooltip" data_placement="bottom" title="Show List of Users"}}
{{> makeButton btn_class="usersListIcon navbarButton collapseSectionButton" i_class="user" rel="tooltip" data_placement="bottom" title="Show List of Users"}}
{{/if}}
<!-- display/hide whiteboard toggle -->
{{#if getInSession "display_whiteboard"}}
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton" i_class="pencil" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}}
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="pencil" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}}
{{else}}
{{> makeButton btn_class="whiteboardIcon navbarButton" i_class="pencil" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}}
{{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="pencil" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}}
{{/if}}
<!-- display/hide chat bar toggle -->
{{#if getInSession "display_chatbar"}}
{{> makeButton btn_class="navbarIconToggleActive chatBarIcon navbarButton" i_class="comment" rel="tooltip" data_placement="bottom" title="Hide Message Pane"}}
{{> makeButton btn_class="navbarIconToggleActive chatBarIcon navbarButton collapseSectionButton" i_class="comment" rel="tooltip" data_placement="bottom" title="Hide Message Pane"}}
{{else}}
{{> makeButton btn_class="chatBarIcon navbarButton" i_class="comment" rel="tooltip" data_placement="bottom" title="Show Message Pane"}}
{{> makeButton btn_class="chatBarIcon navbarButton collapseSectionButton" i_class="comment" rel="tooltip" data_placement="bottom" title="Show Message Pane"}}
{{/if}}
<!-- display/hide webcam streams toggle -->
@ -40,29 +43,33 @@
{{else}}
{{> makeButton btn_class="videoFeedIcon navbarButton" i_class="facetime-video" sharingVideo=false rel="tooltip" data_placement="bottom" title="Show Webcams"}}
{{/if}} -->
</div>
<div class='audioControllersSection'>
<!-- Join/hang up audio call -->
{{#if isCurrentUserSharingAudio}}
{{> makeButton btn_class="navbarIconToggleActive audioFeedIcon navbarButton" i_class="volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}}
<div class='collapseSection'>
{{> makeButton btn_class="navbarIconToggleActive audioFeedIcon navbarButton audioButton" i_class="volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}}
</div>
{{#if isCurrentUserMuted}}
{{> makeButton btn_class="muteIcon navbarButton" i_class="volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}}
{{> makeButton btn_class="muteIcon navbarButton audioButton" i_class="volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}}
{{else}}
{{#if isCurrentUserTalking}}
{{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton" i_class="volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
{{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
{{else}}
{{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton" i_class="volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
{{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
{{/if}}
{{/if}}
{{else}}
{{> makeButton btn_class="audioFeedIcon navbarButton" i_class="headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}}
<div class='collapseSection'>
{{> makeButton btn_class="audioFeedIcon navbarButton audioButton" i_class="headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}}
</div>
{{/if}}
</div>
<div class='collapseSection'>
{{#if isCurrentUserRaisingHand}}
{{> makeButton btn_class="lowerHand navbarIconToggleActive navbarButton" i_class="hand-up" rel="tooltip" data_placement="bottom" title="Lower your hand"}}
{{> makeButton btn_class="lowerHand navbarIconToggleActive navbarButton collapseSectionButton" i_class="hand-up" rel="tooltip" data_placement="bottom" title="Lower your hand"}}
{{else}}
{{> makeButton btn_class="raiseHand navbarButton" i_class="hand-up" rel="tooltip" data_placement="bottom" title="Raise your hand"}}
{{> makeButton btn_class="raiseHand navbarButton collapseSectionButton" i_class="hand-up" rel="tooltip" data_placement="bottom" title="Raise your hand"}}
{{/if}}
{{> recordingStatus}}
@ -99,6 +106,8 @@
{{> footer}}
{{/if}}
</div>
{{> slidingMenu}}
<div id='darkened-screen'></div>
</body>
</template>
@ -114,3 +123,39 @@
{{/if}}
{{/with}}
</template>
<template name='slidingMenu'>
<div class="sliding-menu" id="sliding-menu">
<div class="slideSection">
{{#if getInSession "display_usersList"}}
{{> makeButton btn_class="navbarIconToggleActive usersListIcon slideButton" i_class="user" rel="tooltip" data_placement="right" title="Hide List of Users"}}
{{else}}
{{> makeButton btn_class="usersListIcon slideButton" i_class="user" rel="tooltip" data_placement="right" title="Show List of Users"}}
{{/if}}
{{#if getInSession "display_whiteboard"}}
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="pencil" rel="tooltip" data_placement="right" title="Hide Whiteboard"}}
{{else}}
{{> makeButton btn_class="whiteboardIcon slideButton" i_class="pencil" rel="tooltip" data_placement="right" title="Show Whiteboard"}}
{{/if}}
{{#if getInSession "display_chatbar"}}
{{> makeButton btn_class="navbarIconToggleActive chatBarIcon slideButton" i_class="comment" rel="tooltip" data_placement="right" title="Hide Message Pane"}}
{{else}}
{{> makeButton btn_class="chatBarIcon slideButton" i_class="comment" rel="tooltip" data_placement="right" title="Show Message Pane"}}
{{/if}}
{{#if isCurrentUserSharingAudio}}
{{> makeButton btn_class="navbarIconToggleActive audioFeedIcon slideButton" i_class="volume-off" sharingAudio=true rel="tooltip" data_placement="right" title="Leave Audio Call"}}
{{else}}
{{> makeButton btn_class="audioFeedIcon slideButton" i_class="headphones" sharingAudio=false rel="tooltip" data_placement="right" title="Join Audio Call"}}
{{/if}}
{{#if isCurrentUserRaisingHand}}
{{> makeButton btn_class="lowerHand navbarIconToggleActive slideButton" i_class="hand-up" rel="tooltip" data_placement="right" title="Lower your hand"}}
{{else}}
{{> makeButton btn_class="raiseHand slideButton" i_class="hand-up" rel="tooltip" data_placement="right" title="Raise your hand"}}
{{/if}}
</div>
</div>
</template>

View File

@ -44,7 +44,7 @@ bottomEntry {
}
#chatbody {
height: 80%;
height: 90%;
overflow-y: scroll;
padding-left: 0px;
padding-right: 0px;

View File

@ -30,7 +30,7 @@ body {
background: extract(@white, 1);
border: 1px solid extract(@lightGrey, 3);
float: left;
height: 80%;
height: 100%;
margin-top: 10px;
}
@ -207,19 +207,16 @@ body {
.logout-dialog.ui-dialog {
.ui-widget-header {
color: extract(@white, 1);
font-size: 12px;
font-weight: bold;
background: extract(@darkGrey, 3);
}
.ui-dialog-content {
font-size: 11px;
font-weight: bold;
text-align: center;
}
}
.logout-dialog.ui-widget-content {
font-size: 10px;
background: extract(@white, 3);
border: 5px solid extract(@darkGrey, 3);
}

View File

@ -17,3 +17,10 @@
width: 100% !important;
}
}
#whiteboard-navbar {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}

View File

@ -65,4 +65,17 @@
.collapseSection {
display: block !important;
}
.logout-dialog.ui-dialog {
.ui-widget-header {
font-size: 12px;
}
.ui-dialog-content {
font-size: 11px;
}
}
.logout-dialog.ui-widget-content {
font-size: 10px;
}
}

View File

@ -16,13 +16,12 @@
body {
position: relative;
height: 1440px;
top: 15px;
}
.navbarButton {
height: 100px;
width: 10%;
width: 15%;
min-width: 60px;
}
@ -32,7 +31,7 @@
padding-left: 5px;
overflow: hidden;
height: 72px;
width: 80%;
width: 70%;
white-space: nowrap;
text-overflow: ellipsis;
margin-left: auto;
@ -62,4 +61,86 @@
.collapseSection {
display: none;
}
.logout-dialog.ui-dialog {
.ui-widget-header {
font-size: 40px;
}
}
.logout-dialog.ui-widget-content {
font-size: 280%;
}
.ui-dialog-buttonset {
width: 100%;
}
.ui-dialog-buttonset button {
width: 40%;
margin-left: 5% !important;
margin-right: 5% !important;
}
/* Sliding menu */
.sliding-menu {
width: 15%;
height: 100%;
position: fixed;
top: 0;
left: -15%;
z-index: 1031;
&.sliding-menu-opened {
left: 0px;
}
a {
border-bottom: 1px solid #258ecd;
padding: 1em;
}
}
.slideSection {
float: left;
margin-top: 101px;
height: 100%;
width: 100%;
}
.slideButton {
display: block;
width: 100%;
height: calc(~'20% - 20px');
}
.slideSection {
margin-bottom: 0.5%;
&.gradientBar {
.linear-gradient(rgb(72,76,85), rgb(65,68,77));
}
.btn {
.linear-gradient(rgb(72,76,85), rgb(65,68,77));
border-left: 1px solid extract(@darkGrey, 2);
border-right: 1px solid extract(@darkGrey, 4);
&.navbarIconToggleActive {
background: extract(@darkGrey, 3);
border-bottom: 4px solid extract(@azure, 1);
}
i {
color: extract(@white, 1);
}
}
}
#darkened-screen {
display: none;
background: black;
opacity: 0.7;
z-index: 1030;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
}

View File

@ -2,7 +2,5 @@
#whiteboard {
-webkit-order: 1;
order: 1;
min-height: 40%;
max-height: 40%;
}
}

View File

@ -141,6 +141,7 @@ Template.message.rendered = ->
Template.chatInput.events
'click #sendMessageButton': (event) ->
$('#sendMessageButton').blur()
sendMessage()
'keypress #newMessageInput': (event) -> # user pressed a button inside the chatbox
@ -294,7 +295,7 @@ Template.tabButtons.events
Template.tabButtons.helpers
hasGotUnreadMailClass: (gotMail) ->
if gotMail and getInSession("displayChatNotifications")
if gotMail
return "gotUnreadMail"
else
return ""
@ -338,12 +339,3 @@ Template.message.helpers
res = str.replace(/&/g, '&amp;').replace(/<(?![au\/])/g, '&lt;').replace(/\/([^au])>/g, '$1&gt;').replace(/([^=])"(?!>)/g, '$1&quot;');
res = toClickable res
res = activateBreakLines res
Template.notificationSettings.events
"click #chatNotificationOff": (event) ->
console.log "off"
setInSession "displayChatNotifications", false
"click #chatNotificationOn": (event) ->
console.log "on"
setInSession "displayChatNotifications", true

View File

@ -52,8 +52,6 @@
<template name="chatOptions">
<p>Chat Options:</p>
{{> optionsFontSize}}
<br/><br/>
{{> notificationSettings}}
</template>
<template name="extraConversations">
@ -89,16 +87,6 @@
{{autoscroll}}
</template>
<template name="notificationSettings">
New Message Notifications:
<form>
<input type="radio" name="chatNotification" id="chatNotificationOn" value="chatNotificationOn" checked="checked" />
<label for="chatNotificationOn">On</label>
<input type="radio" name="chatNotification" id="chatNotificationOff" value="chatNotificationOff" />
<label for="chatNotificationOff">Off</label>
</form>
</template>
<!-- Displays the list of options available -->
<template name="optionsBar">
<div class="optionsBar">

View File

@ -1,8 +1,18 @@
Template.slide.rendered = ->
currentSlide = getCurrentSlideDoc()
if currentSlide?.slide?.png_uri?
createWhiteboardPaper (wpm) ->
displaySlide wpm
pic = new Image()
pic.onload = ->
setInSession 'slideOriginalWidth', this.width
setInSession 'slideOriginalHeight', this.height
$(window).resize( ->
redrawWhiteboard()
)
if window.matchMedia('(orientation: portrait)').matches
$('#whiteboard-paper').height($('#whiteboard-paper').width() * this.height / this.width)
if currentSlide?.slide?.png_uri?
createWhiteboardPaper (wpm) ->
displaySlide wpm
pic.src = currentSlide?.slide?.png_uri
@createWhiteboardPaper = (callback) =>
@whiteboardPaperModel = new Meteor.WhiteboardPaperModel('whiteboard-paper')
@ -11,14 +21,10 @@ Template.slide.rendered = ->
@displaySlide = (wpm) ->
currentSlide = getCurrentSlideDoc()
wpm.create()
pic = new Image()
pic.onload = ->
adjustedDimensions = scaleSlide(this.width, this.height)
wpm._displayPage(currentSlide?.slide?.png_uri, this.width, this.height)
manuallyDisplayShapes()
wpm.scale(adjustedDimensions.width, adjustedDimensions.height)
pic.src = currentSlide?.slide?.png_uri
adjustedDimensions = scaleSlide(getInSession('slideOriginalWidth'), getInSession('slideOriginalHeight'))
wpm._displayPage(currentSlide?.slide?.png_uri, getInSession('slideOriginalWidth'), getInSession('slideOriginalHeight'))
manuallyDisplayShapes()
wpm.scale(adjustedDimensions.width, adjustedDimensions.height)
@manuallyDisplayShapes = ->
currentSlide = getCurrentSlideDoc()
@ -35,9 +41,16 @@ Template.slide.rendered = ->
wpm?.makeShape(shapeType, shapeInfo)
wpm?.updateShape(shapeType, shapeInfo)
@scaleSlide = (originalWidth, originalHeight) ->
boardWidth = $("#whiteboard").width()
# calculates and returns the best fitting {width, height} pair
# based on the image's original width and height
@scaleSlide = (originalWidth, originalHeight) ->
# the size of the whiteboard space (frame) where the slide will be displayed
boardWidth = $("#whiteboard").width()
boardHeight = null # see under
# calculate boardHeight
whiteboardBottom = $("#whiteboard").offset().top + $("#whiteboard").height()
footerTop = $(".myFooter").offset().top
if footerTop < whiteboardBottom
@ -45,24 +58,28 @@ Template.slide.rendered = ->
else
boardHeight = $("#whiteboard").height() - $("#whiteboard-navbar").height() - 10
# this is the best fitting pair
adjustedWidth = null
adjustedHeight = null
# the slide image is in portrait orientation
if originalWidth <= originalHeight
adjustedWidth = boardHeight * originalWidth / originalHeight
$('#whiteboard-paper').width(adjustedWidth)
if boardWidth < adjustedWidth
adjustedHeight = boardHeight * boardWidth / adjustedWidth
adjustedWidth = boardWidth
else
adjustedHeight = boardHeight
$("#whiteboard-paper").height(adjustedHeight)
# ths slide image is in landscape orientation
else
adjustedHeight = boardWidth * originalHeight / originalWidth
$('#whiteboard-paper').height(adjustedHeight)
if boardHeight < adjustedHeight
adjustedWidth = boardWidth * boardHeight / adjustedHeight
adjustedHeight = boardHeight
else
adjustedWidth = boardWidth
$("#whiteboard-paper").width(adjustedWidth)
{ width: adjustedWidth, height: adjustedHeight }

View File

@ -1,19 +1,12 @@
Template.whiteboard.rendered = ->
$(window).resize( ->
redrawWhiteboard()
)
@redrawWhiteboard = () ->
currentSlide = getCurrentSlideDoc()
pic = new Image()
pic.onload = ->
adjustedDimensions = scaleSlide(this.width, this.height)
wpm = whiteboardPaperModel
wpm.setAdjustedDimensions(adjustedDimensions.width, adjustedDimensions.height)
wpm.clearShapes()
wpm.clearCursor()
manuallyDisplayShapes()
wpm.scale(adjustedDimensions.width, adjustedDimensions.height)
wpm.createCursor()
pic.src = currentSlide?.slide?.png_uri
if window.matchMedia('(orientation: portrait)').matches
$('#whiteboard').height($('#whiteboard').width() * getInSession('slideOriginalHeight') / getInSession('slideOriginalWidth') + $('#whiteboard-navbar').height() + 10)
else if $('#whiteboard').height() isnt $('#users').height() + 10
$('#whiteboard').height($('#users').height() + 10)
adjustedDimensions = scaleSlide(getInSession('slideOriginalWidth'), getInSession('slideOriginalHeight'))
wpm = whiteboardPaperModel
wpm.clearShapes()
wpm.clearCursor()
manuallyDisplayShapes()
wpm.scale(adjustedDimensions.width, adjustedDimensions.height)
wpm.createCursor()

View File

@ -28,22 +28,8 @@ class Meteor.WhiteboardPaperModel
@shiftPressed = false
@currentPathCount = 0
# $container = $('#whiteboard-paper')
# @containerWidth = $container.innerWidth()
# @containerHeight = $container.innerHeight()
@_updateContainerDimensions()
# $(window).on "resize.whiteboard_paper", _.bind(@_onWindowResize, @)
# $(document).on "keydown.whiteboard_paper", _.bind(@_onKeyDown, @)
# $(document).on "keyup.whiteboard_paper", _.bind(@_onKeyUp, @)
# Bind to the event triggered when the client connects to the server
# if globals.connection.isConnected()
# @_registerEvents()
# else
# globals.events.on "connection:connected", =>
# @_registerEvents()
@zoomObserver = null
@adjustedWidth = 0
@ -52,13 +38,6 @@ class Meteor.WhiteboardPaperModel
@widthRatio = 100
@heightRatio = 100
# Override the close() to unbind events.
unbindEvents: ->
$(window).off "resize.whiteboard_paper"
$(document).off "keydown.whiteboard_paper"
$(document).off "keyup.whiteboard_paper"
# TODO: other events are being used in the code and should be off() here
# Initializes the paper in the page.
# Can't do these things in initialize() because by then some elements
# are not yet created in the page.
@ -68,19 +47,13 @@ class Meteor.WhiteboardPaperModel
h = $("#"+@container).height()
w = $("#"+@container).width()
#console.log "h: #{h}"
#console.log "w: #{w}"
# @raphaelObj ?= ScaleRaphael(@container, "900", "500")
@raphaelObj ?= ScaleRaphael(@container, w, h)
# $container = $('#whiteboard-contents')
@raphaelObj ?= ScaleRaphael(@container, $container.innerHeight(), $container.innerWidth())
@raphaelObj.canvas.setAttribute "preserveAspectRatio", "xMinYMin slice"
@createCursor()
#@cursor.on "cursor:mousewheel", _.bind(@_zoomSlide, @)
if @slides
@rebuild()
@ -89,13 +62,6 @@ class Meteor.WhiteboardPaperModel
unless navigator.userAgent.indexOf("Firefox") is -1
@raphaelObj.renderfix()
# initializing border around slide to cover up areas which shouldnt show
# @borders = {}
# for border in ['left', 'right', 'top', 'bottom']
# @borders[border] = @raphaelObj.rect(0, 0, 0, 0)
# @borders[border].attr("fill", "#ababab")
# @borders[border].attr( {stroke:"#ababab"} )
@raphaelObj
# Re-add the images to the paper that are found
@ -106,27 +72,6 @@ class Meteor.WhiteboardPaperModel
if @slides.hasOwnProperty(url)
@addImageToPaper url, @slides[url].getWidth(), @slides[url].getHeight()
# A wrapper around ScaleRaphael's `changeSize()` method, more details at:
# http://www.shapevent.com/scaleraphael/
# Also makes sure that the images are redraw in the canvas so they are actually resized.
changeSize: (windowWidth, windowHeight, center=true, clipping=false) ->
if @raphaelObj?
@raphaelObj.changeSize(windowWidth, windowHeight, center, clipping)
# TODO: we can scale the slides and drawings instead of re-adding them, but the logic
# will change quite a bit
# slides
slidesTmp = _.clone(@slides)
urlTmp = @current.slide
@removeAllImagesFromPaper()
@slides = slidesTmp
@rebuild()
@showImageFromPaper(urlTmp?.url)
# drawings
tmp = _.clone(@current.shapeDefinitions)
@clearShapes()
@drawListOfShapes(tmp)
scale: (width, height) ->
@raphaelObj?.changeSize(width, height)
@ -161,10 +106,6 @@ class Meteor.WhiteboardPaperModel
img.toBack()
else
img.hide()
$(@container).on "mousemove", _.bind(@_onMouseMove, @)
$(@container).on "mousewheel", _.bind(@_zoomSlide, @)
# TODO $(img.node).bind "mousewheel", zoomSlide
#@trigger('paper:image:added', img)
# TODO: other places might also required an update in these dimensions
@_updateContainerDimensions()
@ -183,60 +124,6 @@ class Meteor.WhiteboardPaperModel
@slides = {}
@current.slide = null
# Shows an image from the paper.
# The url must be in the slides array.
# @param {string} url the url of the image (must be in slides array)
showImageFromPaper: (url) ->
# TODO: temporary solution
url = @_slideUrl(url)
if not @current.slide? or (@slides[url]? and @current.slide.url isnt url)
@_hideImageFromPaper(@current.slide.url) if @current.slide?
next = @_getImageFromPaper(url)
if next
next.show()
next.toFront()
@current.shapes.forEach (element) ->
element.toFront()
@cursor.toFront()
@current.slide = @slides[url]
# Updates the paper from the server values.
# @param {number} cx_ the x-offset value as a percentage of the original width
# @param {number} cy_ the y-offset value as a percentage of the original height
# @param {number} sw_ the slide width value as a percentage of the original width
# @param {number} sh_ the slide height value as a percentage of the original height
# TODO: not working as it should
updatePaperFromServer: (cx_, cy_, sw_, sh_) ->
# # if updating the slide size (zooming!)
# [slideWidth, slideHeight] = @_currentSlideOriginalDimensions()
# if sw_ and sh_
# @raphaelObj.setViewBox cx_ * slideWidth, cy_ * slideHeight, sw_ * slideWidth, sh_ * slideHeight,
# sw = slideWidth / sw_
# sh = slideHeight / sh_
# # just panning, so use old slide size values
# else
# [sw, sh] = @_currentSlideDimensions()
# @raphaelObj.setViewBox cx_ * slideWidth, cy_ * slideHeight, @raphaelObj._viewBox[2], @raphaelObj._viewBox[3]
# # update corners
# cx = cx_ * sw
# cy = cy_ * sh
# # update position of svg object in the window
# sx = (@containerWidth - slideWidth) / 2
# sy = (@containerHeight - slideHeight) / 2
# sy = 0 if sy < 0
# @raphaelObj.canvas.style.left = sx + "px"
# @raphaelObj.canvas.style.top = sy + "px"
# @raphaelObj.setSize slideWidth - 2, slideHeight - 2
# # update zoom level and cursor position
# z = @raphaelObj._viewBox[2] / slideWidth
# @zoomLevel = z
# dcr = 1
# @cursor.setRadius(dcr * z)
# # force the slice attribute despite Raphael changing it
# @raphaelObj.canvas.setAttribute "preserveAspectRatio", "xMinYMin slice"
# Switches the tool and thus the functions that get
# called when certain events are fired from Raphael.
@ -254,95 +141,9 @@ class Meteor.WhiteboardPaperModel
@cursor.undrag()
@current.rectangle = @_createTool(tool)
@cursor.drag(@current.rectangle.dragOnMove, @current.rectangle.dragOnStart, @current.rectangle.dragOnEnd)
# TODO: the shapes below are still in the old format
# when "panzoom"
# @cursor.undrag()
# @cursor.drag _.bind(@_panDragging, @),
# _.bind(@_panGo, @), _.bind(@_panStop, @)
# when "ellipse"
# @cursor.undrag()
# @cursor.drag _.bind(@_ellipseDragging, @),
# _.bind(@_ellipseDragStart, @), _.bind(@_ellipseDragStop, @)
# when "text"
# @cursor.undrag()
# @cursor.drag _.bind(@_rectDragging, @),
# _.bind(@_textStart, @), _.bind(@_textStop, @)
else
console.log "ERROR: Cannot set invalid tool:", tool
# Sets the fit to page.
# @param {boolean} value If true fit to page. If false fit to width.
# TODO: not really working as it should be
setFitToPage: (value) ->
@fitToPage = value
# TODO: we can scale the slides and drawings instead of re-adding them, but the logic
# will change quite a bit
temp = @slides
@removeAllImagesFromPaper()
@slides = temp
# re-add all the images as they should fit differently
@rebuild()
# set to default zoom level
#globals.connection.emitPaperUpdate 0, 0, 1, 1
# get the shapes to reprocess
#globals.connection.emitAllShapes()
# Socket response - Update zoom variables and viewbox
# @param {number} d the delta value from the scroll event
# @return {undefined}
setZoom: (d) ->
step = 0.05 # step size
if d < 0
@zoomLevel += step # zooming out
else
@zoomLevel -= step # zooming in
[sw, sh] = @_currentSlideDimensions()
[cx, cy] = @_currentSlideOffsets()
x = cx / sw
y = cy / sh
# cannot zoom out further than 100%
z = (if @zoomLevel > 1 then 1 else @zoomLevel)
# cannot zoom in further than 400% (1/4)
z = (if z < 0.25 then 0.25 else z)
# cannot zoom to make corner less than (x,y) = (0,0)
x = (if x < 0 then 0 else x)
y = (if y < 0 then 0 else y)
# cannot view more than the bottom corners
zz = 1 - z
x = (if x > zz then zz else x)
y = (if y > zz then zz else y)
#globals.connection.emitPaperUpdate x, y, z, z # send update to all clients
stopPanning: ->
# nothing to do
# Draws an array of shapes to the paper.
# @param {array} shapes the array of shapes to draw
drawListOfShapes: (shapes) ->
@current.shapeDefinitions = shapes
@current.shapes = @raphaelObj.set()
for shape in shapes
shapeType = shape?.shape?.shape_type
dataBlock = shape?.shape?.shape
data = if _.isString(dataBlock) then JSON.parse(dataBlock) else dataBlock
tool = @_createTool(shapeType)
if tool?
@current.shapes.push tool.draw.apply(tool, data)
else
console.log "shape not recognized at drawListOfShapes", shape
# make sure the cursor is still on top
@cursor.toFront()
#Changes the currently displayed presentation (if any) with this one
#@param {object} containing the "presentation" object -id,name,pages[]
sharePresentation: (data) ->
#globals.events.trigger("connection:all_slides", data.payload)
# Clear all shapes from this paper.
clearShapes: ->
if @current.shapes?
@ -393,76 +194,8 @@ class Meteor.WhiteboardPaperModel
if @viewBoxXpos? && @viewBoxYPos? && @viewBoxWidth? && @viewBoxHeight?
@cursor.setPosition( @viewBoxXpos + x * @viewBoxWidth, @viewBoxYPos + y * @viewBoxHeight )
# Update the slide to move and zoom
# @param {number} xOffset the x value of offset
# @param {number} yOffset the y value of offset
# @param {number} widthRatio the ratio of the previous width
# @param {number} heightRatio the ratio of the previous height
moveAndZoom: (xOffset, yOffset, widthRatio, heightRatio) ->
@globalxOffset = xOffset
@globalyOffset = yOffset
@globalwidthRatio = widthRatio
@globalheightRatio = heightRatio
[slideWidth, slideHeight] = @_currentSlideOriginalDimensions()
#console.log("xOffset: " + xOffset + ", yOffset: " + yOffset);
#console.log("@containerWidth: " + @containerWidth + " @containerHeight: " + @containerHeight);
#console.log("slideWidth: " + slideWidth + " slideHeight: " + slideHeight);
baseWidth = (@containerWidth - slideWidth) / 2
baseHeight = (@containerHeight - slideHeight) / 2
#get the actual size of the slide, depending on the limiting factor (container width or container height)
actualWidth = @current.slide.displayWidth
actualHeight = @current.slide.displayHeight
#console.log("actualWidth:" + actualWidth + " actualHeight: " + actualHeight)
#calculate parameters to pass
newXPos = baseWidth - 2* xOffset * actualWidth / 100
newyPos = baseHeight - 2* yOffset * actualHeight / 100
newWidth = actualWidth / 100 * widthRatio
newHeight = actualHeight / 100 * heightRatio
@viewBoxXpos = newXPos
@viewBoxYPos = newyPos
@viewBoxWidth = newWidth
@viewBoxHeight = newHeight
#console.log("newXPos: " + newXPos + " newyPos: " + newyPos + " newWidth: " + newWidth + " newHeight: " + newHeight)
#set parameters to raphael viewbox
@raphaelObj.setViewBox(newXPos , newyPos, newWidth , newHeight , true)
# update the rectangle elements which create the border when page is zoomed
@borders.left.attr( {width:newXPos, height: @containerHeight} )
@borders.right.attr(
x: newXPos + newWidth
y: 0
width:newXPos
height:@containerHeight
)
@borders.top.attr(
width: @containerWidth
height: newyPos
)
@borders.bottom.attr(
y: newyPos + newHeight
width: @containerWidth
height: @containerHeight
)
# borders should appear infront of every other element (i.e. shapes)
for _, border of @borders
border.toFront()
#update cursor to appear the same size even when page is zoomed in
@cursor.setRadius( 3 * widthRatio / 100 )
zoomAndPan: (widthRatio, heightRatio, xOffset, yOffset) ->
console.log "zoomAndPan #{widthRatio} #{heightRatio} #{xOffset} #{yOffset}"
newX = - xOffset * 2 * @adjustedWidth / 100
newY = - yOffset * 2 * @adjustedHeight / 100
newWidth = @adjustedWidth * widthRatio / 100
@ -473,86 +206,6 @@ class Meteor.WhiteboardPaperModel
@adjustedWidth = width
@adjustedHeight = height
# Registers listeners for events in the gloval event bus
_registerEvents: ->
# globals.events.on "connection:whiteboardDrawPen", (startingData) =>
# type = startingData.payload.shape_type
# color = startingData.payload.data.line.color
# thickness = startingData.payload.data.line.weight
# points = startingData.shape.points
# if type is "line"
# for i in [0..points.length - 1]
# if i is 0
# #make these compatible with a line
# console.log "points[i]: " + points[i]
# lineObject = {
# shape: {
# type: "line",
# coordinate: {
# firstX : points[i].x/100,
# firstY : points[i].y/100
# },
# color: startingData.payload.data.line.color,
# thickness : startingData.payload.data.line.weight
# }
# adding : false #tell the line object that we are NOT adding points but creating a new line
# }
# console.log "lineObject: " + lineObject
# @makeShape type, lineObject
# else
# console.log "points[i]: "+ points[i]
# lineObject = {
# shape: {
# type: "line",
# coordinate: {
# firstX : points[i].x/100,
# firstY : points[i].y/100
# },
# color: startingData.payload.data.line.color,
# thickness : startingData.payload.data.line.weight
# }
# adding : true #tell the line object that we ARE adding points and NOT creating a new line
# }
# console.log "lineObject: " + lineObject
# @updateShape type, lineObject
# globals.events.on "connection:move_and_zoom", (xOffset, yOffset, widthRatio, heightRatio) =>
# @moveAndZoom(xOffset, yOffset, widthRatio, heightRatio)
# globals.events.on "connection:changeslide", (url) =>
# @showImageFromPaper(url)
# globals.events.on "connection:viewBox", (xperc, yperc, wperc, hperc) =>
# xperc = parseFloat(xperc, 10)
# yperc = parseFloat(yperc, 10)
# wperc = parseFloat(wperc, 10)
# hperc = parseFloat(hperc, 10)
# @updatePaperFromServer(xperc, yperc, wperc, hperc)
# globals.events.on "connection:fitToPage", (value) =>
# @setFitToPage(value)
# globals.events.on "connection:zoom", (delta) =>
# @setZoom(delta)
# globals.events.on "connection:paper", (cx, cy, sw, sh) =>
# @updatePaperFromServer(cx, cy, sw, sh)
# globals.events.on "connection:panStop", =>
# @stopPanning()
# globals.events.on "connection:toolChanged", (tool) =>
# @setCurrentTool(tool)
# globals.events.on "connection:textDone", =>
# @textDone()
# globals.events.on "connection:uploadStatus", (message, fade) =>
# globals.events.trigger("whiteboard:paper:uploadStatus", message, fade)
# Update the dimensions of the container.
_updateContainerDimensions: ->
#console.log "update Container Dimensions"
@ -579,149 +232,6 @@ class Meteor.WhiteboardPaperModel
return @raphaelObj.getById(id) if id?
null
# Hides an image from the paper given the URL.
# The url must be in the slides array.
# @param {string} url the url of the image (must be in slides array)
_hideImageFromPaper: (url) ->
img = @_getImageFromPaper(url)
img.hide() if img?
# Update zoom variables on all clients
# @param {Event} e the event that occurs when scrolling
# @param {number} delta the speed/direction at which the scroll occurred
_zoomSlide: (e, delta) ->
#globals.connection.emitZoom delta
# Called when the cursor is moved over the presentation.
# Sends cursor moving event to server.
# @param {Event} e the mouse event
# @param {number} x the x value of cursor at the time in relation to the left side of the browser
# @param {number} y the y value of cursor at the time in relation to the top of the browser
# TODO: this should only be done if the user is the presenter
_onMouseMove: (e, x, y) ->
[sw, sh] = @_currentSlideDimensions()
xLocal = (e.pageX - @containerOffsetLeft) / sw
yLocal = (e.pageY - @containerOffsetTop) / sh
#globals.connection.emitMoveCursor xLocal, yLocal
# When the user is dragging the cursor (click + move)
# @param {number} dx the difference between the x value from panGo and now
# @param {number} dy the difference between the y value from panGo and now
_panDragging: (dx, dy) ->
[slideWidth, slideHeight] = @_currentSlideOriginalDimensions()
sx = (@containerWidth - slideWidth) / 2
sy = (@containerHeight - slideHeight) / 2
[sw, sh] = @_currentSlideDimensions()
# ensuring that we cannot pan outside of the boundaries
x = (@panX - dx)
# cannot pan past the left edge of the page
x = (if x < 0 then 0 else x)
y = (@panY - dy)
# cannot pan past the top of the page
y = (if y < 0 then 0 else y)
if @fitToPage
x2 = slideWidth + x
else
x2 = @containerWidth + x
# cannot pan past the width
x = (if x2 > sw then sw - (@containerWidth - sx * 2) else x)
if @fitToPage
y2 = slideHeight + y
else
# height of image could be greater (or less) than the box it fits in
y2 = @containerHeight + y
# cannot pan below the height
y = (if y2 > sh then sh - (@containerHeight - sy * 2) else y)
#globals.connection.emitPaperUpdate x / sw, y / sh, null, null
# When panning starts
# @param {number} x the x value of the cursor
# @param {number} y the y value of the cursor
_panGo: (x, y) ->
[cx, cy] = @_currentSlideOffsets()
@panX = cx
@panY = cy
# When panning finishes
# @param {Event} e the mouse event
_panStop: (e) ->
@stopPanning()
# Called when the application window is resized.
_onWindowResize: ->
@_updateContainerDimensions()
console.log "_onWindowResize"
#TODO: temporary hacked away fix so that the buttons resize correctly when the window resizes
$("#users-btn").click();
$("#users-btn").click();
#TODO: maybe find solution besides these global values..no conflicts however
[slideWidth, slideHeight] = @_currentSlideOriginalDimensions()
#console.log("xOffset: " + xOffset + ", yOffset: " + yOffset);
#console.log("@containerWidth: " + @containerWidth + " @containerHeight: " + @containerHeight);
#console.log("slideWidth: " + slideWidth + " slideHeight: " + slideHeight);
baseWidth = (@containerWidth - slideWidth) / 2
baseHeight = (@containerHeight - slideHeight) / 2
#get the actual size of the slide, depending on the limiting factor (container width or container height)
if(@containerWidth - slideWidth < @containerHeight - slideHeight)
actualHeight = @containerWidth * slideHeight / slideWidth
actualWidth = @containerWidth
else
actualWidth = @containerHeight * slideWidth / slideHeight
actualHeight = @containerHeight
#console.log("actualWidth:" + actualWidth + " actualHeight: " + actualHeight)
#calculate parameters to pass
newXPos = baseWidth
newyPos = baseHeight
newWidth = actualWidth
newHeight = actualHeight
#now the zooming will still be correct when the window is resized
#and hopefully when rotated on a mobile device
if @globalxOffset? && @globalyOffset? && @globalwidthRatio? && @globalheightRatio?
console.log "has zoomed in"
@moveAndZoom(@globalxOffset, @globalyOffset, @globalwidthRatio, @globalheightRatio)
else
obj =
globalxOffset : @globalxOffset
globalyOffset : @globalyOffset
globalwidthRatio : @globalwidthRatio
globalheightRatio : @globalheightRatio
console.log obj
console.log "not zoomed"
@raphaelObj.setViewBox(newXPos, newyPos, newWidth, newHeight,true)
# when pressing down on a key at anytime
_onKeyDown: (event) ->
unless event
keyCode = window.event.keyCode
else
keyCode = event.keyCode
switch keyCode
when 16 # shift key
@shiftPressed = true
# when releasing any key at any time
_onKeyUp: ->
unless event
keyCode = window.event.keyCode
else
keyCode = event.keyCode
switch keyCode
when 16 # shift key
@shiftPressed = false
_currentSlideDimensions: ->
if @current.slide? then @current.slide.getDimensions() else [0, 0]
@ -774,24 +284,6 @@ class Meteor.WhiteboardPaperModel
_displayPage: (data, originalWidth, originalHeight) ->
@removeAllImagesFromPaper()
# get dimensions for available whiteboard space
# get where to start from the left -> either the end of the user's list or the left edge of the screen
# if getInSession "display_usersList" then xBegin = $("#userListContainer").width()
# else xBegin = 0
# # get where to start from the right -> either the beginning of the chat bar or the right edge of the screen
# if getInSession "display_chatbar" then xEnd = $("#chat").position().left
# else xEnd = $( document ).width();
# # find the height to start the top of the image at
# if getInSession "display_navbar" then yBegin = $("#navbar").height()
# else yBegin = 0
# yEnd = $( document ).height();
# # TODO: add some form of padding to the left, right, top, and bottom boundaries
# #
# boardWidth = xEnd - xBegin
# boardHeight = yEnd - yBegin
@_updateContainerDimensions()
boardWidth = @containerWidth
boardHeight = @containerHeight
@ -801,7 +293,7 @@ class Meteor.WhiteboardPaperModel
# TODO currentSlide undefined in some cases - will check later why
imageWidth = boardWidth * (currentSlide?.slide.width_ratio/100) or boardWidth
imageHeight = boardHeight * (currentSlide?.slide.height_ratio/100) or boardHeight
#alert("_displayPage")
# console.log "xBegin: #{xBegin}"
# console.log "xEnd: #{xEnd}"
# console.log "yBegin: #{yBegin}"
@ -832,7 +324,8 @@ class Meteor.WhiteboardPaperModel
oldRatio = (oldDoc.slide.width_ratio + oldDoc.slide.height_ratio) / 2
newRatio = (newDoc.slide.width_ratio + newDoc.slide.height_ratio) / 2
_this?.currentShapes?.forEach (shape) ->
_this?.current?.shapes?.forEach (shape) ->
shape.attr "stroke-width", shape.attr('stroke-width') * oldRatio / newRatio
_this.cursor.setRadius(6 * newDoc.slide.width_ratio / 100)

View File

@ -15,7 +15,7 @@ class @WhiteboardTextModel extends WhiteboardToolModel
y = startingData.y
width = startingData.textBoxWidth
height = startingData.textBoxHeight
colour = startingData.fontColor
colour = formatColor(startingData.fontColor)
fontSize = startingData.fontSize
calcFontSize = startingData.calcedFontSize
text = startingData.text
@ -28,11 +28,10 @@ class @WhiteboardTextModel extends WhiteboardToolModel
x = (x * @gw) + @xOffset
y = (y * @gh) + @yOffset + calcFontSize
width = width/100 * @gw
colour = Meteor.call("strokeAndThickness",colour, false)
@obj = @paper.text(x/100, y/100, "")
@obj.attr
fill: Meteor.call("strokeAndThickness",colour, false)
"fill": colour
"font-family": "Arial" # TODO: make dynamic
"font-size": calcFontSize
@obj.node.style["text-anchor"] = "start" # force left align
@ -48,7 +47,7 @@ class @WhiteboardTextModel extends WhiteboardToolModel
y = startingData.y
maxWidth = startingData.textBoxWidth
height = startingData.textBoxHeight
colour = startingData.fontColor
colour = formatColor(startingData.fontColor)
fontSize = startingData.fontSize
calcFontSize = startingData.calcedFontSize
myText = startingData.text
@ -61,7 +60,8 @@ class @WhiteboardTextModel extends WhiteboardToolModel
maxWidth = maxWidth/100 * @gw
@obj.attr
fill: "#000"
"fill": colour
"font-family": "Arial" # TODO: make dynamic
"font-size": calcFontSize
cell = @obj.node
while cell? and cell.hasChildNodes()

View File

@ -61,7 +61,16 @@ Meteor.methods
from_lang: messageObject.from_lang
id = Meteor.Chat.insert(entry)
Meteor.log.info "added chat id=[#{id}]:#{messageObject.message}. Chat.size is now #{Meteor.Chat.find({meetingId: meetingId}).count()}"
Meteor.log.info "added chat id=[#{id}]:#{messageObject.message}." #" Chat.size is now #{Meteor.Chat.find({meetingId: meetingId}).count()}"
# called on server start and meeting end
@clearChatCollection = (meetingId) ->
if meetingId?
Meteor.Chat.remove({meetingId: meetingId}, Meteor.log.info "cleared Chat Collection (meetingId: #{meetingId}!")
else
Meteor.Chat.remove({}, Meteor.log.info "cleared Chat Collection (all meetings)!")
# --------------------------------------------------------------------------------------------
# end Private methods on server
# --------------------------------------------------------------------------------------------

View File

@ -14,17 +14,34 @@
duration: duration)
Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}]."
@clearMeetingsCollection = (meetingId) ->
if meetingId?
Meteor.Meetings.remove({meetingId: meetingId}, Meteor.log.info "cleared Meetings Collection (meetingId: #{meetingId}!")
else
Meteor.Meetings.remove({}, Meteor.log.info "cleared Meetings Collection (all meetings)!")
@removeMeetingFromCollection = (meetingId) ->
if Meteor.Meetings.findOne({meetingId: meetingId})?
if Meteor.Users.find({meetingId: meetingId}).count() isnt 0
Meteor.log.info "!!removing a meeting which has users in it"
for user in Meteor.Users.find({meetingId: meetingId}).fetch()
Meteor.log.info "in meetings::removeMeetingFromCollection #{meetingId} #{user.userId}"
removeUserFromCollection meetingId, user.userId
id = Meteor.Meetings.findOne({meetingId: meetingId})
if id?
Meteor.Meetings.remove(id._id)
Meteor.log.info "removed from Meetings:#{meetingId} now there are only #{Meteor.Meetings.find().count()} meetings running"
Meteor.log.info "end of meeting #{meetingId}. Clear the meeting data from all collections"
# delete all users in the meeting
clearUsersCollection(meetingId)
# delete all slides in the meeting
clearSlidesCollection(meetingId)
# delete all shapes in the meeting
clearShapesCollection(meetingId)
# delete all presentations in the meeting
clearPresentationsCollection(meetingId)
# delete all chat messages in the meeting
clearChatCollection(meetingId)
# delete the meeting
clearMeetingsCollection(meetingId)
# --------------------------------------------------------------------------------------------
# end Private methods on server
# --------------------------------------------------------------------------------------------

View File

@ -24,6 +24,15 @@
if id?
Meteor.Presentations.remove(id._id)
Meteor.log.info "----removed presentation[" + presentationId + "] from " + meetingId
# called on server start and meeting end
@clearPresentationsCollection = (meetingId) ->
if meetingId?
Meteor.Presentations.remove({meetingId: meetingId}, Meteor.log.info "cleared Presentations Collection (meetingId: #{meetingId}!")
else
Meteor.Presentations.remove({}, Meteor.log.info "cleared Presentations Collection (all meetings)!")
# --------------------------------------------------------------------------------------------
# end Private methods on server
# --------------------------------------------------------------------------------------------

View File

@ -76,6 +76,15 @@
Meteor.Shapes.remove(shapeToRemove._id)
Meteor.log.info "----removed shape[" + shapeId + "] from " + whiteboardId
Meteor.log.info "remaining shapes on the slide:" + Meteor.Shapes.find({meetingId: meetingId, whiteboardId: whiteboardId}).count()
# called on server start and meeting end
@clearShapesCollection = (meetingId) ->
if meetingId?
Meteor.Shapes.remove({meetingId: meetingId}, Meteor.log.info "cleared Shapes Collection (meetingId: #{meetingId}!")
else
Meteor.Shapes.remove({}, Meteor.log.info "cleared Shapes Collection (all meetings)!")
# --------------------------------------------------------------------------------------------
# end Private methods on server
# --------------------------------------------------------------------------------------------

View File

@ -39,6 +39,14 @@
if id?
Meteor.Slides.remove(id._id)
Meteor.log.info "----removed slide[" + slideId + "] from " + meetingId
# called on server start and meeting end
@clearSlidesCollection = (meetingId) ->
if meetingId?
Meteor.Slides.remove({meetingId: meetingId}, Meteor.log.info "cleared Slides Collection (meetingId: #{meetingId}!")
else
Meteor.Slides.remove({}, Meteor.log.info "cleared Slides Collection (all meetings)!")
# --------------------------------------------------------------------------------------------
# end Private methods on server
# --------------------------------------------------------------------------------------------

View File

@ -117,17 +117,6 @@ Meteor.methods
Meteor.log.info "marking user [#{userId}] as offline in meeting[#{meetingId}]"
Meteor.Users.update({'meetingId': meetingId, 'userId': userId}, {$set:{'user.connection_status':'offline'}})
# Only callable from server
# when the meeting ends
@removeUserFromCollection = (meetingId, userId) ->
Meteor.log.info "in users::removeUserFromCollection, #{meetingId} #{userId}"
u = Meteor.Users.findOne({'meetingId': meetingId, 'userId': userId})
if u?
Meteor.Users.remove(u._id)
Meteor.log.info "----removed user[" + userId + "] from " + meetingId
else
Meteor.log.info "did not find a user [userId] to delete in meetingid:#{meetingId}"
# Corresponds to a valid action on the HTML clientside
# After authorization, publish a user_leaving_request in redis
@ -272,3 +261,10 @@ Meteor.methods
id = Meteor.Users.insert(entry)
Meteor.log.info "added user dummy user id=[#{id}]:#{user.name}.
Users.size is now #{Meteor.Users.find({meetingId: meetingId}).count()}"
# called on server start and on meeting end
@clearUsersCollection = (meetingId) ->
if meetingId?
Meteor.Users.remove({meetingId: meetingId}, Meteor.log.info "cleared Users Collection (meetingId: #{meetingId}!")
else
Meteor.Users.remove({}, Meteor.log.info "cleared Users Collection (all meetings)!")

View File

@ -64,18 +64,3 @@ Meteor.publish 'meetings', (meetingId) ->
Meteor.publish 'presentations', (meetingId) ->
Meteor.log.info "publishing presentations for #{meetingId}"
Meteor.Presentations.find({meetingId: meetingId})
# Clear all data in subcriptions
@clearCollections = ->
Meteor.Users.remove({})
Meteor.log.info "cleared Users Collection!"
Meteor.Chat.remove({})
Meteor.log.info "cleared Chat Collection!"
Meteor.Meetings.remove({})
Meteor.log.info "cleared Meetings Collection!"
Meteor.Shapes.remove({})
Meteor.log.info "cleared Shapes Collection!"
Meteor.Slides.remove({})
Meteor.log.info "cleared Slides Collection!"
Meteor.Presentations.remove({})
Meteor.log.info "cleared Presentations Collection!"

View File

@ -2,7 +2,12 @@ Meteor.startup ->
Meteor.log.info "server start"
#remove all data
clearCollections()
clearUsersCollection()
clearChatCollection()
clearMeetingsCollection()
clearShapesCollection()
clearSlidesCollection()
clearPresentationsCollection()
# create create a PubSub connection, start listening
Meteor.redisPubSub = new Meteor.RedisPubSub(->

View File

@ -1,4 +1,4 @@
xdescribe("Collections", function () {
describe("Collections", function () {
beforeEach(function () {
MeteorStubs.install();
});
@ -19,7 +19,12 @@ xdescribe("Collections", function () {
spyOn(Meteor.Slides, "remove");
spyOn(Meteor.Presentations, "remove");
clearCollections();
clearUsersCollection();
clearChatCollection();
clearMeetingsCollection();
clearShapesCollection();
clearSlidesCollection();
clearPresentationsCollection();
expect(Meteor.Users.remove).toHaveBeenCalled();
expect(Meteor.Chat.remove).toHaveBeenCalled();
@ -35,8 +40,8 @@ xdescribe("Collections", function () {
it("should be handled correctly by insert() on calling addChatToCollection() in case of private chat", function () {
spyOn(Meteor.Users, "findOne").and.callFake(function(doc) {
if(doc.userId == "user001") return { _id: "dbid001" };
else if(doc.userId == "user002") return { _id: "dbid002" };
if(doc.userId == "user001") return { userId: "user001" };
else if(doc.userId == "user002") return { userUd: "user002" };
});
spyOn(Meteor.Chat, "insert");
@ -61,8 +66,8 @@ xdescribe("Collections", function () {
to_username: "Anton",
from_tz_offset: "240",
from_color: "0x000000",
to_userid: "dbid002",//not "user002"
from_userid: "dbid001",//not "user001"
to_userid: "user002",//not "dbid002"
from_userid: "user001",//not "dbid001"
from_time: "123",
from_username: "Maxim",
from_lang: "en"
@ -99,7 +104,7 @@ xdescribe("Collections", function () {
from_tz_offset: "240",
from_color: "0x000000",
to_userid: "public_chat_userid",
from_userid: "dbid001",
from_userid: "user001",
from_time: "123",
from_username: "Maxim",
from_lang: "en"