Переглянути джерело

Adds presentations with Prezi.

master
Yana Stamcheva 11 роки тому
джерело
коміт
6945aa802c
7 змінених файлів з 720 додано та 58 видалено
  1. 335
    39
      app.js
  2. 27
    12
      css/main.css
  3. 4
    1
      css/modaldialog.css
  4. BIN
      images/avatarprezi.png
  5. 13
    4
      index.html
  6. 259
    0
      libs/prezi_player.js
  7. 82
    2
      muc.js

+ 335
- 39
app.js Переглянути файл

@@ -9,6 +9,7 @@ var sharedKey = '';
9 9
 var roomUrl = null;
10 10
 var ssrc2jid = {};
11 11
 var localVideoSrc = null;
12
+var preziPlayer = null;
12 13
 
13 14
 /* window.onbeforeunload = closePageWarning; */
14 15
 
@@ -140,16 +141,14 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
140 141
 
141 142
     var container;
142 143
     var remotes = document.getElementById('remoteVideos');
144
+
143 145
     if (data.peerjid) {
144 146
         container  = document.getElementById('participant_' + Strophe.getResourceFromJid(data.peerjid));
145 147
         if (!container) {
146 148
             console.warn('no container for', data.peerjid);
147 149
             // create for now...
148 150
             // FIXME: should be removed
149
-            container = document.createElement('span');
150
-            container.id = 'participant_' + Strophe.getResourceFromJid(data.peerjid);
151
-            container.className = 'videocontainer';
152
-            remotes.appendChild(container);
151
+            container = addRemoteVideoContainer('participant_' + Strophe.getResourceFromJid(data.peerjid));
153 152
         } else {
154 153
             //console.log('found container for', data.peerjid);
155 154
         }
@@ -173,6 +172,7 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
173 172
         container.id = 'mixedstream';
174 173
         $(container).hide();
175 174
     }
175
+
176 176
     var sel = $('#' + id);
177 177
     sel.hide();
178 178
     RTC.attachMediaStream(sel, data.stream);
@@ -187,10 +187,12 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
187 187
             var pick = $('#remoteVideos>span[id!="mixedstream"]:visible:last>video').get(0);
188 188
             // mute if localvideo
189 189
             var isLocalVideo = false;
190
-            if (pick.src === localVideoSrc)
190
+            if (pick) {
191
+                 if (pick.src === localVideoSrc)
191 192
                  isLocalVideo = true;
192
-
193
-            updateLargeVideo(pick.src, isLocalVideo, pick.volume);
193
+                 
194
+                 updateLargeVideo(pick.src, isLocalVideo, pick.volume);
195
+            }
194 196
         }
195 197
         $('#' + id).parent().remove();
196 198
         resizeThumbnails();
@@ -217,7 +219,7 @@ $(document).bind('callactive.jingle', function (event, videoelem, sid) {
217 219
         resizeThumbnails();
218 220
 
219 221
         updateLargeVideo(videoelem.attr('src'), false, 1);
220
-                 
222
+
221 223
         showFocusIndicator();
222 224
     }
223 225
 });
@@ -238,16 +240,13 @@ $(document).bind('setLocalDescription.jingle', function (event, sid) {
238 240
         newssrcs[type] = ssrc;
239 241
     });
240 242
     console.log('new ssrcs', newssrcs);
241
-    // just blast off presence for everything -- TODO: optimize
242
-    var pres = $pres({to: connection.emuc.myroomjid });
243
-    pres.c('x', {xmlns: 'http://jabber.org/protocol/muc'}).up();
244 243
 
245
-    pres.c('media', {xmlns: 'http://estos.de/ns/mjs'});
244
+    var i = 0;
246 245
     Object.keys(newssrcs).forEach(function (mtype) {
247
-        pres.c('source', {type: mtype, ssrc: newssrcs[mtype]}).up();
246
+        i++;
247
+        connection.emuc.addMediaToPresence(i, mtype, newssrcs[mtype]);
248 248
     });
249
-    pres.up();
250
-    connection.send(pres);
249
+    connection.emuc.sendPresence();
251 250
 });
252 251
 
