yanas 8 лет назад
Родитель
Сommit
f811410b45

+ 26
- 67
css/_base.scss Просмотреть файл

@@ -6,8 +6,8 @@
6 6
 html, body{
7 7
     margin:0px;
8 8
     height:100%;
9
-    color: #424242;
10
-    font-size: 14px;
9
+    color: $defaultColor;
10
+    font-size: 12px;
11 11
     font-weight: 400;
12 12
     background: #000000;
13 13
     overflow: hidden;
@@ -29,25 +29,17 @@ input[type='text'], input[type='password'], textarea {
29 29
     -webkit-user-select: text;
30 30
     user-select: text;
31 31
     display: inline-block;
32
-    font-size: 14px;
33 32
     padding: 5px;
34
-    background: #f3f3f3;
35
-    border-radius: 3px;
36
-    font-weight: 100;
37
-    line-height: 20px;
38
-    height: 40px;
39
-    color: #333;
33
+    color: $defaultDarkColor;
34
+    border-radius: $borderRadius;
35
+    line-height: 32px;
36
+    height: 32px;
40 37
     text-align: left;
41
-    border:1px solid #ACD8F0;
38
+    border:1px solid $inputBorderColor;
42 39
     outline: none; /* removes the default outline */
43 40
     resize: none; /* prevents the user-resizing, adjust to taste */
44 41
 }
45 42
 
46
-input[type='text'], input[type='password'], textarea:focus {
47
-    box-shadow: inset 0 0 3px 2px #ACD8F0; /* provides a more style-able
48
-                                         replacement to the outline */
49
-}
50
-
51 43
 textarea {
52 44
     overflow: hidden;
53 45
     word-wrap: break-word;
@@ -58,28 +50,33 @@ button.no-icon {
58 50
     padding: 0 1em;
59 51
 }
60 52
 
61
-button {
62
-    border: none;
63
-    height: 35px;
64
-    padding: 0 1em 0 2em;
65
-    position: relative;
66
-    border-radius: 1px;
67
-    font-weight: bold;
68
-    color: #fff;
69
-    line-height: 35px;
70
-    background: #2c8ad2;
71
-}
72
-
73 53
 button, input, select, textarea {
74 54
     margin: 0;
75 55
     vertical-align: baseline;
56
+    color: $defaultDarkColor;
57
+    background: $inputLightBackground;
58
+    font-size: 12px;
59
+    border: none;
60
+    box-shadow: none;
61
+    outline: none;
76 62
 }
77 63
 
78
-button, input[type="button"], input[type="reset"], input[type="submit"] {
64
+button, select, input[type="button"],
65
+input[type="reset"], input[type="submit"] {
66
+    height: 32px;
67
+    line-height: 32px;
68
+    padding-left: 4px;
69
+    padding-right: 4px;
79 70
     cursor: pointer;
80
-    -webkit-appearance: button;
81 71
 }
82 72
 
73
+button {
74
+    color: #FFF;
75
+    background-color: $buttonBackground !important;
76
+    border-radius: $borderRadius;
77
+}
78
+
79
+button,
83 80
 form {
84 81
     display: block;
85 82
 }
@@ -137,32 +134,6 @@ form {
137 134
     z-index: 100;
138 135
 }
139 136
 
140
-#toast-container.notification-bottom-right {
141
-    bottom: 140px;
142
-    right: 5px;
143
-}
144
-
145
-#toast-container.notification-bottom-right-center {
146
-    right: 205px;
147
-}
148
-
149
-#toast-container .toast-info {
150
-    -webkit-box-shadow: none;
151
-    box-shadow: none;
152
-}
153
-
154
-.toast-close-button {
155
-    right: -7px;
156
-    top: -19px;
157
-}
158
-
159
-#toast-container .toast-info {
160
-    background-color: black;
161
-    border: 1px solid #3a3a3a;
162
-    width: 220px;
163
-    padding: 10px 10px 10px 50px;
164
-}
165
-
166 137
 .connected {
167 138
     color: #21B9FC;
168 139
     font-size: 12px;
@@ -173,18 +144,6 @@ form {
173 144
     font-size: 12px;
174 145
 }
175 146
 
176
-.toast-close-button:hover,
177
-.toast-close-button:focus {
178
-    color: #ffffff;
179
-    opacity: 1;
180
-    -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
181
-    filter: alpha(opacity=100);
182
-}
183
-
184
-.toast-message .nickname {
185
-    font-weight: bold;
186
-}
187
-
188 147
 /**
189 148
  * Hides an element.
190 149
  */

+ 31
- 0
css/_device_settings_dialog.scss Просмотреть файл

@@ -0,0 +1,31 @@
1
+.settingsContent {
2
+    display: flex;
3
+    display: -webkit-flex;
4
+
5
+    #localVideoPreview {
6
+        width: 50%;
7
+        align-self: baseline;
8
+    }
9
+
10
+    .deviceSelection {
11
+        display: flex;
12
+        display: -webkit-flex;
13
+        -webkit-flex: 1;
14
+        flex: 1;
15
+        flex-direction: column;
16
+        flex-wrap: nowrap;
17
+        justify-content: flex-start;
18
+        align-items: left;
19
+        margin-left: 10px;
20
+
21
+        .device {
22
+            display: flex;
23
+            margin-bottom: 5px;
24
+
25
+            select {
26
+                flex: 1;
27
+                margin_right: 5px;
28
+            }
29
+        }
30
+    }
31
+}

+ 1
- 1
css/_jquery-impromptu.scss Просмотреть файл

@@ -55,7 +55,7 @@ div.jqi .jqibuttons{
55 55
 div.jqi .jqibuttons button{ 
56 56
 	margin: 0;
57 57
 	padding: 5px 20px;
58
-	background-color: transparent;
58
+	background-color: transparent !important;
59 59
 	font-weight: normal; 
60 60
 	border: none;
61 61
 	border-left: solid 1px #e4e4e4; 

+ 0
- 77
css/_settingsmenu.scss Просмотреть файл

@@ -1,77 +0,0 @@
1
-#settings_container input, select {
2
-    margin-top: 10px;
3
-    margin-left: 10%;
4
-    width: 80%;
5
-    font-size: 14px;
6
-    background: #3a3a3a;
7
-    border: none;
8
-    box-shadow: none;
9
-    color: #a7a7a7;
10
-}
11
-
12
-#settings_container .arrow-up {
13
-    width: 0;
14
-    height: 0;
15
-    border-left: 5px solid transparent;
16
-    border-right: 5px solid transparent;
17
-    border-bottom: 5px solid #3a3a3a;
18
-    position: relative;
19
-    top: 10px;
20
-    margin-left: auto;
21
-    margin-right: auto;
22
-}
23
-
24
-#settings_container #avatar {
25
-    width: 24%;
26
-    left: 38%;
27
-    border-radius: 25px;
28
-    position: relative;
29
-}
30
-
31
-#languages_selectbox {
32
-    height: 40px;
33
-    cursor: pointer;
34
-}
35
-
36
-#startMutedOptions,
37
-#followMeOptions {
38
-    padding-left: 10%;
39
-    text-indent: -10%;
40
-    margin-top: 10px;
41
-    display: none; /* hide by default */
42
-    /* clearfix */
43
-    overflow: auto;
44
-    zoom: 1;
45
-}
46
-
47
-#startAudioMuted,
48
-#startVideoMuted,
49
-#followMeCheckBox {
50
-    width: 13px !important;
51
-}
52
-
53
-.startMutedLabel,
54
-.followMeLabel {
55
-    width: 94%;
56
-    float: left;
57
-    cursor: pointer;
58
-}
59
-
60
-#devicesOptions {
61
-    display: none;
62
-    margin-top: 10px;
63
-}
64
-
65
-#devicesOptions label {
66
-    display: block;
67
-    margin-top: 15px;
68
-}
69
-
70
-#devicesOptions span {
71
-    padding-left: 10%;
72
-}
73
-
74
-#devicesOptions select {
75
-    height: 40px;
76
-    cursor: pointer;
77
-}

