Browse Source

Adds a feedback button and dialog.

j8
yanas 10 years ago
parent
commit
73b1d3c7c2

+ 2
- 2
Makefile View File

3
 UGLIFYJS = ./node_modules/.bin/uglifyjs
3
 UGLIFYJS = ./node_modules/.bin/uglifyjs
4
 EXORCIST = ./node_modules/.bin/exorcist
4
 EXORCIST = ./node_modules/.bin/exorcist
5
 CLEANCSS = ./node_modules/.bin/cleancss
5
 CLEANCSS = ./node_modules/.bin/cleancss
6
-CSS_FILES = font.css toastr.css main.css videolayout_default.css font-awesome.css jquery-impromptu.css modaldialog.css notice.css popup_menu.css login_menu.css popover.css jitsi_popover.css contact_list.css chat.css welcome_page.css settingsmenu.css
6
+CSS_FILES = font.css toastr.css main.css videolayout_default.css font-awesome.css jquery-impromptu.css modaldialog.css notice.css popup_menu.css login_menu.css popover.css jitsi_popover.css contact_list.css chat.css welcome_page.css settingsmenu.css feedback.css
7
 DEPLOY_DIR = libs
7
 DEPLOY_DIR = libs
8
 BROWSERIFY_FLAGS = -d
8
 BROWSERIFY_FLAGS = -d
9
 OUTPUT_DIR = .
9
 OUTPUT_DIR = .
10
 
10
 
11
-all: compile uglify deploy clean 
11
+all: compile uglify deploy clean
12
 
12
 
13
 compile:
13
 compile:
14
 	$(NPM) update && $(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js
14
 	$(NPM) update && $(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js

+ 48
- 0
css/feedback.css View File

1
+/**
2
+ * The feedback window inner div css.
3
+ */
4
+.feedback {
5
+    width: 450px;
6
+    display: block;
7
+    margin-left: auto;
8
+    margin-right: auto;
9
+    text-align: center;
10
+    font-size: 22px;
11
+}
12
+
13
+/**
14
+ * Style of the thank you text inside the feedback window.
15
+ */
16
+.feedbackTitle {
17
+    font-size: 22px;
18
+    color: #087dba;
19
+}
20
+
21
+/**
22
+ * Stars div css.
23
+ */
24
+#stars {
25
+    font-size: 30px;
26
+}
27
+
28
+/**
29
+ * Star css.
30
+ */
31
+#stars>a {
32
+    padding-right: 4px;
33
+}
34
+
35
+/**
36
+ * Mouse over a star.
37
+ */
38
+.starHover {
39
+    color: #087dba;
40
+}
41
+
42
+/**
43
+ * Detailed feedback section text area style.
44
+ */
45
+.feedbackDetails textarea {
46
+    resize: vertical;
47
+    min-height: 100px;
48
+}

+ 26
- 2
css/main.css View File

10
     font-family:'Helvetica Neue', Helvetica, sans-serif;
10
     font-family:'Helvetica Neue', Helvetica, sans-serif;
11
     font-weight: 400;
11
     font-weight: 400;
12
     background: #000000;
12
     background: #000000;
13
-    overflow-x: hidden;
13
+    overflow: hidden;
14
 }
14
 }
15
 
15
 
16
 .right-panel {
16
 .right-panel {
236
     bottom: 5;
236
     bottom: 5;
237
     left: 5;
237
     left: 5;
238
     overflow: visible;
238
     overflow: visible;
239
-    z-index: 100;
240
     color: rgba(255,255,255,.50);
239
     color: rgba(255,255,255,.50);
241
 }
240
 }
242
 
241
 
242
+#feedbackButton {
243
+    position: absolute;
244
+    bottom: 60;
245
+    left: 60;
246
+    overflow: visible;
247
+    color: rgba(255,255,255,.50);
248
+}
249
+
250
+div.feedbackButton {
251
+    position: absolute;
252
+    background-color: rgba(0,0,0,.50);
253
+    border-radius: 50%;
254
+    width: 100px;
255
+    height: 100px;
256
+    bottom: -50px;
257
+    left: -50px;
258
+    z-index: 100;
259
+    overflow: hidden;
260
+    transition: all .2s ease-in-out;
261
+}
262
+
263
+div.feedbackButton:hover {
264
+    transform: scale(1.3);
265
+}
266
+
243
 #bottomToolbar {
267
 #bottomToolbar {