253 252
 $(document).bind('joined.muc', function (event, jid, info) {
@@ -256,22 +255,19 @@ $(document).bind('joined.muc', function (event, jid, info) {
256 255
         document.createTextNode(Strophe.getResourceFromJid(jid) + ' (you)')
257 256
     );
258 257
 
259
-    // Once we've joined the muc show the toolbar
260
-    showToolbar();
261
-
262 258
     if (Object.keys(connection.emuc.members).length < 1) {
263 259
         focus = new ColibriFocus(connection, config.hosts.bridge);
264 260
     }
261
+                 
262
+    // Once we've joined the muc show the toolbar
263
+    showToolbar();
265 264
 });
266 265
 
267 266
 $(document).bind('entered.muc', function (event, jid, info, pres) {
268 267
     console.log('entered', jid, info);
269 268
     console.log(focus);
270
-    var container = document.createElement('span');
271
-    container.id = 'participant_' + Strophe.getResourceFromJid(jid);
272
-    container.className = 'videocontainer';
273
-    var remotes = document.getElementById('remoteVideos');
274
-    remotes.appendChild(container);
269
+    
270
+    var container = addRemoteVideoContainer('participant_' + Strophe.getResourceFromJid(jid));
275 271
 
276 272
     var nickfield = document.createElement('span');
277 273
     nickfield.appendChild(document.createTextNode(Strophe.getResourceFromJid(jid)));
@@ -304,7 +300,7 @@ $(document).bind('left.muc', function (event, jid) {
304 300
     var container = document.getElementById('participant_' + Strophe.getResourceFromJid(jid));
305 301
     if (container) {
306 302
         // hide here, wait for video to close before removing
307
-        $(container).hide(); 
303
+        $(container).hide();
308 304
         resizeThumbnails();
309 305
     }
310 306
 
@@ -319,6 +315,10 @@ $(document).bind('left.muc', function (event, jid) {
319 315
             focus = new ColibriFocus(connection, config.hosts.bridge);
320 316
         }
321 317
     }
318
+    
319
+    if (connection.emuc.getPrezi(jid)) {
320
+        $(document).trigger('presentationremoved.muc', [jid, connection.emuc.getPrezi(jid)]);
321
+    }
322 322
 });
323 323
 
324 324
 $(document).bind('presence.muc', function (event, jid, info, pres) {
@@ -355,11 +355,156 @@ $(document).bind('passwordrequired.muc', function (event, jid) {
355 355
             });
356 356
 });
357 357
 
358
+/*
359
+ * Presentation has been removed.
360
+ */
361
+$(document).bind('presentationremoved.muc', function(event, jid, presUrl) {
362
+    console.log('presentation removed', presUrl);
363
+    var presId = getPresentationId(presUrl);
364
+    setPresentationVisible(false);
365
+    $('#participant_' + Strophe.getResourceFromJid(jid) + '_' + presId).remove();
366
+    $('#presentation>iframe').remove();
367
+    if (preziPlayer != null) {
368
+        preziPlayer.destroy();
369
+        preziPlayer = null;
370
+    }
371
+});
372
+
373
+/*
374
+ * Presentation has been added.
375
+ */
376
+$(document).bind('presentationadded.muc', function (event, jid, presUrl, currentSlide) {
377
+    console.log("presentation added", presUrl);
378
+
379
+    var presId = getPresentationId(presUrl);
380
+    var elementId = 'participant_' + Strophe.getResourceFromJid(jid) + '_' + presId;
381
+
382
+    var container = addRemoteVideoContainer(elementId);
383
+    resizeThumbnails();
384
+
385
+    var controlsEnabled = false;
386
+    if (jid === connection.emuc.myroomjid)
387
+        controlsEnabled = true;
388
+
389
+    setPresentationVisible(true);
390
+    $('#largeVideoContainer').hover(
391
+        function (event) {
392
+            if ($('#largeVideo').css('visibility') == 'hidden')
393
+                $('#reloadPresentation').css({display:'inline-block'});
394
+        },
395
+        function (event) {
396
+            if ($('#largeVideo').css('visibility') == 'visible')
397
+                $('#reloadPresentation').css({display:'none'});
398
+            else {
399
+                var e = event.toElement || event.relatedTarget;
400
+
401
+                while(e && e.parentNode && e.parentNode != window) {
402
+                    if (e.parentNode == this ||  e ==  this) {
403
+                        return false;
404
+                    }
405
+                    e = e.parentNode;
406
+                }
407
+                $('#reloadPresentation').css({display:'none'});
408
+            }
409
+        });
410
+
411
+    preziPlayer = new PreziPlayer(
412
+                'presentation',
413
+                {preziId: presId,
414
+                width: $('#largeVideoContainer').width(),
415
+                height: $('#largeVideoContainer').height(),
416
+                controls: controlsEnabled,
417
+                debug: true
418
+                });
419
+
420
+    $('#presentation>iframe').attr('id', preziPlayer.options.preziId);
421
+
422
+//    $('#presentation>iframe').load(function (){
423
+//        console.log("IFRAME LOADED!!!!!!!!!!!!!!!!");
424
+//    });
425
+//    $('#presentation>iframe').ready(function (){
426
+//        console.log("IFRAME READY!!!!!!!!!!!!!!!!");
427
+//    });
428
+                 
429
+    preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
430
+        console.log("prezi status", event.value);
431
+        if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
432
+            if (jid != connection.emuc.myroomjid)
433
+                preziPlayer.flyToStep(currentSlide);
434
+        }
435
+    });
436
+
437
+    preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
438
+        console.log("event value", event.value);
439
+        connection.emuc.addCurrentSlideToPresence(event.value);
440
+        connection.emuc.sendPresence();
441
+    });
442
+
443
+    $("#" + elementId).css('background-image','url(../images/avatarprezi.png)');
444
+    $("#" + elementId).click(
445
+        function () {
446
+            setPresentationVisible(true);
447
+        }
448
+    );
449
+});
450
+
451
+/*
452
+ * Indicates presentation slide change.
453
+ */
454
+$(document).bind('gotoslide.muc', function (event, jid, presUrl, current) {
455
+    if (preziPlayer) {
456
+        preziPlayer.flyToStep(current);
457
+    }
458
+});
459
+
460
+/**
461
+ * Returns the presentation id from the given url.
462
+ */
463
+function getPresentationId (presUrl) {
464
+    var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10);
465
+    return presIdTmp.substring(0, presIdTmp.indexOf('/'));
466
+}
467
+
468
+/*
469
+ * Reloads the current presentation.
470
+ */
471
+function reloadPresentation() {
472
+    var iframe = document.getElementById(preziPlayer.options.preziId);
473
+    iframe.src = iframe.src;
474
+}
475
+
476
+/*
477
+ * Shows/hides a presentation.
478
+ */
479
+function setPresentationVisible(visible) {
480
+    if (visible) {
481
+        $('#largeVideo').fadeOut(300, function () {
482
+            $('#largeVideo').css({visibility:'hidden'});
483
+            $('#presentation>iframe').fadeIn(300, function() {
484
+                $('#presentation>iframe').css({opacity:'1'});
485
+            });
486
+        });
487
+    }
488
+    else {
489
+        if ($('#presentation>iframe')) {
490
+            $('#presentation>iframe').fadeOut(300, function () {
491
+                $('#presentation>iframe').css({opacity:'0'});
492
+                $('#largeVideo').fadeIn(300, function() {
493
+                    $('#largeVideo').css({visibility:'visible'});
494
+                });
495
+            });
496
+        }
497
+    }
498
+}
499
+
358 500
 /**
359 501
  * Updates the large video with the given new video source.
360 502
  */