+ 114
- 0
css/_side_toolbar_container.css Просмотреть файл

@@ -0,0 +1,114 @@
1
+/**
2
+ * Toolbar side panel main container element.
3
+ */
4
+#sideToolbarContainer {
5
+    display: inline-block;
6
+    position:absolute;
7
+    top: 0px;
8
+    left: $defaultToolbarSize;
9
+    width: 0%;
10
+    height: 100%;
11
+    max-width: 200px;
12
+    background-color: rgba(0,0,0,0.8);
13
+    z-index: 800;
14
+    overflow: hidden;
15
+
16
+    /**
17
+     * Labels inside the side panel.
18
+     */
19
+    label {
20
+        color: $defaultSemiDarkColor;
21
+    }
22
+
23
+    /**
24
+     * Form elements and blocks.
25
+     */
26
+    input, label, select, button, a, .sideToolbarBlock {
27
+        display: inline-block;
28
+        margin-top: 15px;
29
+        margin-left: 10%;
30
+        width: 80%;
31
+    }
32
+
33
+    /**
34
+     * Specify colors for edit elements.
35
+     */
36
+    select, input[type="button"], input[type="text"],
37
+    input[type="reset"], input[type="submit"] {
38
+        color: $defaultColor;
39
+        background: $inputBackground;
40
+        border: none;
41
+    }
42
+
43
+    /**
44
+     * Specify styling of elements inside a block.
45
+     */
46
+    .sideToolbarBlock {
47
+        input, label, button, a, select {
48
+            margin-top: 5px;
49
+            margin-left: 0;
50
+            width: 100%;
51
+        }
52
+
53
+        .startMutedLabel,
54
+        .followMeLabel {
55
+            display: inline;
56
+            margin-top: 0;
57
+        }
58
+    }
59
+
60
+    /**
61
+     * Inner container, for example contact list, settings or profile.
62
+     */
63
+    .sideToolbarContainer__inner {
64
+        display: none;
65
+        width: 200px;
66
+        color: #FFF;
67
+
68
+        /**
69
+         * Titles and subtitles of inner containers.
70
+         */
71
+        > div.title,
72
+          div.subTitle {
73
+            color: $defaultColor !important;
74
+            text-align: left;
75
+            margin: 10px 0px 10px 0px;
76
+            padding: 5px 10px 5px 10px;
77
+        }
78
+
79
+        /**
80
+         * Main title size.
81
+         */
82
+        > div.title {
83
+            font-size: 16px;
84
+        }
85
+
86
+        /**
87
+         * Subtitle specific properties.
88
+         */
89
+        > div.subTitle {
90
+            font-size: 12px;
91
+            background: $inputSemiBackground !important;
92
+            margin-top: 20px !important;
93
+            margin-bottom: 8px !important;
94
+        }
95
+
96
+        /**
97
+         * First element after a title.
98
+         */
99
+        .first {
100
+            margin-top: 0px !important;
101
+        }
102
+    }
103
+}
104
+
105
+#device_settings {
106
+    width : auto !important;
107
+    text-align: center;
108
+}
109
+
110
+#startAudioMuted,
111
+#startVideoMuted,
112
+#followMeCheckBox {
113
+    width: 13px !important;
114
+}

+ 41
- 5
css/_toastr.scss Просмотреть файл

@@ -19,32 +19,42 @@
19 19
 .toast-message label {
20 20
   color: #ffffff;
21 21
 }
22
+
23
+.toast-message .nickname {
24
+  font-weight: bold;
25
+}
26
+
22 27
 .toast-message a:hover {
23 28
   color: #cccccc;
24 29
   text-decoration: none;
25 30
 }
31
+
26 32
 .toast-close-button {
27 33
   position: relative;
28 34
   right: -0.3em;
29 35
   top: -0.3em;
30 36
   float: right;
31
-  font-size: 20px;
37
+  font-size: 15px;
38
+  height: 15px;
39
+  width: 15px;
32 40
   font-weight: bold;
33 41
   color: #ffffff;
42
+  background: transparent !important;
34 43
   -webkit-text-shadow: 0 1px 0 #ffffff;
35 44
   text-shadow: 0 1px 0 #ffffff;
36 45
   opacity: 0.8;
37 46
   -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
38 47
   filter: alpha(opacity=80);
39 48
 }
49
+
40 50
 .toast-close-button:hover,
41 51
 .toast-close-button:focus {
42
-  color: #000000;
52
+  color: #ffffff;
43 53
   text-decoration: none;
44 54
   cursor: pointer;
45
-  opacity: 0.4;
46
-  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
47
-  filter: alpha(opacity=40);
55
+  opacity: 1;
56
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
57
+  filter: alpha(opacity=100);
48 58
 }
49 59
 /*Additional properties for button version
50 60
  iOS requires the button element instead of an anchor tag.
@@ -173,4 +183,30 @@ button.toast-close-button {
173 183
     padding: 15px 15px 15px 15px;
174 184
     width: 25em;
175 185
   }
186
+}
187
+
188
+#toast-container.notification-bottom-right {
189
+  bottom: 140px;
190
+  right: 5px;
191
+}
192
+
193
+#toast-container.notification-bottom-right-center {
194
+  right: 205px;
195
+}
196
+
197
+#toast-container .toast-info {
198
+  -webkit-box-shadow: none;
199
+  box-shadow: none;
200
+}
201
+
202
+.toast-close-button {
203
+  right: -7px;
204
+  top: -19px;
205
+}
206
+
207
+#toast-container .toast-info {
208
+  background-color: black;
209
+  border: 1px solid #3a3a3a;
210
+  width: 220px;
211
+  padding: 10px 10px 10px 50px;
176 212
 }

+ 1
- 27
css/_toolbars.scss Просмотреть файл

@@ -74,34 +74,8 @@
74 74
     -webkit-transform: translateX(-100%);
75 75
 }
76 76
 
77
-#sideToolbarContainer {
78
-    display: inline-block;
79
-    position:absolute;
80
-    top: 0px;
81
-    left: $defaultToolbarSize;
82
-    width: 0%;
83
-    height: 100%;
84
-    max-width: 200px;
85
-    background-color: rgba(0,0,0,0.8);
86
-    z-index: 800;
87
-    overflow: hidden;
88
-
89
-    .sideToolbarContainer__inner {
90
-        display: none;
91
-        width: 200px;
92
-        color: #FFF;
93
-
94
-        > div.title {
95
-            text-align: left;
96
-            padding: 10px;
97
-            margin: 2px;
98
-            font-size: 12pt;
99
-        }
100
-    }
101
-}
102
-
103 77
 #toolbar_button_hangup {
104
-    color: #ff0000;
78
+    color: #BF2117;
105 79
     font-size: 2.2em !important;
106 80
 }
107 81
 

+ 16
- 1
css/_variables.scss Просмотреть файл

@@ -9,7 +9,22 @@ $baseFontFamily: 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-seri
9 9
 $defaultToolbarSize: 50px;
10 10
 
11 11
 /**
12
- * Miscellaneous.
12
+ * Color variables.
13 13
  */
