From 4ff1f4a30e64def208a6f8f556d8373dd8ec68cc Mon Sep 17 00:00:00 2001 From: Yana Stamcheva Date: Wed, 12 Feb 2014 23:28:56 +0100 Subject: [PATCH] Adds support for etherpad in meet.jit.si. Issue #36. --- app.js | 36 +++++++++++--- css/main.css | 6 +-- etherpad.js | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 14 +++--- muc.js | 15 ++++++ 5 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 etherpad.js diff --git a/app.js b/app.js index 8b84c7d96..3602885ec 100644 --- a/app.js +++ b/app.js @@ -86,6 +86,7 @@ function doJoin() { window.history.pushState('VideoChat', 'Room: ' + roomnode, window.location.pathname + roomnode); } } + roomjid = roomnode + '@' + config.hosts.muc; if (config.useNicks) { @@ -111,7 +112,9 @@ $(document).bind('mediaready.jingle', function (event, stream) { updateLargeVideo(localVideoSrc, true, 0); $('#localVideo').click(function () { - updateLargeVideo($(this).attr('src'), true, 0); + $(document).trigger("video.selected", [false]); + updateLargeVideo($(this).attr('src'), true, 0); + $('video').each(function (idx, el) { if (el.id.indexOf('mixedmslabel') != -1) { el.volume = 0; @@ -217,6 +220,7 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) { }; sel.click( function () { + $(document).trigger("video.selected", [false]); updateLargeVideo($(this).attr('src'), false, 1); } ); @@ -282,6 +286,10 @@ $(document).bind('joined.muc', function (event, jid, info) { focus = new ColibriFocus(connection, config.hosts.bridge); } + if (focus && config.etherpad_base) { + Etherpad.init(); + } + showFocusIndicator(); // Once we've joined the muc show the toolbar @@ -338,13 +346,13 @@ $(document).bind('left.muc', function (event, jid) { $(container).hide(); resizeThumbnails(); } - if (focus === null && connection.emuc.myroomjid == connection.emuc.list_members[0]) { console.log('welcome to our new focus... myself'); focus = new ColibriFocus(connection, config.hosts.bridge); if (Object.keys(connection.emuc.members).length > 0) { focus.makeConference(Object.keys(connection.emuc.members)); } + $(document).trigger('focusechanged.muc', [focus]); } else if (focus && Object.keys(connection.emuc.members).length === 0) { console.log('everyone left'); @@ -437,11 +445,11 @@ $(document).bind('presentationadded.muc', function (event, jid, presUrl, current setPresentationVisible(true); $('#largeVideoContainer').hover( function (event) { - if ($('#largeVideo').css('visibility') == 'hidden') + if (isPresentationVisible()) $('#reloadPresentation').css({display:'inline-block'}); }, function (event) { - if ($('#largeVideo').css('visibility') == 'visible') + if (!isPresentationVisible()) $('#reloadPresentation').css({display:'none'}); else { var e = event.toElement || event.relatedTarget; @@ -519,6 +527,9 @@ function reloadPresentation() { */ function setPresentationVisible(visible) { if (visible) { + // Trigger the video.selected event to indicate a change in the large video. + $(document).trigger("video.selected", [true]); + $('#largeVideo').fadeOut(300, function () { $('#largeVideo').css({visibility:'hidden'}); $('#presentation>iframe').fadeIn(300, function() { @@ -538,6 +549,10 @@ function setPresentationVisible(visible) { } } +var isPresentationVisible = function () { + return ($('#presentation>iframe') != null && $('#presentation>iframe').css('opacity') == 1); +} + /** * Updates the large video with the given new video source. */ @@ -607,15 +622,20 @@ function resizeLarge() { $('#presentation>iframe').width(availableWidth); $('#presentation>iframe').height(availableWidth / aspectRatio); } - + + if ($('#etherpad>iframe')) { + $('#etherpad>iframe').width(availableWidth); + $('#etherpad>iframe').height(availableWidth / aspectRatio); + } + resizeThumbnails(); } function resizeThumbnails() { // Calculate the available height, which is the inner window height minus 39px for the header - // minus 4px for the delimiter lines on the top and bottom of the large video, + // minus 2px for the delimiter lines on the top and bottom of the large video, // minus the 36px space inside the remoteVideos container used for highlighting shadow. - var availableHeight = window.innerHeight - $('#largeVideo').height() - 79; + var availableHeight = window.innerHeight - $('#largeVideo').height() - 59; var numvids = $('#remoteVideos>span:visible').length; // Remove the 1px borders arround videos and the chat width. @@ -629,7 +649,7 @@ function resizeThumbnails() { } // size videos so that while keeping AR and max height, we have a nice fit - $('#remoteVideos').height(availableHeight+26); // add the 2*18px-padding-top border used for highlighting shadow. + $('#remoteVideos').height(availableHeight); $('#remoteVideos>span').width(availableWidth); $('#remoteVideos>span').height(availableHeight); } diff --git a/css/main.css b/css/main.css index b1ec66c34..6c59de8d9 100644 --- a/css/main.css +++ b/css/main.css @@ -22,7 +22,7 @@ html, body{ margin-left: auto; margin-right: auto; } -#presentation, .videocontainer>video { +#presentation, #etherpad, .videocontainer>video { position: absolute; left: 0px; top: 0px; @@ -53,7 +53,7 @@ html, body{ position:relative; text-align:center; height:196px; - padding-top:10px; + padding: 5px 0px; width:auto; overflow: hidden; border:1px solid transparent; @@ -415,5 +415,5 @@ form { background-clip: padding-box; -webkit-border-radius: 5px; -webkit-background-clip: padding-box; - z-index: 2; + z-index: 3; } diff --git a/etherpad.js b/etherpad.js new file mode 100644 index 000000000..f4be84610 --- /dev/null +++ b/etherpad.js @@ -0,0 +1,136 @@ +var Etherpad = (function (my) { + var etherpadName = null; + + /** + * Initializes the etherpad. + */ + my.init = function (name) { + + if (config.etherpad_base && !etherpadName) { + + if (!name) { + // In case we're the focus we generate the name. + etherpadName = Math.random().toString(36).substring(7) + '_' + (new Date().getTime()).toString(); + shareEtherpad(); + } + else + etherpadName = name; + + this.domain = config.etherpad_base; + this.options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false"; + + createEtherpadButton(); + + this.iframe = document.createElement('iframe'); + this.iframe.src = this.domain + etherpadName + this.options; + this.iframe.frameBorder = 0; + this.iframe.scrolling = "no"; + this.iframe.width = $('#largeVideoContainer').width() || 640; + this.iframe.height = $('#largeVideoContainer').height() || 480; + this.iframe.setAttribute('style', 'visibility: hidden;'); + + document.getElementById('etherpad').appendChild(this.iframe); + } + } + + /** + * Opens/hides the Etherpad. + */ + my.toggleEtherpad = function (isPresentation) { + var largeVideo = null; + if (isPresentationVisible()) + largeVideo = $('#presentation>iframe'); + else + largeVideo = $('#largeVideo'); + + if ($('#etherpad>iframe').css('visibility') == 'hidden') { + largeVideo.fadeOut(300, function () { + if (isPresentationVisible()) + largeVideo.css({opacity:'0'}); + else + largeVideo.css({visibility:'hidden'}); + + $('#etherpad>iframe').fadeIn(300, function() { + $('#etherpad>iframe').css({visibility:'visible'}); + $('#etherpad').css({zIndex:2}); + }); + }); + } + else if ($('#etherpad>iframe')) { + $('#etherpad>iframe').fadeOut(300, function () { + $('#etherpad>iframe').css({visibility:'hidden'}); + $('#etherpad').css({zIndex:0}); + if (!isPresentation) { + $('#largeVideo').fadeIn(300, function() { + $('#largeVideo').css({visibility:'visible'}); + }); + } + }); + } + }; + + /** + * Shares the Etherpad name with other participants. + */ + function shareEtherpad() { + connection.emuc.addEtherpadToPresence(etherpadName); + connection.emuc.sendPresence(); + } + + /** + * Creates the Etherpad button and adds it to the toolbar. + */ + function createEtherpadButton() { + //
+ // + // + var separator = document.createElement('div'); + separator.className = 'header_button_separator'; + + var button = document.createElement('a'); + button.className = 'button'; + button.setAttribute('onclick', 'Etherpad.toggleEtherpad(0);'); + + var buttonImage = document.createElement('i'); + buttonImage.setAttribute('title', 'Open shared document'); + buttonImage.className = 'fa fa-file-text fa-lg'; + + button.appendChild(buttonImage); + + var toolbar = document.getElementById('toolbar'); + toolbar.insertBefore(button, toolbar.childNodes[toolbar.childNodes.length - 4]); + toolbar.insertBefore(separator, button); + } + + /** + * On Etherpad added to muc. + */ + $(document).bind('etherpadadded.muc', function (event, jid, etherpadName) { + console.log("Etherpad added", etherpadName); + if (config.etherpad_base && !focus) { + Etherpad.init(etherpadName); + } + }); + + /** + * On focus changed event. + */ + $(document).bind('focusechanged.muc', function (event, focus) { + console.log("Focus changed"); + if (config.etherpad_base) + shareEtherpad(); + }); + + /** + * On video selected event. + */ + $(document).bind('video.selected', function (event, isPresentation) { + if (!config.etherpad_base) + return; + + if ($('#etherpad>iframe').css('visibility') != 'hidden') + Etherpad.toggleEtherpad(isPresentation); + }); + + return my; +}(Etherpad || {})); \ No newline at end of file diff --git a/index.html b/index.html index 6c4ba55a5..4ce5d9a00 100644 --- a/index.html +++ b/index.html @@ -5,13 +5,14 @@ - + - + + - + @@ -36,11 +37,7 @@
- - +
@@ -58,6 +55,7 @@
+
diff --git a/muc.js b/muc.js index ff8dabbfc..94b39d3b7 100644 --- a/muc.js +++ b/muc.js @@ -43,6 +43,13 @@ Strophe.addConnectionPlugin('emuc', { return true; } + // Parse etherpad tag. + var etherpad = $(pres).find('>etherpad'); + if (etherpad.length) { + $(document).trigger('etherpadadded.muc', [from, etherpad.text()]); + } + + // Parse prezi tag. var presentation = $(pres).find('>prezi'); if (presentation.length) { @@ -188,6 +195,10 @@ Strophe.addConnectionPlugin('emuc', { c('current').t(this.presMap['prezicurrent']).up().up(); } + if (this.presMap['etherpadns']) { + pres.c('etherpad', {xmlns: this.presMap['etherpadns']}).t(this.presMap['etherpadname']).up(); + } + if (this.presMap['medians']) { pres.c('media', {xmlns: this.presMap['medians']}); @@ -232,5 +243,9 @@ Strophe.addConnectionPlugin('emuc', { }, getPrezi: function (roomjid) { return this.preziMap[roomjid]; + }, + addEtherpadToPresence: function(etherpadName) { + this.presMap['etherpadns'] = 'http://jitsi.org/jitmeet/etherpad'; + this.presMap['etherpadname'] = etherpadName; } });