244
     display:block;
268
     display:block;
245
     position: absolute;
269
     position: absolute;

+ 5
- 2
index.html View File

14
     <script src="https://api.callstats.io/static/callstats.min.js"></script>
14
     <script src="https://api.callstats.io/static/callstats.min.js"></script>
15
     <script src="config.js?v=15"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
15
     <script src="config.js?v=15"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
16
     <script src="interface_config.js?v=6"></script>
16
     <script src="interface_config.js?v=6"></script>
17
-    <script src="libs/app.bundle.min.js?v=138"></script>
17
+    <script src="libs/app.bundle.min.js?v=139"></script>
18
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
18
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
19
     <!--
19
     <!--
20
         Link used for inline installation of chrome desktop streaming extension,
20
         Link used for inline installation of chrome desktop streaming extension,
218
                 </label>
218
                 </label>
219
             </div>
219
             </div>
220
             <button id="updateSettings" data-i18n="settings.update"></button>
220
             <button id="updateSettings" data-i18n="settings.update"></button>
221
+            <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>
222
+        </div>
223
+        <div class="feedbackButton">
224
+            <a id="feedbackButton" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[data-content]feedback"><i class="fa fa-heart"></i></a>
221
         </div>
225
         </div>
222
-        <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>
223
     </div>
226
     </div>
224
   </body>
227
   </body>
225
 </html>
228
 </html>

+ 5
- 1
lang/main.json View File

3
     "connectionsettings": "Connection Settings",
3
     "connectionsettings": "Connection Settings",
4
     "poweredby": "powered by",
4
     "poweredby": "powered by",
5
     "downloadlogs": "Download logs",
5
     "downloadlogs": "Download logs",
6
+    "feedback": "Give us your feedback",
6
     "roomUrlDefaultMsg": "Your conference is currently being created...",
7
     "roomUrlDefaultMsg": "Your conference is currently being created...",
7
     "participant": "Participant",
8
     "participant": "Participant",
8
     "me": "me",
9
     "me": "me",
197
         "tokenAuthFailed": "Failed to authenticate with XMPP server: invalid token",
198
         "tokenAuthFailed": "Failed to authenticate with XMPP server: invalid token",
198
         "displayNameRequired": "Please enter your display name:",
199
         "displayNameRequired": "Please enter your display name:",
199
         "extensionRequired": "Extension required:",
200
         "extensionRequired": "Extension required:",
200
-        "firefoxExtensionPrompt": "You need to install a Firefox extension in order to use screen sharing. Please try again after you <a href='__url__'>get it from here</a>!"
201
+        "firefoxExtensionPrompt": "You need to install a Firefox extension in order to use screen sharing. Please try again after you <a href='__url__'>get it from here</a>!",
202
+        "feedbackQuestion": "How was your call?",
203
+        "thankYou": "Thank you for using __appName__!",
204
+        "sorryFeedback": "We're sorry to hear that. Would you like to tell us more?"
201
     },
205
     },
202
     "email":
206
     "email":