361 503
 function updateLargeVideo(newSrc, localVideo, vol) {
362 504
     console.log('hover in', newSrc);
505
+
506
+    setPresentationVisible(false);
507
+
363 508
     if ($('#largeVideo').attr('src') != newSrc) {
364 509
 
365 510
         document.getElementById('largeVideo').volume = vol;
@@ -413,6 +558,9 @@ function resizeLarge() {
413 558
     if (availableWidth < 0 || availableHeight < 0) return;
414 559
     $('#largeVideo').parent().width(availableWidth);
415 560
     $('#largeVideo').parent().height(availableWidth / aspectRatio);
561
+    $('#presentation>iframe').width(availableWidth);
562
+    $('#presentation>iframe').height(availableWidth / aspectRatio);
563
+    
416 564
     resizeThumbnails();
417 565
 }
418 566
 
@@ -466,6 +614,9 @@ $(document).ready(function () {
466 614
 
467 615
     $('#usermsg').autosize();
468 616
 
617
+    // Set the defaults for prompt dialogs.
618
+    jQuery.prompt.setDefaults({persistent: false});
619
+
469 620
     resizeLarge();
470 621
     $(window).resize(function () {
471 622
         resizeLarge();
@@ -513,15 +664,8 @@ function dump(elem, filename){
513 664
             var session = connection.jingle.sessions[sid];
514 665
             if (session.peerconnection && session.peerconnection.updateLog) {
515 666
                 // FIXME: should probably be a .dump call
516
-                /* well, if I need to modify the output format anyway...
517
-                var stats = JSON.parse(JSON.stringify(session.peerconnection.stats));
518
-                Object.keys(stats).forEach(function (name) {
519
-                    stats[name].values = JSON.stringify(stats[name].values);
520
-                });
521
-                */
522 667
                 data["jingle_" + session.sid] = {
523 668
                     updateLog: session.peerconnection.updateLog,
524
-                    stats: session.peerconnection.stats,
525 669
                     url: window.location.href}
526 670
                 ;
527 671
             }
@@ -609,16 +753,16 @@ function openLockDialog() {
609 753
                      submit: function(e,v,m,f){
610 754
                      if(v)
611 755
                      {
612
-                     var lockKey = document.getElementById('lockKey');
756
+                        var lockKey = document.getElementById('lockKey');
613 757
                      
614
-                     if (lockKey.value)
615
-                     {
616
-                        setSharedKey(lockKey.value);
617
-                        lockRoom(true);
758
+                        if (lockKey.value)
759
+                        {
760
+                            setSharedKey(lockKey.value);
761
+                            lockRoom(true);
762
+                        }
618 763
                      }
619 764
                 }
620
-            }
621
-        });
765
+            });
622 766
     }
623 767
 }
624 768
 
@@ -637,11 +781,149 @@ function openLinkDialog() {
637 781
              });
638 782
 }
639 783
 