14
+$defaultColor: #ECEEF1;
15
+$defaultSemiDarkColor: #8E96A8;
16
+$defaultDarkColor: #172B4D;
17
+$defaultBackground: #091E42;
14 18
 $toolbarSelectBackground: rgba(0, 0, 0, 0.6);
19
+$inputBackground: rgba(94, 108, 132, .5);
20
+$inputSemiBackground: rgba(94, 108, 132, .8);
21
+$inputLightBackground: #E5E8EC;
22
+$inputBorderColor: #E5E8EC;
23
+$buttonBackground: #0074E0;
24
+
25
+/**
26
+ * Misc.
27
+ */
28
+$borderRadius: 4px;
29
+
15 30
 

+ 1
- 1
css/_welcome_page.scss Просмотреть файл

@@ -1,4 +1,3 @@
1
-
2 1
 #disable_welcome {
3 2
     display:none;
4 3
 }
@@ -59,6 +58,7 @@
59 58
     font-size: 18px;
60 59
     font-weight: 500;
61 60
     padding-left: 20px;
61
+    color: $defaultDarkColor;
62 62
 }
63 63
 
64 64
 #enter_room_field {

+ 3
- 2
css/main.scss Просмотреть файл

@@ -34,9 +34,10 @@
34 34
 @import 'contact_list';
35 35
 @import 'chat';
36 36
 @import 'welcome_page';
37
-@import 'settingsmenu';
38
-@import 'feedback';
39 37
 @import 'toolbars';
38
+@import 'side_toolbar_container';
39
+@import 'device_settings_dialog';
40
+@import 'feedback';
40 41
 @import 'jquery.contextMenu';
41 42
 @import 'keyboard-shortcuts';
42 43
 

+ 39
- 44
index.html Просмотреть файл

@@ -100,24 +100,11 @@
100 100
                 <div id="notice" class="notice" style="display: none">
101 101
                     <span id="noticeText" class="noticeText"></span>
102 102
                 </div>
103
-                <span id="mainToolbar" class="toolbar">
104
-                    <a class="button icon-share-desktop first" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleDesktopSharingPopover" content="Share screen" data-i18n="[content]toolbar.sharescreen" style="display: none"></a>
105
-                    <a class="button icon-microphone" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
106
-                        <ul id="micMutedPopup" class="loginmenu">
107
-                            <li data-i18n="[html]toolbar.micMutedPopup"></li>
108
-                        </ul>
109
-                        <ul id="unableToUnmutePopup" class="loginmenu">
110
-                            <li data-i18n="[html]toolbar.unableToUnmutePopup"></li>
111
-                        </ul>
112
-                    </a>
113
-                    <a class="button icon-hangup" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" data-i18n="[content]toolbar.hangup"></a>
114
-                    <a class="button icon-camera" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" data-i18n="[content]toolbar.videomute" content="Start / stop camera"></a>
115
-                    <a class="button icon-full-screen last" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen" data-i18n="[content]toolbar.fullscreen"></a>
116
-                </span>
103
+                <span id="mainToolbar" class="toolbar"></span>
117 104
         </div>
118 105
         <div id="subject" class="hide"></div>
119 106
         <div id="extendedToolbar" class="toolbar">
120
-            <a class="button" data-container="body" data-placement="right" data-i18n="[content]toolbar.profile" content="Edit your profile">
107
+            <a class="button" id="toolbar_button_profile" data-container="body" data-placement="right" data-i18n="[content]toolbar.profile" content="Edit your profile">
121 108
                 <img id="avatar" src="images/avatar2.png"/>
122 109
             </a>
123 110
             <span id="authentication" class="authentication" style="display: none">
@@ -154,6 +141,17 @@
154 141
             <a class="button icon-filmstrip" id="toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="right" data-i18n="[content]toolbar.filmstrip" content="Show / hide videos"></a>
155 142
             <a class="button fa fa-heart" id="feedbackButton" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[content]feedback"></a>
156 143
             <div id="sideToolbarContainer">
144
+                <div id="profile_container" class="sideToolbarContainer__inner">
145
+                    <div class="title" data-i18n="profile.title"></div>
146
+                    <div class="sideToolbarBlock first">
147
+                        <label class="first" data-i18n="profile.setDisplayNameLabel"></label>
148
+                        <input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
149
+                    </div>
150
+                    <div class="sideToolbarBlock">
151
+                        <label data-i18n="profile.setEmailLabel"></label>
152
+                        <input type="text" id="setEmail" placeholder="Enter e-mail">
153
+                    </div>
154
+                </div>
157 155
                 <div id="chat_container" class="sideToolbarContainer__inner">
158 156
                     <div id="nickname">
159 157
                         <span data-i18n="chat.nickname.title"></span>
@@ -177,39 +175,36 @@
177 175
                 </div>
178 176
                 <div id="settings_container" class="sideToolbarContainer__inner">
179 177
                     <div class="title" data-i18n="settings.title"></div>
180
-                    <div class="arrow-up"></div>
181
-                    <input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
182
-                    <input type="text" id="setEmail" placeholder="E-Mail">
183
-                    <select id="languages_selectbox"></select>
178
+                    <select class="first" id="languages_selectbox"></select>
179
+                    <div class="subTitle" data-i18n="settings.audioVideo"></div>
180
+                    <div id="devicesOptions">
181
+                        <div class="sideToolbarBlock first">
182
+                            <label class="first" data-i18n="settings.selectCamera"></label>
183
+                            <select id="selectCamera"></select>
184
+                        </div>
185
+                        <div class="sideToolbarBlock">
186
+                            <label data-i18n="settings.selectMic"></label>
187
+                            <select  id="selectMic"></select>
188
+                        </div>
189
+                        <div class="sideToolbarBlock">
190
+                            <label data-i18n="settings.selectAudioOutput"></label>
191
+                            <select  id="selectAudioOutput"></select>
192
+                        </div>
193
+                    </div>
194
+                    <div class="subTitle" data-i18n="settings.moderator"></div>
184 195
                     <div id = "startMutedOptions">
185
-                        <label class = "startMutedLabel">
196
+                        <div class="sideToolbarBlock first">
186 197
                             <input type="checkbox" id="startAudioMuted">
187
-                            <span  data-i18n="settings.startAudioMuted"></span>
188
-                        </label>
189
-                        <label class = "startMutedLabel">
198
+                            <label class="startMutedLabel" for="startAudioMuted" data-i18n="settings.startAudioMuted"></label>
199
+                        </div>
200
+                        <div class="sideToolbarBlock">
190 201
                             <input type="checkbox" id="startVideoMuted">
191
-                            <span data-i18n="settings.startVideoMuted"></span>
192
-                        </label>
193
-                    </div>
194
-                    <div id="devicesOptions">
195
-                        <label className="devicesOptionsLabel">
196
-                            <span data-i18n="settings.selectCamera"></span>
197
-                            <select id="selectCamera"></select>
198
-                        </label>
199
-                        <label className="devicesOptionsLabel">
200
-                            <span data-i18n="settings.selectMic"></span>
201
-                            <select id="selectMic"></select>
202
-                        </label>
203
-                        <label className="devicesOptionsLabel">
204
-                            <span data-i18n="settings.selectAudioOutput"></span>
205
-                            <select id="selectAudioOutput"></select>
206
-                        </label>
202
+                            <label class="startMutedLabel" for="startVideoMuted" data-i18n="settings.startVideoMuted"></label>
203
+                        </div>
207 204
                     </div>