203
     {
207
     {

+ 214
- 0
modules/UI/Feedback.js View File

1
+/**
2
+ * Created by ystamcheva on 2/10/15.
3
+ */
4
+/* jshint -W101 */
5
+var messageHandler = require("./util/MessageHandler");
6
+var callStats = require("../statistics/CallStats");
7
+var APP = require("../../app");
8
+
9
+/**
10
+ * Constructs the html for the overall feedback window.
11
+ *
12
+ * @returns {string} the constructed html string
13
+ */
14
+var constructOverallFeedbackHtml = function() {
15
+    var feedbackQuestion = (Feedback.feedbackScore < 0)
16
+        ? '<br/><br/>' + APP.translation
17
+        .translateString("dialog.feedbackQuestion")
18
+        : '';
19
+
20
+    var message = '<div class="feedback"><div>' +
21
+        '<div class="feedbackTitle">' +
22
+        APP.translation.translateString("dialog.thankYou",
23
+                                        {appName:interfaceConfig.APP_NAME}) +
24
+        '</div>' +
25
+        feedbackQuestion +
26
+        '</div><br/><br/>' +
27
+        '<div id="stars">' +
28
+        '<a><i class="fa fa-star-o fa fa-star"></i></a>' +
29
+        '<a><i class="fa fa-star-o fa fa-star"></i></a>' +
30
+        '<a><i class="fa fa-star-o fa fa-star"></i></a>' +
31
+        '<a><i class="fa fa-star-o fa fa-star"></i></a>' +
32
+        '<a><i class="fa fa-star-o fa fa-star"></i></a>' +
33
+        '</div></div>';
34
+
35
+    return message;
36
+};
37
+
38
+/**
39
+ * Constructs the html for the detailed feedback window.
40
+ *
41
+ * @returns {string} the contructed html string
42
+ */
43
+var constructDetailedFeedbackHtml = function() {
44
+    // Construct the html, which will be served as a dialog message.
45
+    var message = '<div class="feedback">' +
46
+        '<div class="feedbackTitle">' +
47
+        APP.translation.translateString("dialog.sorryFeedback") +
48
+        '</div><br/><br/>' +
49
+        '<div class="feedbackDetails">' +
50
+        '<textarea id="feedbackTextArea" rows="10" cols="50" autofocus>' +
51
+        '</textarea>' +
52
+        '</div></div>';
53
+
54
+    return message;
55
+};
56
+
57
+/**
58
+ * The callback function corresponding to the openFeedbackWindow parameter.
59
+ *
60
+ * @type {function}
61
+ */
62
+var feedbackWindowCallback = null;
63
+
64
+/**
65
+ * Defines all methods in connection to the Feedback window.
66
+ *
67
+ * @type {{feedbackScore: number, openFeedbackWindow: Function,
68
+ * toggleStars: Function, hoverStars: Function, unhoverStars: Function}}
69
+ */
70
+var Feedback = {
71
+    /**
72
+     * The feedback score. -1 indicates no score has been given for now.
73
+     */
74
+    feedbackScore: -1,
75
+    /**
76
+     * Opens the feedback window.
77
+     */
78
+    openFeedbackWindow: function (callback) {
79
+        feedbackWindowCallback = callback;
80
+        // Add all mouse and click listeners.
81
+        var onLoadFunction = function (event) {
82
+            $('#stars >a').each(function(index) {
83
+                // On star mouse over.
84
+                $(this).get(0).onmouseover = function(){
85
+                    Feedback.hoverStars(index);
86
+                };
87
+                // On star mouse leave.
88
+                $(this).get(0).onmouseleave = function(){
89
+                    Feedback.unhoverStars(index);
90
+                };
91
+                // On star click.
92
+                $(this).get(0).onclick = function(){
93
+                    Feedback.toggleStars(index);
94
+                    Feedback.feedbackScore = index+1;
95
+
96
+                    // If the feedback is less than 3 stars we're going to
97
+                    // ask the user for more information.
98
+                    if (Feedback.feedbackScore > 3) {
99
+                        callStats.sendFeedback(Feedback.feedbackScore, "");
100
+                        if (feedbackWindowCallback)
101
+                            feedbackWindowCallback();
102
+                        else
103
+                            APP.UI.messageHandler.closeDialog();
104
+                    }
105
+                    else {
106
+                        feedbackDialog.goToState('detailed_feedback');
107
+                    }
108
+                };
109
+                // Initialise stars to correspond to previously entered feedback.
110
+                if (Feedback.feedbackScore > 0
111
+                    && index < Feedback.feedbackScore) {
112
+                    Feedback.hoverStars(index);
113
+                    Feedback.toggleStars(index);
114
+                }
115
+            });
116
+        };
117
+
118
+        // Defines the different states of the feedback window.
119
+        var states = {
120
+            overall_feedback: {
121
+                html: constructOverallFeedbackHtml(),
122
+                persistent: true,
123
+                buttons: {},
124
+                closeText: '',
125
+                focus: "div[id='stars']",
126
+                position: {width: 500}
127
+            },
128
+            detailed_feedback: {
129
+                html: constructDetailedFeedbackHtml(),
130
+                buttons: {"Submit": true, "Cancel": false},
131
+                closeText: '',
132
+                focus: "textarea[id='feedbackTextArea']",
133
+                position: {width: 500},
134
+                submit: function(e,v,m,f) {
135
+                    e.preventDefault();
136
+                    if (v) {
137
+                        var feedbackDetails
138
+                            = document.getElementById("feedbackTextArea").value;
139
+
140
+                        if (feedbackDetails && feedbackDetails.length > 0)
141
+                            callStats.sendFeedback( Feedback.feedbackScore,
142
+                                                    feedbackDetails);
143
+
144
+                        if (feedbackWindowCallback)
145
+                            feedbackWindowCallback();
146
+                        else
147
+                            APP.UI.messageHandler.closeDialog();
148
+                    } else {
149
+                        // User cancelled
150
+                        if (feedbackWindowCallback)
151
+                            feedbackWindowCallback();
152
+                        else
153
+                            APP.UI.messageHandler.closeDialog();
154
+                    }
155
+                }
156
+            }
157
+        };
158
+
159
+        // Create the feedback dialog.
160
+        var feedbackDialog
161
+            = APP.UI.messageHandler.openDialogWithStates(
162
+                states,
163
+                {   persistent: true,
164
+                    buttons: {},
165
+                    closeText: '',
166
+                    loaded: onLoadFunction,
167
+                    position: {width: 500}}, null);
168
+    },
169
+    /**
170
+     * Toggles the appropriate css class for the given number of stars, to
171
+     * indicate that those stars have been clicked/selected.
172
+     *
173
+     * @param starCount the number of stars, for which to toggle the css class
174
+     */
175
+    toggleStars: function (starCount)
176
+    {
177
+        $('#stars >a >i').each(function(index) {
178
+            if (index <= starCount) {
179
+                $(this).removeClass("fa-star-o");
180
+            }
181
+            else
182
+                $(this).addClass("fa-star-o");
183
+        });
184
+    },
185
+    /**
186
+     * Toggles the appropriate css class for the given number of stars, to
187
+     * indicate that those stars have been hovered.
188
+     *
189
+     * @param starCount the number of stars, for which to toggle the css class
190
+     */
191
+    hoverStars: function (starCount)
192
+    {
193
+        $('#stars >a >i').each(function(index) {
194
+            if (index <= starCount)
195
+                $(this).addClass("starHover");
196
+        });
197
+    },
198
+    /**
199
+     * Toggles the appropriate css class for the given number of stars, to
200
+     * indicate that those stars have been un-hovered.
201
+     *
202
+     * @param starCount the number of stars, for which to toggle the css class
203
+     */
204
+    unhoverStars: function (starCount)
205
+    {
206
+        $('#stars >a >i').each(function(index) {
207
+            if (index <= starCount && $(this).hasClass("fa-star-o"))
208
+                $(this).removeClass("starHover");
209
+        });
210
+    }
211
+};
212
+
213
+// Exports the Feedback class.
214
+module.exports = Feedback;

+ 5
- 0
modules/UI/UI.js View File

33
 var StatisticsEvents = require("../../service/statistics/Events");
33
 var StatisticsEvents = require("../../service/statistics/Events");
34
 var UIEvents = require("../../service/UI/UIEvents");
34
 var UIEvents = require("../../service/UI/UIEvents");
35
 var MemberEvents = require("../../service/members/Events");
35
 var MemberEvents = require("../../service/members/Events");
36
+var Feedback = require("./Feedback");
36
 
37
 
37
 var eventEmitter = new EventEmitter();
38
 var eventEmitter = new EventEmitter();
38
 var roomNode = null;
39
 var roomNode = null;
423
         $("#downloadlog").click(function (event) {
424
         $("#downloadlog").click(function (event) {
424
             dump(event.target);
425
             dump(event.target);
425
         });
426
         });
427
+        $("#feedbackButton").click(function (event) {
428
+            Feedback.openFeedbackWindow();
429
+        });
426
     }
430
     }