784
+/*
785
+ * Opens the settings dialog.
786
+ */
787
+function openSettingsDialog() {
788
+    $.prompt('<h2>Configure your conference</h2>' +
789
+             '<input type="checkbox" id="initMuted"> Participants join muted<br/>' +
790
+             '<input type="checkbox" id="requireNicknames"> Require nicknames<br/><br/>' +
791
+             'Set a secrect key to lock your room: <input id="lockKey" type="text" placeholder="your shared key" autofocus>',
792
+             {
793
+                persistent: false,
794
+                buttons: { "Save": true , "Cancel": false},
795
+                defaultButton: 1,
796
+                loaded: function(event) {
797
+                    document.getElementById('lockKey').focus();
798
+                },
799
+                submit: function(e,v,m,f){
800
+                    if(v)
801
+                    {
802
+                        if ($('#initMuted').is(":checked"))
803
+                        {
804
+                            // it is checked
805
+                        }
806
+
807
+                        if ($('#requireNicknames').is(":checked"))
808
+                        {
809
+                            // it is checked                        
810
+                        }
811
+             /*
812
+                        var lockKey = document.getElementById('lockKey');
813
+             
814
+                        if (lockKey.value)
815
+                        {
816
+                            setSharedKey(lockKey.value);
817
+                            lockRoom(true);
818
+                        }
819
+              */
820
+                    }
821
+                }
822
+             });
823
+}
824
+
825
+/*
826
+ * Opens the Prezi dialog, from which the user could choose a presentation to load.
827
+ */
828
+function openPreziDialog() {
829
+    var myprezi = connection.emuc.getPrezi(connection.emuc.myroomjid);
830
+    if (myprezi) {
831
+        $.prompt("Are you sure you would like to remove your Prezi?",
832
+                {
833
+                title: "Remove Prezi",
834
+                buttons: { "Remove": true, "Cancel": false},
835
+                defaultButton: 1,
836
+                submit: function(e,v,m,f){
837
+                if(v)
838
+                {
839
+                    connection.emuc.removePreziFromPresence();
840
+                    connection.emuc.sendPresence();
841
+                }
842
+            }
843
+        });
844
+    }
845
+    else if (preziPlayer != null) {
846
+        $.prompt("Another participant is already sharing a Prezi. This conference allows only one Prezi at a time.",
847
+                 {
848
+                 title: "Share a Prezi",
849
+                 buttons: { "Ok": true},
850
+                 defaultButton: 0,
851
+                 submit: function(e,v,m,f){
852
+                    $.prompt.close();
853
+                 }
854
+                 });
855
+    }
856
+    else {
857
+        var openPreziState = {
858
+        state0: {
859
+            html:   '<h2>Share a Prezi</h2>' +
860
+                    '<input id="preziUrl" type="text" placeholder="e.g. http://prezi.com/wz7vhjycl7e6/my-prezi" autofocus>',
861
+            persistent: false,
862
+            buttons: { "Share": true , "Cancel": false},
863
+            defaultButton: 1,
864
+            submit: function(e,v,m,f){
865
+                e.preventDefault();
866
+                if(v)
867
+                {
868
+                    var preziUrl = document.getElementById('preziUrl');
869
+
870
+                    if (preziUrl.value)
871
+                    {
872
+                        if (preziUrl.value.indexOf('http://prezi.com/') != 0
873
+                            && preziUrl.value.indexOf('https://prezi.com/') != 0)
874
+                        {
875
+                            $.prompt.goToState('state1');
876
+                            return false;
877
+                        }
878
+                        else {
879
+                            var presIdTmp = preziUrl.value.substring(preziUrl.value.indexOf("prezi.com/") + 10);
880
+                            if (presIdTmp.indexOf('/') < 2) {
881
+                                $.prompt.goToState('state1');
882
+                                return false;
883
+                            }
884
+                            else {
885
+                                connection.emuc.addPreziToPresence(preziUrl.value, 0);
886
+                                connection.emuc.sendPresence();
887
+                                $.prompt.close();
888
+                            }
889
+                        }
890
+                    }
891
+                }
892
+                else
893
+                    $.prompt.close();
894
+            }
895
+        },
896
+        state1: {
897
+            html:   '<h2>Share a Prezi</h2>' +
898
+                    'Please provide a correct prezi link.',
899
+            persistent: false,
900
+            buttons: { "Back": true, "Cancel": false },
901
+            defaultButton: 1,
902
+            submit:function(e,v,m,f) {
903
+                e.preventDefault();
904
+                if(v==0)
905
+                    $.prompt.close();
906
+                else
907
+                    $.prompt.goToState('state0');
908
+            }
909
+        }
910
+        };
911
+
912
+        var myPrompt = jQuery.prompt(openPreziState);
913
+        
914
+        myPrompt.on('impromptu:loaded', function(e) {
915
+                    document.getElementById('preziUrl').focus();
916
+                    });
917
+        myPrompt.on('impromptu:statechanged', function(e) {
918
+                    document.getElementById('preziUrl').focus();
919
+                    });
920
+    }
921
+}
922
+
640 923
 /*
641 924
  * Locks / unlocks the room.
642 925
  */
