Browse Source

Adds display name management. Closes issue #23.

j8
Yana Stamcheva 11 years ago
parent
commit
cc887f4a8a
5 changed files with 220 additions and 31 deletions
  1. 152
    16
      app.js
  2. 1
    2
      css/jquery-impromptu.css
  3. 38
    2
      css/main.css
  4. 5
    5
      index.html
  5. 24
    6
      muc.js

+ 152
- 16
app.js View File

25
     RTCPeerconnection = TraceablePeerConnection; 
25
     RTCPeerconnection = TraceablePeerConnection; 
26
 
26
 
27
     connection = new Strophe.Connection(document.getElementById('boshURL').value || config.bosh || '/http-bind');
27
     connection = new Strophe.Connection(document.getElementById('boshURL').value || config.bosh || '/http-bind');
28
+
29
+    if (nickname) {
30
+        connection.emuc.addDisplayNameToPresence(nickname);
31
+    }
32
+
28
     if (connection.disco) {
33
     if (connection.disco) {
29
         // for chrome, add multistream cap
34
         // for chrome, add multistream cap
30
     }
35
     }
270
 $(document).bind('joined.muc', function (event, jid, info) {
275
 $(document).bind('joined.muc', function (event, jid, info) {
271
     updateRoomUrl(window.location.href);
276
     updateRoomUrl(window.location.href);
272
     document.getElementById('localNick').appendChild(
277
     document.getElementById('localNick').appendChild(
273
-        document.createTextNode(Strophe.getResourceFromJid(jid) + ' (you)')
278
+        document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
274
     );
279
     );
275
 
280
 
276
     if (Object.keys(connection.emuc.members).length < 1) {
281
     if (Object.keys(connection.emuc.members).length < 1) {
277
         focus = new ColibriFocus(connection, config.hosts.bridge);
282
         focus = new ColibriFocus(connection, config.hosts.bridge);
278
     }
283
     }
279
-                 
284
+
285
+    showFocusIndicator();
286
+
280
     // Once we've joined the muc show the toolbar
287
     // Once we've joined the muc show the toolbar
281
     showToolbar();
288
     showToolbar();
289
+
290
+    var displayName = '';
291
+    if (info.displayName)
292
+        displayName = info.displayName + ' (me)';
293
+
294
+    showDisplayName('localVideoContainer', displayName);
282
 });
295
 });
283
 
296
 
284
 $(document).bind('entered.muc', function (event, jid, info, pres) {
297
 $(document).bind('entered.muc', function (event, jid, info, pres) {
285
     console.log('entered', jid, info);
298
     console.log('entered', jid, info);
286
     console.log(focus);
299
     console.log(focus);
287
-    
288
-    var container = addRemoteVideoContainer('participant_' + Strophe.getResourceFromJid(jid));
300
+
301
+    var videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
302
+    var container = addRemoteVideoContainer(videoSpanId);
303
+
304
+    if (info.displayName)
305
+        showDisplayName(videoSpanId, info.displayName);
289
 
306
 
290
     var nickfield = document.createElement('span');
307
     var nickfield = document.createElement('span');
291
     nickfield.appendChild(document.createTextNode(Strophe.getResourceFromJid(jid)));
308
     nickfield.appendChild(document.createTextNode(Strophe.getResourceFromJid(jid)));
350
         //console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
367
         //console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
351
         ssrc2jid[ssrc.getAttribute('ssrc')] = jid;
368
         ssrc2jid[ssrc.getAttribute('ssrc')] = jid;
352
     });
369
     });
370
+
371
+    if (info.displayName) {
372
+        if (jid === connection.emuc.myroomjid)
373
+            showDisplayName('localVideoContainer', info.displayName + ' (me)');
374
+        else
375
+            showDisplayName('participant_' + Strophe.getResourceFromJid(jid), info.displayName);
376
+    }
353
 });
377
 });
354
 
378
 