427
     else
431
     else
428
     {
432
     {
429
         $("#header").css("display", "none");
433
         $("#header").css("display", "none");
430
         $("#bottomToolbar").css("display", "none");
434
         $("#bottomToolbar").css("display", "none");
435
+        $("#feedbackButton").css("display", "none");
431
         $("#downloadlog").css("display", "none");
436
         $("#downloadlog").css("display", "none");
432
         $("#remoteVideos").css("padding", "0px 0px 18px 0px");
437
         $("#remoteVideos").css("padding", "0px 0px 18px 0px");
433
         $("#remoteVideos").css("right", "0px");
438
         $("#remoteVideos").css("right", "0px");

+ 19
- 27
modules/UI/toolbars/Toolbar.js View File

11
 var AuthenticationEvents
11
 var AuthenticationEvents
12
     = require("../../../service/authentication/AuthenticationEvents");
12
     = require("../../../service/authentication/AuthenticationEvents");
13
 var AnalyticsAdapter = require("../../statistics/AnalyticsAdapter");
13
 var AnalyticsAdapter = require("../../statistics/AnalyticsAdapter");
14
+var Feedback = require("../Feedback");
14
 
15
 
15
 var roomUrl = null;
16
 var roomUrl = null;
16
 var sharedKey = '';
17
 var sharedKey = '';
135
     'hangup': '#toolbar_button_hangup'
136
     'hangup': '#toolbar_button_hangup'
136
 };
137
 };