643 926
 function lockRoom(lock) {
644
-    console.log("LOCK", sharedKey);
645 927
     if (lock)
646 928
         connection.emuc.lockRoom(sharedKey);
647 929
     else
@@ -695,6 +977,11 @@ function openChat() {
695 977
  */
696 978
 function showToolbar() {
697 979
     $('#toolbar').css({visibility:"visible"});
980
+    if (focus != null)
981
+    {
982
+//        TODO: Enable settings functionality. Need to uncomment the settings button in index.html.
983
+//        $('#settingsButton').css({visibility:"visible"});
984
+    }
698 985
 }
699 986
 
700 987
 /*
@@ -745,6 +1032,15 @@ function showFocusIndicator() {
745 1032
     }
746 1033
 }
747 1034
 
1035
+function addRemoteVideoContainer(id) {
1036
+    var container = document.createElement('span');
1037
+    container.id = id;
1038
+    container.className = 'videocontainer';
1039
+    var remotes = document.getElementById('remoteVideos');
1040
+    remotes.appendChild(container);
1041
+    return container;
1042
+}
1043
+
748 1044
 /*
749 1045
  * Creates the element indicating the focus of the conference.
750 1046
  */

+ 27
- 12
css/main.css Переглянути файл

@@ -21,14 +21,15 @@ html, body{
21 21
     margin-left: auto;
22 22
     margin-right: auto;
23 23
 }
24
-.videocontainer>video {
24
+#presentation, .videocontainer>video {
25 25
     position: absolute;
26 26
     left: 0px;
27 27
     top: 0px;
28
-    z-index: 0;
28
+    z-index: 1;
29 29
     width: 100%;
30 30
     height: 100%;
31 31
 }
32
+
32 33
 .videocontainer>span {
33 34
     display: none; /* enable when you want nicks to be shown */
34 35
     position: absolute;
@@ -39,9 +40,6 @@ html, body{
39 40
     font-size: 10pt;
40 41
 }
41 42
 
42
-#largeVideo {
43
-}
44
-
45 43
 #localVideo {
46 44
     -moz-transform: scaleX(-1);
47 45
     -webkit-transform: scaleX(-1);
@@ -168,11 +166,6 @@ html, body{
168 166
     background-color:#087dba;
169 167
 }
170 168
 
171
-#toolbar {
172
-    visibility:hidden;
173
-    height:39px;
174
-}
175
-
176 169
 #left {
177 170
 	display:block;
178 171
     position: absolute;
@@ -207,6 +200,10 @@ html, body{
207 200
     visibility: hidden;
208 201
 }
209 202
 
203
+#settingsButton {
204
+    visibility: hidden;
205
+}
206
+
210 207
 .button {
211 208
     display: inline-block;
212 209
     position: relative;
@@ -274,7 +271,7 @@ a.button:hover {
274 271
     z-index:1;
275 272
 }
276 273
 
277
-input, textarea {
274
+input[type='text'], textarea {
278 275
     border: 0px none;
279 276
     display: inline-block;
280 277
     font-size: 14px;
@@ -292,7 +289,7 @@ input, textarea {
292 289
     resize: none; /* prevents the user-resizing, adjust to taste */
293 290
 }
294 291
 
295
-input, textarea:focus {
292
+input[type='text'], textarea:focus {
296 293
     box-shadow: inset 0 0 3px 2px #ACD8F0; /* provides a more style-able
297 294
                                          replacement to the outline */
298 295
 }
@@ -359,4 +356,22 @@ form {
359 356
     font-size: 11pt;
360 357
     text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
361 358
     border: 0px;
359
+    z-index: 2;
360
+}
361
+
362
+#reloadPresentation {
363
+    display: none;
364
+    position: absolute;
365
+    color: #FFFFFF;
366
+    top: 0;
367
+    right: 0;
368
+    padding: 10px 10px;
369
+    font-size: 11pt;
370
+    cursor: pointer;
371
+    background: rgba(0, 0, 0, 0.3);
372
+    border-radius: 5px;
373
+    background-clip: padding-box;
374
+    -webkit-border-radius: 5px;
375
+    -webkit-background-clip: padding-box;
376
+    z-index: 2;
362 377
 }

+ 4
- 1
css/modaldialog.css Переглянути файл

@@ -12,8 +12,11 @@
12 12
 }
13 13
 
14 14
 .jqistates input {
15
+    margin: 10px 0;
16
+}
17
+
18
+.jqistates input[type="text"] {
15 19
     width: 100%;
16
-    margin: 20px 0;
17 20
 }
18 21
 
19 22
 .jqibuttons button {

BIN
images/avatarprezi.png Переглянути файл


+ 13
- 4
index.html Переглянути файл

@@ -6,14 +6,15 @@
6 6
     <script src="libs/colibri.js?v=3"></script><!-- colibri focus implementation -->
7 7
     <script src="muc.js?v=3"></script><!-- simple MUC library -->
8 8
     <script src="estos_log.js?v=1"></script><!-- simple stanza logger -->
9
-    <script src="app.js?v=3"></script><!-- application logic -->
9
+    <script src="app.js?v=10"></script><!-- application logic -->
10 10
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
11
-    <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=3"/>
11
+    <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=10"/>
12 12
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=2">
13 13
     <link rel="stylesheet" href="css/modaldialog.css?v=2">
14 14
     <script src="libs/jquery-impromptu.js"></script>
15 15
     <script src="libs/jquery.autosize.js"></script>
16 16
     <script src="config.js"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
17
+    <script src="libs/prezi_player.js"></script>
17 18
   </head>
18 19
   <body>
19 20
     <div id="header">
@@ -29,6 +30,12 @@
29 30
             <a class="button" onclick="openLinkDialog();"><i title="Invite others" class="fa fa-link fa-lg"></i></a>
30 31
             <div class="header_button_separator"></div>
31 32
             <a class="button" onclick='openChat();'><i id="chat" title="Open chat" class="fa fa-comments fa-lg"></i></a>
33
+            <div class="header_button_separator"></div>
34
+            <a class="button" onclick='openPreziDialog();'><i title="Share prezi" class="fa fa-desktop fa-lg"></i></a>
35
+            <!--span id="settingsButton">
36
+                <div class="header_button_separator"></div>
37
+                <a class="button" onclick='openSettingsDialog();'><i title="Settings" class="fa fa-cog fa-lg"></i></a>
38
+            </span-->
32 39
         </span>
33 40
     </div>
34 41
     <div id="settings">
@@ -43,8 +50,10 @@
43 50
 
44 51
     <div id="videospace">
45 52
         <div class="fade_line"></div>
46
-        <div class="videocontainer">
47
-          <video id="largeVideo" autoplay oncontextmenu="return false;"></video>
53
+        <div id="largeVideoContainer" class="videocontainer">
54
+            <div id="reloadPresentation"><a onclick='reloadPresentation();'><i title="Reload Prezi" class="fa fa-repeat fa-lg"></i></a></div>
55
+            <div id="presentation"></div>
56
+            <video id="largeVideo" autoplay oncontextmenu="return false;"></video>
48 57
         </div>
49 58
         <div class="fade_line"></div>
50 59
         <div id="remoteVideos">

+ 259
- 0
libs/prezi_player.js Переглянути файл

@@ -0,0 +1,259 @@
1
+(function() {
2
+    "use strict";
3
+    var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
4
+
5
+    window.PreziPlayer = (function() {
6
+
7
+        PreziPlayer.API_VERSION = 1;
8
+        PreziPlayer.CURRENT_STEP = 'currentStep';
9
+        PreziPlayer.CURRENT_OBJECT = 'currentObject';
10
+        PreziPlayer.STATUS_LOADING = 'loading';
11
+        PreziPlayer.STATUS_READY = 'ready';
12
+        PreziPlayer.STATUS_CONTENT_READY = 'contentready';
13
+        PreziPlayer.EVENT_CURRENT_STEP = "currentStepChange";
14
+        PreziPlayer.EVENT_CURRENT_OBJECT = "currentObjectChange";
15
+        PreziPlayer.EVENT_STATUS = "statusChange";
16
+        PreziPlayer.EVENT_PLAYING = "isAutoPlayingChange";
17
+        PreziPlayer.EVENT_IS_MOVING = "isMovingChange";
18
+        PreziPlayer.domain = "http://prezi.com";
19
+        PreziPlayer.path = "/player/";
20
+        PreziPlayer.players = {};
21
+        PreziPlayer.binded_methods = ['changesHandler'];
22
+
23
+        PreziPlayer.createMultiplePlayers = function(optionArray){
24
+            for(var i=0; i<optionArray.length; i++) {
25
+                var optionSet = optionArray[i];
26
+                new PreziPlayer(optionSet.id, optionSet);
27
+            };
28
+        };
29
+
30
+        PreziPlayer.messageReceived = function(event){
31
+            var message, item, player;
32
+            try {
33
+                message = JSON.parse(event.data);
34
+            } catch (e) {}
35
+            if (message.id && (player = PreziPlayer.players[message.id])){
36
+                if (player.options.debug === true) {
37
+                    if (console && console.log) console.log('received', message);
38
+                }
39
+                if (message.type === "changes"){
40
+                    player.changesHandler(message);
41
+                }
42
+                for (var i=0; i<player.callbacks.length; i++) {
43
+                    item = player.callbacks[i];
44
+                    if (item && message.type === item.event){
45
+                        item.callback(message);
46
+                    }
47
+                }
48
+            }
49
+        };
50
+
51
+        function PreziPlayer(id, options) {
52
+            var params, paramString = "", _this = this;
53
+            if (PreziPlayer.players[id]){
54
+                PreziPlayer.players[id].destroy();
55
+            }
56
+            for(var i=0; i<PreziPlayer.binded_methods.length; i++) {
57
+                var method_name = PreziPlayer.binded_methods[i];
58
+                _this[method_name] = __bind(_this[method_name], _this);
59
+            };
60
+            options = options || {};
61
+            this.options = options;
62
+            this.values = {'status': PreziPlayer.STATUS_LOADING};
63
+            this.values[PreziPlayer.CURRENT_STEP] = 0;
64
+            this.values[PreziPlayer.CURRENT_OBJECT] = null;
65
+            this.callbacks = [];
66
+            this.id = id;
67
+            this.embedTo = document.getElementById(id);
68
+            if (!this.embedTo) {
69
+                throw "The element id is not available.";
70
+            }
71
+            this.iframe = document.createElement('iframe');
72
+            params = [
73
+                { name: 'oid', value: options.preziId },
74
+                { name: 'explorable', value: options.explorable ? 1 : 0 },
75
+                { name: 'controls', value: options.controls ? 1 : 0 }
76
+            ];
77
+            for(var i=0; i<params.length; i++) {
78
+                var param = params[i];
79
+                paramString += (i===0 ? "?" : "&") + param.name + "=" + param.value;
80
+            };
81
+            this.iframe.src = PreziPlayer.domain + PreziPlayer.path + paramString;
82
+            this.iframe.frameBorder = 0;
83
+            this.iframe.scrolling = "no";
84
+            this.iframe.width = options.width || 640;
85
+            this.iframe.height = options.height || 480;
86
+            this.embedTo.innerHTML = '';
87
+            try {
88
+                this.embedTo.appendChild(this.iframe);
89
+            }
90
+            catch (err) {
91
+                console.log("CATCH ERROR");
92
+            }
93
+                          
94
+
95
+            this.initPollInterval = setInterval(function(){
96
+                _this.sendMessage({'action': 'init'});
97
+            }, 200);
98
+            PreziPlayer.players[id] = this;
99
+        }
100
+
101
+        PreziPlayer.prototype.changesHandler = function(message) {
102
+            var key, value, j, item;
103
+            if (this.initPollInterval) {
104
+                clearInterval(this.initPollInterval);
105
+                this.initPollInterval = false;
106
+            }
107
+            for (key in message.data) {
108
+                if (message.data.hasOwnProperty(key)){
109
+                    value = message.data[key];
110
+                    this.values[key] = value;
111
+                    for (j=0; j<this.callbacks.length; j++) {
112
+                        item = this.callbacks[j];
113
+                        if (item && item.event === key + "Change"){
114
+                            item.callback({type: item.event, value: value});
115
+                        }
116
+                    }
117
+                }
118
+            }
119
+        };
120
+
121
+        PreziPlayer.prototype.destroy = function() {
122
+            if (this.initPollInterval) {
123
+                clearInterval(this.initPollInterval);
124
+                this.initPollInterval = false;
125
+            }
126
+            this.embedTo.innerHTML = '';
127
+        };
128
+
129
+        PreziPlayer.prototype.sendMessage = function(message) {
130
+            if (this.options.debug === true) {
131
+                if (console && console.log) console.log('sent', message);
132
+            }
133
+            message.version = PreziPlayer.API_VERSION;
134
+            message.id = this.id;
135
+            return this.iframe.contentWindow.postMessage(JSON.stringify(message), '*');
136
+        };
137
+
138
+        PreziPlayer.prototype.nextStep = /* nextStep is DEPRECATED */
139
+        PreziPlayer.prototype.flyToNextStep = function() {
140
+            return this.sendMessage({
141
+                'action': 'present',
142
+                'data': ['moveToNextStep']
143
+            });
144
+        };
145
+
146
+        PreziPlayer.prototype.previousStep = /* previousStep is DEPRECATED */
147
+        PreziPlayer.prototype.flyToPreviousStep = function() {
148
+            return this.sendMessage({
149
+                'action': 'present',
150
+                'data': ['moveToPrevStep']
151
+            });
152
+        };
153
+
154
+        PreziPlayer.prototype.toStep = /* toStep is DEPRECATED */
155
+        PreziPlayer.prototype.flyToStep = function(step) {
156
+            return this.sendMessage({
157
+                'action': 'present',
158
+                'data': ['moveToStep', step]
159
+            });
160
+        };
161
+
162
+        PreziPlayer.prototype.toObject = /* toObject is DEPRECATED */
163
+        PreziPlayer.prototype.flyToObject = function(objectId) {
164
+            return this.sendMessage({
165
+                'action': 'present',
166
+                'data': ['moveToObject', objectId]
167
+            });
168
+        };
169
+
170
+        PreziPlayer.prototype.play = function(defaultDelay) {
171
+            return this.sendMessage({
172
+                'action': 'present',
173
+                'data': ['startAutoPlay', defaultDelay]
174
+            });
175
+        };
176
+
177
+        PreziPlayer.prototype.stop = function() {
178
+            return this.sendMessage({
179
+                'action': 'present',
180
+                'data': ['stopAutoPlay']
181
+            });
182
+        };
183
+
184
+        PreziPlayer.prototype.pause = function(defaultDelay) {
185
+            return this.sendMessage({
186
+                'action': 'present',
187
+                'data': ['pauseAutoPlay', defaultDelay]
188
+            });
189
+        };
190
+
191
+        PreziPlayer.prototype.getCurrentStep = function() {
192
+            return this.values.currentStep;
193
+        };
194
+
195
+        PreziPlayer.prototype.getCurrentObject = function() {
196
+            return this.values.currentObject;
197
+        };
198
+
199
+        PreziPlayer.prototype.getStatus = function() {
200
+            return this.values.status;
201
+        };
202
+
203
+        PreziPlayer.prototype.isPlaying = function() {
204
+            return this.values.isAutoPlaying;
205
+        };
206
+
207
+        PreziPlayer.prototype.getStepCount = function() {
208
+            return this.values.stepCount;
209
+        };
210
+
211
+        PreziPlayer.prototype.getTitle = function() {
212
+            return this.values.title;
213
+        };
214
+
215
+        PreziPlayer.prototype.setDimensions = function(dims) {
216
+            for (var parameter in dims) {
217
+                this.iframe[parameter] = dims[parameter];
218
+            }
219
+        }
220
+
221
+        PreziPlayer.prototype.getDimensions = function() {
222
+            return {
223
+                width: parseInt(this.iframe.width, 10),
224
+                height: parseInt(this.iframe.height, 10)
225
+            }
226
+        }
227
+
228
+        PreziPlayer.prototype.on = function(event, callback) {
229
+            this.callbacks.push({
230
+                event: event,
231
+                callback: callback
232
+            });
233
+        };
234
+
235
+        PreziPlayer.prototype.off = function(event, callback) {
236
+            var j, item;
237
+            if (event === undefined) {
238
+                this.callbacks = [];
239
+            }
240
+            j = this.callbacks.length;
241
+            while (j--) {
242
+                item = this.callbacks[j];
243
+                if (item && item.event === event && (callback === undefined || item.callback === callback)){
244
+                    this.callbacks.splice(j, 1);
245
+                }
246
+            }
247
+        };
248
+
249
+        if (window.addEventListener) {
250
+            window.addEventListener('message', PreziPlayer.messageReceived, false);
251
+        } else {
252
+            window.attachEvent('onmessage', PreziPlayer.messageReceived);
253
+        }
254
+
255
+        return PreziPlayer;
256
+
257
+    })();
258
+
259
+})();

+ 82
- 2
muc.js Переглянути файл

@@ -7,13 +7,21 @@ Strophe.addConnectionPlugin('emuc', {
7 7
     roomjid: null,
8 8
     myroomjid: null,
9 9
     members: {},
10
+    presMap: {},
11
+    preziMap: {},
10 12
     joined: false,
11 13
     isOwner: false,
12 14
     init: function (conn) {
13 15
         this.connection = conn;
14 16
     },
17
+    initPresenceMap: function (myroomjid) {
18
+        this.presMap['to'] = myroomjid;
19
+        this.presMap['xns'] = 'http://jabber.org/protocol/muc';
20
+    },
15 21
     doJoin: function (jid, password) {
16 22
         this.myroomjid = jid;
23
+        this.initPresenceMap(this.myroomjid);
24
+
17 25
         if (!this.roomjid) {
18 26
             this.roomjid = Strophe.getBareJidFromJid(jid);
19 27
             // add handlers (just once)
@@ -30,11 +38,35 @@ Strophe.addConnectionPlugin('emuc', {
30 38
         this.connection.send(join);
31 39
     },
32 40
     onPresence: function (pres) {
41
+        console.log("PRESENCE", pres);
33 42
         var from = pres.getAttribute('from');
34 43
         var type = pres.getAttribute('type');
35 44
         if (type != null) {
36 45
             return true;
37 46
         }
47
+
48
+        var presentation = $(pres).find('>prezi');
49
+        if (presentation.length)
50
+        {
51
+            var url = presentation.attr('url');
52
+            var current = presentation.find('>current').text();
53
+            console.log('presentation info received from', from, url);
54
+
55
+            if (this.preziMap[from] == null) {
56
+                this.preziMap[from] = url;
57
+
58
+                $(document).trigger('presentationadded.muc', [from, url, current]);
59
+            }
60
+            else {
61
+                $(document).trigger('gotoslide.muc', [from, url, current]);
62
+            }
63
+        }
64
+        else if (this.preziMap[from] != null) {
65
+            var url = this.preziMap[from];
66
+            delete this.preziMap[from];
67
+            $(document).trigger('presentationremoved.muc', [from, url]);
68
+        }
69
+
38 70
         if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="201"]').length) {
39 71
             // http://xmpp.org/extensions/xep-0045.html#createroom-instant
40 72
             this.isOwner = true;
@@ -110,7 +142,6 @@ Strophe.addConnectionPlugin('emuc', {
110 142
                     var formsubmit = $iq({to: ob.roomjid, type: 'set'}).c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'});
111 143
                     formsubmit.c('x', {xmlns: 'jabber:x:data', type: 'submit'});
112 144
                     formsubmit.c('field', {'var': 'FORM_TYPE'}).c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up();
113
-                    console.log("THE KEY TO SET", key);
114 145
                     formsubmit.c('field', {'var': 'muc#roomconfig_roomsecret'}).c('value').t(key).up().up();
115 146
                     // FIXME: is muc#roomconfig_passwordprotectedroom required?
116 147
                     this.connection.sendIQ(formsubmit,
@@ -129,6 +160,55 @@ Strophe.addConnectionPlugin('emuc', {
129 160
                 console.warn('setting password failed', err);
130 161
             }
131 162
         );
163
+    },
164
+    sendPresence: function () {
165
+        var pres = $pres({to: this.presMap['to'] });
166
+        pres.c('x', {xmlns: this.presMap['xns']}).up();
167
+        if (this.presMap['prezins']) {
168
+            pres.c('prezi', {xmlns: this.presMap['prezins'], 'url': this.presMap['preziurl']}).
169
+                            c('current').t(this.presMap['prezicurrent']).up().up();
170
+        }
171
+
172
+        if (this.presMap['medians'])
173
+        {
174
+            pres.c('media', {xmlns: this.presMap['medians']});
175
+            var sourceNumber = 0;
176
+            Object.keys(this.presMap).forEach(function (key) {
177
+                if (key.indexOf('source') >= 0) {
178
+                     sourceNumber++;
179
+                }
180
+            });
181
+            if (sourceNumber > 0)
182
+                for (var i = 1; i <= sourceNumber/2; i ++) {
183
+                    pres.c('source',
184
+                           {type: this.presMap['source' + i + '_type'],
185
+                           ssrc: this.presMap['source' + i + '_ssrc']}).up();
186
+                }
187
+        }
188
+        pres.up();
189
+        connection.send(pres);
190
+    },
191
+    addMediaToPresence: function (sourceNumber, mtype, ssrcs) {
192
+        if (!this.presMap['medians'])
193
+            this.presMap['medians'] = 'http://estos.de/ns/mjs';
194
+
195
+        this.presMap['source' + sourceNumber + '_type'] = mtype;
196
+        this.presMap['source' + sourceNumber + '_ssrc'] = ssrcs;
197
+    },
198
+    addPreziToPresence: function (url, currentSlide) {
199
+        this.presMap['prezins'] = 'http://jitsi.org/jitmeet/prezi';
200
+        this.presMap['preziurl'] = url;
201
+        this.presMap['prezicurrent'] = currentSlide;
202
+    },
203
+    removePreziFromPresence: function () {
204
+        delete this.presMap['prezins'];
205
+        delete this.presMap['preziurl'];
206
+        delete this.presMap['prezicurrent'];
207
+    },
208
+    addCurrentSlideToPresence: function (currentSlide) {
209
+        this.presMap['prezicurrent'] = currentSlide;
210
+    },
211
+    getPrezi: function (roomjid) {
212
+        return this.preziMap[roomjid];
132 213
     }
133 214
 });
134
-

Завантаження…
Відмінити
Зберегти