208
-                    <div id="followMeOptions">
209
-                        <label class = "followMeLabel">
210
-                            <input type="checkbox" id="followMeCheckBox">
211
-                            <span  data-i18n="settings.followMe"></span>
212
-                        </label>
205
+                    <div id="followMeOptions" class="sideToolbarBlock">
206
+                        <input type="checkbox" id="followMeCheckBox">
207
+                        <label class="followMeLabel" for="followMeCheckBox" data-i18n="settings.followMe"></label>
213 208
                     </div>
214 209
                     <a id="downloadlog" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[data-content]downloadlogs" ><i class="fa fa-cloud-download"></i></a>
215 210
                 </div>

+ 1
- 0
interface_config.js Просмотреть файл

@@ -16,6 +16,7 @@ var interfaceConfig = {
16 16
     INVITATION_POWERED_BY: true,
17 17
     // the toolbar buttons line is intentionally left in one line, to be able
18 18
     // to easily override values or remove them using regex
19
+    MAIN_TOOLBAR_BUTTONS: ['microphone', 'camera', 'desktop', 'fullscreen', 'hangup'], // jshint ignore:line
19 20
     TOOLBAR_BUTTONS: ['authentication', 'microphone', 'camera', 'desktop', 'recording', 'security', 'invite', 'chat', 'etherpad', 'sharedvideo', 'fullscreen', 'sip', 'dialpad', 'settings', 'hangup', 'filmstrip', 'contacts'], // jshint ignore:line
20 21
     // Determines how the video would fit the screen. 'both' would fit the whole
21 22
     // screen, 'height' would fit the original video height to the height of the

+ 19
- 9
lang/main.json Просмотреть файл

@@ -1,5 +1,5 @@
1 1
 {
2
-    "contactlist": "On Call (__participants__)",
2
+    "contactlist": "ON CALL (__participants__)",
3 3
     "connectionsettings": "Connection Settings",
4 4
     "poweredby": "powered by",
5 5
     "downloadlogs": "Download logs",
@@ -109,17 +109,27 @@
109 109
     },
110 110
     "settings":
111 111
     {
112
-        "title": "Settings",
112
+        "title": "SETTINGS",
113 113
         "update": "Update",
114 114
         "name": "Name",
115
-        "startAudioMuted": "Start without audio",
116
-        "startVideoMuted": "Start without video",
115
+        "startAudioMuted": "Everyone starts muted",
116
+        "startVideoMuted": "Everyone starts hidden",
117 117
         "selectCamera": "Select camera",
118 118
         "selectMic": "Select microphone",
119 119
         "selectAudioOutput": "Select audio output",
120
-        "followMe": "Enable follow me",
120
+        "followMe": "Everyone follows me",
121 121
         "noDevice": "None",
122
-        "noPermission": "Permission to use device is not granted"
122
+        "noPermission": "Permission to use device is not granted",
123
+        "cameraAndMic": "Camera and microphone",
124
+        "moderator": "MODERATOR",
125
+        "password": "SET PASSWORD",
126
+        "audioVideo": "AUDIO / VIDEO",
127
+        "setPasswordLabel": "Lock your room with a password."
128
+    },
129
+    "profile": {
130
+        "title": "PROFILE",
131
+        "setDisplayNameLabel": "Set your display name",
132
+        "setEmailLabel": "Set your gravatar email"
123 133
     },
124 134
     "videothumbnail":
125 135
     {
@@ -221,18 +231,18 @@
221 231
         "Remove": "Remove",
222 232
         "passwordMsg": "Set a password to lock your room",
223 233
         "Invite": "Invite",
224
-        "shareLink": "Share this link with everyone you want to invite",
234
+        "shareLink": "Copy and share this link",
225 235
         "settings1": "Configure your conference",
226 236
         "settings2": "Participants join muted",
227 237
         "settings3": "Require nicknames<br/><br/>Set a password to lock your room:",
228
-        "yourPassword": "your password",
238
+        "yourPassword": "Enter new password",
229 239
         "Back": "Back",
230 240
         "serviceUnavailable": "Service unavailable",
231 241
         "gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
232 242
         "Yes": "Yes",
233 243
         "reservationError": "Reservation system error",
234 244
         "reservationErrorMsg": "Error code: __code__, message: __msg__",
235
-        "password": "password",
245
+        "password": "Enter password",
236 246
         "userPassword": "user password",
237 247
         "token": "token",
238 248
         "tokenAuthFailed": "Failed to authenticate with XMPP server: invalid token",

+ 35
- 8
modules/UI/UI.js Просмотреть файл

@@ -19,6 +19,7 @@ import GumPermissionsOverlay from './gum_overlay/UserMediaPermissionsGuidanceOve
19 19
 import VideoLayout from "./videolayout/VideoLayout";
20 20
 import FilmStrip from "./videolayout/FilmStrip";
21 21
 import SettingsMenu from "./side_pannels/settings/SettingsMenu";
22
+import Profile from "./side_pannels/profile/Profile";
22 23
 import Settings from "./../settings/Settings";
23 24
 import { reload } from '../util/helpers';
24 25
 import RingOverlay from "./ring_overlay/RingOverlay";
@@ -140,7 +141,7 @@ function setupToolbars() {
140 141
  * (a.k.a. presentation mode in Chrome).
141 142
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
142 143
  */
143
-function toggleFullScreen () {
144
+UI.toggleFullScreen = function() {
144 145
                             // alternative standard method
145 146
     let isNotFullScreen = !document.fullscreenElement &&
146 147
             !document.mozFullScreenElement && // current working methods
@@ -169,7 +170,7 @@ function toggleFullScreen () {
169 170
             document.webkitExitFullscreen();
170 171
         }
171 172
     }
172
-}
173
+};
173 174
 
174 175
 /**
175 176
  * Notify user that server has shut down.
@@ -251,7 +252,7 @@ UI.changeDisplayName = function (id, displayName) {
251 252
     VideoLayout.onDisplayNameChanged(id, displayName);
252 253
 
253 254
     if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
254
-        SettingsMenu.changeDisplayName(displayName);
255
+        Profile.changeDisplayName(displayName);
255 256
         Chat.setChatConversationMode(!!displayName);
256 257
     }
257 258
 };
@@ -355,16 +356,20 @@ function registerListeners() {
355 356
         }
356 357
     });
357 358
 
358
-    UI.addListener(UIEvents.FULLSCREEN_TOGGLE, toggleFullScreen);
359
+    UI.addListener(UIEvents.FULLSCREEN_TOGGLE, UI.toggleFullScreen);
359 360
 
360 361
     UI.addListener(UIEvents.TOGGLE_CHAT, UI.toggleChat);
361 362
 
362 363
     UI.addListener(UIEvents.TOGGLE_SETTINGS, function () {
363
-        SideContainerToggler.toggle("settings_container");
364
+        UI.toggleSidePanel("settings_container");
364 365
     });
365 366
 
366 367
     UI.addListener(UIEvents.TOGGLE_CONTACT_LIST, UI.toggleContactList);
367 368
 
369
+    UI.addListener( UIEvents.TOGGLE_PROFILE, function() {
370
+        UI.toggleSidePanel("profile_container");
371
+    });
372
+
368 373
     UI.addListener(UIEvents.TOGGLE_FILM_STRIP, UI.handleToggleFilmStrip);
369 374
 
370 375
     UI.addListener(UIEvents.FOLLOW_ME_ENABLED, function (isEnabled) {
@@ -379,6 +384,7 @@ function registerListeners() {
379 384
 function bindEvents() {
380 385
     function onResize() {
381 386
         SideContainerToggler.resize();
387
+        VideoLayout.resizeVideoArea();
382 388
     }
383 389
 
384 390
     // Resize and reposition videos in full screen mode.
@@ -499,6 +505,7 @@ UI.start = function () {
499 505
         };
500 506
 
501 507
         SettingsMenu.init(eventEmitter);
508
+        Profile.init(eventEmitter);
502 509
     }
503 510
 
504 511
     if(APP.tokenData.callee) {
@@ -716,16 +723,26 @@ UI.isFilmStripVisible = function () {
716 723
  * Toggles chat panel.
717 724
  */
718 725
 UI.toggleChat = function () {
719
-    SideContainerToggler.toggle("chat_container");
726
+    UI.toggleSidePanel("chat_container");
720 727
 };
721 728
 
722 729
 /**
723 730
  * Toggles contact list panel.
724 731
  */
725 732
 UI.toggleContactList = function () {
726
-    SideContainerToggler.toggle("contacts_container");
733
+    UI.toggleSidePanel("contacts_container");
727 734
 };
728 735
 
736
+/**
737
+ * Toggles the given side panel.
738
+ *
739
+ * @param {String} sidePanelId the identifier of the side panel to toggle
740
+ */
741
+UI.toggleSidePanel = function (sidePanelId) {
742
+    SideContainerToggler.toggle(sidePanelId);
743
+};
744
+
745
+
729 746
 /**
730 747
  * Handle new user display name.
731 748
  */
@@ -817,6 +834,16 @@ UI.removeListener = function (type, listener) {
817 834
     eventEmitter.removeListener(type, listener);
818 835
 };
819 836
 
837
+/**
838
+ * Emits the event of given type by specifying the parameters in options.
839
+ *
840
+ * @param type the type of the event we're emitting
841
+ * @param options the parameters for the event
842
+ */
843
+UI.emitEvent = function (type, options) {
844
+    eventEmitter.emit(type, options);
845
+};
846
+
820 847
 UI.clickOnVideo = function (videoNumber) {
821 848
     var remoteVideos = $(".videocontainer:not(#mixedstream)");
822 849
     if (remoteVideos.length > videoNumber) {
@@ -843,7 +870,7 @@ function changeAvatar(id, avatarUrl) {
843 870
     VideoLayout.changeUserAvatar(id, avatarUrl);
844 871
     ContactList.changeUserAvatar(id, avatarUrl);
845 872
     if (APP.conference.isLocalId(id)) {
846
-        SettingsMenu.changeAvatar(avatarUrl);
873
+        Profile.changeAvatar(avatarUrl);
847 874
     }
848 875
 }
849 876
 

+ 61
- 0
modules/UI/side_pannels/profile/Profile.js Просмотреть файл

@@ -0,0 +1,61 @@
1
+/* global APP, $, JitsiMeetJS */
2
+import UIUtil from "../../util/UIUtil";
3
+import UIEvents from "../../../../service/UI/UIEvents";
4
+import languages from "../../../../service/translation/languages";
5
+import Settings from '../../../settings/Settings';
6
+
7
+export default {
8
+    init (emitter) {
9
+        // DISPLAY NAME
10
+        function updateDisplayName () {
11
+            emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
12
+        }
13
+
14
+        $('#setDisplayName')
15
+            .val(Settings.getDisplayName())
16
+            .keyup(function (event) {
17
+                if (event.keyCode === 13) { // enter
18
+                    updateDisplayName();
19
+                }
20
+            })
21
+            .focusout(updateDisplayName);
22
+
23
+
24
+        // EMAIL
25
+        function updateEmail () {
26
+            emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
27
+        }
28
+
29
+        $('#setEmail')
30
+            .val(Settings.getEmail())
31
+            .keyup(function (event) {
32
+                if (event.keyCode === 13) { // enter
33
+                    updateEmail();
34
+                }
35
+            }).focusout(updateEmail);
36
+    },
37
+
38
+    /**
39
+     * Check if settings menu is visible or not.
40
+     * @returns {boolean}
41
+     */
42
+    isVisible () {
43
+        return UIUtil.isVisible(document.getElementById("profile_container"));
44
+    },
45
+
46
+    /**
47
+     * Change user display name in the settings menu.
48
+     * @param {string} newDisplayName
49
+     */
50
+    changeDisplayName (newDisplayName) {
51
+        $('#setDisplayName').val(newDisplayName);
52
+    },
53
+
54
+    /**
55
+     * Change user avatar in the settings menu.
56
+     * @param {string} avatarUrl url of the new avatar
57
+     */
58
+    changeAvatar (avatarUrl) {
59
+        $('#avatar').attr('src', avatarUrl);
60
+    }
61
+};

+ 288
- 0
modules/UI/side_pannels/settings/SettingsDialog.js Просмотреть файл

@@ -0,0 +1,288 @@
1
+/* global APP, $, JitsiMeetJS */
2
+import UIUtil from "../../util/UIUtil";
3
+import UIEvents from "../../../../service/UI/UIEvents";
4
+import languages from "../../../../service/translation/languages";
5
+import Settings from '../../../settings/Settings';
6
+import mediaDeviceHelper from '../../../devices/mediaDeviceHelper';
7
+
8
+const RTCUIUtils = JitsiMeetJS.util.RTCUIHelper;
9
+
10
+var constructAudioIndicatorHtml = function() {
11
+    return '<span>'
12
+            + '<span id="audioLevel0" class="audioLevelDot"></span>'
13
+            + '<span id="audioLevel1" class="audioLevelDot"></span>'
14
+            + '<span id="audioLevel2" class="audioLevelDot"></span>'
15
+            + '<span id="audioLevel3" class="audioLevelDot"></span>'
16
+            + '<span id="audioLevel4" class="audioLevelDot"></span>'
17
+            + '<span id="audioLevel5" class="audioLevelDot"></span>'
18
+            + '<span id="audioLevel6" class="audioLevelDot"></span>'
19
+            + '<span id="audioLevel7" class="audioLevelDot"></span>'
20
+            + '<span id="audioLevel8" class="audioLevelDot"></span>'
21
+            + '<span id="audioLevel9" class="audioLevelDot"></span>'
22
+            + '</span>';
23
+};
24
+
25
+var constructMediaSettingsHtml = function() {
26
+    return '<div class="settingsContent">'
27
+            + '<video id="localVideoPreview"></video>'
28
+            //+ constructAudioIndicatorHtml()
29
+            + '<div class="deviceSelection">'
30
+                + '<span class="device">'
31
+                    + '<select id="selectCamera"></select> '
32
+                + '</span>'
33
+                + '<span class="device">'
34
+                    + '<select id="selectMic"></select> '
35
+                + '</span>'
36
+                + '<span class="device">'
37
+                    + '<select id="selectAudioOutput"></select> '
38
+                + '</span>'
39
+            + '</div>'
40
+        + '</div>';
41
+};
42
+
43
+/**
44
+ * The callback function corresponding to the openSettingsWindow parameter.
45
+ *
46
+ * @type {function}
47
+ */
48
+var settingsWindowCallback = null;
49
+
50
+/**
51
+ * Defines all methods in connection to the Settings dialog.
52
+ */
53
+var SettingsDialog = {
54
+    init(eventEmitter) {
55
+        this.eventEmitter = eventEmitter;
56
+    },
57
+
58
+    /**
59
+     * Generate html select options for available physical devices.
60
+     * @param {{ deviceId, label }[]} items available devices
61
+     * @param {string} [selectedId] id of selected device
62
+     * @param {boolean} permissionGranted if permission to use selected device
63
+     * type is granted
64
+     * @returns {string}
65
+     */
66
+    _generateDevicesOptions(items, selectedId, permissionGranted) {
67
+        if (!permissionGranted && items.length) {
68
+            return '<option data-i18n="settings.noPermission"></option>';
69
+        }
70
+
71
+        var options = items.map(function (item) {
72
+            let attrs = {
73
+                value: item.deviceId
74
+            };
75
+
76
+            if (item.deviceId === selectedId) {
77
+                attrs.selected = 'selected';
78
+            }
79
+
80
+            let attrsStr = UIUtil.attrsToString(attrs);
81
+            return `<option ${attrsStr}>${item.label}</option>`;
82
+        });
83
+
84
+        if (!items.length) {
85
+            options.unshift('<option data-i18n="settings.noDevice"></option>');
86
+        }
87
+
88
+        return options.join('');
89
+    },
90
+
91
+    _onLoadMediaSettings() {
92
+        let localVideoPreview = document.getElementById("localVideoPreview");
93
+        RTCUIUtils.setAutoPlay(localVideoPreview, true);
94
+        RTCUIUtils.setVolume(localVideoPreview, 0);
95
+
96
+        let localVideo = APP.conference.getVideoStream();
97
+        if (localVideo)
98
+            localVideoPreview = localVideo.attach(localVideoPreview);
99
+
100
+        this.eventEmitter.addListener(UIEvents.VIDEO_STREAM_CHANGED,
101
+            function(newStream)
102
+            {
103
+                newStream.attach(localVideoPreview);
104
+            });
105
+
106
+        // DEVICES LIST
107
+        JitsiMeetJS.mediaDevices.isDeviceListAvailable()
108
+            .then((isDeviceListAvailable) => {
109
+                if (isDeviceListAvailable &&
110
+                    JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) {
111
+
112
+                    this._initializeDeviceSelectionSettings();
113
+                }
114
+            });
115
+
116
+        APP.UI.eventEmitter.addListener(UIEvents.DEVICE_LIST_CHANGED,
117
+            (devices) => {
118
+                this._changeDevicesList(devices);
119
+            });
120
+    },
121
+
122
+    /**
123
+     * Initializes the device list with the current available media devices
124
+     * and attaches all listeners needed for device change user
125
+     * event handling.
126
+     */
127
+    _initializeDeviceSelectionSettings() {
128
+        this._changeDevicesList(mediaDeviceHelper.getCurrentMediaDevices());
129
+
130
+        $('#selectCamera').change(function () {
131
+            let cameraDeviceId = $(this).val();
132
+                if (cameraDeviceId !== Settings.getCameraDeviceId()) {
133
+                this.eventEmitter
134
+                    .emit(UIEvents.VIDEO_DEVICE_CHANGED, cameraDeviceId);
135
+            }
136
+        });
137
+        $('#selectMic').change(function () {
138
+            let micDeviceId = $(this).val();
139
+            if (micDeviceId !== Settings.getMicDeviceId()) {
140
+                this.eventEmitter
141
+                    .emit(UIEvents.AUDIO_DEVICE_CHANGED, micDeviceId);
142
+            }
143
+        });
144
+        $('#selectAudioOutput').change(function () {
145
+            let audioOutputDeviceId = $(this).val();
146
+            if (audioOutputDeviceId !== Settings.getAudioOutputDeviceId()) {
147
+                this.eventEmitter.emit(
148
+                    UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED, audioOutputDeviceId);
149
+            }
150
+        });
151
+    },
152
+
153
+    /**
154
+     * Sets microphone's <select> element to select microphone ID from settings.
155
+     */
156
+    setSelectedMicFromSettings () {
157
+        $('#selectMic').val(Settings.getMicDeviceId());
158
+    },
159
+
160
+    /**
161
+     * Sets camera's <select> element to select camera ID from settings.
162
+     */
163
+    setSelectedCameraFromSettings () {
164
+        $('#selectCamera').val(Settings.getCameraDeviceId());
165
+    },
166
+
167
+    /**
168
+     * Sets audio outputs's <select> element to select audio output ID from
169
+     * settings.
170
+     */
171
+    setSelectedAudioOutputFromSettings () {
172
+        $('#selectAudioOutput').val(Settings.getAudioOutputDeviceId());
173
+    },
174
+
175
+    /**
176
+     * Change available cameras/microphones or hide selects completely if
177
+     * no devices available.
178
+     * @param {{ deviceId, label, kind }[]} devices list of available devices
179
+     */
180
+    _changeDevicesList (devices) {
181
+        let $selectCamera= $('#selectCamera'),
182
+            $selectMic = $('#selectMic'),
183
+            $selectAudioOutput = $('#selectAudioOutput'),
184
+            $selectAudioOutputParent = $selectAudioOutput.parent();
185
+
186
+        let audio = devices.audioinput,
187
+            video = devices.videoinput,
188
+            audioOutput = devices.audiooutput,
189
+            selectedAudioDevice = audio.find(
190
+                d => d.deviceId === Settings.getMicDeviceId()) || audio[0],
191
+            selectedVideoDevice = video.find(
192
+                d => d.deviceId === Settings.getCameraDeviceId()) || video[0],
193
+            selectedAudioOutputDevice = audioOutput.find(
194
+                d => d.deviceId === Settings.getAudioOutputDeviceId()),
195
+            videoPermissionGranted =
196
+                JitsiMeetJS.mediaDevices.isDevicePermissionGranted('video'),
197
+            audioPermissionGranted =
198
+                JitsiMeetJS.mediaDevices.isDevicePermissionGranted('audio');
199
+
200
+        $selectCamera
201
+            .html(this._generateDevicesOptions(
202
+                video,
203
+                selectedVideoDevice ? selectedVideoDevice.deviceId : '',
204
+                videoPermissionGranted))
205
+            .prop('disabled', !video.length || !videoPermissionGranted);
206
+
207
+        $selectMic
208
+            .html(this._generateDevicesOptions(
209
+                audio,
210
+                selectedAudioDevice ? selectedAudioDevice.deviceId : '',
211
+                audioPermissionGranted))
212
+            .prop('disabled', !audio.length || !audioPermissionGranted);
213
+
214
+        if (JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output')) {
215
+            $selectAudioOutput
216
+                .html(this._generateDevicesOptions(
217
+                    audioOutput,
218
+                    selectedAudioOutputDevice
219
+                        ? selectedAudioOutputDevice.deviceId
220
+                        : 'default',
221
+                    videoPermissionGranted || audioPermissionGranted))
222
+                .prop('disabled', !audioOutput.length ||
223
+                (!videoPermissionGranted && !audioPermissionGranted));
224
+
225
+            $selectAudioOutputParent.show();
226
+        } else {
227
+            $selectAudioOutputParent.hide();
228
+        }
229
+
230
+        $('#devicesOptions').show();
231
+
232
+        APP.translation.translateElement($('#settings_container option'));
233
+    },
234
+
235
+    /**
236
+     * Opens the feedback window.
237
+     */
238
+    openSettingsDialog: function (callback) {
239
+        settingsWindowCallback = callback;
240
+
241
+        var htmlString = '<div class="settingsDialog">'
242
+                            + constructMediaSettingsHtml()
243
+                            + '</div>';
244
+
245
+        // Defines the different states of the feedback window.
246
+        var states = {
247
+            mediaSettings: {
248
+                title: APP.translation.translateString("settings.title"),
249
+                html: htmlString,
250
+                persistent: false,
251
+                buttons: {},
252
+                closeText: '',
253
+                //focus: "div[id='stars']",
254
+                position: {width: 600}
255
+            }
256
+        };
257
+
258
+        const cancelButton
259
+            = APP.translation.generateTranslationHTML("dialog.Cancel");
260
+        const saveButton
261
+            = APP.translation.generateTranslationHTML("dialog.Save");
262
+
263
+        // Create the settings dialog.
264
+        var settingsDialog
265
+            = APP.UI.messageHandler.openDialogWithStates(
266
+            states,
267
+            {
268
+                persistent: false,
269
+                buttons: [
270
+                    {title: cancelButton, value: false},
271
+                    {title: saveButton, value: true}
272
+                ],
273
+                closeText: '',
274
+                loaded: this._onLoadMediaSettings.bind(this),
275
+                position: {width: 500},
276
+                submit: function (e, v, m, f) {
277
+                    e.preventDefault();
278
+                    if (!v) {
279
+
280
+                    }
281
+                }
282
+            }, null);
283
+        JitsiMeetJS.analytics.sendEvent('settings.open');
284
+    }
285
+};
286
+
287
+// Exports the SettingsDialog class.
288
+module.exports = SettingsDialog;

+ 1
- 45
modules/UI/side_pannels/settings/SettingsMenu.js Просмотреть файл

@@ -62,34 +62,6 @@ function generateDevicesOptions(items, selectedId, permissionGranted) {
62 62
 
63 63
 export default {
64 64
     init (emitter) {
65
-
66
-        // DISPLAY NAME
67
-        function updateDisplayName () {
68
-            emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
69
-        }
70
-        $('#setDisplayName')
71
-            .val(Settings.getDisplayName())
72
-            .keyup(function (event) {
73
-                if (event.keyCode === 13) { // enter
74
-                    updateDisplayName();
75
-                }
76
-            })
77
-            .focusout(updateDisplayName);
78
-
79
-
80
-        // EMAIL
81
-        function updateEmail () {
82
-            emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
83
-        }
84
-
85
-        $('#setEmail')
86
-            .val(Settings.getEmail())
87
-            .keyup(function (event) {
88
-            if (event.keyCode === 13) { // enter
89
-                updateEmail();
90
-            }
91
-        }).focusout(updateEmail);
92
-
93 65
         // START MUTED
94 66
         $("#startMutedOptions").change(function () {
95 67
             let startAudioMuted = $("#startAudioMuted").is(":checked");
@@ -194,22 +166,6 @@ export default {
194 166
         return UIUtil.isVisible(document.getElementById("settings_container"));
195 167
     },
196 168
 
197
-    /**
198
-     * Change user display name in the settings menu.
199
-     * @param {string} newDisplayName
200
-     */
201
-    changeDisplayName (newDisplayName) {
202
-        $('#setDisplayName').val(newDisplayName);
203
-    },
204
-
205
-    /**
206
-     * Change user avatar in the settings menu.
207
-     * @param {string} avatarUrl url of the new avatar
208
-     */
209
-    changeAvatar (avatarUrl) {
210
-        $('#avatar').attr('src', avatarUrl);
211
-    },
212
-
213 169
     /**
214 170
      * Sets microphone's <select> element to select microphone ID from settings.
215 171
      */
@@ -292,4 +248,4 @@ export default {
292 248
 
293 249
         APP.translation.translateElement($('#settings_container option'));
294 250
     }
295
-};
251
+};

+ 107
- 20
modules/UI/toolbars/Toolbar.js Просмотреть файл

@@ -20,9 +20,13 @@ function openLinkDialog () {
20 20
     } else {
21 21
         inviteAttributes = "value=\"" + encodeURI(roomUrl) + "\"";
22 22
     }
23
+
24
+    let title = APP.translation.generateTranslationHTML("dialog.shareLink");
23 25
     APP.UI.messageHandler.openTwoButtonDialog(
24
-        "dialog.shareLink", null, null,
25
-        `<input id="inviteLinkRef" type="text" ${inviteAttributes} onclick="this.select();" readonly>`,
26
+        null, null, null,
27
+        '<h2>' + title + '</h2>'
28
+        + '<input id="inviteLinkRef" type="text" '
29
+        + inviteAttributes + ' onclick="this.select();" readonly>',
26 30
         false, "dialog.Invite",
27 31
         function (e, v) {
28 32
             if (v && roomUrl) {
@@ -38,7 +42,8 @@ function openLinkDialog () {
38 42
                 document.getElementById('inviteLinkRef').select();
39 43
             } else {
40 44
                 if (event && event.target) {
41
-                    $(event.target).find('button[value=true]').prop('disabled', true);
45
+                    $(event.target).find('button[value=true]')
46
+                        .prop('disabled', true);
42 47
                 }
43 48
             }
44 49
         },
@@ -50,6 +55,10 @@ function openLinkDialog () {
50 55
 }
51 56
 
52 57
 const buttonHandlers = {
58
+    "toolbar_button_profile": function () {
59
+        JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled');
60
+        emitter.emit(UIEvents.TOGGLE_PROFILE);
61
+    },
53 62
     "toolbar_button_mute": function () {
54 63
         let sharedVideoManager = APP.UI.getSharedVideoManager();
55 64
 
@@ -116,7 +125,7 @@ const buttonHandlers = {
116 125
     },
117 126
     "toolbar_button_fullScreen": function() {
118 127
         JitsiMeetJS.analytics.sendEvent('toolbar.fullscreen.enabled');
119
-        UIUtil.buttonClick("#toolbar_button_fullScreen",
128
+        UIUtil.buttonClick("toolbar_button_fullScreen",
120 129
             "icon-full-screen icon-exit-full-screen");
121 130
         emitter.emit(UIEvents.FULLSCREEN_TOGGLE);
122 131
     },
@@ -163,45 +172,55 @@ const buttonHandlers = {
163 172
         emitter.emit(UIEvents.TOGGLE_FILM_STRIP);
164 173
     }
165 174
 };
175
+
166 176
 const defaultToolbarButtons = {
167 177
     'microphone': {
168
-        id: '#toolbar_button_mute',
178
+        id: 'toolbar_button_mute',
179
+        className: "button icon-microphone",
169 180
         shortcut: 'M',
170 181
         shortcutAttr: 'mutePopover',
171 182
         shortcutFunc: function() {
172 183
             JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
173 184
             APP.conference.toggleAudioMuted();
174 185
         },
175
-        shortcutDescription: "keyboardShortcuts.mute"
186
+        shortcutDescription: "keyboardShortcuts.mute",
187
+        content: "Mute / Unmute",
188
+        i18n: "[content]toolbar.mute"
176 189
     },
177 190
     'camera': {
178
-        id: '#toolbar_button_camera',
191
+        id: 'toolbar_button_camera',
192
+        className: "button icon-camera",
179 193
         shortcut: 'V',
180 194
         shortcutAttr: 'toggleVideoPopover',
181 195
         shortcutFunc: function() {
182 196
             JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
183 197
             APP.conference.toggleVideoMuted();
184 198
         },
185
-        shortcutDescription: "keyboardShortcuts.videoMute"
199
+        shortcutDescription: "keyboardShortcuts.videoMute",
200
+        content: "Start / stop camera",
201
+        i18n: "[content]toolbar.videomute"
186 202
     },
187 203
     'desktop': {
188
-        id: '#toolbar_button_desktopsharing',
204
+        id: 'toolbar_button_desktopsharing',
205
+        className: "button icon-share-desktop",
189 206
         shortcut: 'D',
190 207
         shortcutAttr: 'toggleDesktopSharingPopover',
191 208
         shortcutFunc: function() {
192 209
             JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
193 210
             APP.conference.toggleScreenSharing();
194 211
         },
195
-        shortcutDescription: "keyboardShortcuts.toggleScreensharing"
212
+        shortcutDescription: "keyboardShortcuts.toggleScreensharing",
213
+        content: "Share screen",
214
+        i18n: "[content]toolbar.sharescreen"
196 215
     },
197 216
     'security': {
198
-        id: '#toolbar_button_security'
217
+        id: 'toolbar_button_security'
199 218
     },
200 219
     'invite': {
201
-        id: '#toolbar_button_link'
220
+        id: 'toolbar_button_link'
202 221
     },
203 222
     'chat': {
204
-        id: '#toolbar_button_chat',
223
+        id: 'toolbar_button_chat',
205 224
         shortcut: 'C',
206 225
         shortcutAttr: 'toggleChatPopover',
207 226
         shortcutFunc: function() {
@@ -212,24 +231,41 @@ const defaultToolbarButtons = {
212 231
         sideContainerId: "chat_container"
213 232
     },
214 233
     'contacts': {
215
-        id: '#toolbar_contact_list',
234
+        id: 'toolbar_contact_list',
216 235
         sideContainerId: "contacts_container"
217 236
     },
237
+    'profile': {
238
+        id: 'toolbar_button_profile',
239
+        sideContainerId: "profile_container"
240
+    },
218 241
     'etherpad': {
219
-        id: '#toolbar_button_etherpad'
242
+        id: 'toolbar_button_etherpad'
220 243
     },
221 244
     'fullscreen': {
222
-        id: '#toolbar_button_fullScreen'
245
+        id: 'toolbar_button_fullScreen',
246
+        className: "button icon-full-screen",
247
+        shortcut: 'F',
248
+        shortcutAttr: 'toggleFullscreenPopover',
249
+        shortcutFunc: function() {
250
+            JitsiMeetJS.analytics.sendEvent('shortcut.fullscreen.toggled');
251
+            APP.UI.toggleFullScreen();
252
+        },
253
+        shortcutDescription: "keyboardShortcuts.toggleChat",
254
+        content: "Enter / Exit Full Screen",
255
+        i18n: "[content]toolbar.fullscreen"
223 256
     },
224 257
     'settings': {
225
-        id: '#toolbar_button_settings',
258
+        id: 'toolbar_button_settings',
226 259
         sideContainerId: "settings_container"
227 260
     },
228 261
     'hangup': {
229
-        id: '#toolbar_button_hangup'
262
+        id: 'toolbar_button_hangup',
263
+        className: "button icon-hangup",
264
+        content: "Hang Up",
265
+        i18n: "[content]toolbar.hangup"
230 266
     },
231 267
     'filmstrip': {
232
-        id: '#toolbar_film_strip',
268
+        id: 'toolbar_film_strip',
233 269
         shortcut: "F",
234 270
         shortcutAttr: "filmstripPopover",
235 271
         shortcutFunc: function() {
@@ -272,6 +308,8 @@ const Toolbar = {
272 308
         this.toolbarSelector = $("#mainToolbarContainer");
273 309
         this.extendedToolbarSelector = $("#extendedToolbar");
274 310
 
311
+        this._initMainToolbarButtons();
312
+
275 313
         UIUtil.hideDisabledButtons(defaultToolbarButtons);
276 314
 
277 315
         Object.keys(defaultToolbarButtons).forEach(
@@ -298,7 +336,7 @@ const Toolbar = {
298 336
 
299 337
         APP.UI.addListener(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
300 338
             function(containerId, isVisible) {
301
-                Toolbar._handleSideToolbarContainerToggled(  containerId,
339
+                Toolbar._handleSideToolbarContainerToggled( containerId,
302 340
                                                             isVisible);
303 341
             });
304 342
     },
@@ -617,9 +655,58 @@ const Toolbar = {
617 655
                 if (button.sideContainerId
618 656
                     && button.sideContainerId === containerId) {
619 657
                     UIUtil.buttonClick(button.id, "selected");
658
+                    return;
620 659
                 }
621 660
             }
622 661
         );
662
+    },
663
+    /**
664
+     * TODO: Fix mic popups
665
+     * <a class="button icon-microphone" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
666
+     *   <ul id="micMutedPopup" class="loginmenu">
667
+     *       <li data-i18n="[html]toolbar.micMutedPopup"></li>
668
+     *   </ul>
669
+     *   <ul id="unableToUnmutePopup" class="loginmenu">
670
+     *       <li data-i18n="[html]toolbar.unableToUnmutePopup"></li>
671
+     *   </ul>
672
+     * </a>
673
+     */
674
+    _initMainToolbarButtons() {
675
+        interfaceConfig.MAIN_TOOLBAR_BUTTONS.forEach((value, index) => {
676
+            if (value && value in defaultToolbarButtons) {
677
+                let button = defaultToolbarButtons[value];
678
+                this._addMainToolbarButton(
679
+                    button,
680
+                    (index === 0),
681
+                    (index === interfaceConfig.MAIN_TOOLBAR_BUTTONS.length -1));
682
+            }
683
+        });
684
+    },
685
+
686
+    _addMainToolbarButton(button, isFirst, isLast) {
687
+        let buttonElement = document.createElement("a");
688
+        if (button.className)
689
+            buttonElement.className = button.className
690
+                                    + ((isFirst) ? " first" : "")
691
+                                    + ((isLast) ? " last" : "");
692
+
693
+        buttonElement.id = button.id;
694
+
695
+        if (button.shortcutAttr)
696
+            buttonElement.setAttribute("shortcut", button.shortcutAttr);
697
+
698
+        if (button.content)
699
+            buttonElement.setAttribute("content", button.content);
700
+
701
+        if (button.i18n)
702
+            buttonElement.setAttribute("data-i18n", button.i18n);
703
+
704
+        buttonElement.setAttribute("data-container", "body");
705
+        buttonElement.setAttribute("data-toggle", "popover");
706
+        buttonElement.setAttribute("data-placement", "bottom");
707
+
708
+        document.getElementById("mainToolbar")
709
+            .appendChild(buttonElement);
623 710
     }
624 711
 };
625 712
 

+ 2
- 1
modules/UI/util/UIUtil.js Просмотреть файл

@@ -18,7 +18,8 @@
18 18
      * Changes the style class of the element given by id.
19 19
      */
20 20
     buttonClick: function(id, classname) {
21
-        $(id).toggleClass(classname); // add the class to the clicked element
21
+        // add the class to the clicked element
22
+        $("#" + id).toggleClass(classname);
22 23
     },
23 24
     /**
24 25
      * Returns the text width for the given element.

+ 4
- 0
service/UI/UIEvents.js Просмотреть файл

@@ -37,6 +37,10 @@ export default {
37 37
     TOGGLE_CHAT: "UI.toggle_chat",
38 38
     TOGGLE_SETTINGS: "UI.toggle_settings",
39 39
     TOGGLE_CONTACT_LIST: "UI.toggle_contact_list",
40
+    /**
41
+     * Notifies that the profile toolbar button has been clicked.
42
+     */
43
+    TOGGLE_PROFILE: "UI.toggle_profile",
40 44
     /**
41 45
      * Notifies that a command to toggle the film strip has been issued. The
42 46
      * event may optionally specify a {Boolean} (primitive) value to assign to

Загрузка…
Отмена
Сохранить