355
 $(document).bind('passwordrequired.muc', function (event, jid) {
379
 $(document).bind('passwordrequired.muc', function (event, jid) {
371
 
395
 
372
                         if (lockKey.value != null)
396
                         if (lockKey.value != null)
373
                         {
397
                         {
374
-                            setSharedKey(lockKey);
398
+                            setSharedKey(lockKey.value);
375
                             connection.emuc.doJoin(jid, lockKey.value);
399
                             connection.emuc.doJoin(jid, lockKey.value);
376
                         }
400
                         }
377
                     }
401
                     }
559
 function resizeLarge() {
583
 function resizeLarge() {
560
     resizeChat();
584
     resizeChat();
561
     var availableHeight = window.innerHeight;
585
     var availableHeight = window.innerHeight;
562
-    var chatspaceWidth = $('#chatspace').width();
586
+    var chatspaceWidth = $('#chatspace').is(":visible")
587
+                            ? $('#chatspace').width()
588
+                            : 0;
563
 
589
 
564
     var numvids = $('#remoteVideos>video:visible').length;
590
     var numvids = $('#remoteVideos>video:visible').length;
565
     if (numvids < 5)
591
     if (numvids < 5)
631
 }
657
 }
632
 
658
 
633
 $(document).ready(function () {
659
 $(document).ready(function () {
660
+    var storedDisplayName = window.localStorage.displayname;
661
+    if (storedDisplayName) {
662
+        nickname = storedDisplayName;
663
+
664
+        setChatConversationMode(true);
665
+    }
666
+
634
     $('#nickinput').keydown(function(event) {
667
     $('#nickinput').keydown(function(event) {
635
         if (event.keyCode == 13) {
668
         if (event.keyCode == 13) {
636
             event.preventDefault();
669
             event.preventDefault();
638
             this.value = '';
671
             this.value = '';
639
             if (!nickname) {
672
             if (!nickname) {
640
                 nickname = val;
673
                 nickname = val;
641
-                $('#nickname').css({visibility:"hidden"});
642
-                $('#chatconversation').css({visibility:'visible'});
643
-                $('#usermsg').css({visibility:'visible'});
644
-                $('#usermsg').focus();
674
+                window.localStorage.displayname = nickname;
675
+
676
+                connection.emuc.addDisplayNameToPresence(nickname);
677
+                connection.emuc.sendPresence();
678
+
679
+                setChatConversationMode(true);
680
+
645
                 return;
681
                 return;
646
             }
682
             }
647
         }
683
         }
743
         divClassName = "localuser";
779
         divClassName = "localuser";
744
     else
780
     else
745
         divClassName = "remoteuser";
781
         divClassName = "remoteuser";
746
-   
782
+
747
     //replace links and smileys
783
     //replace links and smileys
748
     message = processReplacements(message);
784
     message = processReplacements(message);
749
 
785
 
1072
  */
1108
  */
1073
 function showFocusIndicator() {
1109
 function showFocusIndicator() {
1074
     if (focus != null) {
1110
     if (focus != null) {
1075
-        var localVideoToolbar = document.getElementById('localVideoToolbar');
1111
+        var indicatorSpan = $('#localVideoContainer .focusindicator');
1076
 
1112
 
1077
-        if (localVideoToolbar.childNodes.length === 0)
1113
+        if (indicatorSpan.children().length == 0)
1078
         {
1114
         {
1079
-            createFocusIndicatorElement(localVideoToolbar);
1115
+            createFocusIndicatorElement(indicatorSpan[0]);
1080
         }
1116
         }
1081
     }
1117
     }
1082
     else if (Object.keys(connection.jingle.sessions).length > 0) {
1118
     else if (Object.keys(connection.jingle.sessions).length > 0) {
1121
     }, 5);
1157
     }, 5);
1122
 }
1158
 }
1123
 
1159
 
1124
-
1125
 /*
1160
 /*
1126
  * Toggles the application in and out of full screen mode 
1161
  * Toggles the application in and out of full screen mode 
1127
  * (a.k.a. presentation mode in Chrome).
1162
  * (a.k.a. presentation mode in Chrome).
1128
  */
1163
  */
1129
-function toggleFullScreen() {    
1164
+function toggleFullScreen() {
1130
     var fsElement = document.documentElement;
1165
     var fsElement = document.documentElement;
1131
 
1166
 
1132
     if (!document.mozFullScreen && !document.webkitIsFullScreen){
1167
     if (!document.mozFullScreen && !document.webkitIsFullScreen){
1151
         }
1186
         }
1152
     }
1187
     }
1153
 }
1188
 }
1189
+
1190
+/**
1191
+ *
1192
+ */
1193
+function showDisplayName(videoSpanId, displayName) {
1194
+    var nameSpan = $('#' + videoSpanId + '>span.displayname');
1195
+
1196
+    // If we already have a display name for this video.
1197
+    if (nameSpan.length > 0) {
1198
+        var nameSpanElement = nameSpan.get(0);
1199
+
1200
+        if (nameSpanElement.id == 'localDisplayName'
1201
+            && $('#localDisplayName').html() != displayName)
1202
+            $('#localDisplayName').html(displayName);
1203
+        else
1204
+            $('#' + videoSpanId + '_name').html(displayName);
1205
+    }
1206
+    else {
1207
+        var editButton = null;
1208
+        if (videoSpanId == 'localVideoContainer') {
1209
+            editButton = createEditDisplayNameButton();
1210
+        }
1211
+
1212
+        if (displayName.length) {
1213
+            nameSpan = document.createElement('span');
1214
+            nameSpan.className = 'displayname';
1215
+            nameSpan.innerHTML = displayName;
1216
+            $('#' + videoSpanId)[0].appendChild(nameSpan);
1217
+        }
1218
+
1219
+        if (!editButton) {
1220
+            nameSpan.id = videoSpanId + '_name';
1221
+        }
1222
+        else {
1223
+            nameSpan.id = 'localDisplayName';
1224
+            $('#' + videoSpanId)[0].appendChild(editButton);
1225
+            
1226
+            var editableText = document.createElement('input');
1227
+            editableText.className = 'displayname';
1228
+            editableText.id = 'editDisplayName';
1229
+
1230
+            if (displayName.length)
1231
+                editableText.value = displayName.substring(0, displayName.indexOf(' (me)'));
1232
+
1233
+            editableText.setAttribute('style', 'display:none;');
1234
+            editableText.setAttribute('placeholder', 'ex. Jane Pink');
1235
+            $('#' + videoSpanId)[0].appendChild(editableText);
1236
+
1237
+            $('#localVideoContainer .displayname').bind("click", function(e) {
1238
+                e.preventDefault();
1239
+                $('#localDisplayName').hide();
1240
+                $('#editDisplayName').show();
1241
+                $('#editDisplayName').focus();
1242
+                $('#editDisplayName').select();
1243
+
1244
+                var inputDisplayNameHandler = function(name) {
1245
+                    if (nickname != name) {
1246
+                        nickname = name;
1247
+                        window.localStorage.displayname = nickname;
1248
+                        connection.emuc.addDisplayNameToPresence(nickname);
1249
+                        connection.emuc.sendPresence();
1250
+                    }
1251
+
1252
+                    if (!$('#localDisplayName').is(":visible")) {
1253
+                        $('#localDisplayName').html(name + " (me)");
1254
+                        $('#localDisplayName').show();
1255
+                        $('#editDisplayName').hide();
1256
+                    }
1257
+                };
1258
+
1259
+                $('#editDisplayName').one("focusout", function (e) {
1260
+                    inputDisplayNameHandler(this.value);
1261
+                });
1262
+
1263
+                $('#editDisplayName').on('keydown', function (e) {
1264
+                    if (e.keyCode == 13) {
1265
+                        e.preventDefault();
1266
+                        inputDisplayNameHandler(this.value);
1267
+                    }
1268
+                });
1269
+            });
1270
+        }
1271
+    }
1272
+}
1273
+
1274
+function createEditDisplayNameButton() {
1275
+    var editButton = document.createElement('a');
1276
+    editButton.className = 'displayname';
1277
+    editButton.innerHTML = '<i class="fa fa-pencil"></i>';
1278
+
1279
+    return editButton;
1280
+}
1281
+
1282
+function setChatConversationMode(isConversationMode) {
1283
+    if (isConversationMode) {
1284
+        $('#nickname').css({visibility:"hidden"});
1285
+        $('#chatconversation').css({visibility:'visible'});
1286
+        $('#usermsg').css({visibility:'visible'});
1287
+        $('#usermsg').focus();
1288
+    }
1289
+}

+ 1
- 2
css/jquery-impromptu.css View File

8
 	background-color: #000;
8
 	background-color: #000;
9
 }
9
 }
10
 div.jqi{ 
10
 div.jqi{ 
11
-	width: 400px; 
12
-	font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; 
11
+	width: 400px;
13
 	position: absolute; 
12
 	position: absolute; 
14
 	background-color: #ffffff; 
13
 	background-color: #ffffff; 
15
 	font-size: 11px; 
14
 	font-size: 11px; 

+ 38
- 2
css/main.css View File

2
     margin:0px;
2
     margin:0px;
3
     height:100%;
3
     height:100%;
4
     color: #424242;
4
     color: #424242;
5
-    font-family:'YanoneKaffeesatzLight',Verdana,Tahoma,Arial;
5
+    font-family:'Helvetica Neue', Helvetica, sans-serif;
6
 	font-weight: 400;
6
 	font-weight: 400;
7
     background: #e9e9e9;
7
     background: #e9e9e9;
8
     overflow-x: hidden;
8
     overflow-x: hidden;
295
     line-height: 20px;
295
     line-height: 20px;
296
     height: 40px;
296
     height: 40px;
297
     color: #333;
297
     color: #333;
298
-    font-weight: bold;
299
     text-align: left;
298
     text-align: left;
300
     border:1px solid #ACD8F0;
299
     border:1px solid #ACD8F0;
301
     outline: none; /* removes the default outline */
300
     outline: none; /* removes the default outline */
365
     z-index: 2;
364
     z-index: 2;
366
 }
365
 }
367
 
366
 
367
+.videocontainer>span.displayname,
368
+.videocontainer>input.displayname {
369
+    display: inline-block;
370
+    position: absolute;
371
+    background: -webkit-linear-gradient(left, rgba(0,0,0,.7), rgba(0,0,0,0));
372
+    color: #b7b7b7;
373
+    bottom: 0;
374
+    left: 0;
375
+    padding: 3px 5px;
376
+    width: 100%;
377
+    height: auto;
378
+    max-height: 18px;
379
+    font-size: 9pt;
380
+    text-align: left;
381
+    text-overflow: ellipsis;
382
+    overflow: hidden;
383
+    white-space: nowrap;
384
+    z-index: 2;
385
+    box-sizing: border-box;
386
+}
387
+
388
+#localVideoContainer>span.displayname:hover {
389
+    cursor: text;
390
+}
391
+
392
+.videocontainer>a.displayname {
393
+    display: inline-block;
394
+    position: absolute;
395
+    color: #b7b7b7;
396
+    bottom: 0;
397
+    right: 0;
398
+    padding: 3px 5px;
399
+    font-size: 9pt;
400
+    cursor: pointer;
401
+    z-index: 2;
402
+}
403
+
368
 #reloadPresentation {
404
 #reloadPresentation {
369
     display: none;
405
     display: none;
370
     position: absolute;
406
     position: absolute;

+ 5
- 5
index.html View File

5
     <script src="libs/strophejingle.bundle.js?v=7"></script><!-- strophe.jingle bundle -->
5
     <script src="libs/strophejingle.bundle.js?v=7"></script><!-- strophe.jingle bundle -->
6
     <script src="libs/colibri.js?v=7"></script><!-- colibri focus implementation -->
6
     <script src="libs/colibri.js?v=7"></script><!-- colibri focus implementation -->
7
     <script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
7
     <script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
8
-    <script src="muc.js?v=4"></script><!-- simple MUC library -->
8
+    <script src="muc.js?v=5"></script><!-- simple MUC library -->
9
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
9
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
10
-    <script src="app.js?v=17"></script><!-- application logic -->
10
+    <script src="app.js?v=18"></script><!-- application logic -->
11
     <script src="smileys.js?v=1"></script><!-- smiley images -->
11
     <script src="smileys.js?v=1"></script><!-- smiley images -->
12
     <script src="replacement.js?v=5"></script><!-- link and smiley replacement -->
12
     <script src="replacement.js?v=5"></script><!-- link and smiley replacement -->
13
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
13
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
14
-    <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=14"/>
15
-    <link rel="stylesheet" href="css/jquery-impromptu.css?v=3">
14
+    <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=15"/>
15
+    <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
16
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
16
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
17
     <script src="libs/jquery-impromptu.js"></script>
17
     <script src="libs/jquery-impromptu.js"></script>
18
     <script src="libs/jquery.autosize.js"></script>
18
     <script src="libs/jquery.autosize.js"></script>
65
             <span id="localVideoContainer" class="videocontainer">
65
             <span id="localVideoContainer" class="videocontainer">
66
                 <span id="localNick"></span>
66
                 <span id="localNick"></span>
67
                 <video id="localVideo" autoplay oncontextmenu="return false;" muted></video>
67
                 <video id="localVideo" autoplay oncontextmenu="return false;" muted></video>
68
-                <span id="localVideoToolbar" class="focusindicator"></span>
68
+                <span class="focusindicator"></span>
69
             </span>
69
             </span>
70
         </div>
70
         </div>
71
     </div>
71
     </div>

+ 24
- 6
muc.js View File

31
             this.connection.addHandler(this.onPresenceError.bind(this), null, 'presence', 'error', null, this.roomjid, {matchBare: true});
31
             this.connection.addHandler(this.onPresenceError.bind(this), null, 'presence', 'error', null, this.roomjid, {matchBare: true});
32
             this.connection.addHandler(this.onMessage.bind(this), null, 'message', null, null, this.roomjid, {matchBare: true});
32
             this.connection.addHandler(this.onMessage.bind(this), null, 'message', null, null, this.roomjid, {matchBare: true});
33
         }
33
         }
34
-
35
-        var join = $pres({to: this.myroomjid }).c('x', {xmlns: 'http://jabber.org/protocol/muc'});
36
         if (password !== undefined) {
34
         if (password !== undefined) {
37
-            join.c('password').t(password);
35
+            this.presMap['password'] = password;
38
         }
36
         }
39
-        this.connection.send(join);
37
+        this.sendPresence();
40
     },
