Merge pull request #896 from jitsi/fix-feedback-dialog
Feedback dialog changes
This commit is contained in:
commit
298338f076
|
@ -69,6 +69,9 @@
|
||||||
.icon-exit-full-screen:before {
|
.icon-exit-full-screen:before {
|
||||||
content: "\e90c";
|
content: "\e90c";
|
||||||
}
|
}
|
||||||
|
.icon-star:before {
|
||||||
|
content: "\e916";
|
||||||
|
}
|
||||||
.icon-star-full:before {
|
.icon-star-full:before {
|
||||||
content: "\e90a";
|
content: "\e90a";
|
||||||
}
|
}
|
||||||
|
@ -105,9 +108,6 @@
|
||||||
.icon-settings:before {
|
.icon-settings:before {
|
||||||
content: "\e915";
|
content: "\e915";
|
||||||
}
|
}
|
||||||
.icon-star:before {
|
|
||||||
content: "\e916";
|
|
||||||
}
|
|
||||||
.icon-share-desktop:before {
|
.icon-share-desktop:before {
|
||||||
content: "\e917";
|
content: "\e917";
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,3 +62,15 @@ $defaultWatermarkLink: '../images/watermark.png';
|
||||||
*/
|
*/
|
||||||
$toolbarZ: 900;
|
$toolbarZ: 900;
|
||||||
$overlayZ: 800;
|
$overlayZ: 800;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Font Colors TODO: Change colors when general dialogs are implemented.
|
||||||
|
*/
|
||||||
|
$defaultFontColor: #777;
|
||||||
|
$defaultLightFontColor: #F1F1F1;
|
||||||
|
$defaultDarkFontColor: #000;
|
||||||
|
$buttonFontColor: #777;
|
||||||
|
$buttonHoverFontColor: #287ade;
|
||||||
|
$linkFontColor: #489afe;
|
||||||
|
$linkHoverFontColor: #287ade;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
@import 'toastr';
|
@import 'toastr';
|
||||||
@import 'base';
|
@import 'base';
|
||||||
@import 'overlay/overlay';
|
@import 'overlay/overlay';
|
||||||
|
@import 'modals/dialog';
|
||||||
|
@import 'modals/feedback/feedback';
|
||||||
@import 'videolayout_default';
|
@import 'videolayout_default';
|
||||||
@import 'jquery-impromptu';
|
@import 'jquery-impromptu';
|
||||||
@import 'modaldialog';
|
@import 'modaldialog';
|
||||||
|
@ -38,7 +40,6 @@
|
||||||
@import 'toolbars';
|
@import 'toolbars';
|
||||||
@import 'side_toolbar_container';
|
@import 'side_toolbar_container';
|
||||||
@import 'device_settings_dialog';
|
@import 'device_settings_dialog';
|
||||||
@import 'feedback';
|
|
||||||
@import 'jquery.contextMenu';
|
@import 'jquery.contextMenu';
|
||||||
@import 'keyboard-shortcuts';
|
@import 'keyboard-shortcuts';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
.dialog{
|
||||||
|
visibility: visible;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: $defaultDarkFontColor;
|
||||||
|
}
|
||||||
|
.aui-dialog2-content:last-child {
|
||||||
|
border-bottom-right-radius: 5px;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
}
|
||||||
|
.aui-dialog2-content:first-child {
|
||||||
|
border-top-right-radius: 5px;
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
}
|
||||||
|
.aui-dialog2-footer{
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.aui-button {
|
||||||
|
height: 36px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent!important;
|
||||||
|
border-left: solid 1px #e4e4e4;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
&_close {
|
||||||
|
color: $defaultFontColor;
|
||||||
|
}
|
||||||
|
&_submit {
|
||||||
|
color: $linkFontColor;
|
||||||
|
&:hover {
|
||||||
|
color: $linkHoverFontColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.shake-rotate {
|
.shake-rotate {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
-webkit-animation-duration: .4s;
|
-webkit-animation-duration: .4s;
|
||||||
animation-duration: .4s;
|
animation-duration: .4s;
|
||||||
-webkit-animation-iteration-count: infinite;
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
@ -43,65 +45,65 @@
|
||||||
animation-timing-function: ease-in-out
|
animation-timing-function: ease-in-out
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-center {
|
.feedback {
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedbackDetails textarea {
|
|
||||||
resize: vertical;
|
|
||||||
min-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback-rating {
|
|
||||||
line-height: 1.2;
|
|
||||||
padding: 20px 0;
|
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
padding: auto;
|
|
||||||
margin: auto;
|
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-top: 10px;
|
font-weight: 400;
|
||||||
margin-left: 0px;
|
font-size: 14px;
|
||||||
margin-bottom: 0px;
|
|
||||||
margin-right: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.star-label {
|
&__content {
|
||||||
font-size: 16px;
|
text-align: center;
|
||||||
color: $rateStarLabelColor;
|
|
||||||
}
|
}
|
||||||
|
&__footer {
|
||||||
|
|
||||||
.star-btn {
|
|
||||||
color: $rateStarDefault;
|
|
||||||
font-size: 36px;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
text-decoration: none;
|
|
||||||
@include transition(all .2s ease);
|
|
||||||
|
|
||||||
&.starHover,
|
|
||||||
&.active,
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $rateStarActivity;
|
color: #287ade;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__rating {
|
||||||
|
line-height: 1.2;
|
||||||
|
padding: 20px 0;
|
||||||
|
|
||||||
.fa {
|
p {
|
||||||
top: -6px;
|
margin: 10px 0 0;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
&.rated:hover .fa {
|
|
||||||
top: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa {
|
.star-label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: $rateStarLabelColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.star-btn {
|
||||||
|
color: $rateStarDefault;
|
||||||
|
font-size: 36px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
@include transition(all .2s ease);
|
||||||
|
|
||||||
|
&.starHover,
|
||||||
|
&.active,
|
||||||
|
&:hover {
|
||||||
|
color: $rateStarActivity;
|
||||||
|
> i:before {
|
||||||
|
content: "\e90a";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__details {
|
||||||
|
text-align: left;
|
||||||
|
textarea {
|
||||||
|
min-height: 100px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -262,5 +262,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="aui-feedback-dialog" class="dialog feedback aui-layer aui-dialog2 aui-dialog2-medium" style="display: none;"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -38,5 +38,7 @@ var interfaceConfig = {
|
||||||
LOCAL_THUMBNAIL_RATIO_WIDTH: 16,
|
LOCAL_THUMBNAIL_RATIO_WIDTH: 16,
|
||||||
LOCAL_THUMBNAIL_RATIO_HEIGHT: 9,
|
LOCAL_THUMBNAIL_RATIO_HEIGHT: 9,
|
||||||
REMOTE_THUMBNAIL_RATIO_WIDTH: 1,
|
REMOTE_THUMBNAIL_RATIO_WIDTH: 1,
|
||||||
REMOTE_THUMBNAIL_RATIO_HEIGHT: 1
|
REMOTE_THUMBNAIL_RATIO_HEIGHT: 1,
|
||||||
|
// Enables feedback star animation.
|
||||||
|
ENABLE_FEEDBACK_ANIMATION: false
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,326 +0,0 @@
|
||||||
/* global $, APP, config, interfaceConfig, JitsiMeetJS */
|
|
||||||
import UIEvents from "../../service/UI/UIEvents";
|
|
||||||
import UIUtil from "./util/UIUtil";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the html for the overall feedback window.
|
|
||||||
*
|
|
||||||
* @returns {string} the constructed html string
|
|
||||||
*/
|
|
||||||
var constructOverallFeedbackHtml = function() {
|
|
||||||
var feedbackQuestion = (Feedback.feedbackScore < 0)
|
|
||||||
? '<br/><br/>' + APP.translation
|
|
||||||
.translateString("dialog.feedbackQuestion")
|
|
||||||
: '';
|
|
||||||
|
|
||||||
var message = '<div class="feedback"><div>' +
|
|
||||||
'<div class="feedbackTitle">' +
|
|
||||||
APP.translation.translateString("dialog.thankYou",
|
|
||||||
{appName:interfaceConfig.APP_NAME}) +
|
|
||||||
'</div>' +
|
|
||||||
feedbackQuestion +
|
|
||||||
'</div><br/><br/>' +
|
|
||||||
'<div id="stars">' +
|
|
||||||
'<a><i class="icon-star icon-star-full"></i></a>' +
|
|
||||||
'<a><i class="icon-star icon-star-full"></i></a>' +
|
|
||||||
'<a><i class="icon-star icon-star-full"></i></a>' +
|
|
||||||
'<a><i class="icon-star icon-star-full"></i></a>' +
|
|
||||||
'<a><i class="icon-star icon-star-full"></i></a>' +
|
|
||||||
'</div></div>';
|
|
||||||
|
|
||||||
return message;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the html for the detailed feedback window.
|
|
||||||
*
|
|
||||||
* @returns {string} the contructed html string
|
|
||||||
*/
|
|
||||||
var constructDetailedFeedbackHtml = function() {
|
|
||||||
// Construct the html, which will be served as a dialog message.
|
|
||||||
var message = '<div class="feedback">' +
|
|
||||||
'<div class="feedbackTitle">' +
|
|
||||||
APP.translation.translateString("dialog.sorryFeedback") +
|
|
||||||
'</div><br/><br/>' +
|
|
||||||
'<div class="feedbackDetails">' +
|
|
||||||
'<textarea id="feedbackTextArea" rows="10" cols="50" autofocus>' +
|
|
||||||
'</textarea>' +
|
|
||||||
'</div></div>';
|
|
||||||
|
|
||||||
return message;
|
|
||||||
};
|
|
||||||
|
|
||||||
var createRateFeedbackHTML = function () {
|
|
||||||
var rate = APP.translation.translateString('dialog.rateExperience'),
|
|
||||||
help = APP.translation.translateString('dialog.feedbackHelp');
|
|
||||||
|
|
||||||
return `
|
|
||||||
<div class="feedback-rating text-center">
|
|
||||||
<h2>${ rate }</h2>
|
|
||||||
<p class="star-label"> </p>
|
|
||||||
<div id="stars" class="feedback-stars">
|
|
||||||
<a class="star-btn">
|
|
||||||
<i class="fa fa-star shake-rotate"></i>
|
|
||||||
</a>
|
|
||||||
<a class="star-btn">
|
|
||||||
<i class="fa fa-star shake-rotate"></i>
|
|
||||||
</a>
|
|
||||||
<a class="star-btn">
|
|
||||||
<i class="fa fa-star shake-rotate"></i>
|
|
||||||
</a>
|
|
||||||
<a class="star-btn">
|
|
||||||
<i class="fa fa-star shake-rotate"></i>
|
|
||||||
</a>
|
|
||||||
<a class="star-btn">
|
|
||||||
<i class="fa fa-star shake-rotate"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<p> </p>
|
|
||||||
<p>${ help }</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The callback function corresponding to the openFeedbackWindow parameter.
|
|
||||||
*
|
|
||||||
* @type {function}
|
|
||||||
*/
|
|
||||||
var feedbackWindowCallback = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows / hides the feedback button.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function _toggleFeedbackIcon() {
|
|
||||||
$('#feedbackButtonDiv').toggleClass("hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows / hides the feedback button.
|
|
||||||
* @param {show} set to {true} to show the feedback button or to {false}
|
|
||||||
* to hide it
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function _showFeedbackButton (show) {
|
|
||||||
var feedbackButton = $("#feedbackButtonDiv");
|
|
||||||
|
|
||||||
if (show)
|
|
||||||
feedbackButton.css("display", "block");
|
|
||||||
else
|
|
||||||
feedbackButton.css("display", "none");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines all methods in connection to the Feedback window.
|
|
||||||
*
|
|
||||||
* @type {{feedbackScore: number, openFeedbackWindow: Function,
|
|
||||||
* toggleStars: Function, hoverStars: Function, unhoverStars: Function}}
|
|
||||||
*/
|
|
||||||
var Feedback = {
|
|
||||||
/**
|
|
||||||
* The feedback score. -1 indicates no score has been given for now.
|
|
||||||
*/
|
|
||||||
feedbackScore: -1,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise the Feedback functionality.
|
|
||||||
* @param emitter the EventEmitter to associate with the Feedback.
|
|
||||||
*/
|
|
||||||
init: function (emitter) {
|
|
||||||
// CallStats is the way we send feedback, so we don't have to initialise
|
|
||||||
// if callstats isn't enabled.
|
|
||||||
if (!APP.conference.isCallstatsEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If enabled property is still undefined, i.e. it hasn't been set from
|
|
||||||
// some other module already, we set it to true by default.
|
|
||||||
if (typeof this.enabled == "undefined")
|
|
||||||
this.enabled = true;
|
|
||||||
|
|
||||||
_showFeedbackButton(this.enabled);
|
|
||||||
|
|
||||||
let $feedbackButton = $("#feedbackButton");
|
|
||||||
|
|
||||||
$feedbackButton.click(function (event) {
|
|
||||||
Feedback.openFeedbackWindow();
|
|
||||||
});
|
|
||||||
|
|
||||||
UIUtil.setTooltip($feedbackButton.get(0), 'feedback', 'right');
|
|
||||||
|
|
||||||
// Show / hide the feedback button whenever the film strip is
|
|
||||||
// shown / hidden.
|
|
||||||
emitter.addListener(UIEvents.TOGGLE_FILM_STRIP, function () {
|
|
||||||
_toggleFeedbackIcon();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Enables/ disabled the feedback feature.
|
|
||||||
*/
|
|
||||||
enableFeedback: function (enable) {
|
|
||||||
if (this.enabled !== enable)
|
|
||||||
_showFeedbackButton(enable);
|
|
||||||
this.enabled = enable;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the feedback functionality is enabled.
|
|
||||||
*
|
|
||||||
* @return true if the feedback functionality is enabled, false otherwise.
|
|
||||||
*/
|
|
||||||
isEnabled: function() {
|
|
||||||
return this.enabled && APP.conference.isCallstatsEnabled();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the feedback window is currently visible and false
|
|
||||||
* otherwise.
|
|
||||||
* @return {boolean} true if the feedback window is visible, false
|
|
||||||
* otherwise
|
|
||||||
*/
|
|
||||||
isVisible: function() {
|
|
||||||
return $(".feedback").is(":visible");
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the feedback window.
|
|
||||||
*/
|
|
||||||
openFeedbackWindow: function (callback) {
|
|
||||||
feedbackWindowCallback = callback;
|
|
||||||
// Add all mouse and click listeners.
|
|
||||||
var onLoadFunction = function (event) {
|
|
||||||
$('#stars >a').each(function(index) {
|
|
||||||
// On star mouse over.
|
|
||||||
$(this).get(0).onmouseover = function(){
|
|
||||||
Feedback.hoverStars(index);
|
|
||||||
};
|
|
||||||
// On star mouse leave.
|
|
||||||
$(this).get(0).onmouseleave = function(){
|
|
||||||
Feedback.unhoverStars(index);
|
|
||||||
};
|
|
||||||
// On star click.
|
|
||||||
$(this).get(0).onclick = function(){
|
|
||||||
Feedback.toggleStars(index);
|
|
||||||
Feedback.feedbackScore = index+1;
|
|
||||||
|
|
||||||
// If the feedback is less than 3 stars we're going to
|
|
||||||
// ask the user for more information.
|
|
||||||
if (Feedback.feedbackScore > 3) {
|
|
||||||
APP.conference.sendFeedback(Feedback.feedbackScore, "");
|
|
||||||
if (feedbackWindowCallback)
|
|
||||||
feedbackWindowCallback();
|
|
||||||
else
|
|
||||||
APP.UI.messageHandler.closeDialog();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
feedbackDialog.goToState('detailed_feedback');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Init stars to correspond to previously entered feedback.
|
|
||||||
if (Feedback.feedbackScore > 0
|
|
||||||
&& index < Feedback.feedbackScore) {
|
|
||||||
Feedback.hoverStars(index);
|
|
||||||
Feedback.toggleStars(index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Defines the different states of the feedback window.
|
|
||||||
var states = {
|
|
||||||
overall_feedback: {
|
|
||||||
html: createRateFeedbackHTML(),
|
|
||||||
persistent: false,
|
|
||||||
buttons: {},
|
|
||||||
closeText: '',
|
|
||||||
focus: "div[id='stars']",
|
|
||||||
position: {width: 500}
|
|
||||||
},
|
|
||||||
detailed_feedback: {
|
|
||||||
html: constructDetailedFeedbackHtml(),
|
|
||||||
buttons: {"Submit": true, "Cancel": false},
|
|
||||||
closeText: '',
|
|
||||||
focus: "textarea[id='feedbackTextArea']",
|
|
||||||
position: {width: 500},
|
|
||||||
submit: function(e,v,m,f) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (v) {
|
|
||||||
var feedbackDetails
|
|
||||||
= document.getElementById("feedbackTextArea").value;
|
|
||||||
|
|
||||||
if (feedbackDetails && feedbackDetails.length > 0) {
|
|
||||||
APP.conference.sendFeedback( Feedback.feedbackScore,
|
|
||||||
feedbackDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feedbackWindowCallback)
|
|
||||||
feedbackWindowCallback();
|
|
||||||
else
|
|
||||||
APP.UI.messageHandler.closeDialog();
|
|
||||||
} else {
|
|
||||||
// User cancelled
|
|
||||||
if (feedbackWindowCallback)
|
|
||||||
feedbackWindowCallback();
|
|
||||||
else
|
|
||||||
APP.UI.messageHandler.closeDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the feedback dialog.
|
|
||||||
var feedbackDialog
|
|
||||||
= APP.UI.messageHandler.openDialogWithStates(
|
|
||||||
states,
|
|
||||||
{ persistent: false,
|
|
||||||
buttons: {},
|
|
||||||
closeText: '',
|
|
||||||
loaded: onLoadFunction,
|
|
||||||
position: {width: 500}}, null);
|
|
||||||
JitsiMeetJS.analytics.sendEvent('feedback.open');
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Toggles the appropriate css class for the given number of stars, to
|
|
||||||
* indicate that those stars have been clicked/selected.
|
|
||||||
*
|
|
||||||
* @param starCount the number of stars, for which to toggle the css class
|
|
||||||
*/
|
|
||||||
toggleStars: function (starCount)
|
|
||||||
{
|
|
||||||
$('#stars >a >i').each(function(index) {
|
|
||||||
if (index <= starCount) {
|
|
||||||
$(this).removeClass("icon-star");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
$(this).addClass("icon-star");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Toggles the appropriate css class for the given number of stars, to
|
|
||||||
* indicate that those stars have been hovered.
|
|
||||||
*
|
|
||||||
* @param starCount the number of stars, for which to toggle the css class
|
|
||||||
*/
|
|
||||||
hoverStars: function (starCount)
|
|
||||||
{
|
|
||||||
$('#stars >a >i').each(function(index) {
|
|
||||||
if (index <= starCount)
|
|
||||||
$(this).addClass("starHover");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Toggles the appropriate css class for the given number of stars, to
|
|
||||||
* indicate that those stars have been un-hovered.
|
|
||||||
*
|
|
||||||
* @param starCount the number of stars, for which to toggle the css class
|
|
||||||
*/
|
|
||||||
unhoverStars: function (starCount)
|
|
||||||
{
|
|
||||||
$('#stars >a >i').each(function(index) {
|
|
||||||
if (index <= starCount && $(this).hasClass("icon-star"))
|
|
||||||
$(this).removeClass("starHover");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Exports the Feedback class.
|
|
||||||
module.exports = Feedback;
|
|
|
@ -29,7 +29,7 @@ var EventEmitter = require("events");
|
||||||
UI.messageHandler = require("./util/MessageHandler");
|
UI.messageHandler = require("./util/MessageHandler");
|
||||||
var messageHandler = UI.messageHandler;
|
var messageHandler = UI.messageHandler;
|
||||||
var JitsiPopover = require("./util/JitsiPopover");
|
var JitsiPopover = require("./util/JitsiPopover");
|
||||||
var Feedback = require("./Feedback");
|
var Feedback = require("./feedback/Feedback");
|
||||||
|
|
||||||
import FollowMe from "../FollowMe";
|
import FollowMe from "../FollowMe";
|
||||||
|
|
||||||
|
@ -1126,7 +1126,7 @@ UI.requestFeedback = function () {
|
||||||
if (Feedback.isEnabled()) {
|
if (Feedback.isEnabled()) {
|
||||||
// If the user has already entered feedback, we'll show the
|
// If the user has already entered feedback, we'll show the
|
||||||
// window and immidiately start the conference dispose timeout.
|
// window and immidiately start the conference dispose timeout.
|
||||||
if (Feedback.feedbackScore > 0) {
|
if (Feedback.getFeedbackScore() > 0) {
|
||||||
Feedback.openFeedbackWindow();
|
Feedback.openFeedbackWindow();
|
||||||
resolve();
|
resolve();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* global $, APP, config, interfaceConfig, JitsiMeetJS */
|
||||||
|
import UIEvents from "../../../service/UI/UIEvents";
|
||||||
|
import FeedabckWindow from "./FeedbackWindow";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows / hides the feedback button.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function _toggleFeedbackIcon() {
|
||||||
|
$('#feedbackButtonDiv').toggleClass("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows / hides the feedback button.
|
||||||
|
* @param {show} set to {true} to show the feedback button or to {false}
|
||||||
|
* to hide it
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function _showFeedbackButton (show) {
|
||||||
|
var feedbackButton = $("#feedbackButtonDiv");
|
||||||
|
|
||||||
|
if (show)
|
||||||
|
feedbackButton.css("display", "block");
|
||||||
|
else
|
||||||
|
feedbackButton.css("display", "none");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines all methods in connection to the Feedback window.
|
||||||
|
*
|
||||||
|
* @type {{openFeedbackWindow: Function}}
|
||||||
|
*/
|
||||||
|
var Feedback = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the Feedback functionality.
|
||||||
|
* @param emitter the EventEmitter to associate with the Feedback.
|
||||||
|
*/
|
||||||
|
init: function (emitter) {
|
||||||
|
// CallStats is the way we send feedback, so we don't have to initialise
|
||||||
|
// if callstats isn't enabled.
|
||||||
|
if (!APP.conference.isCallstatsEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If enabled property is still undefined, i.e. it hasn't been set from
|
||||||
|
// some other module already, we set it to true by default.
|
||||||
|
if (typeof this.enabled == "undefined")
|
||||||
|
this.enabled = true;
|
||||||
|
|
||||||
|
_showFeedbackButton(this.enabled);
|
||||||
|
|
||||||
|
this.window = new FeedabckWindow({});
|
||||||
|
|
||||||
|
$("#feedbackButton").click(Feedback.openFeedbackWindow);
|
||||||
|
|
||||||
|
// Show / hide the feedback button whenever the film strip is
|
||||||
|
// shown / hidden.
|
||||||
|
emitter.addListener(UIEvents.TOGGLE_FILM_STRIP, function () {
|
||||||
|
_toggleFeedbackIcon();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Enables/ disabled the feedback feature.
|
||||||
|
*/
|
||||||
|
enableFeedback: function (enable) {
|
||||||
|
if (this.enabled !== enable)
|
||||||
|
_showFeedbackButton(enable);
|
||||||
|
this.enabled = enable;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the feedback functionality is enabled.
|
||||||
|
*
|
||||||
|
* @return true if the feedback functionality is enabled, false otherwise.
|
||||||
|
*/
|
||||||
|
isEnabled: function() {
|
||||||
|
return this.enabled && APP.conference.isCallstatsEnabled();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the feedback window is currently visible and false
|
||||||
|
* otherwise.
|
||||||
|
* @return {boolean} true if the feedback window is visible, false
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
isVisible: function() {
|
||||||
|
return $(".feedback").is(":visible");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the feedback window.
|
||||||
|
*/
|
||||||
|
openFeedbackWindow: function (callback) {
|
||||||
|
Feedback.window.show(callback);
|
||||||
|
|
||||||
|
JitsiMeetJS.analytics.sendEvent('feedback.open');
|
||||||
|
},
|
||||||
|
|
||||||
|
getFeedbackScore: function() {
|
||||||
|
return Feedback.window.feedbackScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Feedback;
|
|
@ -0,0 +1,223 @@
|
||||||
|
/* global $, APP, interfaceConfig, AJS */
|
||||||
|
/* jshint -W101 */
|
||||||
|
|
||||||
|
const selector = '#aui-feedback-dialog';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the appropriate css class for the given number of stars, to
|
||||||
|
* indicate that those stars have been clicked/selected.
|
||||||
|
*
|
||||||
|
* @param starCount the number of stars, for which to toggle the css class
|
||||||
|
*/
|
||||||
|
let toggleStars = function(starCount) {
|
||||||
|
$('#stars > a').each(function(index, el) {
|
||||||
|
if (index <= starCount) {
|
||||||
|
el.classList.add("starHover");
|
||||||
|
} else
|
||||||
|
el.classList.remove("starHover");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the html for the detailed feedback window.
|
||||||
|
*
|
||||||
|
* @returns {string} the contructed html string
|
||||||
|
*/
|
||||||
|
let constructDetailedFeedbackHtml = function() {
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="aui-dialog2-content feedback__content">
|
||||||
|
<div class="feedback__details">
|
||||||
|
<p>${APP.translation.translateString("dialog.sorryFeedback")}</p>
|
||||||
|
<br/><br/>
|
||||||
|
<textarea id="feedbackTextArea" rows="10" cols="50" autofocus></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="aui-dialog2-footer feedback__footer">
|
||||||
|
<div class="aui-dialog2-footer-actions">
|
||||||
|
<button id="dialog-close-button" class="aui-button aui-button_close">Close</button>
|
||||||
|
<button id="dialog-submit-button" class="aui-button aui-button_submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the html for the rated feedback window.
|
||||||
|
*
|
||||||
|
* @returns {string} the contructed html string
|
||||||
|
*/
|
||||||
|
let createRateFeedbackHTML = function (Feedback) {
|
||||||
|
let rateExperience
|
||||||
|
= APP.translation.translateString('dialog.rateExperience'),
|
||||||
|
feedbackHelp = APP.translation.translateString('dialog.feedbackHelp'),
|
||||||
|
feedbackQuestion = (Feedback.feedbackScore < 0)
|
||||||
|
? `<p><br/>${APP.translation.translateString('dialog.feedbackQuestion')}</p>`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
let starClassName = (interfaceConfig.ENABLE_FEEDBACK_ANIMATION)
|
||||||
|
? "icon-star shake-rotate"
|
||||||
|
: "icon-star";
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="aui-dialog2-content feedback__content">
|
||||||
|
${feedbackQuestion}
|
||||||
|
<form action="javascript:false;" onsubmit="return false;">
|
||||||
|
<div class="feedback__rating">
|
||||||
|
<h2>${ rateExperience }</h2>
|
||||||
|
<p class="star-label"> </p>
|
||||||
|
<div id="stars" class="feedback-stars">
|
||||||
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<p> </p>
|
||||||
|
<p>${ feedbackHelp }</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for Rate Feedback
|
||||||
|
*
|
||||||
|
* @param Feedback
|
||||||
|
*/
|
||||||
|
let onLoadRateFunction = function (Feedback) {
|
||||||
|
$('#stars > a').each((index, el) => {
|
||||||
|
el.onmouseover = function(){
|
||||||
|
toggleStars(index);
|
||||||
|
};
|
||||||
|
el.onmouseleave = function(){
|
||||||
|
toggleStars(Feedback.feedbackScore - 1);
|
||||||
|
};
|
||||||
|
el.onclick = function(){
|
||||||
|
Feedback.feedbackScore = index + 1;
|
||||||
|
|
||||||
|
// If the feedback is less than 3 stars we're going to
|
||||||
|
// ask the user for more information.
|
||||||
|
if (Feedback.feedbackScore > 3) {
|
||||||
|
APP.conference.sendFeedback(Feedback.feedbackScore, "");
|
||||||
|
Feedback.hide();
|
||||||
|
} else {
|
||||||
|
Feedback.setState('detailed_feedback');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Init stars to correspond to previously entered feedback.
|
||||||
|
if (Feedback.feedbackScore > 0) {
|
||||||
|
toggleStars(Feedback.feedbackScore - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for Detailed Feedback
|
||||||
|
*
|
||||||
|
* @param Feedback
|
||||||
|
*/
|
||||||
|
let onLoadDetailedFunction = function(Feedback) {
|
||||||
|
let submitBtn = Feedback.$el.find('#dialog-submit-button');
|
||||||
|
let closeBtn = Feedback.$el.find('#dialog-close-button');
|
||||||
|
|
||||||
|
if (submitBtn && submitBtn.length) {
|
||||||
|
submitBtn.on('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
Feedback.onFeedbackSubmitted();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (closeBtn && closeBtn.length) {
|
||||||
|
closeBtn.on('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
Feedback.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#feedbackTextArea').focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Dialog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export default class Dialog {
|
||||||
|
|
||||||
|
constructor(options) {
|
||||||
|
this.feedbackScore = -1;
|
||||||
|
this.onCloseCallback = null;
|
||||||
|
|
||||||
|
this.states = {
|
||||||
|
rate_feedback: {
|
||||||
|
getHtml: createRateFeedbackHTML,
|
||||||
|
onLoad: onLoadRateFunction
|
||||||
|
},
|
||||||
|
detailed_feedback: {
|
||||||
|
getHtml: constructDetailedFeedbackHtml,
|
||||||
|
onLoad: onLoadDetailedFunction
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.state = options.state || 'rate_feedback';
|
||||||
|
|
||||||
|
this.window = AJS.dialog2(selector, {
|
||||||
|
closeOnOutsideClick: true
|
||||||
|
});
|
||||||
|
this.$el = this.window.$el;
|
||||||
|
|
||||||
|
this.setState();
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(state) {
|
||||||
|
let newState = state || this.state;
|
||||||
|
|
||||||
|
let htmlStr = this.states[newState].getHtml(this);
|
||||||
|
|
||||||
|
this.$el.html(htmlStr);
|
||||||
|
|
||||||
|
this.states[newState].onLoad(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
show(cb) {
|
||||||
|
this.setState('rate_feedback');
|
||||||
|
if (typeof cb == 'function') {
|
||||||
|
this.onCloseCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.window.show();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.window.hide();
|
||||||
|
|
||||||
|
if (this.onCloseCallback) {
|
||||||
|
this.onCloseCallback();
|
||||||
|
this.onCloseCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFeedbackSubmitted() {
|
||||||
|
let message = this.$el.find('textarea').val();
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
if (message && message.length > 0) {
|
||||||
|
APP.conference.sendFeedback(
|
||||||
|
self.feedbackScore,
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from "../../../service/UI/UIEvents";
|
||||||
import UIUtil from '../util/UIUtil';
|
import UIUtil from '../util/UIUtil';
|
||||||
import VideoLayout from '../videolayout/VideoLayout';
|
import VideoLayout from '../videolayout/VideoLayout';
|
||||||
import Feedback from '../Feedback.js';
|
import Feedback from '../feedback/Feedback.js';
|
||||||
import Toolbar from '../toolbars/Toolbar';
|
import Toolbar from '../toolbars/Toolbar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,7 +24,7 @@ const FilmStrip = {
|
||||||
*/
|
*/
|
||||||
toggleFilmStrip (visible) {
|
toggleFilmStrip (visible) {
|
||||||
if (typeof visible === 'boolean'
|
if (typeof visible === 'boolean'
|
||||||
&& this.isFilmStripVisible() == visible) {
|
&& this.isFilmStripVisible() == visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ const FilmStrip = {
|
||||||
var eventEmitter = this.eventEmitter;
|
var eventEmitter = this.eventEmitter;
|
||||||
if (eventEmitter) {
|
if (eventEmitter) {
|
||||||
eventEmitter.emit(
|
eventEmitter.emit(
|
||||||
UIEvents.TOGGLED_FILM_STRIP,
|
UIEvents.TOGGLED_FILM_STRIP,
|
||||||
this.isFilmStripVisible());
|
this.isFilmStripVisible());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ const FilmStrip = {
|
||||||
/**
|
/**
|
||||||
* Normalizes local and remote thumbnail ratios
|
* Normalizes local and remote thumbnail ratios
|
||||||
*/
|
*/
|
||||||
normalizeThumbnailRatio () {
|
normalizeThumbnailRatio () {
|
||||||
let remoteHeightRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_HEIGHT;
|
let remoteHeightRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_HEIGHT;
|
||||||
let remoteWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_WIDTH;
|
let remoteWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_WIDTH;
|
||||||
|
|
||||||
|
@ -120,11 +120,11 @@ const FilmStrip = {
|
||||||
*/
|
*/
|
||||||
let videoAreaAvailableWidth
|
let videoAreaAvailableWidth
|
||||||
= UIUtil.getAvailableVideoWidth()
|
= UIUtil.getAvailableVideoWidth()
|
||||||
- UIUtil.parseCssInt(this.filmStrip.css('right'), 10)
|
- UIUtil.parseCssInt(this.filmStrip.css('right'), 10)
|
||||||
- UIUtil.parseCssInt(this.filmStrip.css('paddingLeft'), 10)
|
- UIUtil.parseCssInt(this.filmStrip.css('paddingLeft'), 10)
|
||||||
- UIUtil.parseCssInt(this.filmStrip.css('paddingRight'), 10)
|
- UIUtil.parseCssInt(this.filmStrip.css('paddingRight'), 10)
|
||||||
- UIUtil.parseCssInt(this.filmStrip.css('borderLeftWidth'), 10)
|
- UIUtil.parseCssInt(this.filmStrip.css('borderLeftWidth'), 10)
|
||||||
- UIUtil.parseCssInt(this.filmStrip.css('borderRightWidth'), 10)
|
- UIUtil.parseCssInt(this.filmStrip.css('borderRightWidth'), 10)
|
||||||
- 5;
|
- 5;
|
||||||
|
|
||||||
let availableWidth = videoAreaAvailableWidth;
|
let availableWidth = videoAreaAvailableWidth;
|
||||||
|
|
Loading…
Reference in New Issue