137
 
138
 
139
+/**
140
+ * Hangs up this call.
141
+ */
138
 function hangup() {
142
 function hangup() {
139
-    APP.xmpp.disposeConference();
140
-    if(config.enableWelcomePage) {
141
-        setTimeout(function() {
142
-            window.localStorage.welcomePageDisabled = false;
143
-            window.location.pathname = "/";
144
-        }, 10000);
145
-
143
+    var conferenceDispose = function () {
144
+        APP.xmpp.disposeConference();
145
+
146
+        if (config.enableWelcomePage) {
147
+            setTimeout(function() {
148
+                window.localStorage.welcomePageDisabled = false;
149
+                window.location.pathname = "/";
150
+            }, 3000);
151
+        }
146
     }
152
     }
147
 
153
 
148
-    var title = APP.translation.generateTranslationHTML(
149
-        "dialog.sessTerminated");
150
-    var msg = APP.translation.generateTranslationHTML(
151
-        "dialog.hungUp");
152
-    var button = APP.translation.generateTranslationHTML(
153
-        "dialog.joinAgain");
154
-    var buttons = [];
155
-    buttons.push({title: button, value: true});
156
-
157
-    UI.messageHandler.openDialog(
158
-        title,
159
-        msg,
160
-        true,
161
-        buttons,
162
-        function(event, value, message, formVals) {
163
-            window.location.reload();
164
-            return false;
165
-        }
166
-    );
154
+    if (Feedback.feedbackScore > 0) {
155
+        Feedback.openFeedbackWindow();
156
+        conferenceDispose();
157
+    }
158
+    else
159
+        Feedback.openFeedbackWindow(conferenceDispose);
167
 }
160
 }
168
 
161
 
169
 /**
162
 /**
170
  * Starts or stops the recording for the conference.
163
  * Starts or stops the recording for the conference.
171
  */
164
  */
172
-
173
 function toggleRecording(predefinedToken) {
165
 function toggleRecording(predefinedToken) {
174
     APP.xmpp.toggleRecording(function (callback) {
166
     APP.xmpp.toggleRecording(function (callback) {
175
         if (predefinedToken) {
167
         if (predefinedToken) {

+ 2
- 1
modules/UI/util/MessageHandler.js View File

84
     };
84
     };
85
 
85
 
86
     /**
86
     /**
87
-     * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
87
+     * Shows a message to the user with two buttons: first is given as a
88
+     * parameter and the second is Cancel.
88
      *
89
      *
89
      * @param titleString the title of the message
90
      * @param titleString the title of the message
90
      * @param msgString the text of the message
91
      * @param msgString the text of the message

+ 20
- 1
modules/statistics/CallStats.js View File

77
         }
77
         }
78
         callStats.sendFabricEvent(this.peerconnection,
78
         callStats.sendFabricEvent(this.peerconnection,
79
             callStats.fabricEvent.fabricSetupFailed, this.confID);
79
             callStats.fabricEvent.fabricSetupFailed, this.confID);
80
-    }
80
+    },
81
+    /**
82
+     * Sends the given feedback through CallStats.
83
+     *
84
+     * @param overallFeedback an integer between 1 and 5 indicating the
85
+     * user feedback
86
+     * @param detailedFeedback detailed feedback from the user. Not yet used
87
+     */
88
+    sendFeedback: function(overallFeedback, detailedFeedback) {
89
+        if(!callStats) {
90
+            return;
91
+        }
92
+        var feedbackString =    '{"userID":"' + this.userID + '"' +
93
+                                ', "overall":' + overallFeedback +
94
+                                ', "comment": "' + detailedFeedback + '"}';
81
 
95
 
96
+        var feedbackJSON = JSON.parse(feedbackString);
97
+        
98
+        callStats.sendUserFeedback(
99
+            this.confID, feedbackJSON);
100
+    }
82
 };
101
 };
83
 module.exports = CallStats;
102
 module.exports = CallStats;

Loading…
Cancel
Save