38
     },
41
     onPresence: function (pres) {
39
     onPresence: function (pres) {
42
-        console.log("PRESENCE", pres);
43
         var from = pres.getAttribute('from');
40
         var from = pres.getAttribute('from');
44
         var type = pres.getAttribute('type');
41
         var type = pres.getAttribute('type');
45
         if (type != null) {
42
         if (type != null) {
83
         var tmp = $(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>item');
80
         var tmp = $(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>item');
84
         member.affiliation = tmp.attr('affiliation');
81
         member.affiliation = tmp.attr('affiliation');
85
         member.role = tmp.attr('role');
82
         member.role = tmp.attr('role');
83
+
84
+        var nicktag = $(pres).find('>nick[xmlns="http://jabber.org/protocol/nick"]');
85
+        member.displayName = (nicktag.length > 0 ? nicktag.text() : null);
86
+
86
         if (from == this.myroomjid) {
87
         if (from == this.myroomjid) {
87
             if (member.affiliation == 'owner') this.isOwner = true;
88
             if (member.affiliation == 'owner') this.isOwner = true;
88
             if (!this.joined) {
89
             if (!this.joined) {
90
                 $(document).trigger('joined.muc', [from, member]);
91
                 $(document).trigger('joined.muc', [from, member]);
91
                 this.list_members.push(from);
92
                 this.list_members.push(from);
92
             }
93
             }
94
+            else
95
+                $(document).trigger('presence.muc', [from, member, pres]);
93
         } else if (this.members[from] === undefined) {
96
         } else if (this.members[from] === undefined) {
94
             // new participant
97
             // new participant
95
             this.members[from] = member;
98
             this.members[from] = member;
167
     },
170
     },
168
     sendPresence: function () {
171
     sendPresence: function () {
169
         var pres = $pres({to: this.presMap['to'] });
172
         var pres = $pres({to: this.presMap['to'] });
170
-        pres.c('x', {xmlns: this.presMap['xns']}).up();
173
+        pres.c('x', {xmlns: this.presMap['xns']});
174
+
175
+        if (this.presMap['password']) {
176
+            pres.c('password').t(this.presMap['password']).up();
177
+        }
178
+
179
+        pres.up();
180
+
181
+        if (this.presMap['displayName']) {
182
+            // XEP-0172
183
+            pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'}).t(this.presMap['displayName']).up();
184
+        }
185
+
171
         if (this.presMap['prezins']) {
186
         if (this.presMap['prezins']) {
172
             pres.c('prezi', {xmlns: this.presMap['prezins'], 'url': this.presMap['preziurl']}).
187
             pres.c('prezi', {xmlns: this.presMap['prezins'], 'url': this.presMap['preziurl']}).
173
                             c('current').t(this.presMap['prezicurrent']).up().up();
188
                             c('current').t(this.presMap['prezicurrent']).up().up();
192
         pres.up();
207
         pres.up();
193
         connection.send(pres);
208
         connection.send(pres);
194
     },
209
     },
210
+    addDisplayNameToPresence: function (displayName) {
211
+        this.presMap['displayName'] = displayName;
212
+    },
195
     addMediaToPresence: function (sourceNumber, mtype, ssrcs) {
213
     addMediaToPresence: function (sourceNumber, mtype, ssrcs) {
196
         if (!this.presMap['medians'])
214
         if (!this.presMap['medians'])
197
             this.presMap['medians'] = 'http://estos.de/ns/mjs';
215
             this.presMap['medians'] = 'http://estos.de/ns/mjs';

Loading…
Cancel
Save